From f4db1adc84bf09c9e0addc213d818daf5df64d7a Mon Sep 17 00:00:00 2001 From: spalger Date: Sat, 25 Jan 2020 05:19:26 -0700 Subject: [PATCH 01/83] build immutable bundles for new platform plugins --- .browserslistrc | 5 + .github/CODEOWNERS | 1 + package.json | 27 +- .../serializers/absolute_path_serializer.ts | 4 +- .../package.json | 2 +- packages/kbn-interpreter/package.json | 10 +- packages/kbn-optimizer/README.md | 100 + .../kbn-optimizer/babel.config.js | 9 +- .../kbn-optimizer/index.d.ts | 2 +- packages/kbn-optimizer/package.json | 44 + .../mock_repo/plugins/bar/kibana.json | 4 + .../mock_repo/plugins/bar}/public/index.ts | 5 +- .../mock_repo/plugins/bar/public/lib.ts | 10 +- .../mock_repo/plugins/baz/kibana.json | 3 + .../mock_repo/plugins/baz/server/index.ts | 20 + .../mock_repo/plugins/baz/server/lib.ts | 22 + .../mock_repo/plugins/foo/kibana.json | 4 + .../mock_repo/plugins/foo/public/ext.ts | 20 + .../mock_repo/plugins/foo/public/index.ts | 21 + .../mock_repo/plugins/foo/public/lib.ts | 22 + .../test_plugins/test_baz/kibana.json | 3 + .../test_plugins/test_baz/server/index.ts | 20 + .../test_plugins/test_baz/server/lib.ts | 22 + .../src/assign_bundles_to_workers.test.ts | 268 + .../src/assign_bundles_to_workers.ts | 162 + packages/kbn-optimizer/src/cli.ts | 103 + packages/kbn-optimizer/src/closure.ts | 40 + .../src/common/bundle_definition.ts | 34 + .../src/common/compiler_messages.ts | 98 + packages/kbn-optimizer/src/common/index.ts | 23 + .../kbn-optimizer/src/common/worker_config.ts | 101 + .../src/common/worker_messages.ts | 64 + .../src/get_bundle_definitions.test.ts | 68 + .../src/get_bundle_definitions.ts | 28 +- packages/kbn-optimizer/src/index.ts | 23 + .../basic_optimization.test.ts.snap | 430 + .../basic_optimization.test.ts | 109 + packages/kbn-optimizer/src/log.ts | 24 + .../src/log_optimizer_state.test.ts | 124 + .../kbn-optimizer/src/log_optimizer_state.ts | 96 + .../src/new_platform_plugins.test.ts | 60 + .../kbn-optimizer/src/new_platform_plugins.ts | 69 + packages/kbn-optimizer/src/observe_worker.ts | 168 + packages/kbn-optimizer/src/optimizer.ts | 121 + packages/kbn-optimizer/src/optimizer_cache.ts | 100 + .../src/optimizer_config.test.ts | 379 + .../kbn-optimizer/src/optimizer_config.ts | 161 + .../src/worker/block_legacy_code_plugin.ts | 89 + .../src/worker/postcss.config.js | 22 + .../kbn-optimizer/src/worker/run_worker.ts | 208 + .../kbn-optimizer/src/worker/theme_loader.ts | 32 + .../src/worker/webpack.config.ts | 240 + .../src/worker/webpack_helpers.ts | 66 + packages/kbn-optimizer/tsconfig.json | 7 + .../integration_tests/generate_plugin.test.js | 33 +- packages/kbn-pm/dist/index.js | 9371 ++++++++++------- packages/kbn-pm/package.json | 6 +- packages/kbn-storybook/package.json | 2 +- .../kbn-test/src/functional_tests/tasks.js | 9 + packages/kbn-ui-framework/package.json | 12 +- packages/kbn-ui-shared-deps/package.json | 4 +- renovate.json5 | 8 + scripts/build_new_platform_plugins.js | 20 + src/cli/cluster/cluster_manager.test.ts | 139 +- src/cli/cluster/cluster_manager.ts | 235 +- src/cli/cluster/log.ts | 56 + src/cli/cluster/run_kbn_optimizer.ts | 57 + src/cli/cluster/worker.test.ts | 4 +- src/cli/cluster/worker.ts | 1 + src/cli/command.js | 4 +- src/cli/serve/serve.js | 2 +- src/core/public/plugins/plugin_loader.test.ts | 10 +- src/core/public/plugins/plugin_loader.ts | 2 +- .../server/http/base_path_proxy_server.ts | 57 +- src/core/server/legacy/legacy_service.test.ts | 2 +- .../server/plugins/plugins_service.test.ts | 7 +- src/core/server/plugins/plugins_service.ts | 5 +- src/core/server/plugins/types.ts | 6 +- src/core/server/server.api.md | 2 +- src/dev/build/build_distributables.js | 2 + .../build/tasks/build_new_platform_plugins.js | 39 + src/dev/build/tasks/index.js | 1 + .../dashboard_embeddable_container/index.ts | 8 +- .../public/index.scss | 3 - src/legacy/core_plugins/data/index.ts | 1 - .../core_plugins/data/public/index.scss | 3 - .../core_plugins/embeddable_api/index.ts | 7 +- .../embeddable_api/public/index.scss | 3 - .../core_plugins/inspector_views/package.json | 4 - .../inspector_views/public/index.scss | 4 - src/legacy/core_plugins/interpreter/index.ts | 1 - .../interpreter/public/index.scss | 4 - .../core_plugins/navigation/package.json | 4 - .../core_plugins/navigation/public/index.scss | 3 - src/legacy/server/sass/build.js | 20 +- src/legacy/server/sass/build_all.js | 4 +- .../ui/ui_exports/ui_export_defaults.js | 3 - .../ui/ui_render/bootstrap/template.js.hbs | 46 +- src/legacy/ui/ui_render/ui_render_mixin.js | 1 + src/optimize/base_optimizer.js | 33 +- .../no_placeholder/no_placeholder.plugin.js | 20 + .../plugin/placeholder/placeholder.plugin.js | 20 + src/optimize/bundles_route/bundles_route.js | 14 +- src/optimize/index.js | 6 +- src/optimize/intentionally_empty_module.js | 18 + .../np_ui_plugin_public_dirs.js} | 42 +- src/optimize/watch/optmzr_role.js | 5 +- src/optimize/watch/watch_optimizer.js | 3 +- src/optimize/watch/watch_server.js | 5 +- .../public/index.ts | 2 + src/plugins/data/public/index.ts | 2 + .../ui/filter_bar/filter_editor/_index.scss | 2 +- src/plugins/embeddable/public/index.ts | 2 + src/plugins/expressions/public/index.ts | 2 + src/plugins/inspector/public/index.ts | 2 + src/plugins/navigation/public/index.ts | 2 + .../services/dashboard/add_panel.js | 23 +- .../test_suites/core_plugins/rendering.ts | 4 +- test/scripts/jenkins_build_kibana.sh | 6 + test/scripts/jenkins_xpack_build_kibana.sh | 5 + vars/kibanaPipeline.groovy | 1 + x-pack/index.js | 4 - .../legacy/plugins/apm/cypress/package.json | 2 +- .../shareable_runtime/webpack.config.js | 11 +- x-pack/legacy/plugins/searchprofiler/index.ts | 27 - .../plugins/searchprofiler/public/index.scss | 12 - .../legacy/plugins/security/public/index.scss | 5 - x-pack/legacy/plugins/watcher/index.ts | 19 - x-pack/package.json | 4 +- .../plugins/searchprofiler/public/README.md | 3 - x-pack/plugins/searchprofiler/public/index.ts | 1 + .../searchprofiler/public/styles/_index.scss | 0 .../searchprofiler/public/styles/_mixins.scss | 0 .../components/_highlight_details_flyout.scss | 0 .../styles/components/_percentage_badge.scss | 0 .../styles/components/_profile_tree.scss | 0 .../public/styles/containers/_main.scss | 0 .../containers/_profile_query_editor.scss | 0 x-pack/plugins/security/public/_index.scss | 2 + x-pack/plugins/security/public/index.ts | 1 + .../plugins/watcher/public/index.scss | 3 - x-pack/plugins/watcher/public/index.ts | 2 + yarn.lock | 545 +- 143 files changed, 10508 insertions(+), 4464 deletions(-) create mode 100644 packages/kbn-optimizer/README.md rename src/cli/color.js => packages/kbn-optimizer/babel.config.js (84%) rename webpackShims/tinymath.js => packages/kbn-optimizer/index.d.ts (93%) create mode 100644 packages/kbn-optimizer/package.json create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json rename {src/legacy/core_plugins/navigation => packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar}/public/index.ts (79%) rename src/legacy/core_plugins/inspector_views/index.js => packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/lib.ts (80%) create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/kibana.json create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/index.ts create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/lib.ts create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/ext.ts create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/index.ts create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/lib.ts create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/server/index.ts create mode 100644 packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/server/lib.ts create mode 100644 packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts create mode 100644 packages/kbn-optimizer/src/assign_bundles_to_workers.ts create mode 100644 packages/kbn-optimizer/src/cli.ts create mode 100644 packages/kbn-optimizer/src/closure.ts create mode 100644 packages/kbn-optimizer/src/common/bundle_definition.ts create mode 100644 packages/kbn-optimizer/src/common/compiler_messages.ts create mode 100644 packages/kbn-optimizer/src/common/index.ts create mode 100644 packages/kbn-optimizer/src/common/worker_config.ts create mode 100644 packages/kbn-optimizer/src/common/worker_messages.ts create mode 100644 packages/kbn-optimizer/src/get_bundle_definitions.test.ts rename src/cli/log.js => packages/kbn-optimizer/src/get_bundle_definitions.ts (60%) create mode 100644 packages/kbn-optimizer/src/index.ts create mode 100644 packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap create mode 100644 packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts create mode 100644 packages/kbn-optimizer/src/log.ts create mode 100644 packages/kbn-optimizer/src/log_optimizer_state.test.ts create mode 100644 packages/kbn-optimizer/src/log_optimizer_state.ts create mode 100644 packages/kbn-optimizer/src/new_platform_plugins.test.ts create mode 100644 packages/kbn-optimizer/src/new_platform_plugins.ts create mode 100644 packages/kbn-optimizer/src/observe_worker.ts create mode 100644 packages/kbn-optimizer/src/optimizer.ts create mode 100644 packages/kbn-optimizer/src/optimizer_cache.ts create mode 100644 packages/kbn-optimizer/src/optimizer_config.test.ts create mode 100644 packages/kbn-optimizer/src/optimizer_config.ts create mode 100644 packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts create mode 100644 packages/kbn-optimizer/src/worker/postcss.config.js create mode 100644 packages/kbn-optimizer/src/worker/run_worker.ts create mode 100644 packages/kbn-optimizer/src/worker/theme_loader.ts create mode 100644 packages/kbn-optimizer/src/worker/webpack.config.ts create mode 100644 packages/kbn-optimizer/src/worker/webpack_helpers.ts create mode 100644 packages/kbn-optimizer/tsconfig.json create mode 100644 scripts/build_new_platform_plugins.js create mode 100644 src/cli/cluster/log.ts create mode 100644 src/cli/cluster/run_kbn_optimizer.ts create mode 100644 src/dev/build/tasks/build_new_platform_plugins.js delete mode 100644 src/legacy/core_plugins/dashboard_embeddable_container/public/index.scss delete mode 100644 src/legacy/core_plugins/data/public/index.scss delete mode 100644 src/legacy/core_plugins/embeddable_api/public/index.scss delete mode 100644 src/legacy/core_plugins/inspector_views/package.json delete mode 100644 src/legacy/core_plugins/inspector_views/public/index.scss delete mode 100644 src/legacy/core_plugins/interpreter/public/index.scss delete mode 100644 src/legacy/core_plugins/navigation/package.json delete mode 100644 src/legacy/core_plugins/navigation/public/index.scss create mode 100644 src/optimize/bundles_route/__tests__/fixtures/plugin/no_placeholder/no_placeholder.plugin.js create mode 100644 src/optimize/bundles_route/__tests__/fixtures/plugin/placeholder/placeholder.plugin.js create mode 100644 src/optimize/intentionally_empty_module.js rename src/{legacy/core_plugins/navigation/index.ts => optimize/np_ui_plugin_public_dirs.js} (53%) delete mode 100644 x-pack/legacy/plugins/searchprofiler/index.ts delete mode 100644 x-pack/legacy/plugins/searchprofiler/public/index.scss delete mode 100644 x-pack/legacy/plugins/watcher/index.ts delete mode 100644 x-pack/plugins/searchprofiler/public/README.md rename x-pack/{legacy => }/plugins/searchprofiler/public/styles/_index.scss (100%) rename x-pack/{legacy => }/plugins/searchprofiler/public/styles/_mixins.scss (100%) rename x-pack/{legacy => }/plugins/searchprofiler/public/styles/components/_highlight_details_flyout.scss (100%) rename x-pack/{legacy => }/plugins/searchprofiler/public/styles/components/_percentage_badge.scss (100%) rename x-pack/{legacy => }/plugins/searchprofiler/public/styles/components/_profile_tree.scss (100%) rename x-pack/{legacy => }/plugins/searchprofiler/public/styles/containers/_main.scss (100%) rename x-pack/{legacy => }/plugins/searchprofiler/public/styles/containers/_profile_query_editor.scss (100%) rename x-pack/{legacy => }/plugins/watcher/public/index.scss (80%) diff --git a/.browserslistrc b/.browserslistrc index a788f9544ab8a..d74cd2310c939 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -1,3 +1,8 @@ +[production] last 2 versions > 5% Safari 7 # for PhantomJS support: https://github.com/elastic/kibana/issues/27136 + +[dev] +last 1 chrome versions +last 1 firefox versions diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ba468c5a2d989..6c15cbbfcda42 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -91,6 +91,7 @@ /packages/*babel*/ @elastic/kibana-operations /packages/kbn-dev-utils*/ @elastic/kibana-operations /packages/kbn-es/ @elastic/kibana-operations +/packages/kbn-optimizer/ @elastic/kibana-operations /packages/kbn-pm/ @elastic/kibana-operations /packages/kbn-test/ @elastic/kibana-operations /packages/kbn-ui-shared-deps/ @elastic/kibana-operations diff --git a/package.json b/package.json index 9707d3863d295..1de2d32b3c134 100644 --- a/package.json +++ b/package.json @@ -137,12 +137,6 @@ "@kbn/test-subj-selector": "0.2.1", "@kbn/ui-framework": "1.0.0", "@kbn/ui-shared-deps": "1.0.0", - "@types/flot": "^0.0.31", - "@types/json-stable-stringify": "^1.0.32", - "@types/lodash.clonedeep": "^4.5.4", - "@types/node-forge": "^0.9.0", - "@types/react-grid-layout": "^0.16.7", - "@types/recompose": "^0.30.5", "JSONStream": "1.3.5", "abortcontroller-polyfill": "^1.3.0", "angular": "^1.7.9", @@ -152,11 +146,12 @@ "angular-route": "^1.7.8", "angular-sanitize": "^1.7.8", "angular-sortable-view": "^0.0.17", - "autoprefixer": "9.6.1", + "autoprefixer": "^9.7.4", "babel-loader": "^8.0.6", "bluebird": "3.5.5", "boom": "^7.2.0", "brace": "0.11.1", + "browserslist-useragent": "^3.0.2", "cache-loader": "^4.1.0", "chalk": "^2.4.2", "check-disk-space": "^2.1.0", @@ -165,7 +160,7 @@ "commander": "3.0.2", "compare-versions": "3.5.1", "core-js": "^3.2.1", - "css-loader": "2.1.1", + "css-loader": "^3.4.2", "d3": "3.5.17", "d3-cloud": "1.2.5", "deep-freeze-strict": "^1.1.1", @@ -226,7 +221,7 @@ "opn": "^5.5.0", "oppsy": "^2.0.0", "pegjs": "0.10.0", - "postcss-loader": "3.0.0", + "postcss-loader": "^3.0.0", "prop-types": "15.6.0", "proxy-from-env": "1.0.0", "pug": "^2.0.4", @@ -259,7 +254,7 @@ "seedrandom": "^3.0.5", "semver": "^5.5.0", "style-it": "^2.1.3", - "style-loader": "0.23.1", + "style-loader": "^1.1.3", "symbol-observable": "^1.2.0", "tar": "4.4.13", "terser-webpack-plugin": "^2.1.2", @@ -279,7 +274,7 @@ "vega-schema-url-parser": "1.0.0", "vega-tooltip": "^0.12.0", "vision": "^5.3.3", - "webpack": "4.41.0", + "webpack": "^4.41.5", "webpack-merge": "4.2.2", "whatwg-fetch": "^3.0.0", "wrapper-webpack-plugin": "^2.1.0", @@ -300,6 +295,7 @@ "@kbn/eslint-plugin-eslint": "1.0.0", "@kbn/expect": "1.0.0", "@kbn/plugin-generator": "1.0.0", + "@kbn/optimizer": "1.0.0", "@kbn/test": "1.0.0", "@kbn/utility-types": "1.0.0", "@microsoft/api-documenter": "7.7.2", @@ -312,6 +308,7 @@ "@types/babel__core": "^7.1.2", "@types/bluebird": "^3.1.1", "@types/boom": "^7.2.0", + "@types/browserslist-useragent": "^3.0.0", "@types/chance": "^1.0.0", "@types/cheerio": "^0.22.10", "@types/chromedriver": "^2.38.0", @@ -324,6 +321,7 @@ "@types/enzyme": "^3.9.0", "@types/eslint": "^6.1.3", "@types/fetch-mock": "^7.3.1", + "@types/flot": "^0.0.31", "@types/getopts": "^2.0.1", "@types/glob": "^7.1.1", "@types/globby": "^8.0.0", @@ -337,10 +335,12 @@ "@types/joi": "^13.4.2", "@types/jquery": "^3.3.31", "@types/js-yaml": "^3.11.1", + "@types/json-stable-stringify": "^1.0.32", "@types/json5": "^0.0.30", "@types/license-checker": "15.0.0", "@types/listr": "^0.14.0", "@types/lodash": "^3.10.1", + "@types/lodash.clonedeep": "^4.5.4", "@types/lru-cache": "^5.1.0", "@types/markdown-it": "^0.0.7", "@types/minimatch": "^2.0.29", @@ -348,6 +348,7 @@ "@types/moment-timezone": "^0.5.12", "@types/mustache": "^0.8.31", "@types/node": "^10.12.27", + "@types/node-forge": "^0.9.0", "@types/numeral": "^0.0.26", "@types/opn": "^5.1.0", "@types/pegjs": "^0.10.1", @@ -357,11 +358,13 @@ "@types/reach__router": "^1.2.6", "@types/react": "^16.9.11", "@types/react-dom": "^16.9.4", + "@types/react-grid-layout": "^0.16.7", "@types/react-redux": "^6.0.6", "@types/react-resize-detector": "^4.0.1", "@types/react-router": "^5.1.3", "@types/react-router-dom": "^5.1.3", "@types/react-virtualized": "^9.18.7", + "@types/recompose": "^0.30.6", "@types/redux": "^3.6.31", "@types/redux-actions": "^2.6.1", "@types/request": "^2.48.2", @@ -460,7 +463,7 @@ "pixelmatch": "^5.1.0", "pkg-up": "^2.0.0", "pngjs": "^3.4.0", - "postcss": "^7.0.5", + "postcss": "^7.0.26", "postcss-url": "^8.0.0", "prettier": "^1.19.1", "proxyquire": "1.8.0", diff --git a/packages/kbn-dev-utils/src/serializers/absolute_path_serializer.ts b/packages/kbn-dev-utils/src/serializers/absolute_path_serializer.ts index 661ed7329347f..9edc63dd7d842 100644 --- a/packages/kbn-dev-utils/src/serializers/absolute_path_serializer.ts +++ b/packages/kbn-dev-utils/src/serializers/absolute_path_serializer.ts @@ -17,7 +17,9 @@ * under the License. */ -export function createAbsolutePathSerializer(rootPath: string) { +import { REPO_ROOT } from '../repo_root'; + +export function createAbsolutePathSerializer(rootPath: string = REPO_ROOT) { return { print: (value: string) => value.replace(rootPath, '').replace(/\\/g, '/'), test: (value: any) => typeof value === 'string' && value.startsWith(rootPath), diff --git a/packages/kbn-eslint-import-resolver-kibana/package.json b/packages/kbn-eslint-import-resolver-kibana/package.json index 9fae27011767e..332f7e8a20cc2 100755 --- a/packages/kbn-eslint-import-resolver-kibana/package.json +++ b/packages/kbn-eslint-import-resolver-kibana/package.json @@ -16,6 +16,6 @@ "glob-all": "^3.1.0", "lru-cache": "^4.1.5", "resolve": "^1.7.1", - "webpack": "^4.41.0" + "webpack": "^4.41.5" } } diff --git a/packages/kbn-interpreter/package.json b/packages/kbn-interpreter/package.json index 27ef70d871856..d3dc0cff248fc 100644 --- a/packages/kbn-interpreter/package.json +++ b/packages/kbn-interpreter/package.json @@ -23,15 +23,15 @@ "@kbn/dev-utils": "1.0.0", "babel-loader": "^8.0.6", "copy-webpack-plugin": "^5.0.4", - "css-loader": "2.1.1", + "css-loader": "^3.4.2", "del": "^5.1.0", "getopts": "^2.2.4", "pegjs": "0.10.0", - "sass-loader": "^7.3.1", - "style-loader": "0.23.1", + "sass-loader": "^8.0.2", + "style-loader": "^1.1.3", "supports-color": "^7.0.0", "url-loader": "2.2.0", - "webpack": "4.41.0", - "webpack-cli": "^3.3.9" + "webpack": "^4.41.5", + "webpack-cli": "^3.3.10" } } diff --git a/packages/kbn-optimizer/README.md b/packages/kbn-optimizer/README.md new file mode 100644 index 0000000000000..65ce1637faea4 --- /dev/null +++ b/packages/kbn-optimizer/README.md @@ -0,0 +1,100 @@ +# @kbn/optimizer + +`@kbn/optimizer` is a package for building new platform UI plugins (and hopefully more soon). + +New Platform plugins with `"ui": true` in their `kibana.json` file will have their `public/index.ts` file (and all of its dependencies) bundled into the `target/public` directory of the plugin. The build output does not need to be updated when other plugins are updated and is included in the distributable without requiring that we ship `@kbn/optimizer` 🎉. + +## Webpack config + +The [Webpack config][WebpackConfig] is designed to provide the majority of what was available in the legacy optimizer and is the same for all plugins to promote consistency and keep things sane for the operations team. It has support for JS/TS built with babel, url imports of image and font files, and support for importing `scss` and `css` files. SCSS is pre-processed by [postcss][PostCss], built for both light and dark mode and injected automatically into the page when the parent module is loaded (page reloads are still required for switching between light/dark mode). CSS is injected into the DOM as it is written on disk when the parent module is loaded (no postcss support). + +Source maps are enabled execpt when building the distributable. They show the code actually being executed by the browser to strike a balance between debuggability and performance. They are not configurable at this time but will be configurable once we have a developer configuration solution that doesn't rely on the server (see [#55656](https://github.com/elastic/kibana/issues/55656)). + +### IE Support + +To make front-end code easier to debug the optimizer uses the `BROWSERSLIST_ENV=dev` environment variable (by default) to build JS and CSS that is compatible with modern browsers. In order to support older browsers like IE in development you will need to specify the `BROWSERSLIST_ENV=production` environment variable or build a distributable for testing. + +## Running the optimizer + +The `@kbn/optimizer` is automatically executed from the dev cli, the Kibana build scripts, and in CI. If you're running Kibana locally in some other way you might need to build the plugins manually, which you can do by running `node scripts/build_new_platform_plugins` (pass `--help` for options). + +## API + +To run the optimizer from code, you can import the [`Optimizer`][Optimizer] and [`OptimizerConfig`][OptimizerConfig] classes. Create an [`OptimizerConfig`][OptimizerConfig] instance by calling it's static `create()` method with some options, then pass it to the [`Optimizer`][Optimizer] constructor. Calling `Optimizer#run()` will return an observable of [`OptimizerState`][Optimizer] objects, which are either bits of stdio from the workers or [`OptimizerStateSummary`][Optimizer] objects. You can use the [`logOptimizerState()`][LogOptimizerState] helper to write the relevant bits of state to a tooling log. + +Example: +```ts +import { Optimizer, OptimizerConfig, logOptimizerState } from '@kbn/optimizer'; +import { REPO_ROOT, ToolingLog } from '@kbn/dev-utils'; + +const log = new ToolingLog({ + level: 'verbose', + writeTo: process.stdout, +}) + +const config = OptimizerConfig.create({ + repoRoot: Path.resolve(__dirname, '../../..'), + watch: false, + oss: true, + dist: true +}); + +const optimizer = new Optimizer(config); + +await optimizer + .run() + .pipe(logOptimizerState(log, config)) + .toPromise(); +``` + +This is essentially what we're doing in [`the build_new_platform_plugins script`][Cli] and the new [build system task][BuildTask]. + +## Internals + +The optimizer runs webpack instances in worker processes. Each worker is configured to build one or more plugins via a [`WorkerConfig`][WorkerConfig] object (created by [`OptimizerConfig`][OptimizerConfig]) which is JSON serialized and passed to the worker as it's only argument. + +Plugins/bundles are assigned to workers based on the number of modules historically seen in each bundle in an effort to evenly distribute the load across the worker pool (see [`assignBundlesToWorkers`][AssignBundlesToWorkers]). + +The number of workers available is automatically chosen by dividing the number of cores available by 3 (minimum of 2). + +The [`WorkerConfig`][WorkerConfig] includes the location of the repo (it might be one of many builds, or the main repo), wether we are running in watch mode, wether we are building a distributable, and a list of [`BundleDefinition`][BundleDefinition] objects which include the details necessary to create a webpack config for a specific plugin's bundle (created using [`webpack.config.ts`][WebpackConfig]). + +Each worker communicates state back to the main process by sending [`WorkerMessage`][WorkerMessage] and [`CompilerMessage`][CompilerMessage] objects using IPC. + +The Optimizer captures all of these messages and produces a stream of [`OptimizerStateSummary`][Optimizer] and [`WorkerStdio`][ObserveWorker] objects. Workers shouldn't produce any data on their stdio streams, but when they do it's probably because something is wrong so make sure to show them to users somehow. All other messages represent the total state of all workers. + +```ts +interface OptimizerStateSummary { + type: 'running' | 'compiler issue' | 'compiler success'; + durSec: number; + bundles: BundleState[]; +} +``` + +Optimizer state summary types: +
+
'running'
+
Emitted when any worker is in a running state. To determine which compilers are running, look for BundleState objects with type 'running'.
+
'compiler issue'
+
Emitted when all workers are done running and any compiler completed with a 'compiler issue' status. Compiler issues include things like "unable to resolve module" or syntax errors in the source modules and can be fixed by users when running in watch mode.
+
'compiler success'
+
Emitted when all workers are done running and all compilers completed with 'compiler success'.
+
+ +Workers have several error message they may emit which indicate unrecoverable errors. When any of those messages are received the stream will error and the workers will be torn down. + +For an example of how to handle these states checkout the [`logOptimizerState()`][LogOptimizerState] helper. + +[PostCss]: https://postcss.org/ +[Cli]: src/cli.ts +[Optimizer]: src/optimizer.ts +[ObserveWorker]: src/observe_worker.ts +[CompilerMessage]: src/common/compiler_messages.ts +[WorkerMessage]: src/common/worker_messages.ts +[WebpackConfig]: src/worker/webpack.config.ts +[BundleDefinition]: src/common/bundle_definition.ts +[WorkerConfig]: src/common/worker_config.ts +[OptimizerConfig]: src/optimizer_config.ts +[LogOptimizerState]: src/log_optimizer_state.ts +[AssignBundlesToWorkers]: src/assign_bundles_to_workers.ts +[BuildTask]: ../../src/dev/build/tasks/build_new_platform_plugins.js \ No newline at end of file diff --git a/src/cli/color.js b/packages/kbn-optimizer/babel.config.js similarity index 84% rename from src/cli/color.js rename to packages/kbn-optimizer/babel.config.js index a02fb551c4181..ff657603f4c8d 100644 --- a/src/cli/color.js +++ b/packages/kbn-optimizer/babel.config.js @@ -17,8 +17,7 @@ * under the License. */ -import chalk from 'chalk'; - -export const green = chalk.black.bgGreen; -export const red = chalk.white.bgRed; -export const yellow = chalk.black.bgYellow; +module.exports = { + presets: ['@kbn/babel-preset/node_preset'], + ignore: ['**/*.test.js'], +}; diff --git a/webpackShims/tinymath.js b/packages/kbn-optimizer/index.d.ts similarity index 93% rename from webpackShims/tinymath.js rename to packages/kbn-optimizer/index.d.ts index 45aa86a6ef64a..aa55df9215c2f 100644 --- a/webpackShims/tinymath.js +++ b/packages/kbn-optimizer/index.d.ts @@ -17,4 +17,4 @@ * under the License. */ -module.exports = require('tinymath/lib/tinymath.es5.js'); +export * from './src/index'; diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json new file mode 100644 index 0000000000000..30b9af2e1475e --- /dev/null +++ b/packages/kbn-optimizer/package.json @@ -0,0 +1,44 @@ +{ + "name": "@kbn/optimizer", + "version": "1.0.0", + "private": true, + "license": "Apache-2.0", + "main": "./target/index.js", + "scripts": { + "build": "babel src --out-dir target --copy-files --delete-dir-on-start --extensions .ts --ignore *.test.ts --source-maps=inline", + "kbn:bootstrap": "yarn build", + "kbn:watch": "yarn build --watch" + }, + "dependencies": { + "@babel/cli": "^7.5.5", + "@kbn/babel-preset": "1.0.0", + "@kbn/dev-utils": "1.0.0", + "@kbn/ui-shared-deps": "1.0.0", + "@types/loader-utils": "^1.1.3", + "@types/webpack": "^4.41.3", + "autoprefixer": "^9.7.4", + "babel-loader": "^8.0.6", + "clean-webpack-plugin": "^3.0.0", + "cpy": "^8.0.0", + "css-loader": "^3.4.2", + "del": "^5.1.0", + "file-loader": "^4.2.0", + "is-path-inside": "^3.0.2", + "istanbul-instrumenter-loader": "^3.0.1", + "jest-raw-loader": "^1.0.1", + "loader-utils": "^1.2.3", + "node-sass": "^4.13.0", + "postcss-loader": "^3.0.0", + "raw-loader": "^3.1.0", + "rxjs": "^6.5.3", + "sass-loader": "^8.0.2", + "script-loader": "^0.7.2", + "style-loader": "^1.1.3", + "terser-webpack-plugin": "^2.1.2", + "tinymath": "1.2.1", + "url-loader": "^2.2.0", + "val-loader": "^1.1.1", + "webpack": "^4.41.5", + "webpack-merge": "^4.2.2" + } +} \ No newline at end of file diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json new file mode 100644 index 0000000000000..20c8046daa65e --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/kibana.json @@ -0,0 +1,4 @@ +{ + "id": "bar", + "ui": true +} diff --git a/src/legacy/core_plugins/navigation/public/index.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts similarity index 79% rename from src/legacy/core_plugins/navigation/public/index.ts rename to packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts index 7ddb4819cdb3a..12e580bbb76b3 100644 --- a/src/legacy/core_plugins/navigation/public/index.ts +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts @@ -17,7 +17,4 @@ * under the License. */ -// TODO these are imports from the old plugin world. -// Once the new platform is ready, they can get removed -// and handled by the platform itself in the setup method -// of the ExpressionExectorService +export * from './lib'; diff --git a/src/legacy/core_plugins/inspector_views/index.js b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/lib.ts similarity index 80% rename from src/legacy/core_plugins/inspector_views/index.js rename to packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/lib.ts index a37b6bb3db426..091fae72ad635 100644 --- a/src/legacy/core_plugins/inspector_views/index.js +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/lib.ts @@ -17,12 +17,6 @@ * under the License. */ -import { resolve } from 'path'; - -export default function(kibana) { - return new kibana.Plugin({ - uiExports: { - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - }, - }); +export function barLibFn() { + return 'bar'; } diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/kibana.json new file mode 100644 index 0000000000000..6e4e9c70a115c --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/kibana.json @@ -0,0 +1,3 @@ +{ + "id": "baz" +} diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/index.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/index.ts new file mode 100644 index 0000000000000..12e580bbb76b3 --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/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 * from './lib'; diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/lib.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/lib.ts new file mode 100644 index 0000000000000..870e5a8045280 --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz/server/lib.ts @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export function bazLibFn() { + return 'baz'; +} diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json new file mode 100644 index 0000000000000..256856181ccd8 --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/kibana.json @@ -0,0 +1,4 @@ +{ + "id": "foo", + "ui": true +} diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/ext.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/ext.ts new file mode 100644 index 0000000000000..3064d6814e2b1 --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/ext.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 const ext = 'TRUE'; diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/index.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/index.ts new file mode 100644 index 0000000000000..9d3871df24739 --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/index.ts @@ -0,0 +1,21 @@ +/* + * 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 * from './lib'; +export * from './ext'; diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/lib.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/lib.ts new file mode 100644 index 0000000000000..04a8c7e5b1eec --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo/public/lib.ts @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export function fooLibFn() { + return 'foo'; +} diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json b/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json new file mode 100644 index 0000000000000..b9e044523a6a5 --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/kibana.json @@ -0,0 +1,3 @@ +{ + "id": "test_baz" +} diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/server/index.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/server/index.ts new file mode 100644 index 0000000000000..12e580bbb76b3 --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/server/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 * from './lib'; diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/server/lib.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/server/lib.ts new file mode 100644 index 0000000000000..870e5a8045280 --- /dev/null +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz/server/lib.ts @@ -0,0 +1,22 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export function bazLibFn() { + return 'baz'; +} diff --git a/packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts b/packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts new file mode 100644 index 0000000000000..54c4e7cfd77a1 --- /dev/null +++ b/packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts @@ -0,0 +1,268 @@ +/* + * 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 { getBundleDefinitions } from './get_bundle_definitions'; +import { OptimizerCache } from './optimizer_cache'; +import { assignBundlesToWorkers, Worker, Options } from './assign_bundles_to_workers'; +import { BundleDefinition } from './common'; + +const REPO = '/repo'; +const BIG_BUNDLES = 'dqv'.split(''); +const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'.split(''); +const pluginsWithCounts = (n: number) => + ALPHABET.slice(0, n).map(id => ({ + directory: `/repo/plugins/${id}`, + id, + isUiPlugin: true, + })); + +const pluginsWithoutCounts = (n: number) => + ' ' + .repeat(n) + .split('') + .map((_, i) => `foo${i + 1}`) + .map(id => ({ + directory: `/repo/plugins/${id}`, + id, + isUiPlugin: true, + })); + +const cache = new OptimizerCache(false); +jest + .spyOn(cache, 'getBundleModuleCount') + .mockImplementation(id => + ALPHABET.includes(id) + ? (ALPHABET.indexOf(id) + 1) * (BIG_BUNDLES.includes(id) ? 10 : 1) + : undefined + ); + +const moduleCount = (b: BundleDefinition) => cache.getBundleModuleCount(b.id); +const hasModuleCount = (b: BundleDefinition) => moduleCount(b) !== undefined; +const noModuleCount = (b: BundleDefinition) => moduleCount(b) === undefined; +const summarizeBundles = (w: Worker) => + [ + w.moduleCount ? `${w.moduleCount} known modules` : '', + w.newBundles ? `${w.newBundles} new bundles` : '', + ] + .filter(Boolean) + .join(', '); + +const readConfigs = (workers: Worker[]) => + workers.map( + (w, i) => `worker ${i} (${summarizeBundles(w)}) => ${w.config.bundles.map(b => b.id).join(',')}` + ); + +const assertReturnVal = (workers: Worker[]) => { + expect(workers).toBeInstanceOf(Array); + for (const worker of workers) { + expect(worker).toEqual({ + moduleCount: expect.any(Number), + newBundles: expect.any(Number), + config: { + repoRoot: REPO, + watch: expect.any(Boolean), + dist: expect.any(Boolean), + profileWebpack: expect.any(Boolean), + bundles: expect.any(Array), + }, + }); + + expect(worker.config.bundles.filter(noModuleCount).length).toBe(worker.newBundles); + expect( + worker.config.bundles.filter(hasModuleCount).reduce((sum, b) => sum + moduleCount(b)!, 0) + ).toBe(worker.moduleCount); + } +}; + +const defaultOptions: Omit = { + maxWorkerCount: 4, + watch: false, + dist: false, + cache, + repoRoot: REPO, + profileWebpack: false, +}; + +it('creates less workers if maxWorkersCount is larger than bundle count', () => { + const workers = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions(pluginsWithCounts(2), REPO), + maxWorkerCount: 10, + }); + + assertReturnVal(workers); + expect(workers.length).toBe(2); + expect(readConfigs(workers)).toMatchInlineSnapshot(` + Array [ + "worker 0 (1 known modules) => a", + "worker 1 (2 known modules) => b", + ] + `); +}); + +it('assigns unknown plugin counts as evenly as possible', () => { + const configs = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions(pluginsWithoutCounts(10), REPO), + maxWorkerCount: 3, + }); + + assertReturnVal(configs); + expect(readConfigs(configs)).toMatchInlineSnapshot(` + Array [ + "worker 0 (4 new bundles) => foo9,foo6,foo3,foo1", + "worker 1 (3 new bundles) => foo8,foo5,foo2", + "worker 2 (3 new bundles) => foo7,foo4,foo10", + ] + `); +}); + +it('distributes bundles without module counts evenly after assigning modules with known counts evenly', () => { + const configs = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions([...pluginsWithCounts(16), ...pluginsWithoutCounts(10)], REPO), + }); + + assertReturnVal(configs); + expect(readConfigs(configs)).toMatchInlineSnapshot(` + Array [ + "worker 0 (42 known modules, 3 new bundles) => n,m,h,g,foo9,foo5,foo10", + "worker 1 (43 known modules, 3 new bundles) => o,l,i,f,a,foo8,foo4,foo1", + "worker 2 (43 known modules, 2 new bundles) => d,c,foo7,foo3", + "worker 3 (44 known modules, 2 new bundles) => p,k,j,e,b,foo6,foo2", + ] + `); +}); + +it('distributes 2 bundles to workers evenly', () => { + const configs = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions(pluginsWithCounts(2), REPO), + }); + + assertReturnVal(configs); + expect(readConfigs(configs)).toMatchInlineSnapshot(` + Array [ + "worker 0 (1 known modules) => a", + "worker 1 (2 known modules) => b", + ] + `); +}); + +it('distributes 5 bundles to workers evenly', () => { + const configs = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions(pluginsWithCounts(5), REPO), + }); + + assertReturnVal(configs); + expect(readConfigs(configs)).toMatchInlineSnapshot(` + Array [ + "worker 0 (3 known modules) => b,a", + "worker 1 (3 known modules) => c", + "worker 2 (5 known modules) => e", + "worker 3 (40 known modules) => d", + ] + `); +}); + +it('distributes 10 bundles to workers evenly', () => { + const configs = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions(pluginsWithCounts(10), REPO), + }); + + assertReturnVal(configs); + expect(readConfigs(configs)).toMatchInlineSnapshot(` + Array [ + "worker 0 (16 known modules) => h,g,a", + "worker 1 (17 known modules) => i,f,b", + "worker 2 (18 known modules) => j,e,c", + "worker 3 (40 known modules) => d", + ] + `); +}); + +it('distributes 15 bundles to workers evenly', () => { + const configs = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions(pluginsWithCounts(15), REPO), + }); + + assertReturnVal(configs); + expect(readConfigs(configs)).toMatchInlineSnapshot(` + Array [ + "worker 0 (38 known modules) => m,l,g,f", + "worker 1 (39 known modules) => n,k,h,e,a", + "worker 2 (39 known modules) => o,j,i,c,b", + "worker 3 (40 known modules) => d", + ] + `); +}); + +it('distributes 20 bundles to workers evenly', () => { + const configs = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions(pluginsWithCounts(20), REPO), + }); + + assertReturnVal(configs); + expect(readConfigs(configs)).toMatchInlineSnapshot(` + Array [ + "worker 0 (76 known modules) => d,m,j,h,e", + "worker 1 (76 known modules) => s,r,n,l,g,f", + "worker 2 (77 known modules) => t,p,o,k,i,c,b,a", + "worker 3 (170 known modules) => q", + ] + `); +}); + +it('distributes 25 bundles to workers evenly', () => { + const configs = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions(pluginsWithCounts(25), REPO), + }); + + assertReturnVal(configs); + expect(readConfigs(configs)).toMatchInlineSnapshot(` + Array [ + "worker 0 (161 known modules) => d,w,t,r,o,m,k,i,f,e,a", + "worker 1 (161 known modules) => y,x,u,s,p,n,l,j,h,g,c,b", + "worker 2 (170 known modules) => q", + "worker 3 (220 known modules) => v", + ] + `); +}); + +it('distributes 30 bundles to workers evenly', () => { + const configs = assignBundlesToWorkers({ + ...defaultOptions, + bundles: getBundleDefinitions(pluginsWithCounts(30), REPO), + }); + + assertReturnVal(configs); + expect(readConfigs(configs)).toMatchInlineSnapshot(` + Array [ + "worker 0 (172 known modules) => z,y,w,t,r,o,m,k,i,g,e", + "worker 1 (173 known modules) => q,b,a", + "worker 2 (173 known modules) => d,x,u,s,p,n,l,j,h,f,c", + "worker 3 (220 known modules) => v", + ] + `); +}); diff --git a/packages/kbn-optimizer/src/assign_bundles_to_workers.ts b/packages/kbn-optimizer/src/assign_bundles_to_workers.ts new file mode 100644 index 0000000000000..5961a148ce67b --- /dev/null +++ b/packages/kbn-optimizer/src/assign_bundles_to_workers.ts @@ -0,0 +1,162 @@ +/* + * 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 { BundleDefinition, WorkerConfig } from './common'; +import { OptimizerCache } from './optimizer_cache'; + +// helper types used inside getWorkerConfigs so we don't have +// to calculate moduleCounts over and over + +export interface Worker extends HasModuleCount { + newBundles: number; + config: WorkerConfig; +} + +interface WrappedBundleWithCount extends HasModuleCount { + def: BundleDefinition; +} + +interface WrappedBundleWithoutCount { + moduleCount: undefined; + def: BundleDefinition; +} + +interface HasModuleCount { + moduleCount: number; +} + +type WrappedBundle = WrappedBundleWithCount | WrappedBundleWithoutCount; + +/** assign a wrapped bundle to a worker */ +const assignBundle = (worker: Worker, { moduleCount, def }: WrappedBundle) => { + if (moduleCount !== undefined) { + worker.moduleCount += moduleCount; + } else { + worker.newBundles += 1; + } + + worker.config.bundles.push(def); +}; + +/** compare items with module counts */ +const byModuleCount = (a: HasModuleCount, b: HasModuleCount) => a.moduleCount - b.moduleCount; + +/** compare items with module counts in descending order */ +const byModuleCountDesc = (a: HasModuleCount, b: HasModuleCount) => byModuleCount(b, a); + +export interface Options { + bundles: BundleDefinition[]; + cache: OptimizerCache; + maxWorkerCount: number; + repoRoot: string; + watch: boolean; + dist: boolean; + profileWebpack: boolean; +} + +/** + * Create WorkerConfig objects for each worker we will use to build the bundles. + * + * We need to evenly assign bundles to workers so that each worker will have + * about the same amount of work to do. We do this by tracking the module count + * of each bundle in the OptimizerCache and determining the overall workload + * of a worker by the sum of modules it will have to compile for all of its + * bundles. + * + * We only know the module counts after the first build of a new bundle, so + * when we encounter a bundle without a module count in the cache we just + * assign them to workers round-robin, starting with the workers which have + * the smallest number of modules to build. + */ +export function assignBundlesToWorkers(options: Options) { + const workerCount = Math.min(options.bundles.length, options.maxWorkerCount); + const workers: Worker[] = []; + for (let i = 0; i < workerCount; i++) { + workers.push({ + moduleCount: 0, + newBundles: 0, + config: { + repoRoot: options.repoRoot, + watch: options.watch, + dist: options.dist, + profileWebpack: options.profileWebpack, + bundles: [], + }, + }); + } + + /** + * wrap all bundles with their module count and sort them by id + * descending so that subsequent sorting will be deterministic + * even if we're sorting by module count, which may be the same + * for two bundles + */ + const wrappedBundled = options.bundles + .map(b => ({ + moduleCount: options.cache.getBundleModuleCount(b.id), + def: b, + })) + .sort((a, b) => b.def.id.localeCompare(a.def.id)); + + /** + * separate the bundles which do and don't have module counts + */ + const bundlesWithCountsDesc = wrappedBundled + .filter((b): b is WrappedBundleWithCount => b.moduleCount !== undefined) + .sort(byModuleCountDesc); + const bundlesWithoutModuleCounts = wrappedBundled.filter( + (b): b is WrappedBundleWithoutCount => b.moduleCount === undefined + ); + + /** + * assign largest bundles to the smallest worker until it is + * no longer the smallest worker and repeat until all bundles + * with module counts are assigned + */ + while (bundlesWithCountsDesc.length) { + const [smallestWorker, nextSmallestWorker] = workers.sort(byModuleCount); + + while (!nextSmallestWorker || smallestWorker.moduleCount <= nextSmallestWorker.moduleCount) { + const bundle = bundlesWithCountsDesc.shift(); + + if (!bundle) { + break; + } + + assignBundle(smallestWorker, bundle); + } + } + + /** + * assign bundles without module counts to workers round-robin + * starting with the smallest workers + */ + workers.sort(byModuleCount); + while (bundlesWithoutModuleCounts.length) { + for (const worker of workers) { + const bundle = bundlesWithoutModuleCounts.shift(); + if (!bundle) { + break; + } + assignBundle(worker, bundle); + } + } + + return workers; +} diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts new file mode 100644 index 0000000000000..3710d736e7a0f --- /dev/null +++ b/packages/kbn-optimizer/src/cli.ts @@ -0,0 +1,103 @@ +/* + * 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 'source-map-support/register'; + +import Path from 'path'; + +import { run, REPO_ROOT, createFlagError } from '@kbn/dev-utils'; + +import { logOptimizerState } from './log_optimizer_state'; +import { OptimizerConfig } from './optimizer_config'; +import { Optimizer } from './optimizer'; + +run( + async ({ log, flags }) => { + const watch = flags.watch ?? false; + if (typeof watch !== 'boolean') { + throw createFlagError('expected --watch to have no value'); + } + + const oss = flags.oss ?? false; + if (typeof oss !== 'boolean') { + throw createFlagError('expected --oss to have no value'); + } + + const dist = flags.dist ?? false; + if (typeof dist !== 'boolean') { + throw createFlagError('expected --dist to have no value'); + } + + const examples = flags.examples ?? false; + if (typeof examples !== 'boolean') { + throw createFlagError('expected --no-examples to have no value'); + } + + const profileWebpack = flags.profile ?? false; + if (typeof profileWebpack !== 'boolean') { + throw createFlagError('expected --profile to have no value'); + } + + const maxWorkerCount = flags.workers ? Number.parseInt(String(flags.workers), 10) : undefined; + if (maxWorkerCount !== undefined && (!Number.isFinite(maxWorkerCount) || maxWorkerCount < 1)) { + throw createFlagError('expected --workers to be a number greater than 0'); + } + + const extraPluginScanDirs = ([] as string[]) + .concat((flags['scan-dir'] as string | string[]) || []) + .map(p => Path.resolve(p)); + if (!extraPluginScanDirs.every(s => typeof s === 'string')) { + throw createFlagError('expected --scan-dir to be a string'); + } + + const config = OptimizerConfig.create({ + repoRoot: REPO_ROOT, + watch, + maxWorkerCount, + oss, + dist, + examples, + profileWebpack, + extraPluginScanDirs, + }); + + await new Optimizer(config) + .run() + .pipe(logOptimizerState(log, config)) + .toPromise(); + }, + { + flags: { + boolean: ['watch', 'oss', 'examples', 'dist', 'profile'], + string: ['workers', 'scan-dir'], + default: { + examples: true, + }, + help: ` + --watch run the optimizer in watch mode + --workers max number of workers to use + --oss only build oss plugins + --profile profile the webpack builds and write stats.json files to build outputs + --no-examples don't build the example plugins + --dist build new platform plugins in a way that is suitable for inclusion in the Kibana distributable + --scan-dir add a directory to the list of directories scanned for plugins (specify as many times as necessary) + `, + }, + } +); diff --git a/packages/kbn-optimizer/src/closure.ts b/packages/kbn-optimizer/src/closure.ts new file mode 100644 index 0000000000000..38b3412f773df --- /dev/null +++ b/packages/kbn-optimizer/src/closure.ts @@ -0,0 +1,40 @@ +/* + * 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 * as Rx from 'rxjs'; + +type Operator = (source: Rx.Observable) => Rx.Observable; + +/** + * Wrap an operator chain in a closure so that is can have some local state + * + * This could also be done with new Rx.Obseravble(...) but that gives + * the closure access to the subscriber, and I often wish I didn't have + * access to such a powerful/dangerous object. + * + * Using closure makes sure that only operators are used so errors + * and subscriptions are managed correctly without worry. + */ +export const closure = (fn: Operator): Operator => { + return (source: Rx.Observable) => { + return new Rx.Observable(subscriber => { + return fn(source).subscribe(subscriber); + }); + }; +}; diff --git a/packages/kbn-optimizer/src/common/bundle_definition.ts b/packages/kbn-optimizer/src/common/bundle_definition.ts new file mode 100644 index 0000000000000..c89b8a9bcfd86 --- /dev/null +++ b/packages/kbn-optimizer/src/common/bundle_definition.ts @@ -0,0 +1,34 @@ +/* + * 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 const VALID_BUNDLE_TYPES = ['plugin' as const]; + +export interface BundleDefinition { + readonly type: typeof VALID_BUNDLE_TYPES[0]; + /** Unique id for this bundle */ + readonly id: string; + /** Webpack entry request for this plugin, relative to the contextDir */ + readonly entry: string; + /** Absolute path to the plugin source directory */ + readonly contextDir: string; + /** Absolute path to the root of the repository */ + readonly sourceRoot: string; + /** Absolute path to the directory where output should be written */ + readonly outputDir: string; +} diff --git a/packages/kbn-optimizer/src/common/compiler_messages.ts b/packages/kbn-optimizer/src/common/compiler_messages.ts new file mode 100644 index 0000000000000..0b384c2a7f9ed --- /dev/null +++ b/packages/kbn-optimizer/src/common/compiler_messages.ts @@ -0,0 +1,98 @@ +/* + * 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. + */ + +/** + * Message sent when a compiler encouters an unresolvable error. + * The worker will be shut down following this message. + */ +export interface CompilerErrorMessage { + type: 'compiler error'; + id: string; + errorMessage: string; + errorStack?: string; +} + +/** + * Message sent when a compiler starts running, either for the first + * time or because of changes detected when watching. + */ +export interface CompilerRunningMessage { + type: 'running'; + id: string; +} + +/** + * Message sent when a compiler encounters an error that + * prevents the bundle from building correctly. When in + * watch mode these issues can be fixed by the user. + * (ie. unresolved import, syntax error, etc.) + */ +export interface CompilerIssueMessage { + type: 'compiler issue'; + id: string; + failure: string; +} + +/** + * Message sent when a compiler completes successfully and + * the bundle has been written to disk or updated on disk. + */ +export interface CompilerSuccessMessage { + type: 'compiler success'; + id: string; + moduleCount: number; +} + +export type CompilerState = CompilerRunningMessage | CompilerIssueMessage | CompilerSuccessMessage; + +export class CompilerMessages { + constructor(private bundle: string) {} + + running(): CompilerRunningMessage { + return { + id: this.bundle, + type: 'running', + }; + } + + compilerFailure(options: { failure: string }): CompilerIssueMessage { + return { + id: this.bundle, + type: 'compiler issue', + failure: options.failure, + }; + } + + compilerSuccess(options: { moduleCount: number }): CompilerSuccessMessage { + return { + id: this.bundle, + type: 'compiler success', + moduleCount: options.moduleCount, + }; + } + + error(error: Error): CompilerErrorMessage { + return { + id: this.bundle, + type: 'compiler error', + errorMessage: error.message, + errorStack: error.stack, + }; + } +} diff --git a/packages/kbn-optimizer/src/common/index.ts b/packages/kbn-optimizer/src/common/index.ts new file mode 100644 index 0000000000000..5f56fa41734a1 --- /dev/null +++ b/packages/kbn-optimizer/src/common/index.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 * from './bundle_definition'; +export * from './worker_config'; +export * from './worker_messages'; +export * from './compiler_messages'; diff --git a/packages/kbn-optimizer/src/common/worker_config.ts b/packages/kbn-optimizer/src/common/worker_config.ts new file mode 100644 index 0000000000000..dffc6e6f29b52 --- /dev/null +++ b/packages/kbn-optimizer/src/common/worker_config.ts @@ -0,0 +1,101 @@ +/* + * 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 Path from 'path'; + +import { BundleDefinition, VALID_BUNDLE_TYPES } from './bundle_definition'; + +export interface WorkerConfig { + readonly repoRoot: string; + readonly watch: boolean; + readonly dist: boolean; + readonly bundles: BundleDefinition[]; + readonly profileWebpack: boolean; +} + +type UnknownVals = { + [k in keyof T]: unknown; +}; + +export function parseWorkerConfig(json: string) { + try { + if (typeof json !== 'string') { + throw new Error('expected config to be a JSON string'); + } + + const parsed: UnknownVals = JSON.parse(json); + if (!(parsed && typeof parsed === 'object')) { + throw new Error('config must be an object'); + } + + if (!(parsed.watch === undefined || typeof parsed.watch === 'boolean')) { + throw new Error('`watch` config must be a boolean when defined'); + } + + if (!(parsed.dist === undefined || typeof parsed.dist === 'boolean')) { + throw new Error('`dist` config must be a boolean when defined'); + } + + if (typeof parsed.profileWebpack !== 'boolean') { + throw new Error('`profileWebpack` must be a boolean'); + } + + if (!Array.isArray(parsed.bundles)) { + throw new Error('config.bundles must be an array'); + } + + for (const parsedBundle of parsed.bundles as Array>) { + if (!(parsedBundle && typeof parsedBundle === 'object')) { + throw new Error('config.bundles[] must be an object'); + } + + if (!VALID_BUNDLE_TYPES.includes(parsedBundle.type as any)) { + throw new Error('config.bundles[] must have a valid `type`'); + } + + if (!(typeof parsedBundle.id === 'string')) { + throw new Error('config.bundles[] must have a string `id` property'); + } + + if (!(typeof parsedBundle.entry === 'string')) { + throw new Error('config.bundles[] must have a string `entry` property'); + } + + if (typeof parsedBundle.outputDir !== 'string') { + throw new Error('`outputDir` config must be a string'); + } + + if ( + !(typeof parsedBundle.contextDir === 'string' && Path.isAbsolute(parsedBundle.contextDir)) + ) { + throw new Error('config.bundles[] must have a string `contextDir` property'); + } + } + + return { + error: undefined, + workerConfig: parsed as WorkerConfig, + }; + } catch (error) { + return { + error: new Error(`unable to parse worker config: ${error.message}`), + workerConfig: undefined, + }; + } +} diff --git a/packages/kbn-optimizer/src/common/worker_messages.ts b/packages/kbn-optimizer/src/common/worker_messages.ts new file mode 100644 index 0000000000000..5df09af315bbf --- /dev/null +++ b/packages/kbn-optimizer/src/common/worker_messages.ts @@ -0,0 +1,64 @@ +/* + * 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 { + CompilerRunningMessage, + CompilerIssueMessage, + CompilerSuccessMessage, + CompilerErrorMessage, +} from './compiler_messages'; + +export type WorkerMessage = + | CompilerRunningMessage + | CompilerIssueMessage + | CompilerSuccessMessage + | CompilerErrorMessage + | WorkerErrorMessage; + +/** + * Message sent when the worker encounters an error that it can't + * recover from, no more messages will be sent and the worker + * will exit after this message. + */ +export interface WorkerErrorMessage { + type: 'worker error'; + errorMessage: string; + errorStack?: string; +} + +const WORKER_STATE_TYPES: Array = [ + 'running', + 'compiler success', + 'compiler issue', + 'worker error', + 'compiler error', +]; + +export const isWorkerMessage = (value: any): value is WorkerMessage => + typeof value === 'object' && value && WORKER_STATE_TYPES.includes(value.type); + +export class WorkerMessages { + error(error: Error): WorkerErrorMessage { + return { + type: 'worker error', + errorMessage: error.message, + errorStack: error.stack, + }; + } +} diff --git a/packages/kbn-optimizer/src/get_bundle_definitions.test.ts b/packages/kbn-optimizer/src/get_bundle_definitions.test.ts new file mode 100644 index 0000000000000..d6c5212941207 --- /dev/null +++ b/packages/kbn-optimizer/src/get_bundle_definitions.test.ts @@ -0,0 +1,68 @@ +/* + * 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 { createAbsolutePathSerializer } from '@kbn/dev-utils'; + +import { getBundleDefinitions } from './get_bundle_definitions'; + +expect.addSnapshotSerializer(createAbsolutePathSerializer('/repo')); + +it('returns a bundle for each plugin', () => { + expect( + getBundleDefinitions( + [ + { + directory: '/repo/plugins/foo', + id: 'foo', + isUiPlugin: true, + }, + { + directory: '/repo/plugins/bar', + id: 'bar', + isUiPlugin: false, + }, + { + directory: '/outside/of/repo/plugins/baz', + id: 'baz', + isUiPlugin: true, + }, + ], + '/repo' + ) + ).toMatchInlineSnapshot(` + Array [ + Object { + "contextDir": /plugins/foo, + "entry": "./public/index", + "id": "foo", + "outputDir": /plugins/foo/target/public, + "sourceRoot": , + "type": "plugin", + }, + Object { + "contextDir": "/outside/of/repo/plugins/baz", + "entry": "./public/index", + "id": "baz", + "outputDir": "/outside/of/repo/plugins/baz/target/public", + "sourceRoot": , + "type": "plugin", + }, + ] + `); +}); diff --git a/src/cli/log.js b/packages/kbn-optimizer/src/get_bundle_definitions.ts similarity index 60% rename from src/cli/log.js rename to packages/kbn-optimizer/src/get_bundle_definitions.ts index 917d06c42c7ca..4e9874d145b60 100644 --- a/src/cli/log.js +++ b/packages/kbn-optimizer/src/get_bundle_definitions.ts @@ -17,18 +17,22 @@ * under the License. */ -import _ from 'lodash'; +import Path from 'path'; -const log = _.restParam(function(color, label, rest1) { - console.log.apply(console, [color(` ${_.trim(label)} `)].concat(rest1)); -}); +import { NewPlatformPlugin } from './new_platform_plugins'; +import { BundleDefinition } from './common'; -import { green, yellow, red } from './color'; - -export default class Log { - constructor(quiet, silent) { - this.good = quiet || silent ? _.noop : _.partial(log, green); - this.warn = quiet || silent ? _.noop : _.partial(log, yellow); - this.bad = silent ? _.noop : _.partial(log, red); - } +export function getBundleDefinitions(plugins: NewPlatformPlugin[], repoRoot: string) { + return plugins + .filter(p => p.isUiPlugin) + .map( + (p): BundleDefinition => ({ + type: 'plugin', + id: p.id, + entry: './public/index', + sourceRoot: repoRoot, + contextDir: p.directory, + outputDir: Path.resolve(p.directory, 'target/public'), + }) + ); } diff --git a/packages/kbn-optimizer/src/index.ts b/packages/kbn-optimizer/src/index.ts new file mode 100644 index 0000000000000..f0d70db342013 --- /dev/null +++ b/packages/kbn-optimizer/src/index.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 * from './optimizer'; +export * from './optimizer_config'; +export * from './log_optimizer_state'; +export { WorkerStdio } from './observe_worker'; diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap new file mode 100644 index 0000000000000..1e135c6fc9888 --- /dev/null +++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap @@ -0,0 +1,430 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`builds expected bundles, saves bundle counts to metadata: OptimizerConfig 1`] = ` +OptimizerConfig { + "bundles": Array [ + Object { + "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, + "entry": "./public/index", + "id": "bar", + "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public, + "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, + "type": "plugin", + }, + Object { + "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, + "entry": "./public/index", + "id": "foo", + "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public, + "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, + "type": "plugin", + }, + ], + "cache": OptimizerCache { + "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/data/.kbn-optimizer-cache.json, + "scheduledWrite": false, + "state": Object { + "moduleCounts": Object {}, + }, + }, + "watch": false, + "workers": Array [ + Object { + "bundles": Array [ + Object { + "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, + "entry": "./public/index", + "id": "foo", + "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public, + "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, + "type": "plugin", + }, + Object { + "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, + "entry": "./public/index", + "id": "bar", + "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public, + "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, + "type": "plugin", + }, + ], + "dist": false, + "profileWebpack": false, + "repoRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, + "watch": false, + }, + ], +} +`; + +exports[`builds expected bundles, saves bundle counts to metadata: bar bundle 1`] = ` +"var __kbnBundles__ = typeof __kbnBundles__ === \\"object\\" ? __kbnBundles__ : {}; __kbnBundles__[\\"plugin/bar\\"] = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = \\"__REPLACE_WITH_PUBLIC_PATH__\\"; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = \\"./public/index.ts\\"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ \\"./public/index.ts\\": +/*!*************************!*\\\\ + !*** ./public/index.ts ***! + \\\\*************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); + +var _lib = __webpack_require__(/*! ./lib */ \\"./public/lib.ts\\"); + +Object.keys(_lib).forEach(function (key) { + if (key === \\"default\\" || key === \\"__esModule\\") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _lib[key]; + } + }); +}); + +/***/ }), + +/***/ \\"./public/lib.ts\\": +/*!***********************!*\\\\ + !*** ./public/lib.ts ***! + \\\\***********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); +exports.barLibFn = barLibFn; + +/* + * 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 barLibFn() { + return 'bar'; +} + +/***/ }) + +/******/ })[\\"plugin\\"]; +//# sourceMappingURL=bar.plugin.js.map" +`; + +exports[`builds expected bundles, saves bundle counts to metadata: foo bundle 1`] = ` +"var __kbnBundles__ = typeof __kbnBundles__ === \\"object\\" ? __kbnBundles__ : {}; __kbnBundles__[\\"plugin/foo\\"] = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = \\"__REPLACE_WITH_PUBLIC_PATH__\\"; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = \\"./public/index.ts\\"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ \\"./public/ext.ts\\": +/*!***********************!*\\\\ + !*** ./public/ext.ts ***! + \\\\***********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); +exports.ext = void 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. + */ +const ext = 'TRUE'; +exports.ext = ext; + +/***/ }), + +/***/ \\"./public/index.ts\\": +/*!*************************!*\\\\ + !*** ./public/index.ts ***! + \\\\*************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); + +var _lib = __webpack_require__(/*! ./lib */ \\"./public/lib.ts\\"); + +Object.keys(_lib).forEach(function (key) { + if (key === \\"default\\" || key === \\"__esModule\\") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _lib[key]; + } + }); +}); + +var _ext = __webpack_require__(/*! ./ext */ \\"./public/ext.ts\\"); + +Object.keys(_ext).forEach(function (key) { + if (key === \\"default\\" || key === \\"__esModule\\") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _ext[key]; + } + }); +}); + +/***/ }), + +/***/ \\"./public/lib.ts\\": +/*!***********************!*\\\\ + !*** ./public/lib.ts ***! + \\\\***********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); +exports.fooLibFn = fooLibFn; + +/* + * 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 fooLibFn() { + return 'foo'; +} + +/***/ }) + +/******/ })[\\"plugin\\"]; +//# sourceMappingURL=foo.plugin.js.map" +`; diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts new file mode 100644 index 0000000000000..6c280c1664de9 --- /dev/null +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -0,0 +1,109 @@ +/* + * 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 Path from 'path'; +import Fs from 'fs'; +import { inspect } from 'util'; +import cpy from 'cpy'; +import del from 'del'; + +import { toArray, tap } from 'rxjs/operators'; +import { createAbsolutePathSerializer } from '@kbn/dev-utils'; +import { Optimizer, OptimizerConfig, OptimizerState } from '@kbn/optimizer'; + +expect.addSnapshotSerializer(createAbsolutePathSerializer()); + +const TMP_DIR = Path.resolve(__dirname, '../__fixtures__/__tmp__'); +const MOCK_REPO_SRC = Path.resolve(__dirname, '../__fixtures__/mock_repo'); +const MOCK_REPO_DIR = Path.resolve(TMP_DIR, 'mock_repo'); + +beforeEach(async () => { + await del(TMP_DIR); + await cpy('**/*', MOCK_REPO_DIR, { + cwd: MOCK_REPO_SRC, + parents: true, + deep: true, + }); +}); + +afterEach(async () => { + await del(TMP_DIR); +}); + +it('builds expected bundles, saves bundle counts to metadata', async () => { + const config = OptimizerConfig.create({ + repoRoot: MOCK_REPO_DIR, + pluginScanDirs: [Path.resolve(MOCK_REPO_DIR, 'plugins')], + maxWorkerCount: 1, + }); + + expect(config).toMatchSnapshot('OptimizerConfig'); + + const optimizer = new Optimizer(config); + + const states = await optimizer + .run() + .pipe( + tap(state => { + if (state.type === 'worker stdio') { + // eslint-disable-next-line no-console + console.log('worker', state.stream, state.chunk.toString('utf8')); + } + }), + toArray() + ) + .toPromise(); + + const assert = (statement: string, truth: boolean, altStates?: OptimizerState[]) => { + if (!truth) { + throw new Error( + `expected optimizer to ${statement}, states: ${inspect(altStates || states, { + colors: true, + depth: Infinity, + })}` + ); + } + }; + + const runningStates = states.filter(s => s.type === 'running'); + assert( + 'produce two or three "running" states', + runningStates.length === 2 || runningStates.length === 3 + ); + + const successStates = states.filter(s => s.type === 'compiler success'); + assert( + 'produce one "compiler success" states', + successStates.length === 1 || successStates.length === 2 + ); + + const otherStates = states.filter(s => s.type !== 'compiler success' && s.type !== 'running'); + assert('produce zero unexpected states', otherStates.length === 0, otherStates); + + expect( + Fs.readFileSync(Path.resolve(MOCK_REPO_DIR, 'plugins/foo/target/public/foo.plugin.js'), 'utf8') + ).toMatchSnapshot('foo bundle'); + + expect( + Fs.readFileSync(Path.resolve(MOCK_REPO_DIR, 'plugins/bar/target/public/bar.plugin.js'), 'utf8') + ).toMatchSnapshot('bar bundle'); + + expect(config.cache.getBundleModuleCount('foo')).toBe(3); + expect(config.cache.getBundleModuleCount('bar')).toBe(2); +}); diff --git a/packages/kbn-optimizer/src/log.ts b/packages/kbn-optimizer/src/log.ts new file mode 100644 index 0000000000000..79093605115f6 --- /dev/null +++ b/packages/kbn-optimizer/src/log.ts @@ -0,0 +1,24 @@ +/* + * 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 Log { + info(tmpl: string, ...args: any[]): void; + success(tmpl: string, ...args: any[]): void; + error(error: string | Error): void; +} diff --git a/packages/kbn-optimizer/src/log_optimizer_state.test.ts b/packages/kbn-optimizer/src/log_optimizer_state.test.ts new file mode 100644 index 0000000000000..5a97d90e34466 --- /dev/null +++ b/packages/kbn-optimizer/src/log_optimizer_state.test.ts @@ -0,0 +1,124 @@ +/* + * 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 * as Rx from 'rxjs'; +import { toArray } from 'rxjs/operators'; +import { REPO_ROOT, ToolingLog, ToolingLogCollectingWriter } from '@kbn/dev-utils'; + +import { OptimizerState } from './optimizer'; +import { OptimizerConfig } from './optimizer_config'; +import { logOptimizerState } from './log_optimizer_state'; + +it('produces expected messages and mirrors state updates downstream', async () => { + const logWriter = new ToolingLogCollectingWriter(); + const log = new ToolingLog(); + log.setWriters([logWriter]); + + const config = OptimizerConfig.create({ + repoRoot: REPO_ROOT, + maxWorkerCount: 2, + }); + + const stateUpdates: OptimizerState[] = [ + { + type: 'worker stdio', + chunk: Buffer.from('something from stderr'), + stream: 'stderr', + }, + { + type: 'worker stdio', + chunk: Buffer.from('something from stdout'), + stream: 'stdout', + }, + { + type: 'running', + durSec: 0, + compilerStates: [ + { + id: 'foo', + type: 'running', + }, + ], + }, + { + type: 'running', + durSec: 1, + compilerStates: [ + { + id: 'foo', + type: 'running', + }, + { + id: 'bar', + type: 'running', + }, + ], + }, + { + type: 'running', + durSec: 10, + compilerStates: [ + { + id: 'foo', + type: 'running', + }, + { + id: 'bar', + type: 'compiler success', + moduleCount: 50, + }, + ], + }, + { + type: 'compiler success', + durSec: 30, + compilerStates: [ + { + id: 'foo', + type: 'compiler success', + moduleCount: 100, + }, + { + id: 'bar', + type: 'compiler success', + moduleCount: 50, + }, + ], + }, + ]; + + const results = await Rx.from(stateUpdates) + .pipe(logOptimizerState(log, config), toArray()) + .toPromise(); + + expect(results).toEqual(stateUpdates.filter(s => s.type !== 'worker stdio')); + + expect(logWriter.messages).toMatchInlineSnapshot(` + Array [ + " info ⚙️ building 28 bundles using 2 workers", + " warn ⚙️ worker stderr something from stderr", + " warn ⚙️ worker stdout something from stdout", + " sill [foo] state = \\"running\\"", + " sill [bar] state = \\"running\\"", + " sill [bar] state = \\"compiler success\\" after 10 seconds", + " sill [foo] state = \\"compiler success\\" after 30 seconds", + " succ ⚙️ all bundles compiled successfully after 30 seconds", + ] + `); +}); diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts new file mode 100644 index 0000000000000..35a8144f4b590 --- /dev/null +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -0,0 +1,96 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ToolingLog } from '@kbn/dev-utils'; +import { inspect } from 'util'; +import { filter } from 'rxjs/operators'; + +import { OptimizerConfig } from './optimizer_config'; +import { OptimizerState, OptimizerStateSummary } from './optimizer'; +import { CompilerState } from './common'; +import { closure } from './closure'; + +export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { + return closure(source => { + const bundleStates = new Map(); + + log.info( + `⚙️ building ${config.bundles.length} bundles using ${config.workers.length} workers${ + config.watch ? ' in watch mode' : '' + }` + ); + + return source.pipe( + filter((s): s is OptimizerStateSummary => { + if (s.type === 'worker stdio') { + const chunk = s.chunk.toString('utf8'); + log.warning( + '⚙️ worker', + s.stream, + chunk.slice(0, chunk.length - (chunk.endsWith('\n') ? 1 : 0)) + ); + return false; + } + + for (const { id, type } of s.compilerStates) { + const prevBundleState = bundleStates.get(id); + + if (type === prevBundleState) { + continue; + } + + bundleStates.set(id, type); + log.verbose( + `[${id}] state = "${type}"${type !== 'running' ? ` after ${s.durSec} seconds` : ''}` + ); + } + + if (s.type === 'running') { + return true; + } + + if (s.type === 'compiler issue') { + log.error('⚙️ webpack compile errors'); + log.indent(4); + for (const b of s.compilerStates) { + if (b.type === 'compiler issue') { + log.error(`[${b.id}] build`); + log.indent(4); + log.error(b.failure); + log.indent(-4); + } + } + log.indent(-4); + return true; + } + + if (s.type === 'compiler success') { + log.success( + config.watch + ? `⚙️ watching for changes in all bundles after ${s.durSec} seconds` + : `⚙️ all bundles compiled successfully after ${s.durSec} seconds` + ); + return true; + } + + throw new Error(`unhandled optimizer state: ${inspect(s)}`); + }) + ); + }); +} diff --git a/packages/kbn-optimizer/src/new_platform_plugins.test.ts b/packages/kbn-optimizer/src/new_platform_plugins.test.ts new file mode 100644 index 0000000000000..7d8cc18fc4d6d --- /dev/null +++ b/packages/kbn-optimizer/src/new_platform_plugins.test.ts @@ -0,0 +1,60 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Path from 'path'; + +import { createAbsolutePathSerializer } from '@kbn/dev-utils'; + +import { findNewPlatformPlugins } from './new_platform_plugins'; + +expect.addSnapshotSerializer(createAbsolutePathSerializer()); + +const FIXTURES_PATH = Path.resolve(__dirname, './__fixtures__'); + +it('parses kibana.json files of plugins found in pluginDirs', () => { + expect( + findNewPlatformPlugins( + [Path.resolve(FIXTURES_PATH, 'mock_repo/plugins')], + [Path.resolve(FIXTURES_PATH, 'mock_repo/test_plugins/test_baz')] + ) + ).toMatchInlineSnapshot(` + Array [ + Object { + "directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar, + "id": "bar", + "isUiPlugin": true, + }, + Object { + "directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/baz, + "id": "baz", + "isUiPlugin": false, + }, + Object { + "directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/foo, + "id": "foo", + "isUiPlugin": true, + }, + Object { + "directory": /packages/kbn-optimizer/src/__fixtures__/mock_repo/test_plugins/test_baz, + "id": "test_baz", + "isUiPlugin": false, + }, + ] + `); +}); diff --git a/packages/kbn-optimizer/src/new_platform_plugins.ts b/packages/kbn-optimizer/src/new_platform_plugins.ts new file mode 100644 index 0000000000000..c4c73412bb639 --- /dev/null +++ b/packages/kbn-optimizer/src/new_platform_plugins.ts @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Path from 'path'; + +import globby from 'globby'; +import loadJsonFile from 'load-json-file'; + +export interface NewPlatformPlugin { + readonly directory: string; + readonly id: string; + readonly isUiPlugin: boolean; +} + +/** + * Helper to find the new platform plugins. + */ +export function findNewPlatformPlugins(scanDirs: string[], paths: string[]) { + return globby + .sync( + Array.from( + new Set([ + ...scanDirs.map(dir => `${dir}/*/kibana.json`), + ...paths.map(path => `${path}/kibana.json`), + ]) + ), + { + absolute: true, + } + ) + .map(path => readNewPlatformPlugin(path)); +} + +function readNewPlatformPlugin(manifestPath: string): NewPlatformPlugin { + if (!Path.isAbsolute(manifestPath)) { + throw new TypeError('expected new platform manifest path to be absolute'); + } + + const manifest = loadJsonFile.sync(manifestPath); + if (!manifest || typeof manifest !== 'object' || Array.isArray(manifest)) { + throw new TypeError('expected new platform plugin manifest to be a JSON encoded object'); + } + + if (typeof manifest.id !== 'string') { + throw new TypeError('expected new platform plugin manifest to have a string id'); + } + + return { + directory: Path.dirname(manifestPath), + id: manifest.id, + isUiPlugin: !!manifest.ui, + }; +} diff --git a/packages/kbn-optimizer/src/observe_worker.ts b/packages/kbn-optimizer/src/observe_worker.ts new file mode 100644 index 0000000000000..ed67204ebbbea --- /dev/null +++ b/packages/kbn-optimizer/src/observe_worker.ts @@ -0,0 +1,168 @@ +/* + * 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 { fork, ChildProcess } from 'child_process'; +import { Readable } from 'stream'; +import { inspect } from 'util'; + +import * as Rx from 'rxjs'; +import { map, takeUntil } from 'rxjs/operators'; + +import { isWorkerMessage, WorkerMessage, WorkerConfig } from './common'; + +export interface WorkerStdio { + type: 'worker stdio'; + stream: 'stdout' | 'stderr'; + chunk: Buffer; +} + +interface ProcResource extends Rx.Unsubscribable { + proc: ChildProcess; +} +const isNumeric = (input: any) => String(input).match(/^[0-9]+$/); + +let inspectPortCounter = 9230; +const inspectFlagIndex = process.execArgv.findIndex(flag => flag.startsWith('--inspect')); +let inspectFlag: string | undefined; +if (inspectFlagIndex !== -1) { + const argv = process.execArgv[inspectFlagIndex]; + if (argv.includes('=')) { + // --inspect=port + const [flag, port] = argv.split('='); + inspectFlag = flag; + inspectPortCounter = Number.parseInt(port, 10) + 1; + } else { + // --inspect + inspectFlag = argv; + if (isNumeric(process.execArgv[inspectFlagIndex + 1])) { + // --inspect port + inspectPortCounter = Number.parseInt(process.execArgv[inspectFlagIndex + 1], 10) + 1; + } + } +} + +function usingWorkerProc(config: WorkerConfig, user: (proc: ChildProcess) => Rx.Observable) { + return Rx.using( + (): ProcResource => { + const proc = fork(require.resolve('./worker/run_worker'), [JSON.stringify(config)], { + stdio: ['ignore', 'pipe', 'pipe', 'ipc'], + execArgv: inspectFlag ? [`${inspectFlag}=${inspectPortCounter++}`] : [], + env: { + ...process.env, + BROWSERSLIST_ENV: config.dist ? 'production' : process.env.BROWSERSLIST_ENV || 'dev', + }, + }); + + return { + proc, + unsubscribe() { + proc.kill('SIGKILL'); + }, + }; + }, + + resource => { + const { proc } = resource as ProcResource; + return user(proc); + } + ); +} + +function observeStdio$(stream: Readable, name: WorkerStdio['stream']) { + return Rx.fromEvent(stream, 'data').pipe( + takeUntil( + Rx.race( + Rx.fromEvent(stream, 'end'), + Rx.fromEvent(stream, 'error').pipe( + map(error => { + throw error; + }) + ) + ) + ), + map( + (chunk): WorkerStdio => ({ + type: 'worker stdio', + chunk, + stream: name, + }) + ) + ); +} + +export function observeWorker(config: WorkerConfig): Rx.Observable { + return usingWorkerProc(config, proc => { + let lastMessage: WorkerMessage; + + return Rx.merge( + observeStdio$(proc.stdout!, 'stdout'), + observeStdio$(proc.stderr!, 'stderr'), + Rx.fromEvent<[unknown]>(proc, 'message') + .pipe( + // validate the messages from the process + map(([msg]) => { + if (!isWorkerMessage(msg)) { + throw new Error(`unexpected message from worker: ${JSON.stringify(msg)}`); + } + + lastMessage = msg; + return msg; + }) + ) + .pipe( + takeUntil( + Rx.race( + // throw into stream on error events + Rx.fromEvent(proc, 'error').pipe( + map(error => { + throw new Error(`worker failed to spawn: ${error.message}`); + }) + ), + + // throw into stream on unexpected exits, or emit to trigger the stream to close + Rx.fromEvent<[number | void]>(proc, 'exit').pipe( + map(([code]) => { + const terminalMsgTypes: Array = [ + 'compiler error', + 'worker error', + ]; + + if (!config.watch) { + terminalMsgTypes.push('compiler issue', 'compiler success'); + } + + // verify that this is an expected exit state + if (code === 0 && lastMessage && terminalMsgTypes.includes(lastMessage.type)) { + // emit undefined so that takeUntil completes the observable + return; + } + + throw new Error( + `worker exitted unexpectedly with code ${code} [last message: ${inspect( + lastMessage + )}]` + ); + }) + ) + ) + ) + ) + ); + }); +} diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts new file mode 100644 index 0000000000000..0709b9b643919 --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -0,0 +1,121 @@ +/* + * 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 * as Rx from 'rxjs'; +import { mergeMap, map, tap } from 'rxjs/operators'; +import { createFailError } from '@kbn/dev-utils'; + +import { observeWorker, WorkerStdio } from './observe_worker'; +import { OptimizerConfig } from './optimizer_config'; +import { CompilerState, WorkerMessage } from './common'; +import { closure } from './closure'; + +export interface OptimizerStateSummary { + type: CompilerState['type']; + durSec: number; + compilerStates: CompilerState[]; +} + +export type OptimizerState = OptimizerStateSummary | WorkerStdio; + +const getSummaryType = (states: CompilerState[]) => { + const types = states.map(s => s.type); + + if (types.includes('running')) { + return 'running'; + } + + if (types.includes('compiler issue')) { + return 'compiler issue'; + } + + if (types.every(s => s === 'compiler success')) { + return 'compiler success'; + } + + throw new Error(`unable to summarize bundle states: ${JSON.stringify(states)}`); +}; + +export class Optimizer { + constructor(private readonly config: OptimizerConfig) {} + + run() { + return Rx.from(this.config.workers).pipe( + mergeMap(config => observeWorker(config)), + closure(msg$ => { + let prevSummaryType: OptimizerStateSummary['type'] | undefined; + let startTime = Date.now(); + const compilerStates: CompilerState[] = []; + + return msg$.pipe( + map( + (msg: WorkerMessage | WorkerStdio): OptimizerState => { + if (msg.type === 'worker stdio') { + return msg; + } + + if (msg.type === 'worker error' || msg.type === 'compiler error') { + const error = new Error(msg.errorMessage); + error.stack = msg.errorStack; + throw error; + } + + const existingIndex = compilerStates.findIndex(s => s.id === msg.id); + if (existingIndex === -1) { + compilerStates.push(msg); + } else { + compilerStates.splice(existingIndex, 1, msg); + } + + if (msg.type === 'compiler success') { + this.config.cache.saveBundleModuleCount(msg.id, msg.moduleCount); + } + + const type = getSummaryType(compilerStates); + if (prevSummaryType !== 'running' && type === 'running') { + // reset start time now that we are running again + startTime = Date.now(); + } + + // stash summary type so we can reset startTime + prevSummaryType = type; + + return { + type, + durSec: Math.round((Date.now() - startTime) / 100) / 10, + compilerStates: Array.from(compilerStates), + }; + } + ), + tap({ + complete: () => { + if (this.config.watch) { + throw new Error('workers unexpected closed in watch mode'); + } + + if (prevSummaryType !== 'compiler success') { + throw createFailError('compilation failed'); + } + }, + }) + ); + }) + ); + } +} diff --git a/packages/kbn-optimizer/src/optimizer_cache.ts b/packages/kbn-optimizer/src/optimizer_cache.ts new file mode 100644 index 0000000000000..eb3c2ff42b6e0 --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer_cache.ts @@ -0,0 +1,100 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Fs from 'fs'; +import Path from 'path'; + +const DEFAULT_STATE = JSON.stringify({}); + +interface State { + moduleCounts: { [key: string]: number | undefined }; +} + +/** + * Helper to read and update metadata for bundles. + * + * Currently only tracks the module count of bundles, allowing + * us to assign bundles to workers in a way that ensures an even + * distribution of modules to be built + */ +export class OptimizerCache { + private state: State | undefined = undefined; + constructor(private readonly path: string | false) {} + + private getState() { + if (!this.state) { + let json; + try { + if (this.path) { + json = Fs.readFileSync(this.path, 'utf8'); + } + } catch (error) { + if (error.code !== 'ENOENT') { + throw error; + } + } + + let partialCache: Partial; + try { + partialCache = JSON.parse(json || DEFAULT_STATE); + } catch (error) { + partialCache = {}; + } + + this.state = { + moduleCounts: partialCache.moduleCounts || {}, + }; + } + + return this.state; + } + + getBundleModuleCount(bundleId: string) { + const state = this.getState(); + return state.moduleCounts[bundleId]; + } + + saveBundleModuleCount(bundleId: string, count: number) { + const current = this.getState(); + + this.setState({ + ...current, + moduleCounts: { + ...current.moduleCounts, + [bundleId]: count, + }, + }); + } + + private scheduledWrite = false; + private setState(updated: State) { + this.state = updated; + + if (!this.scheduledWrite && this.path) { + const path = this.path; + const directory = Path.dirname(path); + this.scheduledWrite = true; + process.nextTick(() => { + this.scheduledWrite = false; + Fs.mkdirSync(directory, { recursive: true }); + Fs.writeFileSync(path, JSON.stringify(this.state, null, 2)); + }); + } + } +} diff --git a/packages/kbn-optimizer/src/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer_config.test.ts new file mode 100644 index 0000000000000..9b69a9edcb33e --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer_config.test.ts @@ -0,0 +1,379 @@ +/* + * 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. + */ + +jest.mock('./assign_bundles_to_workers.ts'); +jest.mock('./new_platform_plugins.ts'); +jest.mock('./optimizer_cache.ts'); +jest.mock('./get_bundle_definitions.ts'); + +import Path from 'path'; +import Os from 'os'; + +import { REPO_ROOT, createAbsolutePathSerializer } from '@kbn/dev-utils'; + +import { OptimizerConfig } from './optimizer_config'; +import { OptimizerCache as OC } from './optimizer_cache'; + +jest.spyOn(Os, 'cpus').mockReturnValue(['foo'] as any); + +expect.addSnapshotSerializer(createAbsolutePathSerializer()); + +beforeEach(() => { + jest.clearAllMocks(); +}); + +describe('OptimizerConfig::parseOptions()', () => { + it('validates that repoRoot is absolute', () => { + expect(() => + OptimizerConfig.parseOptions({ repoRoot: 'foo/bar' }) + ).toThrowErrorMatchingInlineSnapshot(`"repoRoot must be an absolute path"`); + }); + + it('validates that pluginScanDirs are absolute', () => { + expect(() => + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + pluginScanDirs: ['foo/bar'], + }) + ).toThrowErrorMatchingInlineSnapshot(`"pluginScanDirs must all be absolute paths"`); + }); + + it('validates that pluginPaths are absolute', () => { + expect(() => + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + pluginPaths: ['foo/bar'], + }) + ).toThrowErrorMatchingInlineSnapshot(`"pluginPaths must all be absolute paths"`); + }); + + it('validates that extraPluginScanDirs are absolute', () => { + expect(() => + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + extraPluginScanDirs: ['foo/bar'], + }) + ).toThrowErrorMatchingInlineSnapshot(`"extraPluginScanDirs must all be absolute paths"`); + }); + + it('validates that maxWorkerCount is a number', () => { + expect(() => { + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + maxWorkerCount: NaN, + }); + }).toThrowErrorMatchingInlineSnapshot(`"worker count must be a number"`); + }); + + it('validates that bundleMetdataPath is absolute', () => { + expect(() => { + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + optimizerCachePath: 'foo/bar', + }); + }).toThrowErrorMatchingInlineSnapshot(`"optimizerCachePath must be absolute"`); + }); + + it('applies defaults', () => { + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + }) + ).toMatchInlineSnapshot(` + Object { + "dist": false, + "maxWorkerCount": 2, + "optimizerCachePath": /data/.kbn-optimizer-cache.json, + "pluginPaths": Array [], + "pluginScanDirs": Array [ + /src/plugins, + /plugins, + /x-pack/plugins, + ], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); + + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + optimizerCachePath: false, + }) + ).toMatchInlineSnapshot(` + Object { + "dist": false, + "maxWorkerCount": 2, + "optimizerCachePath": false, + "pluginPaths": Array [], + "pluginScanDirs": Array [ + /src/plugins, + /plugins, + /x-pack/plugins, + ], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); + + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + examples: true, + }) + ).toMatchInlineSnapshot(` + Object { + "dist": false, + "maxWorkerCount": 2, + "optimizerCachePath": /data/.kbn-optimizer-cache.json, + "pluginPaths": Array [], + "pluginScanDirs": Array [ + /src/plugins, + /plugins, + /x-pack/plugins, + /examples, + ], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); + + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + oss: true, + }) + ).toMatchInlineSnapshot(` + Object { + "dist": false, + "maxWorkerCount": 2, + "optimizerCachePath": /data/.kbn-optimizer-cache.json, + "pluginPaths": Array [], + "pluginScanDirs": Array [ + /src/plugins, + /plugins, + ], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); + + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + pluginScanDirs: [Path.resolve(REPO_ROOT, 'x/y/z'), '/outside/of/repo'], + }) + ).toMatchInlineSnapshot(` + Object { + "dist": false, + "maxWorkerCount": 2, + "optimizerCachePath": /data/.kbn-optimizer-cache.json, + "pluginPaths": Array [], + "pluginScanDirs": Array [ + /x/y/z, + "/outside/of/repo", + ], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); + }); +}); + +/** + * NOTE: this method is basically just calling others, so we're mocking out the return values + * of each function with a Symbol, including the return values of OptimizerConfig.parseOptions + * and just making sure that the arguments are coming from where we expect + */ +describe('OptimizerConfig::create()', () => { + const assignBundlesToWorkers: jest.Mock = jest.requireMock('./assign_bundles_to_workers.ts') + .assignBundlesToWorkers; + const findNewPlatformPlugins: jest.Mock = jest.requireMock('./new_platform_plugins.ts') + .findNewPlatformPlugins; + const OptimizerCache: jest.MockedClass = jest.requireMock('./optimizer_cache.ts') + .OptimizerCache; + const getBundleDefinitions: jest.Mock = jest.requireMock('./get_bundle_definitions.ts') + .getBundleDefinitions; + + beforeEach(() => { + if ('mock' in OptimizerConfig.parseOptions) { + (OptimizerConfig.parseOptions as jest.Mock).mockRestore(); + } + + assignBundlesToWorkers.mockReturnValue([ + { config: Symbol('worker config 1') }, + { config: Symbol('worker config 2') }, + ]); + findNewPlatformPlugins.mockReturnValue(Symbol('new platform plugins')); + getBundleDefinitions.mockReturnValue(Symbol('bundle definitions')); + + jest.spyOn(OptimizerConfig, 'parseOptions').mockImplementation((): any => ({ + optimizerCachePath: Symbol('parsed bundle metadata path'), + dist: Symbol('parsed dist'), + maxWorkerCount: Symbol('parsed max worker count'), + pluginPaths: Symbol('parsed plugin paths'), + pluginScanDirs: Symbol('parsed plugin scan dirs'), + repoRoot: Symbol('parsed repo root'), + watch: Symbol('parsed watch'), + })); + }); + + it('passes parsed options to findNewPlatformPlugins, OptimizerCache, getBundleDefinitions, and assignBundlesToWorkers', () => { + const config = OptimizerConfig.create({ + repoRoot: REPO_ROOT, + }); + + expect(config).toMatchInlineSnapshot(` + OptimizerConfig { + "bundles": Symbol(bundle definitions), + "cache": OptimizerCache { + "getBundleModuleCount": [MockFunction], + "getState": [MockFunction], + "saveBundleModuleCount": [MockFunction], + "setState": [MockFunction], + }, + "watch": Symbol(parsed watch), + "workers": Array [ + Symbol(worker config 1), + Symbol(worker config 2), + ], + } + `); + + expect(findNewPlatformPlugins.mock).toMatchInlineSnapshot(` + Object { + "calls": Array [ + Array [ + Symbol(parsed plugin scan dirs), + Symbol(parsed plugin paths), + ], + ], + "instances": Array [ + [Window], + ], + "invocationCallOrder": Array [ + 8, + ], + "results": Array [ + Object { + "type": "return", + "value": Symbol(new platform plugins), + }, + ], + } + `); + + expect(OptimizerCache.mock).toMatchInlineSnapshot(` + Object { + "calls": Array [ + Array [ + Symbol(parsed bundle metadata path), + ], + ], + "instances": Array [ + OptimizerCache { + "getBundleModuleCount": [MockFunction], + "getState": [MockFunction], + "saveBundleModuleCount": [MockFunction], + "setState": [MockFunction], + }, + ], + "invocationCallOrder": Array [ + 9, + ], + "results": Array [ + Object { + "type": "return", + "value": undefined, + }, + ], + } + `); + + expect(getBundleDefinitions.mock).toMatchInlineSnapshot(` + Object { + "calls": Array [ + Array [ + Symbol(new platform plugins), + Symbol(parsed repo root), + ], + ], + "instances": Array [ + [Window], + ], + "invocationCallOrder": Array [ + 10, + ], + "results": Array [ + Object { + "type": "return", + "value": Symbol(bundle definitions), + }, + ], + } + `); + + expect(assignBundlesToWorkers.mock).toMatchInlineSnapshot(` + Object { + "calls": Array [ + Array [ + Object { + "bundles": Symbol(bundle definitions), + "cache": OptimizerCache { + "getBundleModuleCount": [MockFunction], + "getState": [MockFunction], + "saveBundleModuleCount": [MockFunction], + "setState": [MockFunction], + }, + "dist": Symbol(parsed dist), + "maxWorkerCount": Symbol(parsed max worker count), + "profileWebpack": undefined, + "repoRoot": Symbol(parsed repo root), + "watch": Symbol(parsed watch), + }, + ], + ], + "instances": Array [ + [Window], + ], + "invocationCallOrder": Array [ + 11, + ], + "results": Array [ + Object { + "type": "return", + "value": Array [ + Object { + "config": Symbol(worker config 1), + }, + Object { + "config": Symbol(worker config 2), + }, + ], + }, + ], + } + `); + }); +}); diff --git a/packages/kbn-optimizer/src/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer_config.ts new file mode 100644 index 0000000000000..24f957ea406ec --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer_config.ts @@ -0,0 +1,161 @@ +/* + * 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 Path from 'path'; +import Os from 'os'; + +import { findNewPlatformPlugins } from './new_platform_plugins'; +import { BundleDefinition, WorkerConfig } from './common'; +import { OptimizerCache } from './optimizer_cache'; +import { assignBundlesToWorkers } from './assign_bundles_to_workers'; +import { getBundleDefinitions } from './get_bundle_definitions'; + +interface Options { + /** absolute path to root of the repo/build */ + repoRoot: string; + /** enable to run the optimizer in watch mode */ + watch?: boolean; + /** the maximum number of workers that will be created */ + maxWorkerCount?: number; + /** absolute path to the file where the optimizer cache will be written */ + optimizerCachePath?: string | false; + /** build assets suitable for use in the distributable */ + dist?: boolean; + /** enable webpack profiling, writes stats.json files to the root of each plugin's output dir */ + profileWebpack?: boolean; + + /** include only oss plugins in default scan dirs */ + oss?: boolean; + /** include examples in default scan dirs */ + examples?: boolean; + /** absolute paths to specific plugins that should be built */ + pluginPaths?: string[]; + /** absolute paths to directories that should be built, overrides the default scan dires */ + pluginScanDirs?: string[]; + /** absolute paths that should be added to the default scan dirs */ + extraPluginScanDirs?: string[]; +} + +interface ParsedOptions { + repoRoot: string; + watch: boolean; + maxWorkerCount: number; + profileWebpack: boolean; + optimizerCachePath: string | false; + dist: boolean; + pluginPaths: string[]; + pluginScanDirs: string[]; +} + +export class OptimizerConfig { + static parseOptions(options: Options): ParsedOptions { + const watch = !!options.watch; + const oss = !!options.oss; + const dist = !!options.dist; + const examples = !!options.examples; + const profileWebpack = !!options.profileWebpack; + + const repoRoot = options.repoRoot; + if (!Path.isAbsolute(repoRoot)) { + throw new TypeError('repoRoot must be an absolute path'); + } + + const pluginScanDirs = options.pluginScanDirs || [ + Path.resolve(repoRoot, 'src/plugins'), + Path.resolve(repoRoot, 'plugins'), + ...(oss ? [] : [Path.resolve(repoRoot, 'x-pack/plugins')]), + ...(examples ? [Path.resolve('examples')] : []), + ]; + if (!pluginScanDirs.every(p => Path.isAbsolute(p))) { + throw new TypeError('pluginScanDirs must all be absolute paths'); + } + + for (const extraPluginScanDir of options.extraPluginScanDirs || []) { + if (!Path.isAbsolute(extraPluginScanDir)) { + throw new TypeError('extraPluginScanDirs must all be absolute paths'); + } + pluginScanDirs.push(extraPluginScanDir); + } + + const pluginPaths = options.pluginPaths || []; + if (!pluginPaths.every(s => Path.isAbsolute(s))) { + throw new TypeError('pluginPaths must all be absolute paths'); + } + + const maxWorkerCount = + options.maxWorkerCount ?? Math.max(Math.ceil(Math.max(Os.cpus()?.length, 1) / 3), 2); + if (typeof maxWorkerCount !== 'number' || !Number.isFinite(maxWorkerCount)) { + throw new TypeError('worker count must be a number'); + } + + const optimizerCachePath = + options.optimizerCachePath === false + ? false + : options.optimizerCachePath || + Path.resolve(options.repoRoot, 'data/.kbn-optimizer-cache.json'); + if (optimizerCachePath && !Path.isAbsolute(optimizerCachePath)) { + throw new TypeError('optimizerCachePath must be absolute'); + } + + return { + watch, + dist, + repoRoot, + maxWorkerCount, + profileWebpack, + optimizerCachePath, + pluginScanDirs, + pluginPaths, + }; + } + + static create(inputOptions: Options) { + const options = OptimizerConfig.parseOptions(inputOptions); + + const plugins = findNewPlatformPlugins(options.pluginScanDirs, options.pluginPaths); + + const cache = new OptimizerCache(options.optimizerCachePath); + + const bundles = getBundleDefinitions(plugins, options.repoRoot); + + const workers = assignBundlesToWorkers({ + bundles, + cache, + maxWorkerCount: options.maxWorkerCount, + repoRoot: options.repoRoot, + watch: options.watch, + dist: options.dist, + profileWebpack: options.profileWebpack, + }); + + return new OptimizerConfig( + cache, + bundles, + workers.map(w => w.config), + options.watch + ); + } + + constructor( + public readonly cache: OptimizerCache, + public readonly bundles: BundleDefinition[], + public readonly workers: WorkerConfig[], + public readonly watch: boolean + ) {} +} diff --git a/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts b/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts new file mode 100644 index 0000000000000..24814674aeb32 --- /dev/null +++ b/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts @@ -0,0 +1,89 @@ +/* + * 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 Path from 'path'; + +import webpack from 'webpack'; +import isPathInside from 'is-path-inside'; + +import { BundleDefinition } from '../common'; + +const ANY_LEGACY_DIR = `${Path.sep}legacy${Path.sep}`; + +interface ResolveData { + /** compilation context */ + context: string; + /** full request (with loaders) */ + request: string; + dependencies: [ + { + module: unknown; + weak: boolean; + optional: boolean; + loc: unknown; + request: string; + userRequest: string; + } + ]; + /** absolute path, but probably includes loaders in some cases */ + userRequest: string; + /** string from source code */ + rawRequest: string; + loaders: unknown; + /** absolute path to file, but probablt includes loaders in some cases */ + resource: string; + /** module type */ + type: string | 'javascript/auto'; + + resourceResolveData: { + context: { + /** absolute path to the file that issued the request */ + issuer: string; + }; + /** absolute path to the resolved file */ + path: string; + }; +} + +export class BlockLegacyCodePlugin { + constructor(private readonly def: BundleDefinition) {} + + apply(compiler: webpack.Compiler) { + compiler.hooks.normalModuleFactory.tap(BlockLegacyCodePlugin.name, normalModuleFactory => { + normalModuleFactory.hooks.afterResolve.tap( + BlockLegacyCodePlugin.name, + (resolveData: ResolveData) => { + const { + rawRequest, + resourceResolveData: { context, path }, + } = resolveData; + + if (path.includes(ANY_LEGACY_DIR) && !isPathInside(path, resolveData.context)) { + const issuerRelative = Path.relative(this.def.sourceRoot, context.issuer); + const resolveRelative = Path.relative(this.def.sourceRoot, path); + // eslint-disable-next-line no-console + console.error( + `[${this.def.id}] is importing from legacy code:\nrequest: ${rawRequest}\nfrom: ${issuerRelative}\nresolved to: ${resolveRelative}` + ); + } + } + ); + }); + } +} diff --git a/packages/kbn-optimizer/src/worker/postcss.config.js b/packages/kbn-optimizer/src/worker/postcss.config.js new file mode 100644 index 0000000000000..571bae86dee37 --- /dev/null +++ b/packages/kbn-optimizer/src/worker/postcss.config.js @@ -0,0 +1,22 @@ +/* + * 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 = { + plugins: [require('autoprefixer')()], +}; diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts new file mode 100644 index 0000000000000..082a1adad3595 --- /dev/null +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -0,0 +1,208 @@ +/* + * 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 'source-map-support/register'; + +import Fs from 'fs'; +import Path from 'path'; + +import webpack, { Stats } from 'webpack'; +import * as Rx from 'rxjs'; +import { mergeMap, map, mapTo, takeUntil } from 'rxjs/operators'; + +import { CompilerMessages, WorkerMessages } from '../common'; +import { getWebpackConfig } from './webpack.config'; +import { isFailureStats, failedStatsToErrorMessage } from './webpack_helpers'; +import { + parseWorkerConfig, + BundleDefinition, + WorkerConfig, + isWorkerMessage, + WorkerMessage, +} from '../common'; + +const PLUGIN_NAME = '@kbn/optimizer'; +const workerMsgs = new WorkerMessages(); +if (!process.send) { + throw new Error('worker process was not started with an IPC channel'); +} + +const send = (msg: WorkerMessage) => { + if (!process.send) { + // parent is gone + process.exit(0); + } else { + process.send(msg); + } +}; + +// check for connected parent on an unref'd timer rather than listening +// to "disconnect" since that listner prevents the process from exiting +setInterval(() => { + if (!process.connected) { + // parent is gone + process.exit(0); + } +}, 1000).unref(); + +const runWorker = (workerConfig: WorkerConfig) => { + const multiCompiler = webpack( + workerConfig.bundles.map(def => getWebpackConfig(def, workerConfig)) + ); + + return Rx.merge( + /** + * convert each compiler into an event stream that represents + * the status of each compiler, if we aren't watching the streams + * will complete after the compilers are complete. + * + * If a significant error occurs the stream will error + */ + Rx.from(multiCompiler.compilers.entries()).pipe( + mergeMap(([compilerIndex, compiler]) => { + const definition = workerConfig.bundles[compilerIndex]; + return observeCompiler(workerConfig, definition, compiler); + }) + ), + + /** + * compilers have been hooked up for their events, trigger run()/watch() + */ + Rx.defer(() => { + if (!workerConfig.watch) { + multiCompiler.run(() => {}); + } else { + multiCompiler.watch({}, () => {}); + } + + return []; + }) + ); +}; + +const observeCompiler = ( + workerConfig: WorkerConfig, + def: BundleDefinition, + compiler: webpack.Compiler +) => { + const compilerMsgs = new CompilerMessages(def.id); + const done$ = new Rx.Subject(); + const { beforeRun, watchRun, done } = compiler.hooks; + + /** + * Called by webpack as a single run compilation is starting + */ + const started$ = Rx.merge( + Rx.fromEventPattern(cb => beforeRun.tap(PLUGIN_NAME, cb)), + Rx.fromEventPattern(cb => watchRun.tap(PLUGIN_NAME, cb)) + ).pipe(mapTo(compilerMsgs.running())); + + /** + * Called by webpack as any compilation is complete. If the + * needAdditionalPass property is set then another compilation + * is about to be started, so we shouldn't send complete quite yet + */ + const complete$ = Rx.fromEventPattern(cb => done.tap(PLUGIN_NAME, cb)).pipe( + mergeMap(stats => { + // @ts-ignore not included in types, but it is real https://github.com/webpack/webpack/blob/ab4fa8ddb3f433d286653cd6af7e3aad51168649/lib/Watching.js#L58 + if (stats.compilation.needAdditionalPass) { + return []; + } + + if (workerConfig.profileWebpack) { + Fs.writeFileSync(Path.resolve(def.outputDir, 'stats.json'), JSON.stringify(stats.toJson())); + } + + if (!workerConfig.watch) { + process.nextTick(() => done$.next()); + } + + if (isFailureStats(stats)) { + return [ + compilerMsgs.compilerFailure({ + failure: failedStatsToErrorMessage(stats), + }), + ]; + } + + return [ + compilerMsgs.compilerSuccess({ + moduleCount: stats.compilation.modules.length, + }), + ]; + }) + ); + + /** + * Called whenever the compilation results in an error that + * prevets assets from being emitted, and prevents watching + * from continuing. + */ + const error$ = Rx.fromEventPattern(cb => compiler.hooks.failed.tap(PLUGIN_NAME, cb)).pipe( + map(error => { + throw compilerMsgs.error(error); + }) + ); + + /** + * Merge events into a single stream, if we're not watching + * complete the stream after our first complete$ event + */ + return Rx.merge(started$, complete$, error$).pipe(takeUntil(done$)); +}; + +const exit = (code: number) => { + process.exitCode = code; + setTimeout(() => { + send( + workerMsgs.error( + new Error('process did not automatically exit within 5 seconds, forcing exit') + ) + ); + process.exit(1); + }, 5000).unref(); +}; + +Rx.defer(() => { + const parse = parseWorkerConfig(process.argv[2]); + + if (parse.error) { + throw parse.error; + } + + return Rx.of(parse.workerConfig); +}) + .pipe(mergeMap(runWorker)) + .subscribe( + msg => { + send(msg); + }, + error => { + if (isWorkerMessage(error)) { + send(error); + } else { + send(workerMsgs.error(error)); + } + + exit(1); + }, + () => { + exit(0); + } + ); diff --git a/packages/kbn-optimizer/src/worker/theme_loader.ts b/packages/kbn-optimizer/src/worker/theme_loader.ts new file mode 100644 index 0000000000000..6d6686a5bde1b --- /dev/null +++ b/packages/kbn-optimizer/src/worker/theme_loader.ts @@ -0,0 +1,32 @@ +/* + * 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 webpack from 'webpack'; +import { stringifyRequest } from 'loader-utils'; + +// eslint-disable-next-line import/no-default-export +export default function(this: webpack.loader.LoaderContext) { + return ` +if (window.__kbnDarkMode__) { + require(${stringifyRequest(this, `${this.resourcePath}?dark`)}) +} else { + require(${stringifyRequest(this, `${this.resourcePath}?light`)}); +} + `; +} diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts new file mode 100644 index 0000000000000..f124c9bc86dbd --- /dev/null +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -0,0 +1,240 @@ +/* + * 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 Path from 'path'; + +import { stringifyRequest } from 'loader-utils'; +import webpack from 'webpack'; +// @ts-ignore +import TerserPlugin from 'terser-webpack-plugin'; +// @ts-ignore +import webpackMerge from 'webpack-merge'; +// @ts-ignore +import { CleanWebpackPlugin } from 'clean-webpack-plugin'; +import * as SharedDeps from '@kbn/ui-shared-deps'; + +import { BundleDefinition, WorkerConfig } from '../common'; +// import { BlockLegacyCodePlugin } from './block_legacy_code_plugin'; + +const IS_CODE_COVERAGE = !!process.env.CODE_COVERAGE; +const ISTANBUL_PRESET_PATH = require.resolve('@kbn/babel-preset/istanbul_preset'); +const PUBLIC_PATH_PLACEHOLDER = '__REPLACE_WITH_PUBLIC_PATH__'; +const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset'); + +export function getWebpackConfig(def: BundleDefinition, worker: WorkerConfig) { + const commonConfig: webpack.Configuration = { + node: { fs: 'empty' }, + context: def.contextDir, + cache: true, + entry: { + [def.id]: def.entry, + }, + + devtool: worker.dist ? false : '#cheap-source-map', + profile: worker.profileWebpack, + + output: { + path: def.outputDir, + filename: '[name].plugin.js', + publicPath: PUBLIC_PATH_PLACEHOLDER, + devtoolModuleFilenameTemplate: info => + `/${def.type}:${def.id}/${Path.relative(def.sourceRoot, info.absoluteResourcePath)}${ + info.query + }`, + jsonpFunction: `${def.id}_bundle_jsonpfunction`, + ...(def.type === 'plugin' + ? { + // When the entry point is loaded, assign it's exported `plugin` + // value to a key on the global `__kbnBundles__` object. + // NOTE: Only actually used by new platform plugins + library: ['__kbnBundles__', `plugin/${def.id}`], + libraryExport: 'plugin', + } + : {}), + }, + + optimization: { + noEmitOnErrors: true, + }, + + externals: { + ...SharedDeps.externals, + }, + + plugins: [new CleanWebpackPlugin() /* , new BlockLegacyCodePlugin(def) */], + + module: { + // no parse rules for a few known large packages which have no require() statements + noParse: [ + /[\///]node_modules[\///]elasticsearch-browser[\///]/, + /[\///]node_modules[\///]lodash[\///]index\.js/, + ], + + rules: [ + { + test: /\.css$/, + include: /node_modules/, + use: [ + { + loader: 'style-loader', + }, + { + loader: 'css-loader', + options: { + sourceMap: !worker.dist, + }, + }, + ], + }, + { + test: /\.scss$/, + exclude: /node_modules/, + oneOf: [ + { + resourceQuery: /dark|light/, + use: [ + { + loader: 'style-loader', + }, + { + loader: 'css-loader', + options: { + sourceMap: !worker.dist, + }, + }, + { + loader: 'postcss-loader', + options: { + sourceMap: !worker.dist, + config: { + path: require.resolve('./postcss.config'), + }, + }, + }, + { + loader: 'sass-loader', + options: { + sourceMap: !worker.dist, + prependData(loaderContext: webpack.loader.LoaderContext) { + return `@import ${stringifyRequest( + loaderContext, + Path.resolve( + worker.repoRoot, + 'src/legacy/ui/public/styles/_styling_constants.scss' + ) + )};\n`; + }, + webpackImporter: false, + implementation: require('node-sass'), + sassOptions(loaderContext: webpack.loader.LoaderContext) { + const darkMode = loaderContext.resourceQuery === '?dark'; + + return { + outputStyle: 'nested', + includePaths: [Path.resolve(worker.repoRoot, 'node_modules')], + sourceMapRoot: `/${def.type}:${def.id}`, + importer: (url: string) => { + if (darkMode && url.includes('eui_colors_light')) { + return { file: url.replace('eui_colors_light', 'eui_colors_dark') }; + } + + return { file: url }; + }, + }; + }, + }, + }, + ], + }, + { + loader: require.resolve('./theme_loader'), + }, + ], + }, + { + test: /\.(woff|woff2|ttf|eot|svg|ico|png|jpg|gif|jpeg)(\?|$)/, + loader: 'url-loader', + options: { + limit: 8192, + }, + }, + { + test: /\.(js|tsx?)$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader', + options: { + babelrc: false, + presets: IS_CODE_COVERAGE + ? [ISTANBUL_PRESET_PATH, BABEL_PRESET_PATH] + : [BABEL_PRESET_PATH], + }, + }, + }, + ], + }, + + resolve: { + extensions: ['.js', '.ts', '.tsx', '.json'], + alias: { + tinymath: require.resolve('tinymath/lib/tinymath.es5.js'), + querystring: require.resolve('querystring-browser'), + }, + }, + + performance: { + // NOTE: we are disabling this as those hints + // are more tailored for the final bundles result + // and not for the webpack compilations performance itself + hints: false, + }, + }; + + const nonDistributableConfig: webpack.Configuration = { + mode: 'development', + }; + + const distributableConfig: webpack.Configuration = { + mode: 'production', + + plugins: [ + new webpack.DefinePlugin({ + 'process.env': { + IS_KIBANA_DISTRIBUTABLE: `"true"`, + }, + }), + ], + + optimization: { + minimizer: [ + new TerserPlugin({ + cache: false, + sourceMap: false, + extractComments: false, + terserOptions: { + compress: false, + mangle: false, + }, + }), + ], + }, + }; + + return webpackMerge(commonConfig, worker.dist ? distributableConfig : nonDistributableConfig); +} diff --git a/packages/kbn-optimizer/src/worker/webpack_helpers.ts b/packages/kbn-optimizer/src/worker/webpack_helpers.ts new file mode 100644 index 0000000000000..65e728db0cc6b --- /dev/null +++ b/packages/kbn-optimizer/src/worker/webpack_helpers.ts @@ -0,0 +1,66 @@ +/* + * 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 webpack from 'webpack'; +import { defaults } from 'lodash'; +// @ts-ignore +import Stats from 'webpack/lib/Stats'; + +export function isFailureStats(stats: webpack.Stats) { + if (stats.hasErrors()) { + return true; + } + + const { warnings } = stats.toJson({ all: false, warnings: true }); + + // 1 - when typescript doesn't do a full type check, as we have the ts-loader + // configured here, it does not have enough information to determine + // whether an imported name is a type or not, so when the name is then + // exported, typescript has no choice but to emit the export. Fortunately, + // the extraneous export should not be harmful, so we just suppress these warnings + // https://github.com/TypeStrong/ts-loader#transpileonly-boolean-defaultfalse + // + // 2 - Mini Css Extract plugin tracks the order for each css import we have + // through the project (and it's successive imports) since version 0.4.2. + // In case we have the same imports more than one time with different + // sequences, this plugin will throw a warning. This should not be harmful, + // but the an issue was opened and can be followed on: + // https://github.com/webpack-contrib/mini-css-extract-plugin/issues/250#issuecomment-415345126 + const filteredWarnings = Stats.filterWarnings(warnings, STATS_WARNINGS_FILTER); + + return filteredWarnings.length > 0; +} + +const STATS_WARNINGS_FILTER = new RegExp( + [ + '(export .* was not found in)', + '|(chunk .* \\[mini-css-extract-plugin\\]\\\nConflicting order between:)', + ].join('') +); + +export function failedStatsToErrorMessage(stats: webpack.Stats) { + const details = stats.toString( + defaults( + { colors: true, warningsFilter: STATS_WARNINGS_FILTER }, + Stats.presetToOptions('minimal') + ) + ); + + return `Optimizations failure.\n${details.split('\n').join('\n ')}`; +} diff --git a/packages/kbn-optimizer/tsconfig.json b/packages/kbn-optimizer/tsconfig.json new file mode 100644 index 0000000000000..e2994f4d02414 --- /dev/null +++ b/packages/kbn-optimizer/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "include": [ + "index.d.ts", + "src/**/*" + ] +} diff --git a/packages/kbn-plugin-generator/integration_tests/generate_plugin.test.js b/packages/kbn-plugin-generator/integration_tests/generate_plugin.test.js index aa6611f3b6738..f8688c1830402 100644 --- a/packages/kbn-plugin-generator/integration_tests/generate_plugin.test.js +++ b/packages/kbn-plugin-generator/integration_tests/generate_plugin.test.js @@ -24,7 +24,7 @@ import util from 'util'; import { stat, readFileSync } from 'fs'; import { snakeCase } from 'lodash'; import del from 'del'; -import { withProcRunner, ToolingLog } from '@kbn/dev-utils'; +import { ProcRunner, ToolingLog } from '@kbn/dev-utils'; import { createLegacyEsTestCluster } from '@kbn/test'; import execa from 'execa'; @@ -92,27 +92,30 @@ describe(`running the plugin-generator via 'node scripts/generate_plugin.js plug }); describe('with es instance', () => { - const log = new ToolingLog(); + const log = new ToolingLog({ + level: 'verbose', + writeTo: process.stdout, + }); + const pr = new ProcRunner(log); const es = createLegacyEsTestCluster({ license: 'basic', log }); beforeAll(es.start); afterAll(es.stop); + afterAll(() => pr.teardown()); it(`'yarn start' should result in the spec plugin being initialized on kibana's stdout`, async () => { - await withProcRunner(log, async proc => { - await proc.run('kibana', { - cmd: 'yarn', - args: [ - 'start', - '--optimize.enabled=false', - '--logging.json=false', - '--migrations.skip=true', - ], - cwd: generatedPath, - wait: /ispec_plugin.+Status changed from uninitialized to green - Ready/, - }); - await proc.stop('kibana'); + await pr.run('kibana', { + cmd: 'yarn', + args: [ + 'start', + '--optimize.enabled=false', + '--logging.json=false', + '--migrations.skip=true', + ], + cwd: generatedPath, + wait: /ispec_plugin.+Status changed from uninitialized to green - Ready/, }); + await pr.stop('kibana'); }); }); diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 8bded9d403c21..dd17b59555f61 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -4497,7 +4497,7 @@ exports.pickLevelFromFlags = tooling_log_1.pickLevelFromFlags; exports.ToolingLogCollectingWriter = tooling_log_1.ToolingLogCollectingWriter; var serializers_1 = __webpack_require__(420); exports.createAbsolutePathSerializer = serializers_1.createAbsolutePathSerializer; -var certs_1 = __webpack_require__(422); +var certs_1 = __webpack_require__(445); exports.CA_CERT_PATH = certs_1.CA_CERT_PATH; exports.ES_KEY_PATH = certs_1.ES_KEY_PATH; exports.ES_CERT_PATH = certs_1.ES_CERT_PATH; @@ -4509,13 +4509,13 @@ exports.KBN_KEY_PATH = certs_1.KBN_KEY_PATH; exports.KBN_CERT_PATH = certs_1.KBN_CERT_PATH; exports.KBN_P12_PATH = certs_1.KBN_P12_PATH; exports.KBN_P12_PASSWORD = certs_1.KBN_P12_PASSWORD; -var run_1 = __webpack_require__(423); +var run_1 = __webpack_require__(446); exports.run = run_1.run; exports.createFailError = run_1.createFailError; exports.createFlagError = run_1.createFlagError; exports.combineErrors = run_1.combineErrors; exports.isFailError = run_1.isFailError; -var repo_root_1 = __webpack_require__(428); +var repo_root_1 = __webpack_require__(422); exports.REPO_ROOT = repo_root_1.REPO_ROOT; var kbn_client_1 = __webpack_require__(451); exports.KbnClient = kbn_client_1.KbnClient; @@ -36959,7 +36959,8 @@ exports.createAbsolutePathSerializer = absolute_path_serializer_1.createAbsolute * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -function createAbsolutePathSerializer(rootPath) { +const repo_root_1 = __webpack_require__(422); +function createAbsolutePathSerializer(rootPath = repo_root_1.REPO_ROOT) { return { print: (value) => value.replace(rootPath, '').replace(/\\/g, '/'), test: (value) => typeof value === 'string' && value.startsWith(rootPath), @@ -36974,79 +36975,6 @@ exports.createAbsolutePathSerializer = createAbsolutePathSerializer; "use strict"; -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -const path_1 = __webpack_require__(16); -exports.CA_CERT_PATH = path_1.resolve(__dirname, '../certs/ca.crt'); -exports.ES_KEY_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.key'); -exports.ES_CERT_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.crt'); -exports.ES_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.p12'); -exports.ES_P12_PASSWORD = 'storepass'; -exports.ES_EMPTYPASSWORD_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch_emptypassword.p12'); -exports.ES_NOPASSWORD_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch_nopassword.p12'); -exports.KBN_KEY_PATH = path_1.resolve(__dirname, '../certs/kibana.key'); -exports.KBN_CERT_PATH = path_1.resolve(__dirname, '../certs/kibana.crt'); -exports.KBN_P12_PATH = path_1.resolve(__dirname, '../certs/kibana.p12'); -exports.KBN_P12_PASSWORD = 'storepass'; - - -/***/ }), -/* 423 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -var run_1 = __webpack_require__(424); -exports.run = run_1.run; -var fail_1 = __webpack_require__(425); -exports.createFailError = fail_1.createFailError; -exports.createFlagError = fail_1.createFlagError; -exports.combineErrors = fail_1.combineErrors; -exports.isFailError = fail_1.isFailError; - - -/***/ }), -/* 424 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -37067,678 +36995,166 @@ exports.isFailError = fail_1.isFailError; */ Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = __webpack_require__(36); -// @ts-ignore @types are outdated and module is super simple -const exit_hook_1 = tslib_1.__importDefault(__webpack_require__(348)); -const tooling_log_1 = __webpack_require__(415); -const fail_1 = __webpack_require__(425); -const flags_1 = __webpack_require__(426); -const proc_runner_1 = __webpack_require__(37); -async function run(fn, options = {}) { - var _a; - const flags = flags_1.getFlags(process.argv.slice(2), options); - if (flags.help) { - process.stderr.write(flags_1.getHelp(options)); - process.exit(1); - } - const log = new tooling_log_1.ToolingLog({ - level: tooling_log_1.pickLevelFromFlags(flags), - writeTo: process.stdout, - }); - process.on('unhandledRejection', error => { - log.error('UNHANDLED PROMISE REJECTION'); - log.error(error); - process.exit(1); - }); - const handleErrorWithoutExit = (error) => { - if (fail_1.isFailError(error)) { - log.error(error.message); - if (error.showHelp) { - log.write(flags_1.getHelp(options)); - } - process.exitCode = error.exitCode; - } - else { - log.error('UNHANDLED ERROR'); - log.error(error); - process.exitCode = 1; - } - }; - const doCleanup = () => { - const tasks = cleanupTasks.slice(0); - cleanupTasks.length = 0; - for (const task of tasks) { - try { - task(); - } - catch (error) { - handleErrorWithoutExit(error); - } - } - }; - const unhookExit = exit_hook_1.default(doCleanup); - const cleanupTasks = [unhookExit]; +const path_1 = tslib_1.__importDefault(__webpack_require__(16)); +const fs_1 = tslib_1.__importDefault(__webpack_require__(23)); +const load_json_file_1 = tslib_1.__importDefault(__webpack_require__(423)); +const isKibanaDir = (dir) => { try { - if (!((_a = options.flags) === null || _a === void 0 ? void 0 : _a.allowUnexpected) && flags.unexpected.length) { - throw fail_1.createFlagError(`Unknown flag(s) "${flags.unexpected.join('", "')}"`); - } - try { - await proc_runner_1.withProcRunner(log, async (procRunner) => { - await fn({ - log, - flags, - procRunner, - addCleanupTask: (task) => cleanupTasks.push(task), - }); - }); - } - finally { - doCleanup(); + const path = path_1.default.resolve(dir, 'package.json'); + const json = load_json_file_1.default.sync(path); + if (json && typeof json === 'object' && 'name' in json && json.name === 'kibana') { + return true; } } catch (error) { - handleErrorWithoutExit(error); - process.exit(); + if (error && error.code === 'ENOENT') { + return false; + } + throw error; + } +}; +// search for the kibana directory, since this file is moved around it might +// not be where we think but should always be a relatively close parent +// of this directory +const startDir = fs_1.default.realpathSync(__dirname); +const { root: rootDir } = path_1.default.parse(startDir); +let cursor = startDir; +while (true) { + if (isKibanaDir(cursor)) { + break; + } + const parent = path_1.default.dirname(cursor); + if (parent === rootDir) { + throw new Error(`unable to find kibana directory from ${startDir}`); } + cursor = parent; } -exports.run = run; +exports.REPO_ROOT = cursor; /***/ }), -/* 425 */ +/* 423 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -const util_1 = __webpack_require__(29); -const FAIL_TAG = Symbol('fail error'); -function createFailError(reason, options = {}) { - const { exitCode = 1, showHelp = false } = options; - return Object.assign(new Error(reason), { - exitCode, - showHelp, - [FAIL_TAG]: true, - }); -} -exports.createFailError = createFailError; -function createFlagError(reason) { - return createFailError(reason, { - showHelp: true, - }); -} -exports.createFlagError = createFlagError; -function isFailError(error) { - return Boolean(error && error[FAIL_TAG]); -} -exports.isFailError = isFailError; -function combineErrors(errors) { - if (errors.length === 1) { - return errors[0]; - } - const exitCode = errors - .filter(isFailError) - .reduce((acc, error) => Math.max(acc, error.exitCode), 1); - const showHelp = errors.some(error => isFailError(error) && error.showHelp); - const message = errors.reduce((acc, error) => { - if (isFailError(error)) { - return acc + '\n' + error.message; - } - return acc + `\nUNHANDLED ERROR\n${util_1.inspect(error)}`; - }, ''); - return createFailError(`${errors.length} errors:\n${message}`, { - exitCode, - showHelp, - }); -} -exports.combineErrors = combineErrors; - - -/***/ }), -/* 426 */ -/***/ (function(module, exports, __webpack_require__) { +const path = __webpack_require__(16); +const {promisify} = __webpack_require__(29); +const fs = __webpack_require__(424); +const stripBom = __webpack_require__(428); +const parseJson = __webpack_require__(429); -"use strict"; +const parse = (data, filePath, options = {}) => { + data = stripBom(data); -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -const tslib_1 = __webpack_require__(36); -const path_1 = __webpack_require__(16); -const dedent_1 = tslib_1.__importDefault(__webpack_require__(14)); -const getopts_1 = tslib_1.__importDefault(__webpack_require__(427)); -function getFlags(argv, options) { - const unexpectedNames = new Set(); - const flagOpts = options.flags || {}; - const { verbose, quiet, silent, debug, help, _, ...others } = getopts_1.default(argv, { - string: flagOpts.string, - boolean: [...(flagOpts.boolean || []), 'verbose', 'quiet', 'silent', 'debug', 'help'], - alias: { - ...(flagOpts.alias || {}), - v: 'verbose', - }, - default: flagOpts.default, - unknown: (name) => { - unexpectedNames.add(name); - return flagOpts.guessTypesForUnexpectedFlags; - }, - }); - const unexpected = []; - for (const unexpectedName of unexpectedNames) { - const matchingArgv = []; - iterArgv: for (const [i, v] of argv.entries()) { - for (const prefix of ['--', '-']) { - if (v.startsWith(prefix)) { - // -/--name=value - if (v.startsWith(`${prefix}${unexpectedName}=`)) { - matchingArgv.push(v); - continue iterArgv; - } - // -/--name (value possibly follows) - if (v === `${prefix}${unexpectedName}`) { - matchingArgv.push(v); - // value follows -/--name - if (argv.length > i + 1 && !argv[i + 1].startsWith('-')) { - matchingArgv.push(argv[i + 1]); - } - continue iterArgv; - } - } - } - // special case for `--no-{flag}` disabling of boolean flags - if (v === `--no-${unexpectedName}`) { - matchingArgv.push(v); - continue iterArgv; - } - // special case for shortcut flags formatted as `-abc` where `a`, `b`, - // and `c` will be three separate unexpected flags - if (unexpectedName.length === 1 && - v[0] === '-' && - v[1] !== '-' && - !v.includes('=') && - v.includes(unexpectedName)) { - matchingArgv.push(`-${unexpectedName}`); - continue iterArgv; - } - } - if (matchingArgv.length) { - unexpected.push(...matchingArgv); - } - else { - throw new Error(`unable to find unexpected flag named "${unexpectedName}"`); - } - } - return { - verbose, - quiet, - silent, - debug, - help, - _, - unexpected, - ...others, - }; -} -exports.getFlags = getFlags; -function getHelp(options) { - var _a, _b; - const usage = options.usage || `node ${path_1.relative(process.cwd(), process.argv[1])}`; - const optionHelp = (dedent_1.default(((_b = (_a = options) === null || _a === void 0 ? void 0 : _a.flags) === null || _b === void 0 ? void 0 : _b.help) || '') + - '\n' + - dedent_1.default ` - --verbose, -v Log verbosely - --debug Log debug messages (less than verbose) - --quiet Only log errors - --silent Don't log anything - --help Show this message - `) - .split('\n') - .filter(Boolean) - .join('\n '); - return ` - ${usage} + if (typeof options.beforeParse === 'function') { + data = options.beforeParse(data); + } - ${dedent_1.default(options.description || 'Runs a dev task') - .split('\n') - .join('\n ')} + return parseJson(data, options.reviver, path.relative(process.cwd(), filePath)); +}; - Options: - ${optionHelp + '\n\n'}`; -} -exports.getHelp = getHelp; +module.exports = async (filePath, options) => parse(await promisify(fs.readFile)(filePath, 'utf8'), filePath, options); +module.exports.sync = (filePath, options) => parse(fs.readFileSync(filePath, 'utf8'), filePath, options); /***/ }), -/* 427 */ +/* 424 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - - -const EMPTYARR = [] -const SHORTSPLIT = /$|[!-@[-`{-~][\s\S]*/g -const isArray = Array.isArray - -const parseValue = function(any) { - if (any === "") return "" - if (any === "false") return false - const maybe = Number(any) - return maybe * 0 === 0 ? maybe : any -} +var fs = __webpack_require__(23) +var polyfills = __webpack_require__(425) +var legacy = __webpack_require__(426) +var clone = __webpack_require__(427) -const parseAlias = function(aliases) { - let out = {}, - key, - alias, - prev, - len, - any, - i, - k +var queue = [] - for (key in aliases) { - any = aliases[key] - alias = out[key] = isArray(any) ? any : [any] +var util = __webpack_require__(29) - for (i = 0, len = alias.length; i < len; i++) { - prev = out[alias[i]] = [key] +function noop () {} - for (k = 0; k < len; k++) { - if (i !== k) prev.push(alias[k]) - } - } +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 out +if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { + process.on('exit', function() { + debug(queue) + __webpack_require__(30).equal(queue.length, 0) + }) } -const parseDefault = function(aliases, defaults) { - let out = {}, - key, - alias, - value, - len, - i +module.exports = patch(clone(fs)) +if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { + module.exports = patch(fs) + fs.__patched = true; +} - for (key in defaults) { - value = defaults[key] - alias = aliases[key] +// Always patch fs.close/closeSync, because we want 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. +module.exports.close = (function (fs$close) { return function (fd, cb) { + return fs$close.call(fs, fd, function (err) { + if (!err) + retry() - out[key] = value + if (typeof cb === 'function') + cb.apply(this, arguments) + }) +}})(fs.close) - if (alias === undefined) { - aliases[key] = EMPTYARR - } else { - for (i = 0, len = alias.length; i < len; i++) { - out[alias[i]] = value - } - } - } +module.exports.closeSync = (function (fs$closeSync) { return function (fd) { + // Note that graceful-fs also retries when fs.closeSync() fails. + // Looks like a bug to me, although it's probably a harmless one. + var rval = fs$closeSync.apply(fs, arguments) + retry() + return rval +}})(fs.closeSync) - return out +// Only patch fs once, otherwise we'll run into a memory leak if +// graceful-fs is loaded multiple times, such as in test environments that +// reset the loaded modules between tests. +// We look for the string `graceful-fs` from the comment above. This +// way we are not adding any extra properties and it will detect if older +// versions of graceful-fs are installed. +if (!/\bgraceful-fs\b/.test(fs.closeSync.toString())) { + fs.closeSync = module.exports.closeSync; + fs.close = module.exports.close; } -const parseOptions = function(aliases, options, value) { - let out = {}, - key, - alias, - len, - end, - i, - k - - if (options !== undefined) { - for (i = 0, len = options.length; i < len; i++) { - key = options[i] - alias = aliases[key] +function patch (fs) { + // Everything that references the open() function needs to be in here + polyfills(fs) + fs.gracefulify = patch + fs.FileReadStream = ReadStream; // Legacy name. + fs.FileWriteStream = WriteStream; // Legacy name. + 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 - out[key] = value + return go$readFile(path, options, cb) - if (alias === undefined) { - aliases[key] = EMPTYARR - } else { - for (k = 0, end = alias.length; k < end; k++) { - out[alias[k]] = value + 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() } - } - } - } - - return out -} - -const write = function(out, key, value, aliases, unknown) { - let i, - prev, - alias = aliases[key], - len = alias === undefined ? -1 : alias.length - - if (len >= 0 || unknown === undefined || unknown(key)) { - prev = out[key] - - if (prev === undefined) { - out[key] = value - } else { - if (isArray(prev)) { - prev.push(value) - } else { - out[key] = [prev, value] - } - } - - for (i = 0; i < len; i++) { - out[alias[i]] = out[key] - } - } -} - -const getopts = function(argv, opts) { - let unknown = (opts = opts || {}).unknown, - aliases = parseAlias(opts.alias), - strings = parseOptions(aliases, opts.string, ""), - values = parseDefault(aliases, opts.default), - bools = parseOptions(aliases, opts.boolean, false), - stopEarly = opts.stopEarly, - _ = [], - out = { _ }, - i = 0, - k = 0, - len = argv.length, - key, - arg, - end, - match, - value - - for (; i < len; i++) { - arg = argv[i] - - if (arg[0] !== "-" || arg === "-") { - if (stopEarly) while (i < len) _.push(argv[i++]) - else _.push(arg) - } else if (arg === "--") { - while (++i < len) _.push(argv[i]) - } else if (arg[1] === "-") { - end = arg.indexOf("=", 2) - if (arg[2] === "n" && arg[3] === "o" && arg[4] === "-") { - key = arg.slice(5, end >= 0 ? end : undefined) - value = false - } else if (end >= 0) { - key = arg.slice(2, end) - value = - bools[key] !== undefined || - (strings[key] === undefined - ? parseValue(arg.slice(end + 1)) - : arg.slice(end + 1)) - } else { - key = arg.slice(2) - value = - bools[key] !== undefined || - (len === i + 1 || argv[i + 1][0] === "-" - ? strings[key] === undefined - ? true - : "" - : strings[key] === undefined - ? parseValue(argv[++i]) - : argv[++i]) - } - write(out, key, value, aliases, unknown) - } else { - SHORTSPLIT.lastIndex = 2 - match = SHORTSPLIT.exec(arg) - end = match.index - value = match[0] - - for (k = 1; k < end; k++) { - write( - out, - (key = arg[k]), - k + 1 < end - ? strings[key] === undefined || - arg.substring(k + 1, (k = end)) + value - : value === "" - ? len === i + 1 || argv[i + 1][0] === "-" - ? strings[key] === undefined || "" - : bools[key] !== undefined || - (strings[key] === undefined ? parseValue(argv[++i]) : argv[++i]) - : bools[key] !== undefined || - (strings[key] === undefined ? parseValue(value) : value), - aliases, - unknown - ) - } - } - } - - for (key in values) if (out[key] === undefined) out[key] = values[key] - for (key in bools) if (out[key] === undefined) out[key] = false - for (key in strings) if (out[key] === undefined) out[key] = "" - - return out -} - -module.exports = getopts - - -/***/ }), -/* 428 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -const tslib_1 = __webpack_require__(36); -const path_1 = tslib_1.__importDefault(__webpack_require__(16)); -const fs_1 = tslib_1.__importDefault(__webpack_require__(23)); -const load_json_file_1 = tslib_1.__importDefault(__webpack_require__(429)); -const isKibanaDir = (dir) => { - try { - const path = path_1.default.resolve(dir, 'package.json'); - const json = load_json_file_1.default.sync(path); - if (json && typeof json === 'object' && 'name' in json && json.name === 'kibana') { - return true; - } - } - catch (error) { - if (error && error.code === 'ENOENT') { - return false; - } - throw error; - } -}; -// search for the kibana directory, since this file is moved around it might -// not be where we think but should always be a relatively close parent -// of this directory -const startDir = fs_1.default.realpathSync(__dirname); -const { root: rootDir } = path_1.default.parse(startDir); -let cursor = startDir; -while (true) { - if (isKibanaDir(cursor)) { - break; - } - const parent = path_1.default.dirname(cursor); - if (parent === rootDir) { - throw new Error(`unable to find kibana directory from ${startDir}`); - } - cursor = parent; -} -exports.REPO_ROOT = cursor; - - -/***/ }), -/* 429 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const path = __webpack_require__(16); -const {promisify} = __webpack_require__(29); -const fs = __webpack_require__(430); -const stripBom = __webpack_require__(434); -const parseJson = __webpack_require__(435); - -const parse = (data, filePath, options = {}) => { - data = stripBom(data); - - if (typeof options.beforeParse === 'function') { - data = options.beforeParse(data); - } - - return parseJson(data, options.reviver, path.relative(process.cwd(), filePath)); -}; - -module.exports = async (filePath, options) => parse(await promisify(fs.readFile)(filePath, 'utf8'), filePath, options); -module.exports.sync = (filePath, options) => parse(fs.readFileSync(filePath, 'utf8'), filePath, options); - - -/***/ }), -/* 430 */ -/***/ (function(module, exports, __webpack_require__) { - -var fs = __webpack_require__(23) -var polyfills = __webpack_require__(431) -var legacy = __webpack_require__(432) -var clone = __webpack_require__(433) - -var queue = [] - -var util = __webpack_require__(29) - -function noop () {} - -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) - } - -if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { - process.on('exit', function() { - debug(queue) - __webpack_require__(30).equal(queue.length, 0) - }) -} - -module.exports = patch(clone(fs)) -if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { - module.exports = patch(fs) - fs.__patched = true; -} - -// Always patch fs.close/closeSync, because we want 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. -module.exports.close = (function (fs$close) { return function (fd, cb) { - return fs$close.call(fs, fd, function (err) { - if (!err) - retry() - - if (typeof cb === 'function') - cb.apply(this, arguments) - }) -}})(fs.close) - -module.exports.closeSync = (function (fs$closeSync) { return function (fd) { - // Note that graceful-fs also retries when fs.closeSync() fails. - // Looks like a bug to me, although it's probably a harmless one. - var rval = fs$closeSync.apply(fs, arguments) - retry() - return rval -}})(fs.closeSync) - -// Only patch fs once, otherwise we'll run into a memory leak if -// graceful-fs is loaded multiple times, such as in test environments that -// reset the loaded modules between tests. -// We look for the string `graceful-fs` from the comment above. This -// way we are not adding any extra properties and it will detect if older -// versions of graceful-fs are installed. -if (!/\bgraceful-fs\b/.test(fs.closeSync.toString())) { - fs.closeSync = module.exports.closeSync; - fs.close = module.exports.close; -} - -function patch (fs) { - // Everything that references the open() function needs to be in here - polyfills(fs) - fs.gracefulify = patch - fs.FileReadStream = ReadStream; // Legacy name. - fs.FileWriteStream = WriteStream; // Legacy name. - 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) - - 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() - } - }) + }) } } @@ -37928,7 +37344,7 @@ function retry () { /***/ }), -/* 431 */ +/* 425 */ /***/ (function(module, exports, __webpack_require__) { var constants = __webpack_require__(25) @@ -38263,7 +37679,7 @@ function patch (fs) { /***/ }), -/* 432 */ +/* 426 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(27).Stream @@ -38387,7 +37803,7 @@ function legacy (fs) { /***/ }), -/* 433 */ +/* 427 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38413,7 +37829,7 @@ function clone (obj) { /***/ }), -/* 434 */ +/* 428 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38435,15 +37851,15 @@ module.exports = string => { /***/ }), -/* 435 */ +/* 429 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const errorEx = __webpack_require__(436); -const fallback = __webpack_require__(438); -const {default: LinesAndColumns} = __webpack_require__(439); -const {codeFrameColumns} = __webpack_require__(440); +const errorEx = __webpack_require__(430); +const fallback = __webpack_require__(432); +const {default: LinesAndColumns} = __webpack_require__(433); +const {codeFrameColumns} = __webpack_require__(434); const JSONError = errorEx('JSONError', { fileName: errorEx.append('in %s'), @@ -38492,14 +37908,14 @@ module.exports = (string, reviver, filename) => { /***/ }), -/* 436 */ +/* 430 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var isArrayish = __webpack_require__(437); +var isArrayish = __webpack_require__(431); var errorEx = function errorEx(name, properties) { if (!name || name.constructor !== String) { @@ -38632,7 +38048,7 @@ module.exports = errorEx; /***/ }), -/* 437 */ +/* 431 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38649,7 +38065,7 @@ module.exports = function isArrayish(obj) { /***/ }), -/* 438 */ +/* 432 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38688,7 +38104,7 @@ function parseJson (txt, reviver, context) { /***/ }), -/* 439 */ +/* 433 */ /***/ (function(__webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; @@ -38752,7 +38168,7 @@ var LinesAndColumns = (function () { /***/ }), -/* 440 */ +/* 434 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38765,7 +38181,7 @@ exports.codeFrameColumns = codeFrameColumns; exports.default = _default; function _highlight() { - const data = _interopRequireWildcard(__webpack_require__(441)); + const data = _interopRequireWildcard(__webpack_require__(435)); _highlight = function () { return data; @@ -38931,7 +38347,7 @@ function _default(rawLines, lineNumber, colNumber, opts = {}) { } /***/ }), -/* 441 */ +/* 435 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38945,7 +38361,7 @@ exports.getChalk = getChalk; exports.default = highlight; function _jsTokens() { - const data = _interopRequireWildcard(__webpack_require__(442)); + const data = _interopRequireWildcard(__webpack_require__(436)); _jsTokens = function () { return data; @@ -38955,7 +38371,7 @@ function _jsTokens() { } function _esutils() { - const data = _interopRequireDefault(__webpack_require__(443)); + const data = _interopRequireDefault(__webpack_require__(437)); _esutils = function () { return data; @@ -38965,7 +38381,7 @@ function _esutils() { } function _chalk() { - const data = _interopRequireDefault(__webpack_require__(447)); + const data = _interopRequireDefault(__webpack_require__(441)); _chalk = function () { return data; @@ -39066,7 +38482,7 @@ function highlight(code, options = {}) { } /***/ }), -/* 442 */ +/* 436 */ /***/ (function(module, exports) { // Copyright 2014, 2015, 2016, 2017, 2018 Simon Lydell @@ -39095,7 +38511,7 @@ exports.matchToToken = function(match) { /***/ }), -/* 443 */ +/* 437 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -39126,15 +38542,15 @@ exports.matchToToken = function(match) { (function () { 'use strict'; - exports.ast = __webpack_require__(444); - exports.code = __webpack_require__(445); - exports.keyword = __webpack_require__(446); + exports.ast = __webpack_require__(438); + exports.code = __webpack_require__(439); + exports.keyword = __webpack_require__(440); }()); /* vim: set sw=4 ts=4 et tw=80 : */ /***/ }), -/* 444 */ +/* 438 */ /***/ (function(module, exports) { /* @@ -39284,7 +38700,7 @@ exports.matchToToken = function(match) { /***/ }), -/* 445 */ +/* 439 */ /***/ (function(module, exports) { /* @@ -39425,7 +38841,7 @@ exports.matchToToken = function(match) { /***/ }), -/* 446 */ +/* 440 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -39455,7 +38871,7 @@ exports.matchToToken = function(match) { (function () { 'use strict'; - var code = __webpack_require__(445); + var code = __webpack_require__(439); function isStrictModeReservedWordES6(id) { switch (id) { @@ -39596,16 +39012,16 @@ exports.matchToToken = function(match) { /***/ }), -/* 447 */ +/* 441 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const escapeStringRegexp = __webpack_require__(3); -const ansiStyles = __webpack_require__(448); -const stdoutColor = __webpack_require__(449).stdout; +const ansiStyles = __webpack_require__(442); +const stdoutColor = __webpack_require__(443).stdout; -const template = __webpack_require__(450); +const template = __webpack_require__(444); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -39831,7 +39247,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 448 */ +/* 442 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40004,7 +39420,7 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 449 */ +/* 443 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40146,7 +39562,7 @@ module.exports = { /***/ }), -/* 450 */ +/* 444 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40281,7 +39697,7 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 451 */ +/* 445 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40305,14 +39721,22 @@ module.exports = (chalk, tmp) => { * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -var kbn_client_1 = __webpack_require__(452); -exports.KbnClient = kbn_client_1.KbnClient; -var kbn_client_requester_1 = __webpack_require__(453); -exports.uriencode = kbn_client_requester_1.uriencode; +const path_1 = __webpack_require__(16); +exports.CA_CERT_PATH = path_1.resolve(__dirname, '../certs/ca.crt'); +exports.ES_KEY_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.key'); +exports.ES_CERT_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.crt'); +exports.ES_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.p12'); +exports.ES_P12_PASSWORD = 'storepass'; +exports.ES_EMPTYPASSWORD_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch_emptypassword.p12'); +exports.ES_NOPASSWORD_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch_nopassword.p12'); +exports.KBN_KEY_PATH = path_1.resolve(__dirname, '../certs/kibana.key'); +exports.KBN_CERT_PATH = path_1.resolve(__dirname, '../certs/kibana.crt'); +exports.KBN_P12_PATH = path_1.resolve(__dirname, '../certs/kibana.p12'); +exports.KBN_P12_PASSWORD = 'storepass'; /***/ }), -/* 452 */ +/* 446 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40336,50 +39760,627 @@ exports.uriencode = kbn_client_requester_1.uriencode; * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -const kbn_client_requester_1 = __webpack_require__(453); -const kbn_client_status_1 = __webpack_require__(495); -const kbn_client_plugins_1 = __webpack_require__(496); -const kbn_client_version_1 = __webpack_require__(497); -const kbn_client_saved_objects_1 = __webpack_require__(498); -const kbn_client_ui_settings_1 = __webpack_require__(499); -class KbnClient { - /** - * Basic Kibana server client that implements common behaviors for talking - * to the Kibana server from dev tooling. - * - * @param log ToolingLog - * @param kibanaUrls Array of kibana server urls to send requests to - * @param uiSettingDefaults Map of uiSetting values that will be merged with all uiSetting resets - */ - constructor(log, kibanaUrls, uiSettingDefaults) { - this.log = log; - this.kibanaUrls = kibanaUrls; - this.uiSettingDefaults = uiSettingDefaults; - this.requester = new kbn_client_requester_1.KbnClientRequester(this.log, this.kibanaUrls); - this.status = new kbn_client_status_1.KbnClientStatus(this.requester); - this.plugins = new kbn_client_plugins_1.KbnClientPlugins(this.status); - this.version = new kbn_client_version_1.KbnClientVersion(this.status); - this.savedObjects = new kbn_client_saved_objects_1.KbnClientSavedObjects(this.log, this.requester); - this.uiSettings = new kbn_client_ui_settings_1.KbnClientUiSettings(this.log, this.requester, this.uiSettingDefaults); - if (!kibanaUrls.length) { - throw new Error('missing Kibana urls'); +var run_1 = __webpack_require__(447); +exports.run = run_1.run; +var fail_1 = __webpack_require__(448); +exports.createFailError = fail_1.createFailError; +exports.createFlagError = fail_1.createFlagError; +exports.combineErrors = fail_1.combineErrors; +exports.isFailError = fail_1.isFailError; + + +/***/ }), +/* 447 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const tslib_1 = __webpack_require__(36); +// @ts-ignore @types are outdated and module is super simple +const exit_hook_1 = tslib_1.__importDefault(__webpack_require__(348)); +const tooling_log_1 = __webpack_require__(415); +const fail_1 = __webpack_require__(448); +const flags_1 = __webpack_require__(449); +const proc_runner_1 = __webpack_require__(37); +async function run(fn, options = {}) { + var _a; + const flags = flags_1.getFlags(process.argv.slice(2), options); + if (flags.help) { + process.stderr.write(flags_1.getHelp(options)); + process.exit(1); + } + const log = new tooling_log_1.ToolingLog({ + level: tooling_log_1.pickLevelFromFlags(flags), + writeTo: process.stdout, + }); + process.on('unhandledRejection', error => { + log.error('UNHANDLED PROMISE REJECTION'); + log.error(error); + process.exit(1); + }); + const handleErrorWithoutExit = (error) => { + if (fail_1.isFailError(error)) { + log.error(error.message); + if (error.showHelp) { + log.write(flags_1.getHelp(options)); + } + process.exitCode = error.exitCode; + } + else { + log.error('UNHANDLED ERROR'); + log.error(error); + process.exitCode = 1; + } + }; + const doCleanup = () => { + const tasks = cleanupTasks.slice(0); + cleanupTasks.length = 0; + for (const task of tasks) { + try { + task(); + } + catch (error) { + handleErrorWithoutExit(error); + } + } + }; + const unhookExit = exit_hook_1.default(doCleanup); + const cleanupTasks = [unhookExit]; + try { + if (!((_a = options.flags) === null || _a === void 0 ? void 0 : _a.allowUnexpected) && flags.unexpected.length) { + throw fail_1.createFlagError(`Unknown flag(s) "${flags.unexpected.join('", "')}"`); + } + try { + await proc_runner_1.withProcRunner(log, async (procRunner) => { + await fn({ + log, + flags, + procRunner, + addCleanupTask: (task) => cleanupTasks.push(task), + }); + }); + } + finally { + doCleanup(); } } - /** - * Make a direct request to the Kibana server - */ - async request(options) { - return await this.requester.request(options); + catch (error) { + handleErrorWithoutExit(error); + process.exit(); } - resolveUrl(relativeUrl) { - return this.requester.resolveUrl(relativeUrl); +} +exports.run = run; + + +/***/ }), +/* 448 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const util_1 = __webpack_require__(29); +const FAIL_TAG = Symbol('fail error'); +function createFailError(reason, options = {}) { + const { exitCode = 1, showHelp = false } = options; + return Object.assign(new Error(reason), { + exitCode, + showHelp, + [FAIL_TAG]: true, + }); +} +exports.createFailError = createFailError; +function createFlagError(reason) { + return createFailError(reason, { + showHelp: true, + }); +} +exports.createFlagError = createFlagError; +function isFailError(error) { + return Boolean(error && error[FAIL_TAG]); +} +exports.isFailError = isFailError; +function combineErrors(errors) { + if (errors.length === 1) { + return errors[0]; } + const exitCode = errors + .filter(isFailError) + .reduce((acc, error) => Math.max(acc, error.exitCode), 1); + const showHelp = errors.some(error => isFailError(error) && error.showHelp); + const message = errors.reduce((acc, error) => { + if (isFailError(error)) { + return acc + '\n' + error.message; + } + return acc + `\nUNHANDLED ERROR\n${util_1.inspect(error)}`; + }, ''); + return createFailError(`${errors.length} errors:\n${message}`, { + exitCode, + showHelp, + }); } -exports.KbnClient = KbnClient; +exports.combineErrors = combineErrors; /***/ }), -/* 453 */ +/* 449 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const tslib_1 = __webpack_require__(36); +const path_1 = __webpack_require__(16); +const dedent_1 = tslib_1.__importDefault(__webpack_require__(14)); +const getopts_1 = tslib_1.__importDefault(__webpack_require__(450)); +function getFlags(argv, options) { + const unexpectedNames = new Set(); + const flagOpts = options.flags || {}; + const { verbose, quiet, silent, debug, help, _, ...others } = getopts_1.default(argv, { + string: flagOpts.string, + boolean: [...(flagOpts.boolean || []), 'verbose', 'quiet', 'silent', 'debug', 'help'], + alias: { + ...(flagOpts.alias || {}), + v: 'verbose', + }, + default: flagOpts.default, + unknown: (name) => { + unexpectedNames.add(name); + return flagOpts.guessTypesForUnexpectedFlags; + }, + }); + const unexpected = []; + for (const unexpectedName of unexpectedNames) { + const matchingArgv = []; + iterArgv: for (const [i, v] of argv.entries()) { + for (const prefix of ['--', '-']) { + if (v.startsWith(prefix)) { + // -/--name=value + if (v.startsWith(`${prefix}${unexpectedName}=`)) { + matchingArgv.push(v); + continue iterArgv; + } + // -/--name (value possibly follows) + if (v === `${prefix}${unexpectedName}`) { + matchingArgv.push(v); + // value follows -/--name + if (argv.length > i + 1 && !argv[i + 1].startsWith('-')) { + matchingArgv.push(argv[i + 1]); + } + continue iterArgv; + } + } + } + // special case for `--no-{flag}` disabling of boolean flags + if (v === `--no-${unexpectedName}`) { + matchingArgv.push(v); + continue iterArgv; + } + // special case for shortcut flags formatted as `-abc` where `a`, `b`, + // and `c` will be three separate unexpected flags + if (unexpectedName.length === 1 && + v[0] === '-' && + v[1] !== '-' && + !v.includes('=') && + v.includes(unexpectedName)) { + matchingArgv.push(`-${unexpectedName}`); + continue iterArgv; + } + } + if (matchingArgv.length) { + unexpected.push(...matchingArgv); + } + else { + throw new Error(`unable to find unexpected flag named "${unexpectedName}"`); + } + } + return { + verbose, + quiet, + silent, + debug, + help, + _, + unexpected, + ...others, + }; +} +exports.getFlags = getFlags; +function getHelp(options) { + var _a, _b; + const usage = options.usage || `node ${path_1.relative(process.cwd(), process.argv[1])}`; + const optionHelp = (dedent_1.default(((_b = (_a = options) === null || _a === void 0 ? void 0 : _a.flags) === null || _b === void 0 ? void 0 : _b.help) || '') + + '\n' + + dedent_1.default ` + --verbose, -v Log verbosely + --debug Log debug messages (less than verbose) + --quiet Only log errors + --silent Don't log anything + --help Show this message + `) + .split('\n') + .filter(Boolean) + .join('\n '); + return ` + ${usage} + + ${dedent_1.default(options.description || 'Runs a dev task') + .split('\n') + .join('\n ')} + + Options: + ${optionHelp + '\n\n'}`; +} +exports.getHelp = getHelp; + + +/***/ }), +/* 450 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const EMPTYARR = [] +const SHORTSPLIT = /$|[!-@[-`{-~][\s\S]*/g +const isArray = Array.isArray + +const parseValue = function(any) { + if (any === "") return "" + if (any === "false") return false + const maybe = Number(any) + return maybe * 0 === 0 ? maybe : any +} + +const parseAlias = function(aliases) { + let out = {}, + key, + alias, + prev, + len, + any, + i, + k + + for (key in aliases) { + any = aliases[key] + alias = out[key] = isArray(any) ? any : [any] + + for (i = 0, len = alias.length; i < len; i++) { + prev = out[alias[i]] = [key] + + for (k = 0; k < len; k++) { + if (i !== k) prev.push(alias[k]) + } + } + } + + return out +} + +const parseDefault = function(aliases, defaults) { + let out = {}, + key, + alias, + value, + len, + i + + for (key in defaults) { + value = defaults[key] + alias = aliases[key] + + out[key] = value + + if (alias === undefined) { + aliases[key] = EMPTYARR + } else { + for (i = 0, len = alias.length; i < len; i++) { + out[alias[i]] = value + } + } + } + + return out +} + +const parseOptions = function(aliases, options, value) { + let out = {}, + key, + alias, + len, + end, + i, + k + + if (options !== undefined) { + for (i = 0, len = options.length; i < len; i++) { + key = options[i] + alias = aliases[key] + + out[key] = value + + if (alias === undefined) { + aliases[key] = EMPTYARR + } else { + for (k = 0, end = alias.length; k < end; k++) { + out[alias[k]] = value + } + } + } + } + + return out +} + +const write = function(out, key, value, aliases, unknown) { + let i, + prev, + alias = aliases[key], + len = alias === undefined ? -1 : alias.length + + if (len >= 0 || unknown === undefined || unknown(key)) { + prev = out[key] + + if (prev === undefined) { + out[key] = value + } else { + if (isArray(prev)) { + prev.push(value) + } else { + out[key] = [prev, value] + } + } + + for (i = 0; i < len; i++) { + out[alias[i]] = out[key] + } + } +} + +const getopts = function(argv, opts) { + let unknown = (opts = opts || {}).unknown, + aliases = parseAlias(opts.alias), + strings = parseOptions(aliases, opts.string, ""), + values = parseDefault(aliases, opts.default), + bools = parseOptions(aliases, opts.boolean, false), + stopEarly = opts.stopEarly, + _ = [], + out = { _ }, + i = 0, + k = 0, + len = argv.length, + key, + arg, + end, + match, + value + + for (; i < len; i++) { + arg = argv[i] + + if (arg[0] !== "-" || arg === "-") { + if (stopEarly) while (i < len) _.push(argv[i++]) + else _.push(arg) + } else if (arg === "--") { + while (++i < len) _.push(argv[i]) + } else if (arg[1] === "-") { + end = arg.indexOf("=", 2) + if (arg[2] === "n" && arg[3] === "o" && arg[4] === "-") { + key = arg.slice(5, end >= 0 ? end : undefined) + value = false + } else if (end >= 0) { + key = arg.slice(2, end) + value = + bools[key] !== undefined || + (strings[key] === undefined + ? parseValue(arg.slice(end + 1)) + : arg.slice(end + 1)) + } else { + key = arg.slice(2) + value = + bools[key] !== undefined || + (len === i + 1 || argv[i + 1][0] === "-" + ? strings[key] === undefined + ? true + : "" + : strings[key] === undefined + ? parseValue(argv[++i]) + : argv[++i]) + } + write(out, key, value, aliases, unknown) + } else { + SHORTSPLIT.lastIndex = 2 + match = SHORTSPLIT.exec(arg) + end = match.index + value = match[0] + + for (k = 1; k < end; k++) { + write( + out, + (key = arg[k]), + k + 1 < end + ? strings[key] === undefined || + arg.substring(k + 1, (k = end)) + value + : value === "" + ? len === i + 1 || argv[i + 1][0] === "-" + ? strings[key] === undefined || "" + : bools[key] !== undefined || + (strings[key] === undefined ? parseValue(argv[++i]) : argv[++i]) + : bools[key] !== undefined || + (strings[key] === undefined ? parseValue(value) : value), + aliases, + unknown + ) + } + } + } + + for (key in values) if (out[key] === undefined) out[key] = values[key] + for (key in bools) if (out[key] === undefined) out[key] = false + for (key in strings) if (out[key] === undefined) out[key] = "" + + return out +} + +module.exports = getopts + + +/***/ }), +/* 451 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var kbn_client_1 = __webpack_require__(452); +exports.KbnClient = kbn_client_1.KbnClient; +var kbn_client_requester_1 = __webpack_require__(453); +exports.uriencode = kbn_client_requester_1.uriencode; + + +/***/ }), +/* 452 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const kbn_client_requester_1 = __webpack_require__(453); +const kbn_client_status_1 = __webpack_require__(495); +const kbn_client_plugins_1 = __webpack_require__(496); +const kbn_client_version_1 = __webpack_require__(497); +const kbn_client_saved_objects_1 = __webpack_require__(498); +const kbn_client_ui_settings_1 = __webpack_require__(499); +class KbnClient { + /** + * Basic Kibana server client that implements common behaviors for talking + * to the Kibana server from dev tooling. + * + * @param log ToolingLog + * @param kibanaUrls Array of kibana server urls to send requests to + * @param uiSettingDefaults Map of uiSetting values that will be merged with all uiSetting resets + */ + constructor(log, kibanaUrls, uiSettingDefaults) { + this.log = log; + this.kibanaUrls = kibanaUrls; + this.uiSettingDefaults = uiSettingDefaults; + this.requester = new kbn_client_requester_1.KbnClientRequester(this.log, this.kibanaUrls); + this.status = new kbn_client_status_1.KbnClientStatus(this.requester); + this.plugins = new kbn_client_plugins_1.KbnClientPlugins(this.status); + this.version = new kbn_client_version_1.KbnClientVersion(this.status); + this.savedObjects = new kbn_client_saved_objects_1.KbnClientSavedObjects(this.log, this.requester); + this.uiSettings = new kbn_client_ui_settings_1.KbnClientUiSettings(this.log, this.requester, this.uiSettingDefaults); + if (!kibanaUrls.length) { + throw new Error('missing Kibana urls'); + } + } + /** + * Make a direct request to the Kibana server + */ + async request(options) { + return await this.requester.request(options); + } + resolveUrl(relativeUrl) { + return this.requester.resolveUrl(relativeUrl); + } +} +exports.KbnClient = KbnClient; + + +/***/ }), +/* 453 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43034,28 +43035,21 @@ module.exports = require("tty"); const os = __webpack_require__(11); const hasFlag = __webpack_require__(12); -const {env} = process; +const env = process.env; let forceColor; if (hasFlag('no-color') || hasFlag('no-colors') || - hasFlag('color=false') || - hasFlag('color=never')) { - forceColor = 0; + hasFlag('color=false')) { + forceColor = false; } else if (hasFlag('color') || hasFlag('colors') || hasFlag('color=true') || hasFlag('color=always')) { - forceColor = 1; + forceColor = true; } if ('FORCE_COLOR' in env) { - if (env.FORCE_COLOR === true || env.FORCE_COLOR === 'true') { - forceColor = 1; - } else if (env.FORCE_COLOR === false || env.FORCE_COLOR === 'false') { - forceColor = 0; - } else { - forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3); - } + forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0; } function translateLevel(level) { @@ -43072,7 +43066,7 @@ function translateLevel(level) { } function supportsColor(stream) { - if (forceColor === 0) { + if (forceColor === false) { return 0; } @@ -43086,15 +43080,11 @@ function supportsColor(stream) { return 2; } - if (stream && !stream.isTTY && forceColor === undefined) { + if (stream && !stream.isTTY && forceColor !== true) { return 0; } - const min = forceColor || 0; - - if (env.TERM === 'dumb') { - return min; - } + const min = forceColor ? 1 : 0; if (process.platform === 'win32') { // Node.js 7.5.0 is the first version of Node.js to include a patch to @@ -43155,6 +43145,10 @@ function supportsColor(stream) { return 1; } + if (env.TERM === 'dumb') { + return min; + } + return min; } @@ -47864,10 +47858,10 @@ module.exports.sync = options => { "use strict"; -const errorEx = __webpack_require__(436); -const fallback = __webpack_require__(438); -const {default: LinesAndColumns} = __webpack_require__(439); -const {codeFrameColumns} = __webpack_require__(440); +const errorEx = __webpack_require__(430); +const fallback = __webpack_require__(432); +const {default: LinesAndColumns} = __webpack_require__(433); +const {codeFrameColumns} = __webpack_require__(434); const JSONError = errorEx('JSONError', { fileName: errorEx.append('in %s'), @@ -79882,7 +79876,7 @@ __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"]; }); -/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(914); +/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(920); /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); /* @@ -80062,16 +80056,24 @@ async function copyToBuild(project, kibanaRoot, buildRoot) { 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); +const os = __webpack_require__(11); +const pAll = __webpack_require__(706); +const arrify = __webpack_require__(708); +const globby = __webpack_require__(709); +const isGlob = __webpack_require__(601); +const cpFile = __webpack_require__(907); +const junk = __webpack_require__(917); +const CpyError = __webpack_require__(918); + +const defaultOptions = { + ignoreJunk: true +}; -const preprocessSrcPath = (srcPath, options) => options.cwd ? path.resolve(options.cwd, srcPath) : srcPath; +const preprocessSourcePath = (source, options) => options.cwd ? path.resolve(options.cwd, source) : source; -const preprocessDestPath = (srcPath, dest, options) => { - let basename = path.basename(srcPath); - const dirname = path.dirname(srcPath); +const preprocessDestinationPath = (source, destination, options) => { + let basename = path.basename(source); + const dirname = path.dirname(source); if (typeof options.rename === 'string') { basename = options.rename; @@ -80080,122 +80082,239 @@ const preprocessDestPath = (srcPath, dest, options) => { } if (options.cwd) { - dest = path.resolve(options.cwd, dest); + destination = path.resolve(options.cwd, destination); } if (options.parents) { - return path.join(dest, dirname, basename); + return path.join(destination, dirname, basename); } - return path.join(dest, basename); + return path.join(destination, basename); }; -const cpy = (src, dest, options = {}) => { - src = arrify(src); - +module.exports = (source, destination, { + concurrency = (os.cpus().length || 1) * 2, + ...options +} = {}) => { 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; - }; + options = { + ...defaultOptions, + ...options + }; - return promise; - } + const promise = (async () => { + source = arrify(source); - const copyStatus = new Map(); - let completedFiles = 0; - let completedSize = 0; + if (source.length === 0 || !destination) { + throw new CpyError('`source` and `destination` required'); + } - 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 - }); + const copyStatus = new Map(); + let completedFiles = 0; + let completedSize = 0; + + let files; + try { + files = await globby(source, options); + + if (options.ignoreJunk) { + files = files.filter(file => junk.not(path.basename(file))); } + } catch (error) { + throw new CpyError(`Cannot glob \`${source}\`: ${error.message}`, error); + } - return Promise.all(files.map(srcPath => { - const from = preprocessSrcPath(srcPath, options); - const to = preprocessDestPath(srcPath, dest, options); + const sourcePaths = source.filter(value => !isGlob(value)); - return cpFile(from, to, options) - .on('progress', event => { - const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; + if (files.length === 0 || (sourcePaths.length > 0 && !sourcePaths.every(value => files.includes(value)))) { + throw new CpyError(`Cannot copy \`${source}\`: the file doesn't exist`); + } - if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { - completedSize -= fileStatus.written; - completedSize += event.written; + const fileProgressHandler = event => { + const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; - if (event.percent === 1 && fileStatus.percent !== 1) { - completedFiles++; - } + if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { + completedSize -= fileStatus.written; + completedSize += event.written; - copyStatus.set(event.src, {written: event.written, percent: event.percent}); + if (event.percent === 1 && fileStatus.percent !== 1) { + completedFiles++; + } - 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); - }); - })); - }); + copyStatus.set(event.src, { + written: event.written, + percent: event.percent + }); - promise.on = (...args) => { - progressEmitter.on(...args); + progressEmitter.emit('progress', { + totalFiles: files.length, + percent: completedFiles / files.length, + completedFiles, + completedSize + }); + } + }; + + return pAll(files.map(sourcePath => { + return async () => { + const from = preprocessSourcePath(sourcePath, options); + const to = preprocessDestinationPath(sourcePath, destination, options); + + try { + await cpFile(from, to, options).on('progress', fileProgressHandler); + } catch (error) { + throw new CpyError(`Cannot copy from \`${from}\` to \`${to}\`: ${error.message}`, error); + } + + return to; + }; + }), {concurrency}); + })(); + + promise.on = (...arguments_) => { + progressEmitter.on(...arguments_); return promise; }; return promise; }; -module.exports = cpy; + +/***/ }), +/* 706 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const pMap = __webpack_require__(707); + +module.exports = (iterable, options) => pMap(iterable, element => element(), options); // TODO: Remove this for the next major release -module.exports.default = cpy; +module.exports.default = module.exports; /***/ }), -/* 706 */ +/* 707 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const pMap = (iterable, mapper, options) => new Promise((resolve, reject) => { + options = Object.assign({ + concurrency: Infinity + }, options); + + if (typeof mapper !== 'function') { + throw new TypeError('Mapper function is required'); + } + + const {concurrency} = options; + + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } + + const ret = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let isIterableDone = false; + let resolvingCount = 0; + let currentIndex = 0; + + const next = () => { + if (isRejected) { + return; + } + + const nextItem = iterator.next(); + const i = currentIndex; + currentIndex++; + + if (nextItem.done) { + isIterableDone = true; + + if (resolvingCount === 0) { + resolve(ret); + } + + return; + } + + resolvingCount++; + + Promise.resolve(nextItem.value) + .then(element => mapper(element, i)) + .then( + value => { + ret[i] = value; + resolvingCount--; + next(); + }, + error => { + isRejected = true; + reject(error); + } + ); + }; + + for (let i = 0; i < concurrency; i++) { + next(); + + if (isIterableDone) { + break; + } + } +}); + +module.exports = pMap; +// TODO: Remove this for the next major release +module.exports.default = pMap; + + +/***/ }), +/* 708 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = function (val) { - if (val === null || val === undefined) { + +const arrify = value => { + if (value === null || value === undefined) { return []; } - return Array.isArray(val) ? val : [val]; + 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; + /***/ }), -/* 707 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const arrayUnion = __webpack_require__(708); +const arrayUnion = __webpack_require__(710); const glob = __webpack_require__(502); -const fastGlob = __webpack_require__(710); -const dirGlob = __webpack_require__(898); -const gitignore = __webpack_require__(901); +const fastGlob = __webpack_require__(712); +const dirGlob = __webpack_require__(900); +const gitignore = __webpack_require__(903); const DEFAULT_FILTER = () => false; @@ -80340,12 +80459,12 @@ module.exports.gitignore = gitignore; /***/ }), -/* 708 */ +/* 710 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(709); +var arrayUniq = __webpack_require__(711); module.exports = function () { return arrayUniq([].concat.apply([], arguments)); @@ -80353,7 +80472,7 @@ module.exports = function () { /***/ }), -/* 709 */ +/* 711 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80422,10 +80541,10 @@ if ('Set' in global) { /***/ }), -/* 710 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(711); +const pkg = __webpack_require__(713); module.exports = pkg.async; module.exports.default = pkg.async; @@ -80438,19 +80557,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 711 */ +/* 713 */ /***/ (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__(714); +var taskManager = __webpack_require__(715); +var reader_async_1 = __webpack_require__(871); +var reader_stream_1 = __webpack_require__(895); +var reader_sync_1 = __webpack_require__(896); +var arrayUtils = __webpack_require__(898); +var streamUtils = __webpack_require__(899); /** * Synchronous API. */ @@ -80516,7 +80635,7 @@ function isString(source) { /***/ }), -/* 712 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80554,13 +80673,13 @@ exports.prepare = prepare; /***/ }), -/* 713 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(714); +var patternUtils = __webpack_require__(716); /** * Generate tasks based on parent directory of each pattern. */ @@ -80651,16 +80770,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 714 */ +/* 716 */ /***/ (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__(717); +var isGlob = __webpack_require__(720); +var micromatch = __webpack_require__(721); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -80806,15 +80925,15 @@ exports.matchAny = matchAny; /***/ }), -/* 715 */ +/* 717 */ /***/ (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__(718); +var pathDirname = __webpack_require__(719); var isWin32 = __webpack_require__(11).platform() === 'win32'; module.exports = function globParent(str) { @@ -80837,7 +80956,7 @@ module.exports = function globParent(str) { /***/ }), -/* 716 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -80868,7 +80987,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 717 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81018,7 +81137,7 @@ module.exports.win32 = win32; /***/ }), -/* 718 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -81070,7 +81189,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 719 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81081,18 +81200,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__(722); +var toRegex = __webpack_require__(824); +var extend = __webpack_require__(832); /** * 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__(835); +var parsers = __webpack_require__(867); +var cache = __webpack_require__(868); +var utils = __webpack_require__(869); var MAX_LENGTH = 1024 * 64; /** @@ -81954,7 +82073,7 @@ module.exports = micromatch; /***/ }), -/* 720 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81964,18 +82083,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__(723); +var unique = __webpack_require__(735); +var extend = __webpack_require__(732); /** * 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__(736); +var parsers = __webpack_require__(751); +var Braces = __webpack_require__(761); +var utils = __webpack_require__(737); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -82279,15 +82398,15 @@ module.exports = braces; /***/ }), -/* 721 */ +/* 723 */ /***/ (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__(724); +var extend = __webpack_require__(732); +var not = __webpack_require__(734); var MAX_LENGTH = 1024 * 64; /** @@ -82434,7 +82553,7 @@ module.exports.makeRe = makeRe; /***/ }), -/* 722 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82447,7 +82566,7 @@ module.exports.makeRe = makeRe; -var isDescriptor = __webpack_require__(723); +var isDescriptor = __webpack_require__(725); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -82472,7 +82591,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 723 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82485,9 +82604,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__(726); +var isAccessor = __webpack_require__(727); +var isData = __webpack_require__(730); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -82501,7 +82620,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 724 */ +/* 726 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -82654,7 +82773,7 @@ function isBuffer(val) { /***/ }), -/* 725 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82667,7 +82786,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(726); +var typeOf = __webpack_require__(728); // accessor descriptor properties var accessor = { @@ -82730,10 +82849,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 726 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(727); +var isBuffer = __webpack_require__(729); var toString = Object.prototype.toString; /** @@ -82852,7 +82971,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 727 */ +/* 729 */ /***/ (function(module, exports) { /*! @@ -82879,7 +82998,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 728 */ +/* 730 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82892,7 +83011,7 @@ function isSlowBuffer (obj) { -var typeOf = __webpack_require__(729); +var typeOf = __webpack_require__(731); // data descriptor properties var data = { @@ -82941,10 +83060,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 729 */ +/* 731 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(727); +var isBuffer = __webpack_require__(729); var toString = Object.prototype.toString; /** @@ -83063,13 +83182,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 730 */ +/* 732 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(731); +var isObject = __webpack_require__(733); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -83103,7 +83222,7 @@ function hasOwn(obj, key) { /***/ }), -/* 731 */ +/* 733 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83123,13 +83242,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 732 */ +/* 734 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(730); +var extend = __webpack_require__(732); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -83196,7 +83315,7 @@ module.exports = toRegex; /***/ }), -/* 733 */ +/* 735 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83246,13 +83365,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 734 */ +/* 736 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(735); +var utils = __webpack_require__(737); module.exports = function(braces, options) { braces.compiler @@ -83535,25 +83654,25 @@ function hasQueue(node) { /***/ }), -/* 735 */ +/* 737 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(736); +var splitString = __webpack_require__(738); 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__(732); +utils.flatten = __webpack_require__(744); +utils.isObject = __webpack_require__(742); +utils.fillRange = __webpack_require__(745); +utils.repeat = __webpack_require__(750); +utils.unique = __webpack_require__(735); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -83885,7 +84004,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 736 */ +/* 738 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83898,7 +84017,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(737); +var extend = __webpack_require__(739); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -84063,14 +84182,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 737 */ +/* 739 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(738); -var assignSymbols = __webpack_require__(741); +var isExtendable = __webpack_require__(740); +var assignSymbols = __webpack_require__(743); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -84130,7 +84249,7 @@ function isEnum(obj, key) { /***/ }), -/* 738 */ +/* 740 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84143,7 +84262,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(739); +var isPlainObject = __webpack_require__(741); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -84151,7 +84270,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 739 */ +/* 741 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84164,7 +84283,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(740); +var isObject = __webpack_require__(742); function isObjectObject(o) { return isObject(o) === true @@ -84195,7 +84314,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 740 */ +/* 742 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84214,7 +84333,7 @@ module.exports = function isObject(val) { /***/ }), -/* 741 */ +/* 743 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84261,7 +84380,7 @@ module.exports = function(receiver, objects) { /***/ }), -/* 742 */ +/* 744 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84290,7 +84409,7 @@ function flat(arr, res) { /***/ }), -/* 743 */ +/* 745 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84304,10 +84423,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__(746); +var extend = __webpack_require__(732); +var repeat = __webpack_require__(748); +var toRegex = __webpack_require__(749); /** * Return a range of numbers or letters. @@ -84505,7 +84624,7 @@ module.exports = fillRange; /***/ }), -/* 744 */ +/* 746 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84518,7 +84637,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(745); +var typeOf = __webpack_require__(747); module.exports = function isNumber(num) { var type = typeOf(num); @@ -84534,10 +84653,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 745 */ +/* 747 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(727); +var isBuffer = __webpack_require__(729); var toString = Object.prototype.toString; /** @@ -84656,7 +84775,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 746 */ +/* 748 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84733,7 +84852,7 @@ function repeat(str, num) { /***/ }), -/* 747 */ +/* 749 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84746,8 +84865,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(746); -var isNumber = __webpack_require__(744); +var repeat = __webpack_require__(748); +var isNumber = __webpack_require__(746); var cache = {}; function toRegexRange(min, max, options) { @@ -85034,7 +85153,7 @@ module.exports = toRegexRange; /***/ }), -/* 748 */ +/* 750 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85059,14 +85178,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 749 */ +/* 751 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(750); -var utils = __webpack_require__(735); +var Node = __webpack_require__(752); +var utils = __webpack_require__(737); /** * Braces parsers @@ -85426,15 +85545,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 750 */ +/* 752 */ /***/ (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__(742); +var define = __webpack_require__(753); +var utils = __webpack_require__(760); var ownNames; /** @@ -85925,7 +86044,7 @@ exports = module.exports = Node; /***/ }), -/* 751 */ +/* 753 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85938,7 +86057,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(752); +var isDescriptor = __webpack_require__(754); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -85963,7 +86082,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 752 */ +/* 754 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85976,9 +86095,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__(755); +var isAccessor = __webpack_require__(756); +var isData = __webpack_require__(758); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -85992,7 +86111,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 753 */ +/* 755 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -86127,7 +86246,7 @@ function isBuffer(val) { /***/ }), -/* 754 */ +/* 756 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86140,7 +86259,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(755); +var typeOf = __webpack_require__(757); // accessor descriptor properties var accessor = { @@ -86203,7 +86322,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 755 */ +/* 757 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -86338,7 +86457,7 @@ function isBuffer(val) { /***/ }), -/* 756 */ +/* 758 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86351,7 +86470,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(757); +var typeOf = __webpack_require__(759); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -86394,7 +86513,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 757 */ +/* 759 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -86529,13 +86648,13 @@ function isBuffer(val) { /***/ }), -/* 758 */ +/* 760 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(745); +var typeOf = __webpack_require__(747); var utils = module.exports; /** @@ -87555,17 +87674,17 @@ function assert(val, message) { /***/ }), -/* 759 */ +/* 761 */ /***/ (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__(732); +var Snapdragon = __webpack_require__(762); +var compilers = __webpack_require__(736); +var parsers = __webpack_require__(751); +var utils = __webpack_require__(737); /** * Customize Snapdragon parser and renderer @@ -87666,17 +87785,17 @@ module.exports = Braces; /***/ }), -/* 760 */ +/* 762 */ /***/ (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__(763); +var define = __webpack_require__(724); +var Compiler = __webpack_require__(792); +var Parser = __webpack_require__(821); +var utils = __webpack_require__(801); var regexCache = {}; var cache = {}; @@ -87847,20 +87966,20 @@ module.exports.Parser = Parser; /***/ }), -/* 761 */ +/* 763 */ /***/ (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__(764); +var CacheBase = __webpack_require__(765); +var Emitter = __webpack_require__(766); +var isObject = __webpack_require__(742); +var merge = __webpack_require__(783); +var pascal = __webpack_require__(786); +var cu = __webpack_require__(787); /** * Optionally define a custom `cache` namespace to use. @@ -88289,7 +88408,7 @@ module.exports.namespace = namespace; /***/ }), -/* 762 */ +/* 764 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88302,7 +88421,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(752); +var isDescriptor = __webpack_require__(754); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -88327,21 +88446,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 763 */ +/* 765 */ /***/ (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__(742); +var Emitter = __webpack_require__(766); +var visit = __webpack_require__(767); +var toPath = __webpack_require__(770); +var union = __webpack_require__(771); +var del = __webpack_require__(775); +var get = __webpack_require__(773); +var has = __webpack_require__(780); +var set = __webpack_require__(774); /** * Create a `Cache` constructor that when instantiated will @@ -88595,7 +88714,7 @@ module.exports.namespace = namespace; /***/ }), -/* 764 */ +/* 766 */ /***/ (function(module, exports, __webpack_require__) { @@ -88764,7 +88883,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 765 */ +/* 767 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88777,8 +88896,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(766); -var mapVisit = __webpack_require__(767); +var visit = __webpack_require__(768); +var mapVisit = __webpack_require__(769); module.exports = function(collection, method, val) { var result; @@ -88801,7 +88920,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 766 */ +/* 768 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88814,7 +88933,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(740); +var isObject = __webpack_require__(742); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -88841,14 +88960,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 767 */ +/* 769 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var visit = __webpack_require__(766); +var visit = __webpack_require__(768); /** * Map `visit` over an array of objects. @@ -88885,7 +89004,7 @@ function isObject(val) { /***/ }), -/* 768 */ +/* 770 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88898,7 +89017,7 @@ function isObject(val) { -var typeOf = __webpack_require__(745); +var typeOf = __webpack_require__(747); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -88925,16 +89044,16 @@ function filter(arr) { /***/ }), -/* 769 */ +/* 771 */ /***/ (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__(733); +var union = __webpack_require__(772); +var get = __webpack_require__(773); +var set = __webpack_require__(774); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -88962,7 +89081,7 @@ function arrayify(val) { /***/ }), -/* 770 */ +/* 772 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88998,7 +89117,7 @@ module.exports = function union(init) { /***/ }), -/* 771 */ +/* 773 */ /***/ (function(module, exports) { /*! @@ -89054,7 +89173,7 @@ function toString(val) { /***/ }), -/* 772 */ +/* 774 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89067,10 +89186,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__(738); +var extend = __webpack_require__(732); +var isPlainObject = __webpack_require__(741); +var isObject = __webpack_require__(733); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -89116,7 +89235,7 @@ function isValidKey(key) { /***/ }), -/* 773 */ +/* 775 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89129,8 +89248,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(740); -var has = __webpack_require__(774); +var isObject = __webpack_require__(742); +var has = __webpack_require__(776); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -89155,7 +89274,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 774 */ +/* 776 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89168,9 +89287,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__(777); +var hasValues = __webpack_require__(779); +var get = __webpack_require__(773); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -89181,7 +89300,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 775 */ +/* 777 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89194,7 +89313,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(776); +var isArray = __webpack_require__(778); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -89202,7 +89321,7 @@ module.exports = function isObject(val) { /***/ }), -/* 776 */ +/* 778 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -89213,7 +89332,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 777 */ +/* 779 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89256,7 +89375,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 778 */ +/* 780 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89269,9 +89388,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__(742); +var hasValues = __webpack_require__(781); +var get = __webpack_require__(773); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -89279,7 +89398,7 @@ module.exports = function(val, prop) { /***/ }), -/* 779 */ +/* 781 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89292,8 +89411,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(780); -var isNumber = __webpack_require__(744); +var typeOf = __webpack_require__(782); +var isNumber = __webpack_require__(746); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -89346,10 +89465,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 780 */ +/* 782 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(727); +var isBuffer = __webpack_require__(729); var toString = Object.prototype.toString; /** @@ -89471,14 +89590,14 @@ module.exports = function kindOf(val) { /***/ }), -/* 781 */ +/* 783 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(782); -var forIn = __webpack_require__(783); +var isExtendable = __webpack_require__(784); +var forIn = __webpack_require__(785); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -89542,7 +89661,7 @@ module.exports = mixinDeep; /***/ }), -/* 782 */ +/* 784 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89555,7 +89674,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(739); +var isPlainObject = __webpack_require__(741); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -89563,7 +89682,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 783 */ +/* 785 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89586,7 +89705,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 784 */ +/* 786 */ /***/ (function(module, exports) { /*! @@ -89613,14 +89732,14 @@ module.exports = pascalcase; /***/ }), -/* 785 */ +/* 787 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var utils = __webpack_require__(786); +var utils = __webpack_require__(788); /** * Expose class utils @@ -89985,7 +90104,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 786 */ +/* 788 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89999,10 +90118,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__(772); +utils.define = __webpack_require__(724); +utils.isObj = __webpack_require__(742); +utils.staticExtend = __webpack_require__(789); /** @@ -90013,7 +90132,7 @@ module.exports = utils; /***/ }), -/* 787 */ +/* 789 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90026,8 +90145,8 @@ module.exports = utils; -var copy = __webpack_require__(788); -var define = __webpack_require__(722); +var copy = __webpack_require__(790); +var define = __webpack_require__(724); var util = __webpack_require__(29); /** @@ -90110,15 +90229,15 @@ module.exports = extend; /***/ }), -/* 788 */ +/* 790 */ /***/ (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__(747); +var copyDescriptor = __webpack_require__(791); +var define = __webpack_require__(724); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -90291,7 +90410,7 @@ module.exports.has = has; /***/ }), -/* 789 */ +/* 791 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90379,16 +90498,16 @@ function isObject(val) { /***/ }), -/* 790 */ +/* 792 */ /***/ (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__(793); +var define = __webpack_require__(724); +var debug = __webpack_require__(795)('snapdragon:compiler'); +var utils = __webpack_require__(801); /** * Create a new `Compiler` with the given `options`. @@ -90542,7 +90661,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(818); + var sourcemaps = __webpack_require__(820); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -90563,7 +90682,7 @@ module.exports = Compiler; /***/ }), -/* 791 */ +/* 793 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90576,7 +90695,7 @@ module.exports = Compiler; -var utils = __webpack_require__(792); +var utils = __webpack_require__(794); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -90691,7 +90810,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 792 */ +/* 794 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90705,8 +90824,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(722); -utils.isObject = __webpack_require__(740); +utils.define = __webpack_require__(724); +utils.isObject = __webpack_require__(742); utils.isString = function(val) { @@ -90721,7 +90840,7 @@ module.exports = utils; /***/ }), -/* 793 */ +/* 795 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -90730,14 +90849,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(794); + module.exports = __webpack_require__(796); } else { - module.exports = __webpack_require__(797); + module.exports = __webpack_require__(799); } /***/ }), -/* 794 */ +/* 796 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -90746,7 +90865,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(795); +exports = module.exports = __webpack_require__(797); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -90928,7 +91047,7 @@ function localstorage() { /***/ }), -/* 795 */ +/* 797 */ /***/ (function(module, exports, __webpack_require__) { @@ -90944,7 +91063,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(796); +exports.humanize = __webpack_require__(798); /** * The currently active debug mode names, and names to skip. @@ -91136,7 +91255,7 @@ function coerce(val) { /***/ }), -/* 796 */ +/* 798 */ /***/ (function(module, exports) { /** @@ -91294,7 +91413,7 @@ function plural(ms, n, name) { /***/ }), -/* 797 */ +/* 799 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -91310,7 +91429,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(795); +exports = module.exports = __webpack_require__(797); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -91489,7 +91608,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(798); + var net = __webpack_require__(800); stream = new net.Socket({ fd: fd, readable: false, @@ -91548,13 +91667,13 @@ exports.enable(load()); /***/ }), -/* 798 */ +/* 800 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 799 */ +/* 801 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91564,9 +91683,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__(732); +exports.SourceMap = __webpack_require__(802); +exports.sourceMapResolve = __webpack_require__(813); /** * Convert backslash in the given string to forward slashes @@ -91609,7 +91728,7 @@ exports.last = function(arr, n) { /***/ }), -/* 800 */ +/* 802 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -91617,13 +91736,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__(803).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(809).SourceMapConsumer; +exports.SourceNode = __webpack_require__(812).SourceNode; /***/ }), -/* 801 */ +/* 803 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -91633,10 +91752,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__(804); +var util = __webpack_require__(806); +var ArraySet = __webpack_require__(807).ArraySet; +var MappingList = __webpack_require__(808).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -92045,7 +92164,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 802 */ +/* 804 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92085,7 +92204,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__(805); // 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 +92310,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 803 */ +/* 805 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92264,7 +92383,7 @@ exports.decode = function (charCode) { /***/ }), -/* 804 */ +/* 806 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92687,7 +92806,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 805 */ +/* 807 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92697,7 +92816,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(804); +var util = __webpack_require__(806); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -92814,7 +92933,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 806 */ +/* 808 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92824,7 +92943,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(804); +var util = __webpack_require__(806); /** * Determine whether mappingB is after mappingA with respect to generated @@ -92899,7 +93018,7 @@ exports.MappingList = MappingList; /***/ }), -/* 807 */ +/* 809 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92909,11 +93028,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__(806); +var binarySearch = __webpack_require__(810); +var ArraySet = __webpack_require__(807).ArraySet; +var base64VLQ = __webpack_require__(804); +var quickSort = __webpack_require__(811).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -93987,7 +94106,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 808 */ +/* 810 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94104,7 +94223,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 809 */ +/* 811 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94224,7 +94343,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 810 */ +/* 812 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94234,8 +94353,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__(803).SourceMapGenerator; +var util = __webpack_require__(806); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -94643,17 +94762,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 811 */ +/* 813 */ /***/ (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__(814) +var resolveUrl = __webpack_require__(815) +var decodeUriComponent = __webpack_require__(816) +var urix = __webpack_require__(818) +var atob = __webpack_require__(819) @@ -94951,7 +95070,7 @@ module.exports = { /***/ }), -/* 812 */ +/* 814 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -95014,7 +95133,7 @@ void (function(root, factory) { /***/ }), -/* 813 */ +/* 815 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -95032,13 +95151,13 @@ module.exports = resolveUrl /***/ }), -/* 814 */ +/* 816 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(815) +var decodeUriComponent = __webpack_require__(817) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -95049,7 +95168,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 815 */ +/* 817 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95150,7 +95269,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 816 */ +/* 818 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -95173,7 +95292,7 @@ module.exports = urix /***/ }), -/* 817 */ +/* 819 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95187,7 +95306,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 818 */ +/* 820 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95195,8 +95314,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__(724); +var utils = __webpack_require__(801); /** * Expose `mixin()`. @@ -95339,19 +95458,19 @@ exports.comment = function(node) { /***/ }), -/* 819 */ +/* 821 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(791); +var use = __webpack_require__(793); 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__(822); +var define = __webpack_require__(724); +var debug = __webpack_require__(795)('snapdragon:parser'); +var Position = __webpack_require__(823); +var utils = __webpack_require__(801); /** * Create a new `Parser` with the given `input` and `options`. @@ -95879,7 +95998,7 @@ module.exports = Parser; /***/ }), -/* 820 */ +/* 822 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95986,13 +96105,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 821 */ +/* 823 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(722); +var define = __webpack_require__(724); /** * Store position for a node @@ -96007,16 +96126,16 @@ module.exports = function Position(start, parser) { /***/ }), -/* 822 */ +/* 824 */ /***/ (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__(825); +var define = __webpack_require__(831); +var extend = __webpack_require__(832); +var not = __webpack_require__(834); var MAX_LENGTH = 1024 * 64; /** @@ -96169,10 +96288,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 823 */ +/* 825 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(824); +var parse = __webpack_require__(826); var types = parse.types; module.exports = function (re, opts) { @@ -96218,13 +96337,13 @@ function isRegExp (x) { /***/ }), -/* 824 */ +/* 826 */ /***/ (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__(827); +var types = __webpack_require__(828); +var sets = __webpack_require__(829); +var positions = __webpack_require__(830); module.exports = function(regexpStr) { @@ -96506,11 +96625,11 @@ module.exports.types = types; /***/ }), -/* 825 */ +/* 827 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(826); -var sets = __webpack_require__(827); +var types = __webpack_require__(828); +var sets = __webpack_require__(829); // All of these are private and only used by randexp. @@ -96623,7 +96742,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 826 */ +/* 828 */ /***/ (function(module, exports) { module.exports = { @@ -96639,10 +96758,10 @@ module.exports = { /***/ }), -/* 827 */ +/* 829 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(826); +var types = __webpack_require__(828); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -96727,10 +96846,10 @@ exports.anyChar = function() { /***/ }), -/* 828 */ +/* 830 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(826); +var types = __webpack_require__(828); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -96750,7 +96869,7 @@ exports.end = function() { /***/ }), -/* 829 */ +/* 831 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96763,8 +96882,8 @@ exports.end = function() { -var isobject = __webpack_require__(740); -var isDescriptor = __webpack_require__(752); +var isobject = __webpack_require__(742); +var isDescriptor = __webpack_require__(754); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -96795,14 +96914,14 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 830 */ +/* 832 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(831); -var assignSymbols = __webpack_require__(741); +var isExtendable = __webpack_require__(833); +var assignSymbols = __webpack_require__(743); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -96862,7 +96981,7 @@ function isEnum(obj, key) { /***/ }), -/* 831 */ +/* 833 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96875,7 +96994,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(739); +var isPlainObject = __webpack_require__(741); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -96883,14 +97002,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 832 */ +/* 834 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(830); -var safe = __webpack_require__(823); +var extend = __webpack_require__(832); +var safe = __webpack_require__(825); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -96962,14 +97081,14 @@ module.exports = toRegex; /***/ }), -/* 833 */ +/* 835 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(834); -var extglob = __webpack_require__(849); +var nanomatch = __webpack_require__(836); +var extglob = __webpack_require__(851); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -97046,7 +97165,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 834 */ +/* 836 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -97057,17 +97176,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(29); -var toRegex = __webpack_require__(721); -var extend = __webpack_require__(835); +var toRegex = __webpack_require__(723); +var extend = __webpack_require__(837); /** * 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__(839); +var parsers = __webpack_require__(840); +var cache = __webpack_require__(843); +var utils = __webpack_require__(845); var MAX_LENGTH = 1024 * 64; /** @@ -97891,14 +98010,14 @@ module.exports = nanomatch; /***/ }), -/* 835 */ +/* 837 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(836); -var assignSymbols = __webpack_require__(741); +var isExtendable = __webpack_require__(838); +var assignSymbols = __webpack_require__(743); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -97958,7 +98077,7 @@ function isEnum(obj, key) { /***/ }), -/* 836 */ +/* 838 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -97971,7 +98090,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(739); +var isPlainObject = __webpack_require__(741); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -97979,7 +98098,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 837 */ +/* 839 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98325,15 +98444,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 838 */ +/* 840 */ /***/ (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__(734); +var toRegex = __webpack_require__(723); +var isOdd = __webpack_require__(841); /** * Characters to use in negation regex (we want to "not" match @@ -98719,7 +98838,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 839 */ +/* 841 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98732,7 +98851,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(840); +var isNumber = __webpack_require__(842); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -98746,7 +98865,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 840 */ +/* 842 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98774,14 +98893,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 841 */ +/* 843 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(842))(); +module.exports = new (__webpack_require__(844))(); /***/ }), -/* 842 */ +/* 844 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98794,7 +98913,7 @@ module.exports = new (__webpack_require__(842))(); -var MapCache = __webpack_require__(820); +var MapCache = __webpack_require__(822); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -98916,7 +99035,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 843 */ +/* 845 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98929,14 +99048,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__(846)(); +var Snapdragon = __webpack_require__(762); +utils.define = __webpack_require__(847); +utils.diff = __webpack_require__(848); +utils.extend = __webpack_require__(837); +utils.pick = __webpack_require__(849); +utils.typeOf = __webpack_require__(850); +utils.unique = __webpack_require__(735); /** * Returns true if the given value is effectively an empty string @@ -99302,7 +99421,7 @@ utils.unixify = function(options) { /***/ }), -/* 844 */ +/* 846 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -99330,7 +99449,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 845 */ +/* 847 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99343,8 +99462,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__(742); +var isDescriptor = __webpack_require__(754); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -99375,7 +99494,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 846 */ +/* 848 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99429,7 +99548,7 @@ function diffArray(one, two) { /***/ }), -/* 847 */ +/* 849 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99442,7 +99561,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(740); +var isObject = __webpack_require__(742); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -99471,7 +99590,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 848 */ +/* 850 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -99606,7 +99725,7 @@ function isBuffer(val) { /***/ }), -/* 849 */ +/* 851 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99616,18 +99735,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__(732); +var unique = __webpack_require__(735); +var toRegex = __webpack_require__(723); /** * 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__(852); +var parsers = __webpack_require__(863); +var Extglob = __webpack_require__(866); +var utils = __webpack_require__(865); var MAX_LENGTH = 1024 * 64; /** @@ -99944,13 +100063,13 @@ module.exports = extglob; /***/ }), -/* 850 */ +/* 852 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(851); +var brackets = __webpack_require__(853); /** * Extglob compilers @@ -100120,7 +100239,7 @@ module.exports = function(extglob) { /***/ }), -/* 851 */ +/* 853 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100130,17 +100249,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(852); -var parsers = __webpack_require__(854); +var compilers = __webpack_require__(854); +var parsers = __webpack_require__(856); /** * 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__(858)('expand-brackets'); +var extend = __webpack_require__(732); +var Snapdragon = __webpack_require__(762); +var toRegex = __webpack_require__(723); /** * Parses the given POSIX character class `pattern` and returns a @@ -100338,13 +100457,13 @@ module.exports = brackets; /***/ }), -/* 852 */ +/* 854 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(853); +var posix = __webpack_require__(855); module.exports = function(brackets) { brackets.compiler @@ -100432,7 +100551,7 @@ module.exports = function(brackets) { /***/ }), -/* 853 */ +/* 855 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100461,14 +100580,14 @@ module.exports = { /***/ }), -/* 854 */ +/* 856 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(855); -var define = __webpack_require__(722); +var utils = __webpack_require__(857); +var define = __webpack_require__(724); /** * Text regex @@ -100687,14 +100806,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 855 */ +/* 857 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(721); -var regexNot = __webpack_require__(732); +var toRegex = __webpack_require__(723); +var regexNot = __webpack_require__(734); var cached; /** @@ -100728,7 +100847,7 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 856 */ +/* 858 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -100737,14 +100856,14 @@ exports.createRegex = function(pattern, include) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(857); + module.exports = __webpack_require__(859); } else { - module.exports = __webpack_require__(860); + module.exports = __webpack_require__(862); } /***/ }), -/* 857 */ +/* 859 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -100753,7 +100872,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(858); +exports = module.exports = __webpack_require__(860); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -100935,7 +101054,7 @@ function localstorage() { /***/ }), -/* 858 */ +/* 860 */ /***/ (function(module, exports, __webpack_require__) { @@ -100951,7 +101070,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(859); +exports.humanize = __webpack_require__(861); /** * The currently active debug mode names, and names to skip. @@ -101143,7 +101262,7 @@ function coerce(val) { /***/ }), -/* 859 */ +/* 861 */ /***/ (function(module, exports) { /** @@ -101301,7 +101420,7 @@ function plural(ms, n, name) { /***/ }), -/* 860 */ +/* 862 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -101317,7 +101436,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(858); +exports = module.exports = __webpack_require__(860); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -101496,7 +101615,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(798); + var net = __webpack_require__(800); stream = new net.Socket({ fd: fd, readable: false, @@ -101555,15 +101674,15 @@ exports.enable(load()); /***/ }), -/* 861 */ +/* 863 */ /***/ (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__(853); +var define = __webpack_require__(864); +var utils = __webpack_require__(865); /** * Characters to use in text regex (we want to "not" match @@ -101718,7 +101837,7 @@ module.exports = parsers; /***/ }), -/* 862 */ +/* 864 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101731,7 +101850,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(752); +var isDescriptor = __webpack_require__(754); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -101756,14 +101875,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 863 */ +/* 865 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(732); -var Cache = __webpack_require__(842); +var regex = __webpack_require__(734); +var Cache = __webpack_require__(844); /** * Utils @@ -101832,7 +101951,7 @@ utils.createRegex = function(str) { /***/ }), -/* 864 */ +/* 866 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101842,16 +101961,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__(762); +var define = __webpack_require__(864); +var extend = __webpack_require__(732); /** * Local dependencies */ -var compilers = __webpack_require__(850); -var parsers = __webpack_require__(861); +var compilers = __webpack_require__(852); +var parsers = __webpack_require__(863); /** * Customize Snapdragon parser and renderer @@ -101917,16 +102036,16 @@ module.exports = Extglob; /***/ }), -/* 865 */ +/* 867 */ /***/ (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__(851); +var nanomatch = __webpack_require__(836); +var regexNot = __webpack_require__(734); +var toRegex = __webpack_require__(824); var not; /** @@ -102007,14 +102126,14 @@ function textRegex(pattern) { /***/ }), -/* 866 */ +/* 868 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(842))(); +module.exports = new (__webpack_require__(844))(); /***/ }), -/* 867 */ +/* 869 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102027,13 +102146,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__(762); +utils.define = __webpack_require__(831); +utils.diff = __webpack_require__(848); +utils.extend = __webpack_require__(832); +utils.pick = __webpack_require__(849); +utils.typeOf = __webpack_require__(870); +utils.unique = __webpack_require__(735); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -102330,7 +102449,7 @@ utils.unixify = function(options) { /***/ }), -/* 868 */ +/* 870 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -102465,7 +102584,7 @@ function isBuffer(val) { /***/ }), -/* 869 */ +/* 871 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102484,9 +102603,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__(872); +var reader_1 = __webpack_require__(885); +var fs_stream_1 = __webpack_require__(889); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -102547,15 +102666,15 @@ exports.default = ReaderAsync; /***/ }), -/* 870 */ +/* 872 */ /***/ (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__(873); +const readdirAsync = __webpack_require__(881); +const readdirStream = __webpack_require__(884); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -102639,7 +102758,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 871 */ +/* 873 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102647,11 +102766,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(872); +const DirectoryReader = __webpack_require__(874); let syncFacade = { - fs: __webpack_require__(877), - forEach: __webpack_require__(878), + fs: __webpack_require__(879), + forEach: __webpack_require__(880), sync: true }; @@ -102680,7 +102799,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 872 */ +/* 874 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102689,9 +102808,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__(875); +const stat = __webpack_require__(877); +const call = __webpack_require__(878); /** * Asynchronously reads the contents of a directory and streams the results @@ -103067,14 +103186,14 @@ module.exports = DirectoryReader; /***/ }), -/* 873 */ +/* 875 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const globToRegExp = __webpack_require__(874); +const globToRegExp = __webpack_require__(876); module.exports = normalizeOptions; @@ -103204,2794 +103323,4648 @@ function normalizeOptions (options, internalOptions) { throw new TypeError('options.basePath must be a string'); } - // Convert the basePath to POSIX (forward slashes) - // so that glob pattern matching works consistently, even on Windows - let posixBasePath = basePath; - if (posixBasePath && sep !== '/') { - posixBasePath = posixBasePath.replace(new RegExp('\\' + sep, 'g'), '/'); + // Convert the basePath to POSIX (forward slashes) + // so that glob pattern matching works consistently, even on Windows + let posixBasePath = basePath; + if (posixBasePath && sep !== '/') { + posixBasePath = posixBasePath.replace(new RegExp('\\' + sep, 'g'), '/'); + + /* istanbul ignore if */ + if (isWindows) { + // Convert Windows root paths (C:\) and UNCs (\\) to POSIX root paths + posixBasePath = posixBasePath.replace(/^([a-zA-Z]\:\/|\/\/)/, '/'); + } + } + + // Determine which facade methods to use + let facade; + if (options.fs === null || options.fs === undefined) { + // The user didn't provide their own facades, so use our internal ones + facade = internalOptions.facade; + } + else if (typeof options.fs === 'object') { + // Merge the internal facade methods with the user-provided `fs` facades + facade = Object.assign({}, internalOptions.facade); + facade.fs = Object.assign({}, internalOptions.facade.fs, options.fs); + } + else { + throw new TypeError('options.fs must be an object'); + } + + return { + recurseDepth, + recurseFn, + recurseRegExp, + recurseGlob, + filterFn, + filterRegExp, + filterGlob, + sep, + basePath, + posixBasePath, + facade, + emit: !!internalOptions.emit, + stats: !!internalOptions.stats, + }; +} + + +/***/ }), +/* 876 */ +/***/ (function(module, exports) { + +module.exports = function (glob, opts) { + if (typeof glob !== 'string') { + throw new TypeError('Expected a string'); + } + + var str = String(glob); + + // The regexp we are building, as a string. + var reStr = ""; + + // Whether we are matching so called "extended" globs (like bash) and should + // support single character matching, matching ranges of characters, group + // matching, etc. + var extended = opts ? !!opts.extended : false; + + // When globstar is _false_ (default), '/foo/*' is translated a regexp like + // '^\/foo\/.*$' which will match any string beginning with '/foo/' + // When globstar is _true_, '/foo/*' is translated to regexp like + // '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT + // which does not have a '/' to the right of it. + // E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but + // these will not '/foo/bar/baz', '/foo/bar/baz.txt' + // Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when + // globstar is _false_ + var globstar = opts ? !!opts.globstar : false; + + // If we are doing extended matching, this boolean is true when we are inside + // a group (eg {*.html,*.js}), and false otherwise. + var inGroup = false; + + // RegExp flags (eg "i" ) to pass in to RegExp constructor. + var flags = opts && typeof( opts.flags ) === "string" ? opts.flags : ""; + + var c; + for (var i = 0, len = str.length; i < len; i++) { + c = str[i]; + + switch (c) { + case "\\": + case "/": + case "$": + case "^": + case "+": + case ".": + case "(": + case ")": + case "=": + case "!": + case "|": + reStr += "\\" + c; + break; + + case "?": + if (extended) { + reStr += "."; + break; + } + + case "[": + case "]": + if (extended) { + reStr += c; + break; + } + + case "{": + if (extended) { + inGroup = true; + reStr += "("; + break; + } + + case "}": + if (extended) { + inGroup = false; + reStr += ")"; + break; + } + + case ",": + if (inGroup) { + reStr += "|"; + break; + } + reStr += "\\" + c; + break; + + case "*": + // Move over all consecutive "*"'s. + // Also store the previous and next characters + var prevChar = str[i - 1]; + var starCount = 1; + while(str[i + 1] === "*") { + starCount++; + i++; + } + var nextChar = str[i + 1]; + + if (!globstar) { + // globstar is disabled, so treat any number of "*" as one + reStr += ".*"; + } else { + // globstar is enabled, so determine if this is a globstar segment + var isGlobstar = starCount > 1 // multiple "*"'s + && (prevChar === "/" || prevChar === undefined) // from the start of the segment + && (nextChar === "/" || nextChar === undefined) // to the end of the segment + + if (isGlobstar) { + // it's a globstar, so match zero or more path segments + reStr += "(?:[^/]*(?:\/|$))*"; + i++; // move over the "/" + } else { + // it's not a globstar, so only match one path segment + reStr += "[^/]*"; + } + } + break; + + default: + reStr += c; + } + } + + // When regexp 'g' flag is specified don't + // constrain the regular expression with ^ & $ + if (!flags || !~flags.indexOf('g')) { + reStr = "^" + reStr + "$"; + } + + return new RegExp(reStr, flags); +}; + + +/***/ }), +/* 877 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const call = __webpack_require__(878); + +module.exports = stat; + +/** + * Retrieves the {@link fs.Stats} for the given path. If the path is a symbolic link, + * then the Stats of the symlink's target are returned instead. If the symlink is broken, + * then the Stats of the symlink itself are returned. + * + * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module + * @param {string} path - The path to return stats for + * @param {function} callback + */ +function stat (fs, path, callback) { + let isSymLink = false; + + call.safe(fs.lstat, path, (err, lstats) => { + if (err) { + // fs.lstat threw an eror + return callback(err); + } + + try { + isSymLink = lstats.isSymbolicLink(); + } + catch (err2) { + // lstats.isSymbolicLink() threw an error + // (probably because fs.lstat returned an invalid result) + return callback(err2); + } + + if (isSymLink) { + // Try to resolve the symlink + symlinkStat(fs, path, lstats, callback); + } + else { + // It's not a symlink, so return the stats as-is + callback(null, lstats); + } + }); +} + +/** + * Retrieves the {@link fs.Stats} for the target of the given symlink. + * If the symlink is broken, then the Stats of the symlink itself are returned. + * + * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module + * @param {string} path - The path of the symlink to return stats for + * @param {object} lstats - The stats of the symlink + * @param {function} callback + */ +function symlinkStat (fs, path, lstats, callback) { + call.safe(fs.stat, path, (err, stats) => { + if (err) { + // The symlink is broken, so return the stats for the link itself + return callback(null, lstats); + } + + try { + // Return the stats for the resolved symlink target, + // and override the `isSymbolicLink` method to indicate that it's a symlink + stats.isSymbolicLink = () => true; + } + catch (err2) { + // Setting stats.isSymbolicLink threw an error + // (probably because fs.stat returned an invalid result) + return callback(err2); + } + + callback(null, stats); + }); +} + + +/***/ }), +/* 878 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +let call = module.exports = { + safe: safeCall, + once: callOnce, +}; + +/** + * Calls a function with the given arguments, and ensures that the error-first callback is _always_ + * invoked exactly once, even if the function throws an error. + * + * @param {function} fn - The function to invoke + * @param {...*} args - The arguments to pass to the function. The final argument must be a callback function. + */ +function safeCall (fn, args) { + // Get the function arguments as an array + args = Array.prototype.slice.call(arguments, 1); + + // Replace the callback function with a wrapper that ensures it will only be called once + let callback = call.once(args.pop()); + args.push(callback); + + try { + fn.apply(null, args); + } + catch (err) { + callback(err); + } +} + +/** + * Returns a wrapper function that ensures the given callback function is only called once. + * Subsequent calls are ignored, unless the first argument is an Error, in which case the + * error is thrown. + * + * @param {function} fn - The function that should only be called once + * @returns {function} + */ +function callOnce (fn) { + let fulfilled = false; + + return function onceWrapper (err) { + if (!fulfilled) { + fulfilled = true; + return fn.apply(this, arguments); + } + else if (err) { + // The callback has already been called, but now an error has occurred + // (most likely inside the callback function). So re-throw the error, + // so it gets handled further up the call stack + throw err; + } + }; +} + + +/***/ }), +/* 879 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const fs = __webpack_require__(23); +const call = __webpack_require__(878); + +/** + * A facade around {@link fs.readdirSync} that allows it to be called + * the same way as {@link fs.readdir}. + * + * @param {string} dir + * @param {function} callback + */ +exports.readdir = function (dir, callback) { + // Make sure the callback is only called once + callback = call.once(callback); + + try { + let items = fs.readdirSync(dir); + callback(null, items); + } + catch (err) { + callback(err); + } +}; + +/** + * A facade around {@link fs.statSync} that allows it to be called + * the same way as {@link fs.stat}. + * + * @param {string} path + * @param {function} callback + */ +exports.stat = function (path, callback) { + // Make sure the callback is only called once + callback = call.once(callback); + + try { + let stats = fs.statSync(path); + callback(null, stats); + } + catch (err) { + callback(err); + } +}; + +/** + * A facade around {@link fs.lstatSync} that allows it to be called + * the same way as {@link fs.lstat}. + * + * @param {string} path + * @param {function} callback + */ +exports.lstat = function (path, callback) { + // Make sure the callback is only called once + callback = call.once(callback); + + try { + let stats = fs.lstatSync(path); + callback(null, stats); + } + catch (err) { + callback(err); + } +}; + + +/***/ }), +/* 880 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = syncForEach; + +/** + * A facade that allows {@link Array.forEach} to be called as though it were asynchronous. + * + * @param {array} array - The array to iterate over + * @param {function} iterator - The function to call for each item in the array + * @param {function} done - The function to call when all iterators have completed + */ +function syncForEach (array, iterator, done) { + array.forEach(item => { + iterator(item, () => { + // Note: No error-handling here because this is currently only ever called + // by DirectoryReader, which never passes an `error` parameter to the callback. + // Instead, DirectoryReader emits an "error" event if an error occurs. + }); + }); + + done(); +} + + +/***/ }), +/* 881 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = readdirAsync; + +const maybe = __webpack_require__(882); +const DirectoryReader = __webpack_require__(874); + +let asyncFacade = { + fs: __webpack_require__(23), + forEach: __webpack_require__(883), + async: true +}; + +/** + * Returns the buffered output from an asynchronous {@link DirectoryReader}, + * via an error-first callback or a {@link Promise}. + * + * @param {string} dir + * @param {object} [options] + * @param {function} [callback] + * @param {object} internalOptions + */ +function readdirAsync (dir, options, callback, internalOptions) { + if (typeof options === 'function') { + callback = options; + options = undefined; + } + + return maybe(callback, new Promise(((resolve, reject) => { + let results = []; + + internalOptions.facade = asyncFacade; + + let reader = new DirectoryReader(dir, options, internalOptions); + let stream = reader.stream; + + stream.on('error', err => { + reject(err); + stream.pause(); + }); + stream.on('data', result => { + results.push(result); + }); + stream.on('end', () => { + resolve(results); + }); + }))); +} + + +/***/ }), +/* 882 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var next = (global.process && process.nextTick) || global.setImmediate || function (f) { + setTimeout(f, 0) +} + +module.exports = function maybe (cb, promise) { + if (cb) { + promise + .then(function (result) { + next(function () { cb(null, result) }) + }, function (err) { + next(function () { cb(err) }) + }) + return undefined + } + else { + return promise + } +} + + +/***/ }), +/* 883 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = asyncForEach; + +/** + * Simultaneously processes all items in the given array. + * + * @param {array} array - The array to iterate over + * @param {function} iterator - The function to call for each item in the array + * @param {function} done - The function to call when all iterators have completed + */ +function asyncForEach (array, iterator, done) { + if (array.length === 0) { + // NOTE: Normally a bad idea to mix sync and async, but it's safe here because + // of the way that this method is currently used by DirectoryReader. + done(); + return; + } + + // Simultaneously process all items in the array. + let pending = array.length; + array.forEach(item => { + iterator(item, () => { + if (--pending === 0) { + done(); + } + }); + }); +} + + +/***/ }), +/* 884 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = readdirStream; + +const DirectoryReader = __webpack_require__(874); + +let streamFacade = { + fs: __webpack_require__(23), + forEach: __webpack_require__(883), + async: true +}; + +/** + * Returns the {@link stream.Readable} of an asynchronous {@link DirectoryReader}. + * + * @param {string} dir + * @param {object} [options] + * @param {object} internalOptions + */ +function readdirStream (dir, options, internalOptions) { + internalOptions.facade = streamFacade; + + let reader = new DirectoryReader(dir, options, internalOptions); + return reader.stream; +} + + +/***/ }), +/* 885 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var path = __webpack_require__(16); +var deep_1 = __webpack_require__(886); +var entry_1 = __webpack_require__(888); +var pathUtil = __webpack_require__(887); +var Reader = /** @class */ (function () { + function Reader(options) { + this.options = options; + this.micromatchOptions = this.getMicromatchOptions(); + this.entryFilter = new entry_1.default(options, this.micromatchOptions); + this.deepFilter = new deep_1.default(options, this.micromatchOptions); + } + /** + * Returns root path to scanner. + */ + Reader.prototype.getRootDirectory = function (task) { + return path.resolve(this.options.cwd, task.base); + }; + /** + * Returns options for reader. + */ + Reader.prototype.getReaderOptions = function (task) { + return { + basePath: task.base === '.' ? '' : task.base, + filter: this.entryFilter.getFilter(task.positive, task.negative), + deep: this.deepFilter.getFilter(task.positive, task.negative), + sep: '/' + }; + }; + /** + * Returns options for micromatch. + */ + Reader.prototype.getMicromatchOptions = function () { + return { + dot: this.options.dot, + nobrace: !this.options.brace, + noglobstar: !this.options.globstar, + noext: !this.options.extension, + nocase: !this.options.case, + matchBase: this.options.matchBase + }; + }; + /** + * Returns transformed entry. + */ + Reader.prototype.transform = function (entry) { + if (this.options.absolute) { + entry.path = pathUtil.makeAbsolute(this.options.cwd, entry.path); + } + if (this.options.markDirectories && entry.isDirectory()) { + entry.path += '/'; + } + var item = this.options.stats ? entry : entry.path; + if (this.options.transform === null) { + return item; + } + return this.options.transform(item); + }; + /** + * Returns true if error has ENOENT code. + */ + Reader.prototype.isEnoentCodeError = function (err) { + return err.code === 'ENOENT'; + }; + return Reader; +}()); +exports.default = Reader; + + +/***/ }), +/* 886 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var pathUtils = __webpack_require__(887); +var patternUtils = __webpack_require__(716); +var DeepFilter = /** @class */ (function () { + function DeepFilter(options, micromatchOptions) { + this.options = options; + this.micromatchOptions = micromatchOptions; + } + /** + * Returns filter for directories. + */ + DeepFilter.prototype.getFilter = function (positive, negative) { + var _this = this; + var maxPatternDepth = this.getMaxPatternDepth(positive); + var negativeRe = this.getNegativePatternsRe(negative); + return function (entry) { return _this.filter(entry, negativeRe, maxPatternDepth); }; + }; + /** + * Returns max depth of the provided patterns. + */ + DeepFilter.prototype.getMaxPatternDepth = function (patterns) { + var globstar = patterns.some(patternUtils.hasGlobStar); + return globstar ? Infinity : patternUtils.getMaxNaivePatternsDepth(patterns); + }; + /** + * Returns RegExp's for patterns that can affect the depth of reading. + */ + DeepFilter.prototype.getNegativePatternsRe = function (patterns) { + var affectDepthOfReadingPatterns = patterns.filter(patternUtils.isAffectDepthOfReadingPattern); + return patternUtils.convertPatternsToRe(affectDepthOfReadingPatterns, this.micromatchOptions); + }; + /** + * Returns «true» for directory that should be read. + */ + DeepFilter.prototype.filter = function (entry, negativeRe, maxPatternDepth) { + if (this.isSkippedByDeepOption(entry.depth)) { + return false; + } + if (this.isSkippedByMaxPatternDepth(entry.depth, maxPatternDepth)) { + return false; + } + if (this.isSkippedSymlinkedDirectory(entry)) { + return false; + } + if (this.isSkippedDotDirectory(entry)) { + return false; + } + return this.isSkippedByNegativePatterns(entry, negativeRe); + }; + /** + * Returns «true» when the «deep» option is disabled or number and depth of the entry is greater that the option value. + */ + DeepFilter.prototype.isSkippedByDeepOption = function (entryDepth) { + return !this.options.deep || (typeof this.options.deep === 'number' && entryDepth >= this.options.deep); + }; + /** + * Returns «true» when depth parameter is not an Infinity and entry depth greater that the parameter value. + */ + DeepFilter.prototype.isSkippedByMaxPatternDepth = function (entryDepth, maxPatternDepth) { + return maxPatternDepth !== Infinity && entryDepth >= maxPatternDepth; + }; + /** + * Returns «true» for symlinked directory if the «followSymlinkedDirectories» option is disabled. + */ + DeepFilter.prototype.isSkippedSymlinkedDirectory = function (entry) { + return !this.options.followSymlinkedDirectories && entry.isSymbolicLink(); + }; + /** + * Returns «true» for a directory whose name starts with a period if «dot» option is disabled. + */ + DeepFilter.prototype.isSkippedDotDirectory = function (entry) { + return !this.options.dot && pathUtils.isDotDirectory(entry.path); + }; + /** + * Returns «true» for a directory whose path math to any negative pattern. + */ + DeepFilter.prototype.isSkippedByNegativePatterns = function (entry, negativeRe) { + return !patternUtils.matchAny(entry.path, negativeRe); + }; + return DeepFilter; +}()); +exports.default = DeepFilter; + + +/***/ }), +/* 887 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var path = __webpack_require__(16); +/** + * Returns «true» if the last partial of the path starting with a period. + */ +function isDotDirectory(filepath) { + return path.basename(filepath).startsWith('.'); +} +exports.isDotDirectory = isDotDirectory; +/** + * Convert a windows-like path to a unix-style path. + */ +function normalize(filepath) { + return filepath.replace(/\\/g, '/'); +} +exports.normalize = normalize; +/** + * Returns normalized absolute path of provided filepath. + */ +function makeAbsolute(cwd, filepath) { + return normalize(path.resolve(cwd, filepath)); +} +exports.makeAbsolute = makeAbsolute; + + +/***/ }), +/* 888 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var pathUtils = __webpack_require__(887); +var patternUtils = __webpack_require__(716); +var EntryFilter = /** @class */ (function () { + function EntryFilter(options, micromatchOptions) { + this.options = options; + this.micromatchOptions = micromatchOptions; + this.index = new Map(); + } + /** + * Returns filter for directories. + */ + EntryFilter.prototype.getFilter = function (positive, negative) { + var _this = this; + var positiveRe = patternUtils.convertPatternsToRe(positive, this.micromatchOptions); + var negativeRe = patternUtils.convertPatternsToRe(negative, this.micromatchOptions); + return function (entry) { return _this.filter(entry, positiveRe, negativeRe); }; + }; + /** + * Returns true if entry must be added to result. + */ + EntryFilter.prototype.filter = function (entry, positiveRe, negativeRe) { + // Exclude duplicate results + if (this.options.unique) { + if (this.isDuplicateEntry(entry)) { + return false; + } + this.createIndexRecord(entry); + } + // Filter files and directories by options + if (this.onlyFileFilter(entry) || this.onlyDirectoryFilter(entry)) { + return false; + } + if (this.isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { + return false; + } + return this.isMatchToPatterns(entry.path, positiveRe) && !this.isMatchToPatterns(entry.path, negativeRe); + }; + /** + * Return true if the entry already has in the cross reader index. + */ + EntryFilter.prototype.isDuplicateEntry = function (entry) { + return this.index.has(entry.path); + }; + /** + * Create record in the cross reader index. + */ + EntryFilter.prototype.createIndexRecord = function (entry) { + this.index.set(entry.path, undefined); + }; + /** + * Returns true for non-files if the «onlyFiles» option is enabled. + */ + EntryFilter.prototype.onlyFileFilter = function (entry) { + return this.options.onlyFiles && !entry.isFile(); + }; + /** + * Returns true for non-directories if the «onlyDirectories» option is enabled. + */ + EntryFilter.prototype.onlyDirectoryFilter = function (entry) { + return this.options.onlyDirectories && !entry.isDirectory(); + }; + /** + * Return true when `absolute` option is enabled and matched to the negative patterns. + */ + EntryFilter.prototype.isSkippedByAbsoluteNegativePatterns = function (entry, negativeRe) { + if (!this.options.absolute) { + return false; + } + var fullpath = pathUtils.makeAbsolute(this.options.cwd, entry.path); + return this.isMatchToPatterns(fullpath, negativeRe); + }; + /** + * Return true when entry match to provided patterns. + * + * First, just trying to apply patterns to the path. + * Second, trying to apply patterns to the path with final slash (need to micromatch to support «directory/**» patterns). + */ + EntryFilter.prototype.isMatchToPatterns = function (filepath, patternsRe) { + return patternUtils.matchAny(filepath, patternsRe) || patternUtils.matchAny(filepath + '/', patternsRe); + }; + return EntryFilter; +}()); +exports.default = EntryFilter; + + +/***/ }), +/* 889 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var stream = __webpack_require__(27); +var fsStat = __webpack_require__(890); +var fs_1 = __webpack_require__(894); +var FileSystemStream = /** @class */ (function (_super) { + __extends(FileSystemStream, _super); + function FileSystemStream() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * Use stream API to read entries for Task. + */ + FileSystemStream.prototype.read = function (patterns, filter) { + var _this = this; + var filepaths = patterns.map(this.getFullEntryPath, this); + var transform = new stream.Transform({ objectMode: true }); + transform._transform = function (index, _enc, done) { + return _this.getEntry(filepaths[index], patterns[index]).then(function (entry) { + if (entry !== null && filter(entry)) { + transform.push(entry); + } + if (index === filepaths.length - 1) { + transform.end(); + } + done(); + }); + }; + for (var i = 0; i < filepaths.length; i++) { + transform.write(i); + } + return transform; + }; + /** + * Return entry for the provided path. + */ + FileSystemStream.prototype.getEntry = function (filepath, pattern) { + var _this = this; + return this.getStat(filepath) + .then(function (stat) { return _this.makeEntry(stat, pattern); }) + .catch(function () { return null; }); + }; + /** + * Return fs.Stats for the provided path. + */ + FileSystemStream.prototype.getStat = function (filepath) { + return fsStat.stat(filepath, { throwErrorOnBrokenSymlinks: false }); + }; + return FileSystemStream; +}(fs_1.default)); +exports.default = FileSystemStream; + + +/***/ }), +/* 890 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const optionsManager = __webpack_require__(891); +const statProvider = __webpack_require__(893); +/** + * Asynchronous API. + */ +function stat(path, opts) { + return new Promise((resolve, reject) => { + statProvider.async(path, optionsManager.prepare(opts), (err, stats) => err ? reject(err) : resolve(stats)); + }); +} +exports.stat = stat; +function statCallback(path, optsOrCallback, callback) { + if (typeof optsOrCallback === 'function') { + callback = optsOrCallback; /* tslint:disable-line: no-parameter-reassignment */ + optsOrCallback = undefined; /* tslint:disable-line: no-parameter-reassignment */ + } + if (typeof callback === 'undefined') { + throw new TypeError('The "callback" argument must be of type Function.'); + } + statProvider.async(path, optionsManager.prepare(optsOrCallback), callback); +} +exports.statCallback = statCallback; +/** + * Synchronous API. + */ +function statSync(path, opts) { + return statProvider.sync(path, optionsManager.prepare(opts)); +} +exports.statSync = statSync; + + +/***/ }), +/* 891 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fsAdapter = __webpack_require__(892); +function prepare(opts) { + const options = Object.assign({ + fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), + throwErrorOnBrokenSymlinks: true, + followSymlinks: true + }, opts); + return options; +} +exports.prepare = prepare; + + +/***/ }), +/* 892 */ +/***/ (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 getFileSystemAdapter(fsMethods) { + if (!fsMethods) { + return exports.FILE_SYSTEM_ADAPTER; + } + return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); +} +exports.getFileSystemAdapter = getFileSystemAdapter; + + +/***/ }), +/* 893 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function sync(path, options) { + const lstat = options.fs.lstatSync(path); + if (!isFollowedSymlink(lstat, options)) { + return lstat; + } + try { + const stat = options.fs.statSync(path); + stat.isSymbolicLink = () => true; + return stat; + } + catch (err) { + if (!options.throwErrorOnBrokenSymlinks) { + return lstat; + } + throw err; + } +} +exports.sync = sync; +function async(path, options, callback) { + options.fs.lstat(path, (err0, lstat) => { + if (err0) { + return callback(err0, undefined); + } + if (!isFollowedSymlink(lstat, options)) { + return callback(null, lstat); + } + options.fs.stat(path, (err1, stat) => { + if (err1) { + return options.throwErrorOnBrokenSymlinks ? callback(err1) : callback(null, lstat); + } + stat.isSymbolicLink = () => true; + callback(null, stat); + }); + }); +} +exports.async = async; +/** + * Returns `true` for followed symlink. + */ +function isFollowedSymlink(stat, options) { + return stat.isSymbolicLink() && options.followSymlinks; +} +exports.isFollowedSymlink = isFollowedSymlink; + + +/***/ }), +/* 894 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var path = __webpack_require__(16); +var FileSystem = /** @class */ (function () { + function FileSystem(options) { + this.options = options; + } + /** + * Return full path to entry. + */ + FileSystem.prototype.getFullEntryPath = function (filepath) { + return path.resolve(this.options.cwd, filepath); + }; + /** + * Return an implementation of the Entry interface. + */ + FileSystem.prototype.makeEntry = function (stat, pattern) { + stat.path = pattern; + stat.depth = pattern.split('/').length; + return stat; + }; + return FileSystem; +}()); +exports.default = FileSystem; + + +/***/ }), +/* 895 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var stream = __webpack_require__(27); +var readdir = __webpack_require__(872); +var reader_1 = __webpack_require__(885); +var fs_stream_1 = __webpack_require__(889); +var TransformStream = /** @class */ (function (_super) { + __extends(TransformStream, _super); + function TransformStream(reader) { + var _this = _super.call(this, { objectMode: true }) || this; + _this.reader = reader; + return _this; + } + TransformStream.prototype._transform = function (entry, _encoding, callback) { + callback(null, this.reader.transform(entry)); + }; + return TransformStream; +}(stream.Transform)); +var ReaderStream = /** @class */ (function (_super) { + __extends(ReaderStream, _super); + function ReaderStream() { + return _super !== null && _super.apply(this, arguments) || this; + } + Object.defineProperty(ReaderStream.prototype, "fsAdapter", { + /** + * Returns FileSystem adapter. + */ + get: function () { + return new fs_stream_1.default(this.options); + }, + enumerable: true, + configurable: true + }); + /** + * Use stream API to read entries for Task. + */ + ReaderStream.prototype.read = function (task) { + var _this = this; + var root = this.getRootDirectory(task); + var options = this.getReaderOptions(task); + var transform = new TransformStream(this); + var readable = this.api(root, task, options); + return readable + .on('error', function (err) { return _this.isEnoentCodeError(err) ? null : transform.emit('error', err); }) + .pipe(transform); + }; + /** + * Returns founded paths. + */ + ReaderStream.prototype.api = function (root, task, options) { + if (task.dynamic) { + return this.dynamicApi(root, options); + } + return this.staticApi(task, options); + }; + /** + * Api for dynamic tasks. + */ + ReaderStream.prototype.dynamicApi = function (root, options) { + return readdir.readdirStreamStat(root, options); + }; + /** + * Api for static tasks. + */ + ReaderStream.prototype.staticApi = function (task, options) { + return this.fsAdapter.read(task.patterns, options.filter); + }; + return ReaderStream; +}(reader_1.default)); +exports.default = ReaderStream; + + +/***/ }), +/* 896 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var readdir = __webpack_require__(872); +var reader_1 = __webpack_require__(885); +var fs_sync_1 = __webpack_require__(897); +var ReaderSync = /** @class */ (function (_super) { + __extends(ReaderSync, _super); + function ReaderSync() { + return _super !== null && _super.apply(this, arguments) || this; + } + Object.defineProperty(ReaderSync.prototype, "fsAdapter", { + /** + * Returns FileSystem adapter. + */ + get: function () { + return new fs_sync_1.default(this.options); + }, + enumerable: true, + configurable: true + }); + /** + * Use sync API to read entries for Task. + */ + ReaderSync.prototype.read = function (task) { + var root = this.getRootDirectory(task); + var options = this.getReaderOptions(task); + try { + var entries = this.api(root, task, options); + return entries.map(this.transform, this); + } + catch (err) { + if (this.isEnoentCodeError(err)) { + return []; + } + throw err; + } + }; + /** + * Returns founded paths. + */ + ReaderSync.prototype.api = function (root, task, options) { + if (task.dynamic) { + return this.dynamicApi(root, options); + } + return this.staticApi(task, options); + }; + /** + * Api for dynamic tasks. + */ + ReaderSync.prototype.dynamicApi = function (root, options) { + return readdir.readdirSyncStat(root, options); + }; + /** + * Api for static tasks. + */ + ReaderSync.prototype.staticApi = function (task, options) { + return this.fsAdapter.read(task.patterns, options.filter); + }; + return ReaderSync; +}(reader_1.default)); +exports.default = ReaderSync; + + +/***/ }), +/* 897 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var fsStat = __webpack_require__(890); +var fs_1 = __webpack_require__(894); +var FileSystemSync = /** @class */ (function (_super) { + __extends(FileSystemSync, _super); + function FileSystemSync() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * Use sync API to read entries for Task. + */ + FileSystemSync.prototype.read = function (patterns, filter) { + var _this = this; + var entries = []; + patterns.forEach(function (pattern) { + var filepath = _this.getFullEntryPath(pattern); + var entry = _this.getEntry(filepath, pattern); + if (entry === null || !filter(entry)) { + return; + } + entries.push(entry); + }); + return entries; + }; + /** + * Return entry for the provided path. + */ + FileSystemSync.prototype.getEntry = function (filepath, pattern) { + try { + var stat = this.getStat(filepath); + return this.makeEntry(stat, pattern); + } + catch (err) { + return null; + } + }; + /** + * Return fs.Stats for the provided path. + */ + FileSystemSync.prototype.getStat = function (filepath) { + return fsStat.statSync(filepath, { throwErrorOnBrokenSymlinks: false }); + }; + return FileSystemSync; +}(fs_1.default)); +exports.default = FileSystemSync; + + +/***/ }), +/* 898 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * Flatten nested arrays (max depth is 2) into a non-nested array of non-array items. + */ +function flatten(items) { + return items.reduce(function (collection, item) { return [].concat(collection, item); }, []); +} +exports.flatten = flatten; + + +/***/ }), +/* 899 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var merge2 = __webpack_require__(591); +/** + * Merge multiple streams and propagate their errors into one stream in parallel. + */ +function merge(streams) { + var mergedStream = merge2(streams); + streams.forEach(function (stream) { + stream.on('error', function (err) { return mergedStream.emit('error', err); }); + }); + return mergedStream; +} +exports.merge = merge; + + +/***/ }), +/* 900 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const path = __webpack_require__(16); +const pathType = __webpack_require__(901); + +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 = (dir, opts) => { + if (opts.files && !Array.isArray(opts.files)) { + throw new TypeError(`Expected \`files\` to be of type \`Array\` but received type \`${typeof opts.files}\``); + } + + if (opts.extensions && !Array.isArray(opts.extensions)) { + throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof opts.extensions}\``); + } + + if (opts.files && opts.extensions) { + return opts.files.map(x => path.join(dir, addExtensions(x, opts.extensions))); + } + + if (opts.files) { + return opts.files.map(x => path.join(dir, `**/${x}`)); + } + + if (opts.extensions) { + return [path.join(dir, `**/*.${getExtensions(opts.extensions)}`)]; + } + + return [path.join(dir, '**')]; +}; + +module.exports = (input, opts) => { + opts = Object.assign({cwd: process.cwd()}, opts); + + if (typeof opts.cwd !== 'string') { + return Promise.reject(new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``)); + } + + return Promise.all([].concat(input).map(x => pathType.dir(getPath(x, opts.cwd)) + .then(isDir => isDir ? getGlob(x, opts) : x))) + .then(globs => [].concat.apply([], globs)); +}; + +module.exports.sync = (input, opts) => { + opts = Object.assign({cwd: process.cwd()}, opts); + + if (typeof opts.cwd !== 'string') { + throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``); + } + + const globs = [].concat(input).map(x => pathType.dirSync(getPath(x, opts.cwd)) ? getGlob(x, opts) : x); + return [].concat.apply([], globs); +}; + + +/***/ }), +/* 901 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const fs = __webpack_require__(23); +const pify = __webpack_require__(902); + +function type(fn, fn2, fp) { + if (typeof fp !== 'string') { + return Promise.reject(new TypeError(`Expected a string, got ${typeof fp}`)); + } + + return pify(fs[fn])(fp) + .then(stats => stats[fn2]()) + .catch(err => { + if (err.code === 'ENOENT') { + return false; + } + + throw err; + }); +} + +function typeSync(fn, fn2, fp) { + if (typeof fp !== 'string') { + throw new TypeError(`Expected a string, got ${typeof fp}`); + } + + try { + return fs[fn](fp)[fn2](); + } catch (err) { + if (err.code === 'ENOENT') { + return false; + } + + throw err; + } +} + +exports.file = type.bind(null, 'stat', 'isFile'); +exports.dir = type.bind(null, 'stat', 'isDirectory'); +exports.symlink = type.bind(null, 'lstat', 'isSymbolicLink'); +exports.fileSync = typeSync.bind(null, 'statSync', 'isFile'); +exports.dirSync = typeSync.bind(null, 'statSync', 'isDirectory'); +exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); + + +/***/ }), +/* 902 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const processFn = (fn, opts) => function () { + const P = opts.promiseModule; + const args = new Array(arguments.length); + + for (let i = 0; i < arguments.length; i++) { + args[i] = arguments[i]; + } + + return new P((resolve, reject) => { + if (opts.errorFirst) { + args.push(function (err, result) { + if (opts.multiArgs) { + const results = new Array(arguments.length - 1); + + for (let i = 1; i < arguments.length; i++) { + results[i - 1] = arguments[i]; + } + + if (err) { + results.unshift(err); + reject(results); + } else { + resolve(results); + } + } else if (err) { + reject(err); + } else { + resolve(result); + } + }); + } else { + args.push(function (result) { + if (opts.multiArgs) { + const results = new Array(arguments.length - 1); + + for (let i = 0; i < arguments.length; i++) { + results[i] = arguments[i]; + } + + resolve(results); + } else { + resolve(result); + } + }); + } + + fn.apply(this, args); + }); +}; + +module.exports = (obj, opts) => { + opts = Object.assign({ + exclude: [/.+(Sync|Stream)$/], + errorFirst: true, + promiseModule: Promise + }, opts); + + const filter = key => { + const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); + return opts.include ? opts.include.some(match) : !opts.exclude.some(match); + }; + + let ret; + if (typeof obj === 'function') { + ret = function () { + if (opts.excludeMain) { + return obj.apply(this, arguments); + } + + return processFn(obj, opts).apply(this, arguments); + }; + } else { + ret = Object.create(Object.getPrototypeOf(obj)); + } + + for (const key in obj) { // eslint-disable-line guard-for-in + const x = obj[key]; + ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; + } + + return ret; +}; + + +/***/ }), +/* 903 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const fs = __webpack_require__(23); +const path = __webpack_require__(16); +const fastGlob = __webpack_require__(712); +const gitIgnore = __webpack_require__(904); +const pify = __webpack_require__(905); +const slash = __webpack_require__(906); + +const DEFAULT_IGNORE = [ + '**/node_modules/**', + '**/bower_components/**', + '**/flow-typed/**', + '**/coverage/**', + '**/.git' +]; + +const readFileP = pify(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.charAt(0) !== '#') + .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 getIsIgnoredPredecate = (ignores, cwd) => { + return p => ignores.ignores(slash(path.relative(cwd, p))); +}; + +const getFile = (file, cwd) => { + const filePath = path.join(cwd, file); + return readFileP(filePath, 'utf8') + .then(content => ({ + content, + cwd, + filePath + })); +}; + +const getFileSync = (file, cwd) => { + const filePath = path.join(cwd, file); + const content = fs.readFileSync(filePath, 'utf8'); + + return { + content, + cwd, + filePath + }; +}; + +const normalizeOptions = (options = {}) => { + const ignore = options.ignore || []; + const cwd = options.cwd || process.cwd(); + return {ignore, cwd}; +}; + +module.exports = options => { + options = normalizeOptions(options); + + return fastGlob('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }) + .then(paths => Promise.all(paths.map(file => getFile(file, options.cwd)))) + .then(files => reduceIgnore(files)) + .then(ignores => 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); +}; + + +/***/ }), +/* 904 */ +/***/ (function(module, exports) { + +// A simple implementation of make-array +function make_array (subject) { + return Array.isArray(subject) + ? subject + : [subject] +} + +const REGEX_BLANK_LINE = /^\s+$/ +const REGEX_LEADING_EXCAPED_EXCLAMATION = /^\\!/ +const REGEX_LEADING_EXCAPED_HASH = /^\\#/ +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 `'/**'` + (match, 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' + (match, p1) => `${p1}[^\\/]*` + ], + + // trailing wildcard + [ + /(\^|\\\/)?\\\*$/, + (match, 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 cache = Object.create(null) + +// @param {pattern} +const make_regex = (pattern, negative, ignorecase) => { + const r = cache[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 cache[pattern] = ignorecase + ? new RegExp(source, 'i') + : new RegExp(source) +} + +// > A blank line matches no files, so it can serve as a separator for readability. +const checkPattern = pattern => pattern + && typeof pattern === 'string' + && !REGEX_BLANK_LINE.test(pattern) + + // > A line starting with # serves as a comment. + && pattern.indexOf('#') !== 0 + +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_LEADING_EXCAPED_EXCLAMATION, '!') + // > Put a backslash ("\") in front of the first hash for patterns that + // > begin with a hash. + .replace(REGEX_LEADING_EXCAPED_HASH, '#') - /* istanbul ignore if */ - if (isWindows) { - // Convert Windows root paths (C:\) and UNCs (\\) to POSIX root paths - posixBasePath = posixBasePath.replace(/^([a-zA-Z]\:\/|\/\/)/, '/'); - } - } + const regex = make_regex(pattern, negative, ignorecase) - // Determine which facade methods to use - let facade; - if (options.fs === null || options.fs === undefined) { - // The user didn't provide their own facades, so use our internal ones - facade = internalOptions.facade; + return { + origin, + pattern, + negative, + regex } - else if (typeof options.fs === 'object') { - // Merge the internal facade methods with the user-provided `fs` facades - facade = Object.assign({}, internalOptions.facade); - facade.fs = Object.assign({}, internalOptions.facade.fs, options.fs); +} + +class IgnoreBase { + constructor ({ + ignorecase = true + } = {}) { + this._rules = [] + this._ignorecase = ignorecase + define(this, KEY_IGNORE, true) + this._initCache() } - else { - throw new TypeError('options.fs must be an object'); + + _initCache () { + this._cache = Object.create(null) } - return { - recurseDepth, - recurseFn, - recurseRegExp, - recurseGlob, - filterFn, - filterRegExp, - filterGlob, - sep, - basePath, - posixBasePath, - facade, - emit: !!internalOptions.emit, - stats: !!internalOptions.stats, - }; -} + // @param {Array.|string|Ignore} pattern + add (pattern) { + this._added = false + if (typeof pattern === 'string') { + pattern = pattern.split(/\r?\n/g) + } -/***/ }), -/* 874 */ -/***/ (function(module, exports) { + make_array(pattern).forEach(this._addPattern, this) -module.exports = function (glob, opts) { - if (typeof glob !== 'string') { - throw new TypeError('Expected a string'); + // Some rules have just added to the ignore, + // making the behavior changed. + if (this._added) { + this._initCache() + } + + return this } - var str = String(glob); + // legacy + addPattern (pattern) { + return this.add(pattern) + } - // The regexp we are building, as a string. - var reStr = ""; + _addPattern (pattern) { + // #32 + if (pattern && pattern[KEY_IGNORE]) { + this._rules = this._rules.concat(pattern._rules) + this._added = true + return + } - // Whether we are matching so called "extended" globs (like bash) and should - // support single character matching, matching ranges of characters, group - // matching, etc. - var extended = opts ? !!opts.extended : false; + if (checkPattern(pattern)) { + const rule = createRule(pattern, this._ignorecase) + this._added = true + this._rules.push(rule) + } + } - // When globstar is _false_ (default), '/foo/*' is translated a regexp like - // '^\/foo\/.*$' which will match any string beginning with '/foo/' - // When globstar is _true_, '/foo/*' is translated to regexp like - // '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT - // which does not have a '/' to the right of it. - // E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but - // these will not '/foo/bar/baz', '/foo/bar/baz.txt' - // Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when - // globstar is _false_ - var globstar = opts ? !!opts.globstar : false; + filter (paths) { + return make_array(paths).filter(path => this._filter(path)) + } - // If we are doing extended matching, this boolean is true when we are inside - // a group (eg {*.html,*.js}), and false otherwise. - var inGroup = false; + createFilter () { + return path => this._filter(path) + } - // RegExp flags (eg "i" ) to pass in to RegExp constructor. - var flags = opts && typeof( opts.flags ) === "string" ? opts.flags : ""; + ignores (path) { + return !this._filter(path) + } - var c; - for (var i = 0, len = str.length; i < len; i++) { - c = str[i]; + // @returns `Boolean` true if the `path` is NOT ignored + _filter (path, slices) { + if (!path) { + return false + } - switch (c) { - case "\\": - case "/": - case "$": - case "^": - case "+": - case ".": - case "(": - case ")": - case "=": - case "!": - case "|": - reStr += "\\" + c; - break; + if (path in this._cache) { + return this._cache[path] + } - case "?": - if (extended) { - reStr += "."; - break; - } + if (!slices) { + // path/to/a.js + // ['path', 'to', 'a.js'] + slices = path.split(SLASH) + } - case "[": - case "]": - if (extended) { - reStr += c; - break; - } + slices.pop() - case "{": - if (extended) { - inGroup = true; - reStr += "("; - break; - } + return this._cache[path] = slices.length + // > It is not possible to re-include a file if a parent directory of + // > that file is excluded. + // If the path contains a parent directory, check the parent first + ? this._filter(slices.join(SLASH) + SLASH, slices) + && this._test(path) - case "}": - if (extended) { - inGroup = false; - reStr += ")"; - break; - } + // Or only test the path + : this._test(path) + } - case ",": - if (inGroup) { - reStr += "|"; - break; - } - reStr += "\\" + c; - break; + // @returns {Boolean} true if a file is NOT ignored + _test (path) { + // Explicitly define variable type by setting matched to `0` + let matched = 0 - case "*": - // Move over all consecutive "*"'s. - // Also store the previous and next characters - var prevChar = str[i - 1]; - var starCount = 1; - while(str[i + 1] === "*") { - starCount++; - i++; + this._rules.forEach(rule => { + // if matched = true, then we only test negative rules + // if matched = false, then we test non-negative rules + if (!(matched ^ rule.negative)) { + matched = rule.negative ^ rule.regex.test(path) } - var nextChar = str[i + 1]; + }) - if (!globstar) { - // globstar is disabled, so treat any number of "*" as one - reStr += ".*"; - } else { - // globstar is enabled, so determine if this is a globstar segment - var isGlobstar = starCount > 1 // multiple "*"'s - && (prevChar === "/" || prevChar === undefined) // from the start of the segment - && (nextChar === "/" || nextChar === undefined) // to the end of the segment + return !matched + } +} - if (isGlobstar) { - // it's a globstar, so match zero or more path segments - reStr += "(?:[^/]*(?:\/|$))*"; - i++; // move over the "/" - } else { - // it's not a globstar, so only match one path segment - reStr += "[^/]*"; - } - } - break; +// 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' + ) +) { + const filter = IgnoreBase.prototype._filter - default: - reStr += c; - } - } + /* eslint no-control-regex: "off" */ + const make_posix = str => /^\\\\\?\\/.test(str) + || /[^\x00-\x80]+/.test(str) + ? str + : str.replace(/\\/g, '/') - // When regexp 'g' flag is specified don't - // constrain the regular expression with ^ & $ - if (!flags || !~flags.indexOf('g')) { - reStr = "^" + reStr + "$"; + IgnoreBase.prototype._filter = function filterWin32 (path, slices) { + path = make_posix(path) + return filter.call(this, path, slices) } +} - return new RegExp(reStr, flags); -}; +module.exports = options => new IgnoreBase(options) /***/ }), -/* 875 */ +/* 905 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(876); +const processFn = (fn, options) => function (...args) { + const P = options.promiseModule; -module.exports = stat; + return new P((resolve, reject) => { + if (options.multiArgs) { + args.push((...result) => { + if (options.errorFirst) { + if (result[0]) { + reject(result); + } else { + result.shift(); + resolve(result); + } + } else { + resolve(result); + } + }); + } else if (options.errorFirst) { + args.push((error, result) => { + if (error) { + reject(error); + } else { + resolve(result); + } + }); + } else { + args.push(resolve); + } -/** - * Retrieves the {@link fs.Stats} for the given path. If the path is a symbolic link, - * then the Stats of the symlink's target are returned instead. If the symlink is broken, - * then the Stats of the symlink itself are returned. - * - * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module - * @param {string} path - The path to return stats for - * @param {function} callback - */ -function stat (fs, path, callback) { - let isSymLink = false; + fn.apply(this, args); + }); +}; - call.safe(fs.lstat, path, (err, lstats) => { - if (err) { - // fs.lstat threw an eror - return callback(err); - } +module.exports = (input, options) => { + options = Object.assign({ + exclude: [/.+(Sync|Stream)$/], + errorFirst: true, + promiseModule: Promise + }, options); - try { - isSymLink = lstats.isSymbolicLink(); - } - catch (err2) { - // lstats.isSymbolicLink() threw an error - // (probably because fs.lstat returned an invalid result) - return callback(err2); - } + const objType = typeof input; + if (!(input !== null && (objType === 'object' || objType === 'function'))) { + throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objType}\``); + } - if (isSymLink) { - // Try to resolve the symlink - symlinkStat(fs, path, lstats, callback); - } - else { - // It's not a symlink, so return the stats as-is - callback(null, lstats); - } - }); -} + const filter = key => { + const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); + return options.include ? options.include.some(match) : !options.exclude.some(match); + }; -/** - * Retrieves the {@link fs.Stats} for the target of the given symlink. - * If the symlink is broken, then the Stats of the symlink itself are returned. - * - * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module - * @param {string} path - The path of the symlink to return stats for - * @param {object} lstats - The stats of the symlink - * @param {function} callback - */ -function symlinkStat (fs, path, lstats, callback) { - call.safe(fs.stat, path, (err, stats) => { - if (err) { - // The symlink is broken, so return the stats for the link itself - return callback(null, lstats); - } + let ret; + if (objType === 'function') { + ret = function (...args) { + return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args); + }; + } else { + ret = Object.create(Object.getPrototypeOf(input)); + } - try { - // Return the stats for the resolved symlink target, - // and override the `isSymbolicLink` method to indicate that it's a symlink - stats.isSymbolicLink = () => true; - } - catch (err2) { - // Setting stats.isSymbolicLink threw an error - // (probably because fs.stat returned an invalid result) - return callback(err2); - } + for (const key in input) { // eslint-disable-line guard-for-in + const property = input[key]; + ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property; + } - callback(null, stats); - }); -} + return ret; +}; /***/ }), -/* 876 */ +/* 906 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +module.exports = input => { + const isExtendedLengthPath = /^\\\\\?\\/.test(input); + const hasNonAscii = /[^\u0000-\u0080]+/.test(input); // eslint-disable-line no-control-regex -let call = module.exports = { - safe: safeCall, - once: callOnce, -}; - -/** - * Calls a function with the given arguments, and ensures that the error-first callback is _always_ - * invoked exactly once, even if the function throws an error. - * - * @param {function} fn - The function to invoke - * @param {...*} args - The arguments to pass to the function. The final argument must be a callback function. - */ -function safeCall (fn, args) { - // Get the function arguments as an array - args = Array.prototype.slice.call(arguments, 1); - - // Replace the callback function with a wrapper that ensures it will only be called once - let callback = call.once(args.pop()); - args.push(callback); - - try { - fn.apply(null, args); - } - catch (err) { - callback(err); - } -} - -/** - * Returns a wrapper function that ensures the given callback function is only called once. - * Subsequent calls are ignored, unless the first argument is an Error, in which case the - * error is thrown. - * - * @param {function} fn - The function that should only be called once - * @returns {function} - */ -function callOnce (fn) { - let fulfilled = false; + if (isExtendedLengthPath || hasNonAscii) { + return input; + } - return function onceWrapper (err) { - if (!fulfilled) { - fulfilled = true; - return fn.apply(this, arguments); - } - else if (err) { - // The callback has already been called, but now an error has occurred - // (most likely inside the callback function). So re-throw the error, - // so it gets handled further up the call stack - throw err; - } - }; -} + return input.replace(/\\/g, '/'); +}; /***/ }), -/* 877 */ +/* 907 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +const path = __webpack_require__(16); +const {constants: fsConstants} = __webpack_require__(23); +const pEvent = __webpack_require__(908); +const CpFileError = __webpack_require__(911); +const fs = __webpack_require__(913); +const ProgressEmitter = __webpack_require__(916); + +const cpFileAsync = async (source, destination, options, progressEmitter) => { + let readError; + const stat = await fs.stat(source); + progressEmitter.size = stat.size; + + const read = await fs.createReadStream(source); + await fs.makeDir(path.dirname(destination)); + const write = fs.createWriteStream(destination, {flags: options.overwrite ? 'w' : 'wx'}); + read.on('data', () => { + progressEmitter.written = write.bytesWritten; + }); + read.once('error', error => { + readError = new CpFileError(`Cannot read from \`${source}\`: ${error.message}`, error); + write.end(); + }); -const fs = __webpack_require__(23); -const call = __webpack_require__(876); + let updateStats = false; + try { + const writePromise = pEvent(write, 'close'); + read.pipe(write); + await writePromise; + progressEmitter.written = progressEmitter.size; + updateStats = true; + } catch (error) { + if (options.overwrite || error.code !== 'EEXIST') { + throw new CpFileError(`Cannot write to \`${destination}\`: ${error.message}`, error); + } + } -/** - * A facade around {@link fs.readdirSync} that allows it to be called - * the same way as {@link fs.readdir}. - * - * @param {string} dir - * @param {function} callback - */ -exports.readdir = function (dir, callback) { - // Make sure the callback is only called once - callback = call.once(callback); + if (readError) { + throw readError; + } - try { - let items = fs.readdirSync(dir); - callback(null, items); - } - catch (err) { - callback(err); - } + if (updateStats) { + const stats = await fs.lstat(source); + + return Promise.all([ + fs.utimes(destination, stats.atime, stats.mtime), + fs.chmod(destination, stats.mode), + fs.chown(destination, stats.uid, stats.gid) + ]); + } }; -/** - * A facade around {@link fs.statSync} that allows it to be called - * the same way as {@link fs.stat}. - * - * @param {string} path - * @param {function} callback - */ -exports.stat = function (path, callback) { - // Make sure the callback is only called once - callback = call.once(callback); +const cpFile = (source, destination, options) => { + if (!source || !destination) { + return Promise.reject(new CpFileError('`source` and `destination` required')); + } + + options = { + overwrite: true, + ...options + }; + + const progressEmitter = new ProgressEmitter(path.resolve(source), path.resolve(destination)); + const promise = cpFileAsync(source, destination, options, progressEmitter); + promise.on = (...args) => { + progressEmitter.on(...args); + return promise; + }; - try { - let stats = fs.statSync(path); - callback(null, stats); - } - catch (err) { - callback(err); - } + return promise; }; -/** - * A facade around {@link fs.lstatSync} that allows it to be called - * the same way as {@link fs.lstat}. - * - * @param {string} path - * @param {function} callback - */ -exports.lstat = function (path, callback) { - // Make sure the callback is only called once - callback = call.once(callback); +module.exports = cpFile; - try { - let stats = fs.lstatSync(path); - callback(null, stats); - } - catch (err) { - callback(err); - } +const checkSourceIsFile = (stat, source) => { + if (stat.isDirectory()) { + throw Object.assign(new CpFileError(`EISDIR: illegal operation on a directory '${source}'`), { + errno: -21, + code: 'EISDIR', + source + }); + } }; +const fixupAttributes = (destination, stat) => { + fs.chmodSync(destination, stat.mode); + fs.chownSync(destination, stat.uid, stat.gid); +}; -/***/ }), -/* 878 */ -/***/ (function(module, exports, __webpack_require__) { +module.exports.sync = (source, destination, options) => { + if (!source || !destination) { + throw new CpFileError('`source` and `destination` required'); + } -"use strict"; + options = { + overwrite: true, + ...options + }; + const stat = fs.statSync(source); + checkSourceIsFile(stat, source); + fs.makeDirSync(path.dirname(destination)); -module.exports = syncForEach; + const flags = options.overwrite ? null : fsConstants.COPYFILE_EXCL; + try { + fs.copyFileSync(source, destination, flags); + } catch (error) { + if (!options.overwrite && error.code === 'EEXIST') { + return; + } -/** - * A facade that allows {@link Array.forEach} to be called as though it were asynchronous. - * - * @param {array} array - The array to iterate over - * @param {function} iterator - The function to call for each item in the array - * @param {function} done - The function to call when all iterators have completed - */ -function syncForEach (array, iterator, done) { - array.forEach(item => { - iterator(item, () => { - // Note: No error-handling here because this is currently only ever called - // by DirectoryReader, which never passes an `error` parameter to the callback. - // Instead, DirectoryReader emits an "error" event if an error occurs. - }); - }); + throw error; + } - done(); -} + fs.utimesSync(destination, stat.atime, stat.mtime); + fixupAttributes(destination, stat); +}; /***/ }), -/* 879 */ +/* 908 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +const pTimeout = __webpack_require__(909); -module.exports = readdirAsync; +const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; -const maybe = __webpack_require__(880); -const DirectoryReader = __webpack_require__(872); +const normalizeEmitter = emitter => { + const addListener = emitter.on || emitter.addListener || emitter.addEventListener; + const removeListener = emitter.off || emitter.removeListener || emitter.removeEventListener; -let asyncFacade = { - fs: __webpack_require__(23), - forEach: __webpack_require__(881), - async: true + if (!addListener || !removeListener) { + throw new TypeError('Emitter is not compatible'); + } + + return { + addListener: addListener.bind(emitter), + removeListener: removeListener.bind(emitter) + }; }; -/** - * Returns the buffered output from an asynchronous {@link DirectoryReader}, - * via an error-first callback or a {@link Promise}. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @param {object} internalOptions - */ -function readdirAsync (dir, options, callback, internalOptions) { - if (typeof options === 'function') { - callback = options; - options = undefined; - } +const normalizeEvents = event => Array.isArray(event) ? event : [event]; - return maybe(callback, new Promise(((resolve, reject) => { - let results = []; +const multiple = (emitter, event, options) => { + let cancel; + const ret = new Promise((resolve, reject) => { + options = { + rejectionEvents: ['error'], + multiArgs: false, + resolveImmediately: false, + ...options + }; - internalOptions.facade = asyncFacade; + if (!(options.count >= 0 && (options.count === Infinity || Number.isInteger(options.count)))) { + throw new TypeError('The `count` option should be at least 0 or more'); + } - let reader = new DirectoryReader(dir, options, internalOptions); - let stream = reader.stream; + // Allow multiple events + const events = normalizeEvents(event); - stream.on('error', err => { - reject(err); - stream.pause(); - }); - stream.on('data', result => { - results.push(result); - }); - stream.on('end', () => { - resolve(results); - }); - }))); -} + const items = []; + const {addListener, removeListener} = normalizeEmitter(emitter); + const onItem = (...args) => { + const value = options.multiArgs ? args : args[0]; -/***/ }), -/* 880 */ -/***/ (function(module, exports, __webpack_require__) { + if (options.filter && !options.filter(value)) { + return; + } -"use strict"; + items.push(value); + if (options.count === items.length) { + cancel(); + resolve(items); + } + }; -var next = (global.process && process.nextTick) || global.setImmediate || function (f) { - setTimeout(f, 0) -} + const rejectHandler = error => { + cancel(); + reject(error); + }; -module.exports = function maybe (cb, promise) { - if (cb) { - promise - .then(function (result) { - next(function () { cb(null, result) }) - }, function (err) { - next(function () { cb(err) }) - }) - return undefined - } - else { - return promise - } -} + cancel = () => { + for (const event of events) { + removeListener(event, onItem); + } + for (const rejectionEvent of options.rejectionEvents) { + removeListener(rejectionEvent, rejectHandler); + } + }; -/***/ }), -/* 881 */ -/***/ (function(module, exports, __webpack_require__) { + for (const event of events) { + addListener(event, onItem); + } -"use strict"; + for (const rejectionEvent of options.rejectionEvents) { + addListener(rejectionEvent, rejectHandler); + } + if (options.resolveImmediately) { + resolve(items); + } + }); -module.exports = asyncForEach; + ret.cancel = cancel; -/** - * Simultaneously processes all items in the given array. - * - * @param {array} array - The array to iterate over - * @param {function} iterator - The function to call for each item in the array - * @param {function} done - The function to call when all iterators have completed - */ -function asyncForEach (array, iterator, done) { - if (array.length === 0) { - // NOTE: Normally a bad idea to mix sync and async, but it's safe here because - // of the way that this method is currently used by DirectoryReader. - done(); - return; - } + if (typeof options.timeout === 'number') { + const timeout = pTimeout(ret, options.timeout); + timeout.cancel = cancel; + return timeout; + } - // Simultaneously process all items in the array. - let pending = array.length; - array.forEach(item => { - iterator(item, () => { - if (--pending === 0) { - done(); - } - }); - }); -} + return ret; +}; +const pEvent = (emitter, event, options) => { + if (typeof options === 'function') { + options = {filter: options}; + } -/***/ }), -/* 882 */ -/***/ (function(module, exports, __webpack_require__) { + options = { + ...options, + count: 1, + resolveImmediately: false + }; -"use strict"; + const arrayPromise = multiple(emitter, event, options); + const promise = arrayPromise.then(array => array[0]); // eslint-disable-line promise/prefer-await-to-then + promise.cancel = arrayPromise.cancel; + return promise; +}; -module.exports = readdirStream; +module.exports = pEvent; +// TODO: Remove this for the next major release +module.exports.default = pEvent; -const DirectoryReader = __webpack_require__(872); +module.exports.multiple = multiple; -let streamFacade = { - fs: __webpack_require__(23), - forEach: __webpack_require__(881), - async: true -}; +module.exports.iterator = (emitter, event, options) => { + if (typeof options === 'function') { + options = {filter: options}; + } -/** - * Returns the {@link stream.Readable} of an asynchronous {@link DirectoryReader}. - * - * @param {string} dir - * @param {object} [options] - * @param {object} internalOptions - */ -function readdirStream (dir, options, internalOptions) { - internalOptions.facade = streamFacade; + // Allow multiple events + const events = normalizeEvents(event); - let reader = new DirectoryReader(dir, options, internalOptions); - return reader.stream; -} + options = { + rejectionEvents: ['error'], + resolutionEvents: [], + limit: Infinity, + multiArgs: false, + ...options + }; + const {limit} = options; + const isValidLimit = limit >= 0 && (limit === Infinity || Number.isInteger(limit)); + if (!isValidLimit) { + throw new TypeError('The `limit` option should be a non-negative integer or Infinity'); + } -/***/ }), -/* 883 */ -/***/ (function(module, exports, __webpack_require__) { + if (limit === 0) { + // Return an empty async iterator to avoid any further cost + return { + [Symbol.asyncIterator]() { + return this; + }, + async next() { + return { + done: true, + value: undefined + }; + } + }; + } -"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 Reader = /** @class */ (function () { - function Reader(options) { - this.options = options; - this.micromatchOptions = this.getMicromatchOptions(); - this.entryFilter = new entry_1.default(options, this.micromatchOptions); - this.deepFilter = new deep_1.default(options, this.micromatchOptions); - } - /** - * Returns root path to scanner. - */ - Reader.prototype.getRootDirectory = function (task) { - return path.resolve(this.options.cwd, task.base); - }; - /** - * Returns options for reader. - */ - Reader.prototype.getReaderOptions = function (task) { - return { - basePath: task.base === '.' ? '' : task.base, - filter: this.entryFilter.getFilter(task.positive, task.negative), - deep: this.deepFilter.getFilter(task.positive, task.negative), - sep: '/' - }; - }; - /** - * Returns options for micromatch. - */ - Reader.prototype.getMicromatchOptions = function () { - return { - dot: this.options.dot, - nobrace: !this.options.brace, - noglobstar: !this.options.globstar, - noext: !this.options.extension, - nocase: !this.options.case, - matchBase: this.options.matchBase - }; - }; - /** - * Returns transformed entry. - */ - Reader.prototype.transform = function (entry) { - if (this.options.absolute) { - entry.path = pathUtil.makeAbsolute(this.options.cwd, entry.path); - } - if (this.options.markDirectories && entry.isDirectory()) { - entry.path += '/'; - } - var item = this.options.stats ? entry : entry.path; - if (this.options.transform === null) { - return item; - } - return this.options.transform(item); - }; - /** - * Returns true if error has ENOENT code. - */ - Reader.prototype.isEnoentCodeError = function (err) { - return err.code === 'ENOENT'; - }; - return Reader; -}()); -exports.default = Reader; + const {addListener, removeListener} = normalizeEmitter(emitter); + let isDone = false; + let error; + let hasPendingError = false; + const nextQueue = []; + const valueQueue = []; + let eventCount = 0; + let isLimitReached = false; -/***/ }), -/* 884 */ -/***/ (function(module, exports, __webpack_require__) { + const valueHandler = (...args) => { + eventCount++; + isLimitReached = eventCount === limit; -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(885); -var patternUtils = __webpack_require__(714); -var DeepFilter = /** @class */ (function () { - function DeepFilter(options, micromatchOptions) { - this.options = options; - this.micromatchOptions = micromatchOptions; - } - /** - * Returns filter for directories. - */ - DeepFilter.prototype.getFilter = function (positive, negative) { - var _this = this; - var maxPatternDepth = this.getMaxPatternDepth(positive); - var negativeRe = this.getNegativePatternsRe(negative); - return function (entry) { return _this.filter(entry, negativeRe, maxPatternDepth); }; - }; - /** - * Returns max depth of the provided patterns. - */ - DeepFilter.prototype.getMaxPatternDepth = function (patterns) { - var globstar = patterns.some(patternUtils.hasGlobStar); - return globstar ? Infinity : patternUtils.getMaxNaivePatternsDepth(patterns); - }; - /** - * Returns RegExp's for patterns that can affect the depth of reading. - */ - DeepFilter.prototype.getNegativePatternsRe = function (patterns) { - var affectDepthOfReadingPatterns = patterns.filter(patternUtils.isAffectDepthOfReadingPattern); - return patternUtils.convertPatternsToRe(affectDepthOfReadingPatterns, this.micromatchOptions); - }; - /** - * Returns «true» for directory that should be read. - */ - DeepFilter.prototype.filter = function (entry, negativeRe, maxPatternDepth) { - if (this.isSkippedByDeepOption(entry.depth)) { - return false; - } - if (this.isSkippedByMaxPatternDepth(entry.depth, maxPatternDepth)) { - return false; - } - if (this.isSkippedSymlinkedDirectory(entry)) { - return false; - } - if (this.isSkippedDotDirectory(entry)) { - return false; - } - return this.isSkippedByNegativePatterns(entry, negativeRe); - }; - /** - * Returns «true» when the «deep» option is disabled or number and depth of the entry is greater that the option value. - */ - DeepFilter.prototype.isSkippedByDeepOption = function (entryDepth) { - return !this.options.deep || (typeof this.options.deep === 'number' && entryDepth >= this.options.deep); - }; - /** - * Returns «true» when depth parameter is not an Infinity and entry depth greater that the parameter value. - */ - DeepFilter.prototype.isSkippedByMaxPatternDepth = function (entryDepth, maxPatternDepth) { - return maxPatternDepth !== Infinity && entryDepth >= maxPatternDepth; - }; - /** - * Returns «true» for symlinked directory if the «followSymlinkedDirectories» option is disabled. - */ - DeepFilter.prototype.isSkippedSymlinkedDirectory = function (entry) { - return !this.options.followSymlinkedDirectories && entry.isSymbolicLink(); - }; - /** - * Returns «true» for a directory whose name starts with a period if «dot» option is disabled. - */ - DeepFilter.prototype.isSkippedDotDirectory = function (entry) { - return !this.options.dot && pathUtils.isDotDirectory(entry.path); - }; - /** - * Returns «true» for a directory whose path math to any negative pattern. - */ - DeepFilter.prototype.isSkippedByNegativePatterns = function (entry, negativeRe) { - return !patternUtils.matchAny(entry.path, negativeRe); - }; - return DeepFilter; -}()); -exports.default = DeepFilter; + const value = options.multiArgs ? args : args[0]; + if (nextQueue.length > 0) { + const {resolve} = nextQueue.shift(); -/***/ }), -/* 885 */ -/***/ (function(module, exports, __webpack_require__) { + resolve({done: false, value}); -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(16); -/** - * Returns «true» if the last partial of the path starting with a period. - */ -function isDotDirectory(filepath) { - return path.basename(filepath).startsWith('.'); -} -exports.isDotDirectory = isDotDirectory; -/** - * Convert a windows-like path to a unix-style path. - */ -function normalize(filepath) { - return filepath.replace(/\\/g, '/'); -} -exports.normalize = normalize; -/** - * Returns normalized absolute path of provided filepath. - */ -function makeAbsolute(cwd, filepath) { - return normalize(path.resolve(cwd, filepath)); -} -exports.makeAbsolute = makeAbsolute; + if (isLimitReached) { + cancel(); + } + return; + } -/***/ }), -/* 886 */ -/***/ (function(module, exports, __webpack_require__) { + valueQueue.push(value); -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(885); -var patternUtils = __webpack_require__(714); -var EntryFilter = /** @class */ (function () { - function EntryFilter(options, micromatchOptions) { - this.options = options; - this.micromatchOptions = micromatchOptions; - this.index = new Map(); - } - /** - * Returns filter for directories. - */ - EntryFilter.prototype.getFilter = function (positive, negative) { - var _this = this; - var positiveRe = patternUtils.convertPatternsToRe(positive, this.micromatchOptions); - var negativeRe = patternUtils.convertPatternsToRe(negative, this.micromatchOptions); - return function (entry) { return _this.filter(entry, positiveRe, negativeRe); }; - }; - /** - * Returns true if entry must be added to result. - */ - EntryFilter.prototype.filter = function (entry, positiveRe, negativeRe) { - // Exclude duplicate results - if (this.options.unique) { - if (this.isDuplicateEntry(entry)) { - return false; - } - this.createIndexRecord(entry); - } - // Filter files and directories by options - if (this.onlyFileFilter(entry) || this.onlyDirectoryFilter(entry)) { - return false; - } - if (this.isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { - return false; - } - return this.isMatchToPatterns(entry.path, positiveRe) && !this.isMatchToPatterns(entry.path, negativeRe); - }; - /** - * Return true if the entry already has in the cross reader index. - */ - EntryFilter.prototype.isDuplicateEntry = function (entry) { - return this.index.has(entry.path); - }; - /** - * Create record in the cross reader index. - */ - EntryFilter.prototype.createIndexRecord = function (entry) { - this.index.set(entry.path, undefined); - }; - /** - * Returns true for non-files if the «onlyFiles» option is enabled. - */ - EntryFilter.prototype.onlyFileFilter = function (entry) { - return this.options.onlyFiles && !entry.isFile(); - }; - /** - * Returns true for non-directories if the «onlyDirectories» option is enabled. - */ - EntryFilter.prototype.onlyDirectoryFilter = function (entry) { - return this.options.onlyDirectories && !entry.isDirectory(); - }; - /** - * Return true when `absolute` option is enabled and matched to the negative patterns. - */ - EntryFilter.prototype.isSkippedByAbsoluteNegativePatterns = function (entry, negativeRe) { - if (!this.options.absolute) { - return false; - } - var fullpath = pathUtils.makeAbsolute(this.options.cwd, entry.path); - return this.isMatchToPatterns(fullpath, negativeRe); - }; - /** - * Return true when entry match to provided patterns. - * - * First, just trying to apply patterns to the path. - * Second, trying to apply patterns to the path with final slash (need to micromatch to support «directory/**» patterns). - */ - EntryFilter.prototype.isMatchToPatterns = function (filepath, patternsRe) { - return patternUtils.matchAny(filepath, patternsRe) || patternUtils.matchAny(filepath + '/', patternsRe); - }; - return EntryFilter; -}()); -exports.default = EntryFilter; + if (isLimitReached) { + cancel(); + } + }; + + const cancel = () => { + isDone = true; + for (const event of events) { + removeListener(event, valueHandler); + } + for (const rejectionEvent of options.rejectionEvents) { + removeListener(rejectionEvent, rejectHandler); + } -/***/ }), -/* 887 */ -/***/ (function(module, exports, __webpack_require__) { + for (const resolutionEvent of options.resolutionEvents) { + removeListener(resolutionEvent, resolveHandler); + } -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var stream = __webpack_require__(27); -var fsStat = __webpack_require__(888); -var fs_1 = __webpack_require__(892); -var FileSystemStream = /** @class */ (function (_super) { - __extends(FileSystemStream, _super); - function FileSystemStream() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - * Use stream API to read entries for Task. - */ - FileSystemStream.prototype.read = function (patterns, filter) { - var _this = this; - var filepaths = patterns.map(this.getFullEntryPath, this); - var transform = new stream.Transform({ objectMode: true }); - transform._transform = function (index, _enc, done) { - return _this.getEntry(filepaths[index], patterns[index]).then(function (entry) { - if (entry !== null && filter(entry)) { - transform.push(entry); - } - if (index === filepaths.length - 1) { - transform.end(); - } - done(); - }); - }; - for (var i = 0; i < filepaths.length; i++) { - transform.write(i); - } - return transform; - }; - /** - * Return entry for the provided path. - */ - FileSystemStream.prototype.getEntry = function (filepath, pattern) { - var _this = this; - return this.getStat(filepath) - .then(function (stat) { return _this.makeEntry(stat, pattern); }) - .catch(function () { return null; }); - }; - /** - * Return fs.Stats for the provided path. - */ - FileSystemStream.prototype.getStat = function (filepath) { - return fsStat.stat(filepath, { throwErrorOnBrokenSymlinks: false }); - }; - return FileSystemStream; -}(fs_1.default)); -exports.default = FileSystemStream; + while (nextQueue.length > 0) { + const {resolve} = nextQueue.shift(); + resolve({done: true, value: undefined}); + } + }; + const rejectHandler = (...args) => { + error = options.multiArgs ? args : args[0]; -/***/ }), -/* 888 */ -/***/ (function(module, exports, __webpack_require__) { + if (nextQueue.length > 0) { + const {reject} = nextQueue.shift(); + reject(error); + } else { + hasPendingError = true; + } -"use strict"; + cancel(); + }; -Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(889); -const statProvider = __webpack_require__(891); -/** - * Asynchronous API. - */ -function stat(path, opts) { - return new Promise((resolve, reject) => { - statProvider.async(path, optionsManager.prepare(opts), (err, stats) => err ? reject(err) : resolve(stats)); - }); -} -exports.stat = stat; -function statCallback(path, optsOrCallback, callback) { - if (typeof optsOrCallback === 'function') { - callback = optsOrCallback; /* tslint:disable-line: no-parameter-reassignment */ - optsOrCallback = undefined; /* tslint:disable-line: no-parameter-reassignment */ - } - if (typeof callback === 'undefined') { - throw new TypeError('The "callback" argument must be of type Function.'); - } - statProvider.async(path, optionsManager.prepare(optsOrCallback), callback); -} -exports.statCallback = statCallback; -/** - * Synchronous API. - */ -function statSync(path, opts) { - return statProvider.sync(path, optionsManager.prepare(opts)); -} -exports.statSync = statSync; + const resolveHandler = (...args) => { + const value = options.multiArgs ? args : args[0]; + if (options.filter && !options.filter(value)) { + return; + } -/***/ }), -/* 889 */ -/***/ (function(module, exports, __webpack_require__) { + if (nextQueue.length > 0) { + const {resolve} = nextQueue.shift(); + resolve({done: true, value}); + } else { + valueQueue.push(value); + } -"use strict"; + cancel(); + }; -Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(890); -function prepare(opts) { - const options = Object.assign({ - fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), - throwErrorOnBrokenSymlinks: true, - followSymlinks: true - }, opts); - return options; -} -exports.prepare = prepare; + for (const event of events) { + addListener(event, valueHandler); + } + for (const rejectionEvent of options.rejectionEvents) { + addListener(rejectionEvent, rejectHandler); + } -/***/ }), -/* 890 */ -/***/ (function(module, exports, __webpack_require__) { + for (const resolutionEvent of options.resolutionEvents) { + addListener(resolutionEvent, resolveHandler); + } -"use strict"; + return { + [symbolAsyncIterator]() { + return this; + }, + async next() { + if (valueQueue.length > 0) { + const value = valueQueue.shift(); + return { + done: isDone && valueQueue.length === 0 && !isLimitReached, + value + }; + } -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 + if (hasPendingError) { + hasPendingError = false; + throw error; + } + + if (isDone) { + return { + done: true, + value: undefined + }; + } + + return new Promise((resolve, reject) => nextQueue.push({resolve, reject})); + }, + async return(value) { + cancel(); + return { + done: isDone, + value + }; + } + }; }; -function getFileSystemAdapter(fsMethods) { - if (!fsMethods) { - return exports.FILE_SYSTEM_ADAPTER; - } - return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); -} -exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 891 */ +/* 909 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -function sync(path, options) { - const lstat = options.fs.lstatSync(path); - if (!isFollowedSymlink(lstat, options)) { - return lstat; - } - try { - const stat = options.fs.statSync(path); - stat.isSymbolicLink = () => true; - return stat; - } - catch (err) { - if (!options.throwErrorOnBrokenSymlinks) { - return lstat; - } - throw err; - } -} -exports.sync = sync; -function async(path, options, callback) { - options.fs.lstat(path, (err0, lstat) => { - if (err0) { - return callback(err0, undefined); - } - if (!isFollowedSymlink(lstat, options)) { - return callback(null, lstat); - } - options.fs.stat(path, (err1, stat) => { - if (err1) { - return options.throwErrorOnBrokenSymlinks ? callback(err1) : callback(null, lstat); - } - stat.isSymbolicLink = () => true; - callback(null, stat); - }); - }); -} -exports.async = async; -/** - * Returns `true` for followed symlink. - */ -function isFollowedSymlink(stat, options) { - return stat.isSymbolicLink() && options.followSymlinks; +const pFinally = __webpack_require__(910); + +class TimeoutError extends Error { + constructor(message) { + super(message); + this.name = 'TimeoutError'; + } } -exports.isFollowedSymlink = isFollowedSymlink; +module.exports = (promise, ms, fallback) => new Promise((resolve, reject) => { + if (typeof ms !== 'number' || ms < 0) { + throw new TypeError('Expected `ms` to be a positive number'); + } -/***/ }), -/* 892 */ -/***/ (function(module, exports, __webpack_require__) { + const timer = setTimeout(() => { + if (typeof fallback === 'function') { + try { + resolve(fallback()); + } catch (err) { + reject(err); + } + return; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(16); -var FileSystem = /** @class */ (function () { - function FileSystem(options) { - this.options = options; - } - /** - * Return full path to entry. - */ - FileSystem.prototype.getFullEntryPath = function (filepath) { - return path.resolve(this.options.cwd, filepath); - }; - /** - * Return an implementation of the Entry interface. - */ - FileSystem.prototype.makeEntry = function (stat, pattern) { - stat.path = pattern; - stat.depth = pattern.split('/').length; - return stat; - }; - return FileSystem; -}()); -exports.default = FileSystem; + const message = typeof fallback === 'string' ? fallback : `Promise timed out after ${ms} milliseconds`; + const err = fallback instanceof Error ? fallback : new TimeoutError(message); + + if (typeof promise.cancel === 'function') { + promise.cancel(); + } + + reject(err); + }, ms); + + pFinally( + promise.then(resolve, reject), + () => { + clearTimeout(timer); + } + ); +}); + +module.exports.TimeoutError = TimeoutError; /***/ }), -/* 893 */ +/* 910 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -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 TransformStream = /** @class */ (function (_super) { - __extends(TransformStream, _super); - function TransformStream(reader) { - var _this = _super.call(this, { objectMode: true }) || this; - _this.reader = reader; - return _this; - } - TransformStream.prototype._transform = function (entry, _encoding, callback) { - callback(null, this.reader.transform(entry)); - }; - return TransformStream; -}(stream.Transform)); -var ReaderStream = /** @class */ (function (_super) { - __extends(ReaderStream, _super); - function ReaderStream() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderStream.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_stream_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use stream API to read entries for Task. - */ - ReaderStream.prototype.read = function (task) { - var _this = this; - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - var transform = new TransformStream(this); - var readable = this.api(root, task, options); - return readable - .on('error', function (err) { return _this.isEnoentCodeError(err) ? null : transform.emit('error', err); }) - .pipe(transform); - }; - /** - * Returns founded paths. - */ - ReaderStream.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderStream.prototype.dynamicApi = function (root, options) { - return readdir.readdirStreamStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderStream.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderStream; -}(reader_1.default)); -exports.default = ReaderStream; + +module.exports = (promise, onFinally) => { + onFinally = onFinally || (() => {}); + + return promise.then( + val => new Promise(resolve => { + resolve(onFinally()); + }).then(() => val), + err => new Promise(resolve => { + resolve(onFinally()); + }).then(() => { + throw err; + }) + ); +}; /***/ }), -/* 894 */ +/* 911 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -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 ReaderSync = /** @class */ (function (_super) { - __extends(ReaderSync, _super); - function ReaderSync() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderSync.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_sync_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use sync API to read entries for Task. - */ - ReaderSync.prototype.read = function (task) { - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - try { - var entries = this.api(root, task, options); - return entries.map(this.transform, this); - } - catch (err) { - if (this.isEnoentCodeError(err)) { - return []; - } - throw err; - } - }; - /** - * Returns founded paths. - */ - ReaderSync.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderSync.prototype.dynamicApi = function (root, options) { - return readdir.readdirSyncStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderSync.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderSync; -}(reader_1.default)); -exports.default = ReaderSync; + +const NestedError = __webpack_require__(912); + +class CpFileError extends NestedError { + constructor(message, nested) { + super(message, nested); + Object.assign(this, nested); + this.name = 'CpFileError'; + } +} + +module.exports = CpFileError; /***/ }), -/* 895 */ +/* 912 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(888); -var fs_1 = __webpack_require__(892); -var FileSystemSync = /** @class */ (function (_super) { - __extends(FileSystemSync, _super); - function FileSystemSync() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - * Use sync API to read entries for Task. - */ - FileSystemSync.prototype.read = function (patterns, filter) { - var _this = this; - var entries = []; - patterns.forEach(function (pattern) { - var filepath = _this.getFullEntryPath(pattern); - var entry = _this.getEntry(filepath, pattern); - if (entry === null || !filter(entry)) { - return; - } - entries.push(entry); - }); - return entries; - }; - /** - * Return entry for the provided path. - */ - FileSystemSync.prototype.getEntry = function (filepath, pattern) { - try { - var stat = this.getStat(filepath); - return this.makeEntry(stat, pattern); - } - catch (err) { - return null; - } - }; - /** - * Return fs.Stats for the provided path. - */ - FileSystemSync.prototype.getStat = function (filepath) { - return fsStat.statSync(filepath, { throwErrorOnBrokenSymlinks: false }); - }; - return FileSystemSync; -}(fs_1.default)); -exports.default = FileSystemSync; +var inherits = __webpack_require__(509); + +var NestedError = function (message, nested) { + this.nested = nested; + + if (typeof message !== 'undefined') { + Object.defineProperty(this, 'message', { + value: message, + writable: true, + enumerable: false, + configurable: true + }); + } + + Error.captureStackTrace(this, this.constructor); + var oldStackDescriptor = Object.getOwnPropertyDescriptor(this, 'stack'); + var stackDescriptor = buildStackDescriptor(oldStackDescriptor, nested); + Object.defineProperty(this, 'stack', stackDescriptor); +}; + +function buildStackDescriptor(oldStackDescriptor, nested) { + if (oldStackDescriptor.get) { + return { + get: function () { + var stack = oldStackDescriptor.get.call(this); + return buildCombinedStacks(stack, this.nested); + } + }; + } else { + var stack = oldStackDescriptor.value; + return { + value: buildCombinedStacks(stack, nested) + }; + } +} +function buildCombinedStacks(stack, nested) { + if (nested) { + stack += '\nCaused By: ' + nested.stack; + } + return stack; +} -/***/ }), -/* 896 */ -/***/ (function(module, exports, __webpack_require__) { +inherits(NestedError, Error); +NestedError.prototype.name = 'NestedError'; -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -/** - * Flatten nested arrays (max depth is 2) into a non-nested array of non-array items. - */ -function flatten(items) { - return items.reduce(function (collection, item) { return [].concat(collection, item); }, []); -} -exports.flatten = flatten; + +module.exports = NestedError; /***/ }), -/* 897 */ +/* 913 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(591); -/** - * Merge multiple streams and propagate their errors into one stream in parallel. - */ -function merge(streams) { - var mergedStream = merge2(streams); - streams.forEach(function (stream) { - stream.on('error', function (err) { return mergedStream.emit('error', err); }); - }); - return mergedStream; -} -exports.merge = merge; +const {promisify} = __webpack_require__(29); +const fs = __webpack_require__(22); +const makeDir = __webpack_require__(914); +const pEvent = __webpack_require__(908); +const CpFileError = __webpack_require__(911); -/***/ }), -/* 898 */ -/***/ (function(module, exports, __webpack_require__) { +const stat = promisify(fs.stat); +const lstat = promisify(fs.lstat); +const utimes = promisify(fs.utimes); +const chmod = promisify(fs.chmod); +const chown = promisify(fs.chown); -"use strict"; +exports.closeSync = fs.closeSync.bind(fs); +exports.createWriteStream = fs.createWriteStream.bind(fs); -const path = __webpack_require__(16); -const pathType = __webpack_require__(899); +exports.createReadStream = async (path, options) => { + const read = fs.createReadStream(path, options); -const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; + try { + await pEvent(read, ['readable', 'end']); + } catch (error) { + throw new CpFileError(`Cannot read from \`${path}\`: ${error.message}`, error); + } -const getPath = (filepath, cwd) => { - const pth = filepath[0] === '!' ? filepath.slice(1) : filepath; - return path.isAbsolute(pth) ? pth : path.join(cwd, pth); + return read; }; -const addExtensions = (file, extensions) => { - if (path.extname(file)) { - return `**/${file}`; - } +exports.stat = path => stat(path).catch(error => { + throw new CpFileError(`Cannot stat path \`${path}\`: ${error.message}`, error); +}); - return `**/${file}.${getExtensions(extensions)}`; -}; +exports.lstat = path => lstat(path).catch(error => { + throw new CpFileError(`lstat \`${path}\` failed: ${error.message}`, error); +}); -const getGlob = (dir, opts) => { - if (opts.files && !Array.isArray(opts.files)) { - throw new TypeError(`Expected \`files\` to be of type \`Array\` but received type \`${typeof opts.files}\``); - } +exports.utimes = (path, atime, mtime) => utimes(path, atime, mtime).catch(error => { + throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); +}); - if (opts.extensions && !Array.isArray(opts.extensions)) { - throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof opts.extensions}\``); - } +exports.chmod = (path, mode) => chmod(path, mode).catch(error => { + throw new CpFileError(`chmod \`${path}\` failed: ${error.message}`, error); +}); - if (opts.files && opts.extensions) { - return opts.files.map(x => path.join(dir, addExtensions(x, opts.extensions))); - } +exports.chown = (path, uid, gid) => chown(path, uid, gid).catch(error => { + throw new CpFileError(`chown \`${path}\` failed: ${error.message}`, error); +}); - if (opts.files) { - return opts.files.map(x => path.join(dir, `**/${x}`)); +exports.statSync = path => { + try { + return fs.statSync(path); + } catch (error) { + throw new CpFileError(`stat \`${path}\` failed: ${error.message}`, error); } +}; - if (opts.extensions) { - return [path.join(dir, `**/*.${getExtensions(opts.extensions)}`)]; +exports.utimesSync = (path, atime, mtime) => { + try { + return fs.utimesSync(path, atime, mtime); + } catch (error) { + throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); } - - return [path.join(dir, '**')]; }; -module.exports = (input, opts) => { - opts = Object.assign({cwd: process.cwd()}, opts); - - if (typeof opts.cwd !== 'string') { - return Promise.reject(new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``)); +exports.chmodSync = (path, mode) => { + try { + return fs.chmodSync(path, mode); + } catch (error) { + throw new CpFileError(`chmod \`${path}\` failed: ${error.message}`, error); } +}; - return Promise.all([].concat(input).map(x => pathType.dir(getPath(x, opts.cwd)) - .then(isDir => isDir ? getGlob(x, opts) : x))) - .then(globs => [].concat.apply([], globs)); +exports.chownSync = (path, uid, gid) => { + try { + return fs.chownSync(path, uid, gid); + } catch (error) { + throw new CpFileError(`chown \`${path}\` failed: ${error.message}`, error); + } }; -module.exports.sync = (input, opts) => { - opts = Object.assign({cwd: process.cwd()}, opts); +exports.makeDir = path => makeDir(path, {fs}).catch(error => { + throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); +}); - if (typeof opts.cwd !== 'string') { - throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``); +exports.makeDirSync = path => { + try { + makeDir.sync(path, {fs}); + } catch (error) { + throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); } +}; - const globs = [].concat(input).map(x => pathType.dirSync(getPath(x, opts.cwd)) ? getGlob(x, opts) : x); - return [].concat.apply([], globs); +exports.copyFileSync = (source, destination, flags) => { + try { + fs.copyFileSync(source, destination, flags); + } catch (error) { + throw new CpFileError(`Cannot copy from \`${source}\` to \`${destination}\`: ${error.message}`, error); + } }; /***/ }), -/* 899 */ +/* 914 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const pify = __webpack_require__(900); +const path = __webpack_require__(16); +const {promisify} = __webpack_require__(29); +const semver = __webpack_require__(915); -function type(fn, fn2, fp) { - if (typeof fp !== 'string') { - return Promise.reject(new TypeError(`Expected a string, got ${typeof fp}`)); +const defaults = { + mode: 0o777 & (~process.umask()), + fs +}; + +const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0'); + +// https://github.com/nodejs/node/issues/8987 +// https://github.com/libuv/libuv/pull/1088 +const checkPath = pth => { + if (process.platform === 'win32') { + const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path.parse(pth).root, '')); + + if (pathHasInvalidWinCharacters) { + const error = new Error(`Path contains invalid characters: ${pth}`); + error.code = 'EINVAL'; + throw error; + } } +}; - return pify(fs[fn])(fp) - .then(stats => stats[fn2]()) - .catch(err => { - if (err.code === 'ENOENT') { - return false; - } +const permissionError = pth => { + // This replicates the exception of `fs.mkdir` with native the + // `recusive` option when run on an invalid drive under Windows. + const error = new Error(`operation not permitted, mkdir '${pth}'`); + error.code = 'EPERM'; + error.errno = -4048; + error.path = pth; + error.syscall = 'mkdir'; + return error; +}; - throw err; +const makeDir = async (input, options) => { + checkPath(input); + options = { + ...defaults, + ...options + }; + + const mkdir = promisify(options.fs.mkdir); + const stat = promisify(options.fs.stat); + + if (useNativeRecursiveOption && options.fs.mkdir === fs.mkdir) { + const pth = path.resolve(input); + + await mkdir(pth, { + mode: options.mode, + recursive: true }); -} -function typeSync(fn, fn2, fp) { - if (typeof fp !== 'string') { - throw new TypeError(`Expected a string, got ${typeof fp}`); + return pth; } - try { - return fs[fn](fp)[fn2](); - } catch (err) { - if (err.code === 'ENOENT') { - return false; - } + const make = async pth => { + try { + await mkdir(pth, options.mode); - throw err; - } -} + return pth; + } catch (error) { + if (error.code === 'EPERM') { + throw error; + } -exports.file = type.bind(null, 'stat', 'isFile'); -exports.dir = type.bind(null, 'stat', 'isDirectory'); -exports.symlink = type.bind(null, 'lstat', 'isSymbolicLink'); -exports.fileSync = typeSync.bind(null, 'statSync', 'isFile'); -exports.dirSync = typeSync.bind(null, 'statSync', 'isDirectory'); -exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); + if (error.code === 'ENOENT') { + if (path.dirname(pth) === pth) { + throw permissionError(pth); + } + if (error.message.includes('null bytes')) { + throw error; + } -/***/ }), -/* 900 */ -/***/ (function(module, exports, __webpack_require__) { + await make(path.dirname(pth)); -"use strict"; + return make(pth); + } + const stats = await stat(pth); + if (!stats.isDirectory()) { + throw error; + } -const processFn = (fn, opts) => function () { - const P = opts.promiseModule; - const args = new Array(arguments.length); + return pth; + } + }; - for (let i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; + return make(path.resolve(input)); +}; + +module.exports = makeDir; + +module.exports.sync = (input, options) => { + checkPath(input); + options = { + ...defaults, + ...options + }; + + if (useNativeRecursiveOption && options.fs.mkdirSync === fs.mkdirSync) { + const pth = path.resolve(input); + + fs.mkdirSync(pth, { + mode: options.mode, + recursive: true + }); + + return pth; } - return new P((resolve, reject) => { - if (opts.errorFirst) { - args.push(function (err, result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); + const make = pth => { + try { + options.fs.mkdirSync(pth, options.mode); + } catch (error) { + if (error.code === 'EPERM') { + throw error; + } - for (let i = 1; i < arguments.length; i++) { - results[i - 1] = arguments[i]; - } + if (error.code === 'ENOENT') { + if (path.dirname(pth) === pth) { + throw permissionError(pth); + } - if (err) { - results.unshift(err); - reject(results); - } else { - resolve(results); - } - } else if (err) { - reject(err); - } else { - resolve(result); + if (error.message.includes('null bytes')) { + throw error; } - }); - } else { - args.push(function (result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - for (let i = 0; i < arguments.length; i++) { - results[i] = arguments[i]; - } + make(path.dirname(pth)); + return make(pth); + } - resolve(results); - } else { - resolve(result); + try { + if (!options.fs.statSync(pth).isDirectory()) { + throw new Error('The path is not a directory'); } - }); + } catch (_) { + throw error; + } } - fn.apply(this, args); - }); + return pth; + }; + + return make(path.resolve(input)); }; -module.exports = (obj, opts) => { - opts = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, opts); - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return opts.include ? opts.include.some(match) : !opts.exclude.some(match); - }; +/***/ }), +/* 915 */ +/***/ (function(module, exports) { - let ret; - if (typeof obj === 'function') { - ret = function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } +exports = module.exports = SemVer - return processFn(obj, opts).apply(this, arguments); - }; - } else { - ret = Object.create(Object.getPrototypeOf(obj)); - } +var debug +/* istanbul ignore next */ +if (typeof process === 'object' && + process.env && + process.env.NODE_DEBUG && + /\bsemver\b/i.test(process.env.NODE_DEBUG)) { + debug = function () { + var args = Array.prototype.slice.call(arguments, 0) + args.unshift('SEMVER') + console.log.apply(console, args) + } +} else { + debug = function () {} +} - for (const key in obj) { // eslint-disable-line guard-for-in - const x = obj[key]; - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; - } +// Note: this is the semver.org version of the spec that it implements +// Not necessarily the package version of this code. +exports.SEMVER_SPEC_VERSION = '2.0.0' - return ret; -}; +var MAX_LENGTH = 256 +var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || + /* istanbul ignore next */ 9007199254740991 +// Max safe segment length for coercion. +var MAX_SAFE_COMPONENT_LENGTH = 16 -/***/ }), -/* 901 */ -/***/ (function(module, exports, __webpack_require__) { +// The actual regexps go on exports.re +var re = exports.re = [] +var src = exports.src = [] +var R = 0 -"use strict"; +// The following Regular Expressions can be used for tokenizing, +// validating, and parsing SemVer version strings. -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); +// ## Numeric Identifier +// A single `0`, or a non-zero digit followed by zero or more digits. -const DEFAULT_IGNORE = [ - '**/node_modules/**', - '**/bower_components/**', - '**/flow-typed/**', - '**/coverage/**', - '**/.git' -]; +var NUMERICIDENTIFIER = R++ +src[NUMERICIDENTIFIER] = '0|[1-9]\\d*' +var NUMERICIDENTIFIERLOOSE = R++ +src[NUMERICIDENTIFIERLOOSE] = '[0-9]+' + +// ## Non-numeric Identifier +// Zero or more digits, followed by a letter or hyphen, and then zero or +// more letters, digits, or hyphens. + +var NONNUMERICIDENTIFIER = R++ +src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*' + +// ## Main Version +// Three dot-separated numeric identifiers. + +var MAINVERSION = R++ +src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')' + +var MAINVERSIONLOOSE = R++ +src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')' + +// ## Pre-release Version Identifier +// A numeric identifier, or a non-numeric identifier. + +var PRERELEASEIDENTIFIER = R++ +src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + + '|' + src[NONNUMERICIDENTIFIER] + ')' + +var PRERELEASEIDENTIFIERLOOSE = R++ +src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + + '|' + src[NONNUMERICIDENTIFIER] + ')' + +// ## Pre-release Version +// Hyphen, followed by one or more dot-separated pre-release version +// identifiers. + +var PRERELEASE = R++ +src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + + '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))' + +var PRERELEASELOOSE = R++ +src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + + '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))' + +// ## Build Metadata Identifier +// Any combination of digits, letters, or hyphens. + +var BUILDIDENTIFIER = R++ +src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+' + +// ## Build Metadata +// Plus sign, followed by one or more period-separated build metadata +// identifiers. + +var BUILD = R++ +src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + + '(?:\\.' + src[BUILDIDENTIFIER] + ')*))' + +// ## Full Version String +// A main version, followed optionally by a pre-release version and +// build metadata. + +// Note that the only major, minor, patch, and pre-release sections of +// the version string are capturing groups. The build metadata is not a +// capturing group, because it should not ever be used in version +// comparison. + +var FULL = R++ +var FULLPLAIN = 'v?' + src[MAINVERSION] + + src[PRERELEASE] + '?' + + src[BUILD] + '?' + +src[FULL] = '^' + FULLPLAIN + '$' + +// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. +// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty +// common in the npm registry. +var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + + src[PRERELEASELOOSE] + '?' + + src[BUILD] + '?' + +var LOOSE = R++ +src[LOOSE] = '^' + LOOSEPLAIN + '$' + +var GTLT = R++ +src[GTLT] = '((?:<|>)?=?)' + +// Something like "2.*" or "1.2.x". +// Note that "x.x" is a valid xRange identifer, meaning "any version" +// Only the first item is strictly required. +var XRANGEIDENTIFIERLOOSE = R++ +src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*' +var XRANGEIDENTIFIER = R++ +src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*' + +var XRANGEPLAIN = R++ +src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:' + src[PRERELEASE] + ')?' + + src[BUILD] + '?' + + ')?)?' + +var XRANGEPLAINLOOSE = R++ +src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:' + src[PRERELEASELOOSE] + ')?' + + src[BUILD] + '?' + + ')?)?' + +var XRANGE = R++ +src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$' +var XRANGELOOSE = R++ +src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$' -const readFileP = pify(fs.readFile); +// Coercion. +// Extract anything that could conceivably be a part of a valid semver +var COERCE = R++ +src[COERCE] = '(?:^|[^\\d])' + + '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:$|[^\\d])' -const mapGitIgnorePatternTo = base => ignore => { - if (ignore.startsWith('!')) { - return '!' + path.posix.join(base, ignore.slice(1)); - } +// Tilde ranges. +// Meaning is "reasonably at or greater than" +var LONETILDE = R++ +src[LONETILDE] = '(?:~>?)' - return path.posix.join(base, ignore); -}; +var TILDETRIM = R++ +src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+' +re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g') +var tildeTrimReplace = '$1~' -const parseGitIgnore = (content, options) => { - const base = slash(path.relative(options.cwd, path.dirname(options.fileName))); +var TILDE = R++ +src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$' +var TILDELOOSE = R++ +src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$' - return content - .split(/\r?\n/) - .filter(Boolean) - .filter(line => line.charAt(0) !== '#') - .map(mapGitIgnorePatternTo(base)); -}; +// Caret ranges. +// Meaning is "at least and backwards compatible with" +var LONECARET = R++ +src[LONECARET] = '(?:\\^)' -const reduceIgnore = files => { - return files.reduce((ignores, file) => { - ignores.add(parseGitIgnore(file.content, { - cwd: file.cwd, - fileName: file.filePath - })); - return ignores; - }, gitIgnore()); -}; +var CARETTRIM = R++ +src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+' +re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g') +var caretTrimReplace = '$1^' -const getIsIgnoredPredecate = (ignores, cwd) => { - return p => ignores.ignores(slash(path.relative(cwd, p))); -}; +var CARET = R++ +src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$' +var CARETLOOSE = R++ +src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$' -const getFile = (file, cwd) => { - const filePath = path.join(cwd, file); - return readFileP(filePath, 'utf8') - .then(content => ({ - content, - cwd, - filePath - })); -}; +// A simple gt/lt/eq thing, or just "" to indicate "any version" +var COMPARATORLOOSE = R++ +src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$' +var COMPARATOR = R++ +src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$' -const getFileSync = (file, cwd) => { - const filePath = path.join(cwd, file); - const content = fs.readFileSync(filePath, 'utf8'); +// An expression to strip any whitespace between the gtlt and the thing +// it modifies, so that `> 1.2.3` ==> `>1.2.3` +var COMPARATORTRIM = R++ +src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + + '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')' - return { - content, - cwd, - filePath - }; -}; +// this one has to use the /g flag +re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g') +var comparatorTrimReplace = '$1$2$3' -const normalizeOptions = (options = {}) => { - const ignore = options.ignore || []; - const cwd = options.cwd || process.cwd(); - return {ignore, cwd}; -}; +// Something like `1.2.3 - 1.2.4` +// Note that these all use the loose form, because they'll be +// checked against either the strict or loose comparator form +// later. +var HYPHENRANGE = R++ +src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAIN] + ')' + + '\\s*$' -module.exports = options => { - options = normalizeOptions(options); +var HYPHENRANGELOOSE = R++ +src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s*$' - return fastGlob('**/.gitignore', { - ignore: DEFAULT_IGNORE.concat(options.ignore), - cwd: options.cwd - }) - .then(paths => Promise.all(paths.map(file => getFile(file, options.cwd)))) - .then(files => reduceIgnore(files)) - .then(ignores => getIsIgnoredPredecate(ignores, options.cwd)); -}; +// Star ranges basically just allow anything at all. +var STAR = R++ +src[STAR] = '(<|>)?=?\\s*\\*' -module.exports.sync = options => { - options = normalizeOptions(options); +// Compile to actual regexp objects. +// All are flag-free, unless they were created above with a flag. +for (var i = 0; i < R; i++) { + debug(i, src[i]) + if (!re[i]) { + re[i] = new RegExp(src[i]) + } +} - 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); +exports.parse = parse +function parse (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } - return getIsIgnoredPredecate(ignores, options.cwd); -}; + if (version instanceof SemVer) { + return version + } + if (typeof version !== 'string') { + return null + } -/***/ }), -/* 902 */ -/***/ (function(module, exports) { + if (version.length > MAX_LENGTH) { + return null + } -// A simple implementation of make-array -function make_array (subject) { - return Array.isArray(subject) - ? subject - : [subject] -} + var r = options.loose ? re[LOOSE] : re[FULL] + if (!r.test(version)) { + return null + } -const REGEX_BLANK_LINE = /^\s+$/ -const REGEX_LEADING_EXCAPED_EXCLAMATION = /^\\!/ -const REGEX_LEADING_EXCAPED_HASH = /^\\#/ -const SLASH = '/' -const KEY_IGNORE = typeof Symbol !== 'undefined' - ? Symbol.for('node-ignore') - /* istanbul ignore next */ - : 'node-ignore' + try { + return new SemVer(version, options) + } catch (er) { + return null + } +} -const define = (object, key, value) => - Object.defineProperty(object, key, {value}) +exports.valid = valid +function valid (version, options) { + var v = parse(version, options) + return v ? v.version : null +} -const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g +exports.clean = clean +function clean (version, options) { + var s = parse(version.trim().replace(/^[=v]+/, ''), options) + return s ? s.version : null +} -// 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. - : '' -) +exports.SemVer = SemVer -// > 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` +function SemVer (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + if (version instanceof SemVer) { + if (version.loose === options.loose) { + return version + } else { + version = version.version + } + } else if (typeof version !== 'string') { + throw new TypeError('Invalid Version: ' + version) + } -// '`foo/`' should not continue with the '`..`' -const DEFAULT_REPLACER_PREFIX = [ + if (version.length > MAX_LENGTH) { + throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') + } - // > Trailing spaces are ignored unless they are quoted with backslash ("\") - [ - // (a\ ) -> (a ) - // (a ) -> (a) - // (a \ ) -> (a ) - /\\?\s+$/, - match => match.indexOf('\\') === 0 - ? ' ' - : '' - ], + if (!(this instanceof SemVer)) { + return new SemVer(version, options) + } - // replace (\ ) with ' ' - [ - /\\\s/g, - () => ' ' - ], + debug('SemVer', version, options) + this.options = options + this.loose = !!options.loose - // Escape metacharacters - // which is written down by users but means special for regular expressions. + var m = version.trim().match(options.loose ? re[LOOSE] : re[FULL]) - // > 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 (!m) { + throw new TypeError('Invalid Version: ' + version) + } - [ - // > [abc] matches any character inside the brackets - // > (in this case a, b, or c); - /\[([^\]/]*)($|\])/g, - (match, p1, p2) => p2 === ']' - ? `[${sanitizeRange(p1)}]` - : `\\${match}` - ], + this.raw = version - [ - // > a question mark (?) matches a single character - /(?!\\)\?/g, - () => '[^/]' - ], + // these are actually numbers + this.major = +m[1] + this.minor = +m[2] + this.patch = +m[3] - // leading slash - [ + if (this.major > MAX_SAFE_INTEGER || this.major < 0) { + throw new TypeError('Invalid major version') + } - // > 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 - /^\//, - () => '^' - ], + if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { + throw new TypeError('Invalid minor version') + } - // replace special metacharacter slash after the leading slash - [ - /\//g, - () => '\\/' - ], + if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { + throw new TypeError('Invalid patch version') + } - [ - // > 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 '\\*' - /^\^*\\\*\\\*\\\//, + // numberify any prerelease numeric ids + if (!m[4]) { + this.prerelease = [] + } else { + this.prerelease = m[4].split('.').map(function (id) { + if (/^[0-9]+$/.test(id)) { + var num = +id + if (num >= 0 && num < MAX_SAFE_INTEGER) { + return num + } + } + return id + }) + } - // '**/foo' <-> 'foo' - () => '^(?:.*\\/)?' - ] -] + this.build = m[5] ? m[5].split('.') : [] + this.format() +} -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 - ? '(?:^|\\/)' +SemVer.prototype.format = function () { + this.version = this.major + '.' + this.minor + '.' + this.patch + if (this.prerelease.length) { + this.version += '-' + this.prerelease.join('.') + } + return this.version +} - // > Otherwise, Git treats the pattern as a shell glob suitable for - // > consumption by fnmatch(3) - : '^' - } - ], +SemVer.prototype.toString = function () { + return this.version +} - // two globstars - [ - // Use lookahead assertions so that we could match more than one `'/**'` - /\\\/\\\*\\\*(?=\\\/|$)/g, +SemVer.prototype.compare = function (other) { + debug('SemVer.compare', this.version, this.options, other) + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } - // Zero, one or several directories - // should not use '*', or it will be replaced by the next replacer + return this.compareMain(other) || this.comparePre(other) +} - // Check if it is not the last `'/**'` - (match, index, str) => index + 6 < str.length +SemVer.prototype.compareMain = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.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. - // '/**/' - ? '(?:\\/[^\\/]+)*' + return compareIdentifiers(this.major, other.major) || + compareIdentifiers(this.minor, other.minor) || + compareIdentifiers(this.patch, other.patch) +} - // case: /** - // > A trailing `"/**"` matches everything inside. +SemVer.prototype.comparePre = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } - // #21: everything inside but it should not include the current folder - : '\\/.+' - ], + // NOT having a prerelease is > having one + if (this.prerelease.length && !other.prerelease.length) { + return -1 + } else if (!this.prerelease.length && other.prerelease.length) { + return 1 + } else if (!this.prerelease.length && !other.prerelease.length) { + return 0 + } - // intermediate wildcards - [ - // Never replace escaped '*' - // ignore rule '\*' will match the path '*' + var i = 0 + do { + var a = this.prerelease[i] + var b = other.prerelease[i] + debug('prerelease compare', i, a, b) + if (a === undefined && b === undefined) { + return 0 + } else if (b === undefined) { + return 1 + } else if (a === undefined) { + return -1 + } else if (a === b) { + continue + } else { + return compareIdentifiers(a, b) + } + } while (++i) +} - // 'abc.*/' -> go - // 'abc.*' -> skip this rule - /(^|[^\\]+)\\\*(?=.+)/g, +SemVer.prototype.compareBuild = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } - // '*.js' matches '.js' - // '*.js' doesn't match 'abc' - (match, p1) => `${p1}[^\\/]*` - ], + var i = 0 + do { + var a = this.build[i] + var b = other.build[i] + debug('prerelease compare', i, a, b) + if (a === undefined && b === undefined) { + return 0 + } else if (b === undefined) { + return 1 + } else if (a === undefined) { + return -1 + } else if (a === b) { + continue + } else { + return compareIdentifiers(a, b) + } + } while (++i) +} - // trailing wildcard - [ - /(\^|\\\/)?\\\*$/, - (match, p1) => { - const prefix = p1 - // '\^': - // '/*' does not match '' - // '/*' does not match everything +// preminor will bump the version up to the next minor release, and immediately +// down to pre-release. premajor and prepatch work the same way. +SemVer.prototype.inc = function (release, identifier) { + switch (release) { + case 'premajor': + this.prerelease.length = 0 + this.patch = 0 + this.minor = 0 + this.major++ + this.inc('pre', identifier) + break + case 'preminor': + this.prerelease.length = 0 + this.patch = 0 + this.minor++ + this.inc('pre', identifier) + break + case 'prepatch': + // If this is already a prerelease, it will bump to the next version + // drop any prereleases that might already exist, since they are not + // relevant at this point. + this.prerelease.length = 0 + this.inc('patch', identifier) + this.inc('pre', identifier) + break + // If the input is a non-prerelease version, this acts the same as + // prepatch. + case 'prerelease': + if (this.prerelease.length === 0) { + this.inc('patch', identifier) + } + this.inc('pre', identifier) + break - // '\\\/': - // 'abc/*' does not match 'abc/' - ? `${p1}[^/]+` + case 'major': + // If this is a pre-major version, bump up to the same major version. + // Otherwise increment major. + // 1.0.0-5 bumps to 1.0.0 + // 1.1.0 bumps to 2.0.0 + if (this.minor !== 0 || + this.patch !== 0 || + this.prerelease.length === 0) { + this.major++ + } + this.minor = 0 + this.patch = 0 + this.prerelease = [] + break + case 'minor': + // If this is a pre-minor version, bump up to the same minor version. + // Otherwise increment minor. + // 1.2.0-5 bumps to 1.2.0 + // 1.2.1 bumps to 1.3.0 + if (this.patch !== 0 || this.prerelease.length === 0) { + this.minor++ + } + this.patch = 0 + this.prerelease = [] + break + case 'patch': + // If this is not a pre-release version, it will increment the patch. + // If it is a pre-release it will bump up to the same patch version. + // 1.2.0-5 patches to 1.2.0 + // 1.2.0 patches to 1.2.1 + if (this.prerelease.length === 0) { + this.patch++ + } + this.prerelease = [] + break + // This probably shouldn't be used publicly. + // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. + case 'pre': + if (this.prerelease.length === 0) { + this.prerelease = [0] + } else { + var i = this.prerelease.length + while (--i >= 0) { + if (typeof this.prerelease[i] === 'number') { + this.prerelease[i]++ + i = -2 + } + } + if (i === -1) { + // didn't increment anything + this.prerelease.push(0) + } + } + if (identifier) { + // 1.2.0-beta.1 bumps to 1.2.0-beta.2, + // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 + if (this.prerelease[0] === identifier) { + if (isNaN(this.prerelease[1])) { + this.prerelease = [identifier, 0] + } + } else { + this.prerelease = [identifier, 0] + } + } + break - // 'a*' matches 'a' - // 'a*' matches 'aa' - : '[^/]*' + default: + throw new Error('invalid increment argument: ' + release) + } + this.format() + this.raw = this.version + return this +} - return `${prefix}(?=$|\\/$)` - } - ], +exports.inc = inc +function inc (version, release, loose, identifier) { + if (typeof (loose) === 'string') { + identifier = loose + loose = undefined + } - [ - // unescape - /\\\\\\/g, - () => '\\' - ] -] + try { + return new SemVer(version, loose).inc(release, identifier).version + } catch (er) { + return null + } +} -const POSITIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, +exports.diff = diff +function diff (version1, version2) { + if (eq(version1, version2)) { + return null + } else { + var v1 = parse(version1) + var v2 = parse(version2) + var prefix = '' + if (v1.prerelease.length || v2.prerelease.length) { + prefix = 'pre' + var defaultResult = 'prerelease' + } + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return prefix + key + } + } + } + return defaultResult // may be undefined + } +} - // 'f' - // matches - // - /f(end) - // - /f/ - // - (start)f(end) - // - (start)f/ - // doesn't match - // - oof - // - foo - // pseudo: - // -> (^|/)f(/|$) +exports.compareIdentifiers = compareIdentifiers - // ending - [ - // 'js' will not match 'js.' - // 'ab' will not match 'abc' - /(?:[^*/])$/, +var numeric = /^[0-9]+$/ +function compareIdentifiers (a, b) { + var anum = numeric.test(a) + var bnum = numeric.test(b) - // 'js*' will not match 'a.js' - // 'js/' will not match 'a.js' - // 'js' will match 'a.js' and 'a.js/' - match => `${match}(?=$|\\/)` - ], + if (anum && bnum) { + a = +a + b = +b + } - ...DEFAULT_REPLACER_SUFFIX -] + return a === b ? 0 + : (anum && !bnum) ? -1 + : (bnum && !anum) ? 1 + : a < b ? -1 + : 1 +} -const NEGATIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, +exports.rcompareIdentifiers = rcompareIdentifiers +function rcompareIdentifiers (a, b) { + return compareIdentifiers(b, a) +} - // #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. +exports.major = major +function major (a, loose) { + return new SemVer(a, loose).major +} - // eg: - // ['node_modules/*', '!node_modules'] - // should ignore `node_modules/a.js` - [ - /(?:[^*])$/, - match => `${match}(?=$|\\/$)` - ], +exports.minor = minor +function minor (a, loose) { + return new SemVer(a, loose).minor +} - ...DEFAULT_REPLACER_SUFFIX -] +exports.patch = patch +function patch (a, loose) { + return new SemVer(a, loose).patch +} -// A simple cache, because an ignore rule only has only one certain meaning -const cache = Object.create(null) +exports.compare = compare +function compare (a, b, loose) { + return new SemVer(a, loose).compare(new SemVer(b, loose)) +} -// @param {pattern} -const make_regex = (pattern, negative, ignorecase) => { - const r = cache[pattern] - if (r) { - return r - } +exports.compareLoose = compareLoose +function compareLoose (a, b) { + return compare(a, b, true) +} - const replacers = negative - ? NEGATIVE_REPLACERS - : POSITIVE_REPLACERS +exports.compareBuild = compareBuild +function compareBuild (a, b, loose) { + var versionA = new SemVer(a, loose) + var versionB = new SemVer(b, loose) + return versionA.compare(versionB) || versionA.compareBuild(versionB) +} - const source = replacers.reduce( - (prev, current) => prev.replace(current[0], current[1].bind(pattern)), - pattern - ) +exports.rcompare = rcompare +function rcompare (a, b, loose) { + return compare(b, a, loose) +} - return cache[pattern] = ignorecase - ? new RegExp(source, 'i') - : new RegExp(source) +exports.sort = sort +function sort (list, loose) { + return list.sort(function (a, b) { + return exports.compareBuild(a, b, loose) + }) } -// > A blank line matches no files, so it can serve as a separator for readability. -const checkPattern = pattern => pattern - && typeof pattern === 'string' - && !REGEX_BLANK_LINE.test(pattern) +exports.rsort = rsort +function rsort (list, loose) { + return list.sort(function (a, b) { + return exports.compareBuild(b, a, loose) + }) +} - // > A line starting with # serves as a comment. - && pattern.indexOf('#') !== 0 +exports.gt = gt +function gt (a, b, loose) { + return compare(a, b, loose) > 0 +} -const createRule = (pattern, ignorecase) => { - const origin = pattern - let negative = false +exports.lt = lt +function lt (a, b, loose) { + return compare(a, b, loose) < 0 +} - // > An optional prefix "!" which negates the pattern; - if (pattern.indexOf('!') === 0) { - negative = true - pattern = pattern.substr(1) - } +exports.eq = eq +function eq (a, b, loose) { + return compare(a, b, loose) === 0 +} - pattern = pattern - // > Put a backslash ("\") in front of the first "!" for patterns that - // > begin with a literal "!", for example, `"\!important!.txt"`. - .replace(REGEX_LEADING_EXCAPED_EXCLAMATION, '!') - // > Put a backslash ("\") in front of the first hash for patterns that - // > begin with a hash. - .replace(REGEX_LEADING_EXCAPED_HASH, '#') +exports.neq = neq +function neq (a, b, loose) { + return compare(a, b, loose) !== 0 +} - const regex = make_regex(pattern, negative, ignorecase) +exports.gte = gte +function gte (a, b, loose) { + return compare(a, b, loose) >= 0 +} - return { - origin, - pattern, - negative, - regex - } +exports.lte = lte +function lte (a, b, loose) { + return compare(a, b, loose) <= 0 } -class IgnoreBase { - constructor ({ - ignorecase = true - } = {}) { - this._rules = [] - this._ignorecase = ignorecase - define(this, KEY_IGNORE, true) - this._initCache() - } +exports.cmp = cmp +function cmp (a, op, b, loose) { + switch (op) { + case '===': + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a === b - _initCache () { - this._cache = Object.create(null) - } + case '!==': + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a !== b - // @param {Array.|string|Ignore} pattern - add (pattern) { - this._added = false + case '': + case '=': + case '==': + return eq(a, b, loose) - if (typeof pattern === 'string') { - pattern = pattern.split(/\r?\n/g) - } + case '!=': + return neq(a, b, loose) - make_array(pattern).forEach(this._addPattern, this) + case '>': + return gt(a, b, loose) - // Some rules have just added to the ignore, - // making the behavior changed. - if (this._added) { - this._initCache() - } + case '>=': + return gte(a, b, loose) - return this - } + case '<': + return lt(a, b, loose) - // legacy - addPattern (pattern) { - return this.add(pattern) + case '<=': + return lte(a, b, loose) + + default: + throw new TypeError('Invalid operator: ' + op) } +} - _addPattern (pattern) { - // #32 - if (pattern && pattern[KEY_IGNORE]) { - this._rules = this._rules.concat(pattern._rules) - this._added = true - return +exports.Comparator = Comparator +function Comparator (comp, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false } + } - if (checkPattern(pattern)) { - const rule = createRule(pattern, this._ignorecase) - this._added = true - this._rules.push(rule) + if (comp instanceof Comparator) { + if (comp.loose === !!options.loose) { + return comp + } else { + comp = comp.value } } - filter (paths) { - return make_array(paths).filter(path => this._filter(path)) + if (!(this instanceof Comparator)) { + return new Comparator(comp, options) } - createFilter () { - return path => this._filter(path) - } + debug('comparator', comp, options) + this.options = options + this.loose = !!options.loose + this.parse(comp) - ignores (path) { - return !this._filter(path) + if (this.semver === ANY) { + this.value = '' + } else { + this.value = this.operator + this.semver.version } - // @returns `Boolean` true if the `path` is NOT ignored - _filter (path, slices) { - if (!path) { - return false - } - - if (path in this._cache) { - return this._cache[path] - } - - if (!slices) { - // path/to/a.js - // ['path', 'to', 'a.js'] - slices = path.split(SLASH) - } - - slices.pop() + debug('comp', this) +} - return this._cache[path] = slices.length - // > It is not possible to re-include a file if a parent directory of - // > that file is excluded. - // If the path contains a parent directory, check the parent first - ? this._filter(slices.join(SLASH) + SLASH, slices) - && this._test(path) +var ANY = {} +Comparator.prototype.parse = function (comp) { + var r = this.options.loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var m = comp.match(r) - // Or only test the path - : this._test(path) + if (!m) { + throw new TypeError('Invalid comparator: ' + comp) } - // @returns {Boolean} true if a file is NOT ignored - _test (path) { - // Explicitly define variable type by setting matched to `0` - let matched = 0 - - this._rules.forEach(rule => { - // if matched = true, then we only test negative rules - // if matched = false, then we test non-negative rules - if (!(matched ^ rule.negative)) { - matched = rule.negative ^ rule.regex.test(path) - } - }) - - return !matched + this.operator = m[1] !== undefined ? m[1] : '' + if (this.operator === '=') { + this.operator = '' } -} - -// 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' - ) -) { - const filter = IgnoreBase.prototype._filter - - /* eslint no-control-regex: "off" */ - const make_posix = str => /^\\\\\?\\/.test(str) - || /[^\x00-\x80]+/.test(str) - ? str - : str.replace(/\\/g, '/') - IgnoreBase.prototype._filter = function filterWin32 (path, slices) { - path = make_posix(path) - return filter.call(this, path, slices) + // if it literally is just '>' or '' then allow anything. + if (!m[2]) { + this.semver = ANY + } else { + this.semver = new SemVer(m[2], this.options.loose) } } -module.exports = options => new IgnoreBase(options) - - -/***/ }), -/* 903 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +Comparator.prototype.toString = function () { + return this.value +} +Comparator.prototype.test = function (version) { + debug('Comparator.test', version, this.options.loose) -const processFn = (fn, options) => function (...args) { - const P = options.promiseModule; + if (this.semver === ANY || version === ANY) { + return true + } - return new P((resolve, reject) => { - if (options.multiArgs) { - args.push((...result) => { - if (options.errorFirst) { - if (result[0]) { - reject(result); - } else { - result.shift(); - resolve(result); - } - } else { - resolve(result); - } - }); - } else if (options.errorFirst) { - args.push((error, result) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); - } else { - args.push(resolve); - } + if (typeof version === 'string') { + try { + version = new SemVer(version, this.options) + } catch (er) { + return false + } + } - fn.apply(this, args); - }); -}; + return cmp(version, this.operator, this.semver, this.options) +} -module.exports = (input, options) => { - options = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, options); +Comparator.prototype.intersects = function (comp, options) { + if (!(comp instanceof Comparator)) { + throw new TypeError('a Comparator is required') + } - const objType = typeof input; - if (!(input !== null && (objType === 'object' || objType === 'function'))) { - throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objType}\``); - } + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return options.include ? options.include.some(match) : !options.exclude.some(match); - }; + var rangeTmp - let ret; - if (objType === 'function') { - ret = function (...args) { - return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args); - }; - } else { - ret = Object.create(Object.getPrototypeOf(input)); - } + if (this.operator === '') { + if (this.value === '') { + return true + } + rangeTmp = new Range(comp.value, options) + return satisfies(this.value, rangeTmp, options) + } else if (comp.operator === '') { + if (comp.value === '') { + return true + } + rangeTmp = new Range(this.value, options) + return satisfies(comp.semver, rangeTmp, options) + } - for (const key in input) { // eslint-disable-line guard-for-in - const property = input[key]; - ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property; - } + var sameDirectionIncreasing = + (this.operator === '>=' || this.operator === '>') && + (comp.operator === '>=' || comp.operator === '>') + var sameDirectionDecreasing = + (this.operator === '<=' || this.operator === '<') && + (comp.operator === '<=' || comp.operator === '<') + var sameSemVer = this.semver.version === comp.semver.version + var differentDirectionsInclusive = + (this.operator === '>=' || this.operator === '<=') && + (comp.operator === '>=' || comp.operator === '<=') + var oppositeDirectionsLessThan = + cmp(this.semver, '<', comp.semver, options) && + ((this.operator === '>=' || this.operator === '>') && + (comp.operator === '<=' || comp.operator === '<')) + var oppositeDirectionsGreaterThan = + cmp(this.semver, '>', comp.semver, options) && + ((this.operator === '<=' || this.operator === '<') && + (comp.operator === '>=' || comp.operator === '>')) - return ret; -}; + return sameDirectionIncreasing || sameDirectionDecreasing || + (sameSemVer && differentDirectionsInclusive) || + oppositeDirectionsLessThan || oppositeDirectionsGreaterThan +} +exports.Range = Range +function Range (range, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } -/***/ }), -/* 904 */ -/***/ (function(module, exports, __webpack_require__) { + if (range instanceof Range) { + if (range.loose === !!options.loose && + range.includePrerelease === !!options.includePrerelease) { + return range + } else { + return new Range(range.raw, options) + } + } -"use strict"; + if (range instanceof Comparator) { + return new Range(range.value, options) + } -module.exports = input => { - const isExtendedLengthPath = /^\\\\\?\\/.test(input); - const hasNonAscii = /[^\u0000-\u0080]+/.test(input); // eslint-disable-line no-control-regex + if (!(this instanceof Range)) { + return new Range(range, options) + } - if (isExtendedLengthPath || hasNonAscii) { - return input; - } + this.options = options + this.loose = !!options.loose + this.includePrerelease = !!options.includePrerelease - return input.replace(/\\/g, '/'); -}; + // First, split based on boolean or || + this.raw = range + this.set = range.split(/\s*\|\|\s*/).map(function (range) { + return this.parseRange(range.trim()) + }, this).filter(function (c) { + // throw out any that are not relevant for whatever reason + return c.length + }) + if (!this.set.length) { + throw new TypeError('Invalid SemVer Range: ' + range) + } -/***/ }), -/* 905 */ -/***/ (function(module, exports, __webpack_require__) { + this.format() +} -"use strict"; +Range.prototype.format = function () { + this.range = this.set.map(function (comps) { + return comps.join(' ').trim() + }).join('||').trim() + return this.range +} -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); +Range.prototype.toString = function () { + return this.range +} -const cpFile = (source, destination, options) => { - if (!source || !destination) { - return Promise.reject(new CpFileError('`source` and `destination` required')); - } +Range.prototype.parseRange = function (range) { + var loose = this.options.loose + range = range.trim() + // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` + var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE] + range = range.replace(hr, hyphenReplace) + debug('hyphen replace', range) + // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` + range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace) + debug('comparator trim', range, re[COMPARATORTRIM]) - options = Object.assign({overwrite: true}, options); + // `~ 1.2.3` => `~1.2.3` + range = range.replace(re[TILDETRIM], tildeTrimReplace) - const progressEmitter = new ProgressEmitter(path.resolve(source), path.resolve(destination)); + // `^ 1.2.3` => `^1.2.3` + range = range.replace(re[CARETTRIM], caretTrimReplace) - const promise = fs - .stat(source) - .then(stat => { - progressEmitter.size = stat.size; - }) - .then(() => fs.createReadStream(source)) - .then(read => fs.makeDir(path.dirname(destination)).then(() => read)) - .then(read => new Promise((resolve, reject) => { - const write = fs.createWriteStream(destination, {flags: options.overwrite ? 'w' : 'wx'}); + // normalize spaces + range = range.split(/\s+/).join(' ') - read.on('data', () => { - progressEmitter.written = write.bytesWritten; - }); + // At this point, the range is completely trimmed and + // ready to be split into comparators. - write.on('error', error => { - if (!options.overwrite && error.code === 'EEXIST') { - resolve(false); - return; - } + var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var set = range.split(' ').map(function (comp) { + return parseComparator(comp, this.options) + }, this).join(' ').split(/\s+/) + if (this.options.loose) { + // in loose mode, throw out any that are not valid comparators + set = set.filter(function (comp) { + return !!comp.match(compRe) + }) + } + set = set.map(function (comp) { + return new Comparator(comp, this.options) + }, this) - reject(new CpFileError(`Cannot write to \`${destination}\`: ${error.message}`, error)); - }); + return set +} - write.on('close', () => { - progressEmitter.written = progressEmitter.size; - resolve(true); - }); +Range.prototype.intersects = function (range, options) { + if (!(range instanceof Range)) { + throw new TypeError('a Range is required') + } - read.pipe(write); - })) - .then(updateStats => { - if (updateStats) { - return fs.lstat(source).then(stats => Promise.all([ - fs.utimes(destination, stats.atime, stats.mtime), - fs.chmod(destination, stats.mode), - fs.chown(destination, stats.uid, stats.gid) - ])); - } - }); + return this.set.some(function (thisComparators) { + return ( + isSatisfiable(thisComparators, options) && + range.set.some(function (rangeComparators) { + return ( + isSatisfiable(rangeComparators, options) && + thisComparators.every(function (thisComparator) { + return rangeComparators.every(function (rangeComparator) { + return thisComparator.intersects(rangeComparator, options) + }) + }) + ) + }) + ) + }) +} - promise.on = (...args) => { - progressEmitter.on(...args); - return promise; - }; +// take a set of comparators and determine whether there +// exists a version which can satisfy it +function isSatisfiable (comparators, options) { + var result = true + var remainingComparators = comparators.slice() + var testComparator = remainingComparators.pop() - return promise; -}; + while (result && remainingComparators.length) { + result = remainingComparators.every(function (otherComparator) { + return testComparator.intersects(otherComparator, options) + }) -module.exports = cpFile; -// TODO: Remove this for the next major release -module.exports.default = cpFile; + testComparator = remainingComparators.pop() + } -const checkSourceIsFile = (stat, source) => { - if (stat.isDirectory()) { - throw Object.assign(new CpFileError(`EISDIR: illegal operation on a directory '${source}'`), { - errno: -21, - code: 'EISDIR', - source - }); - } -}; + return result +} -const fixupAttributes = (destination, stat) => { - fs.chmodSync(destination, stat.mode); - fs.chownSync(destination, stat.uid, stat.gid); -}; +// Mostly just for testing and legacy API reasons +exports.toComparators = toComparators +function toComparators (range, options) { + return new Range(range, options).set.map(function (comp) { + return comp.map(function (c) { + return c.value + }).join(' ').trim().split(' ') + }) +} -const copySyncNative = (source, destination, options) => { - const stat = fs.statSync(source); - checkSourceIsFile(stat, source); - fs.makeDirSync(path.dirname(destination)); +// comprised of xranges, tildes, stars, and gtlt's at this point. +// already replaced the hyphen ranges +// turn into a set of JUST comparators. +function parseComparator (comp, options) { + debug('comp', comp, options) + comp = replaceCarets(comp, options) + debug('caret', comp) + comp = replaceTildes(comp, options) + debug('tildes', comp) + comp = replaceXRanges(comp, options) + debug('xrange', comp) + comp = replaceStars(comp, options) + debug('stars', comp) + return comp +} - const flags = options.overwrite ? null : fsConstants.COPYFILE_EXCL; - try { - fs.copyFileSync(source, destination, flags); - } catch (error) { - if (!options.overwrite && error.code === 'EEXIST') { - return; - } +function isX (id) { + return !id || id.toLowerCase() === 'x' || id === '*' +} - throw error; - } +// ~, ~> --> * (any, kinda silly) +// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 +// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 +// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 +// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 +// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 +function replaceTildes (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceTilde(comp, options) + }).join(' ') +} - fs.utimesSync(destination, stat.atime, stat.mtime); - fixupAttributes(destination, stat); -}; +function replaceTilde (comp, options) { + var r = options.loose ? re[TILDELOOSE] : re[TILDE] + return comp.replace(r, function (_, M, m, p, pr) { + debug('tilde', comp, _, M, m, p, pr) + var ret -const copySyncFallback = (source, destination, options) => { - let bytesRead; - let position; - let read; // eslint-disable-line prefer-const - let write; - const BUF_LENGTH = 100 * 1024; - const buffer = Buffer.alloc(BUF_LENGTH); - const readSync = position => fs.readSync(read, buffer, 0, BUF_LENGTH, position, source); - const writeSync = () => fs.writeSync(write, buffer, 0, bytesRead, undefined, destination); + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { + // ~1.2 == >=1.2.0 <1.3.0 + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else if (pr) { + debug('replaceTilde pr', pr) + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } else { + // ~1.2.3 == >=1.2.3 <1.3.0 + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0' + } - read = fs.openSync(source, 'r'); - bytesRead = readSync(0); - position = bytesRead; - fs.makeDirSync(path.dirname(destination)); + debug('tilde return', ret) + return ret + }) +} - try { - write = fs.openSync(destination, options.overwrite ? 'w' : 'wx'); - } catch (error) { - if (!options.overwrite && error.code === 'EEXIST') { - return; - } +// ^ --> * (any, kinda silly) +// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 +// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 +// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 +// ^1.2.3 --> >=1.2.3 <2.0.0 +// ^1.2.0 --> >=1.2.0 <2.0.0 +function replaceCarets (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceCaret(comp, options) + }).join(' ') +} - throw error; - } +function replaceCaret (comp, options) { + debug('caret', comp, options) + var r = options.loose ? re[CARETLOOSE] : re[CARET] + return comp.replace(r, function (_, M, m, p, pr) { + debug('caret', comp, _, M, m, p, pr) + var ret - writeSync(); + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { + if (M === '0') { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else { + ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0' + } + } else if (pr) { + debug('replaceCaret pr', pr) + if (M === '0') { + if (m === '0') { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + m + '.' + (+p + 1) + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + (+M + 1) + '.0.0' + } + } else { + debug('no pr') + if (M === '0') { + if (m === '0') { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + m + '.' + (+p + 1) + } else { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + (+M + 1) + '.0.0' + } + } - while (bytesRead === BUF_LENGTH) { - bytesRead = readSync(position); - writeSync(); - position += bytesRead; - } + debug('caret return', ret) + return ret + }) +} - const stat = fs.fstatSync(read, source); - fs.futimesSync(write, stat.atime, stat.mtime, destination); - fs.closeSync(read); - fs.closeSync(write); - fixupAttributes(destination, stat); -}; +function replaceXRanges (comp, options) { + debug('replaceXRanges', comp, options) + return comp.split(/\s+/).map(function (comp) { + return replaceXRange(comp, options) + }).join(' ') +} -module.exports.sync = (source, destination, options) => { - if (!source || !destination) { - throw new CpFileError('`source` and `destination` required'); - } +function replaceXRange (comp, options) { + comp = comp.trim() + var r = options.loose ? re[XRANGELOOSE] : re[XRANGE] + return comp.replace(r, function (ret, gtlt, M, m, p, pr) { + debug('xRange', comp, ret, gtlt, M, m, p, pr) + var xM = isX(M) + var xm = xM || isX(m) + var xp = xm || isX(p) + var anyX = xp - options = Object.assign({overwrite: true}, options); + if (gtlt === '=' && anyX) { + gtlt = '' + } - if (fs.copyFileSync) { - copySyncNative(source, destination, options); - } else { - copySyncFallback(source, destination, options); - } -}; + if (xM) { + if (gtlt === '>' || gtlt === '<') { + // nothing is allowed + ret = '<0.0.0' + } else { + // nothing is forbidden + ret = '*' + } + } else if (gtlt && anyX) { + // we know patch is an x, because we have any x at all. + // replace X with 0 + if (xm) { + m = 0 + } + p = 0 + if (gtlt === '>') { + // >1 => >=2.0.0 + // >1.2 => >=1.3.0 + // >1.2.3 => >= 1.2.4 + gtlt = '>=' + if (xm) { + M = +M + 1 + m = 0 + p = 0 + } else { + m = +m + 1 + p = 0 + } + } else if (gtlt === '<=') { + // <=0.7.x is actually <0.8.0, since any 0.7.x should + // pass. Similarly, <=7.x is actually <8.0.0, etc. + gtlt = '<' + if (xm) { + M = +M + 1 + } else { + m = +m + 1 + } + } -/***/ }), -/* 906 */ -/***/ (function(module, exports, __webpack_require__) { + ret = gtlt + M + '.' + m + '.' + p + } else if (xm) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (xp) { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } -/* eslint-disable node/no-deprecated-api */ -var buffer = __webpack_require__(585) -var Buffer = buffer.Buffer + debug('xRange return', ret) -// alternative to using Object.keys for old browsers -function copyProps (src, dst) { - for (var key in src) { - dst[key] = src[key] - } -} -if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { - module.exports = buffer -} else { - // Copy properties from require('buffer') - copyProps(buffer, exports) - exports.Buffer = SafeBuffer + return ret + }) } -function SafeBuffer (arg, encodingOrOffset, length) { - return Buffer(arg, encodingOrOffset, length) +// Because * is AND-ed with everything else in the comparator, +// and '' means "any version", just remove the *s entirely. +function replaceStars (comp, options) { + debug('replaceStars', comp, options) + // Looseness is ignored here. star is always as loose as it gets! + return comp.trim().replace(re[STAR], '') } -// Copy static methods from Buffer -copyProps(Buffer, SafeBuffer) +// This function is passed to string.replace(re[HYPHENRANGE]) +// M, m, patch, prerelease, build +// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 +// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do +// 1.2 - 3.4 => >=1.2.0 <3.5.0 +function hyphenReplace ($0, + from, fM, fm, fp, fpr, fb, + to, tM, tm, tp, tpr, tb) { + if (isX(fM)) { + from = '' + } else if (isX(fm)) { + from = '>=' + fM + '.0.0' + } else if (isX(fp)) { + from = '>=' + fM + '.' + fm + '.0' + } else { + from = '>=' + from + } -SafeBuffer.from = function (arg, encodingOrOffset, length) { - if (typeof arg === 'number') { - throw new TypeError('Argument must not be a number') + if (isX(tM)) { + to = '' + } else if (isX(tm)) { + to = '<' + (+tM + 1) + '.0.0' + } else if (isX(tp)) { + to = '<' + tM + '.' + (+tm + 1) + '.0' + } else if (tpr) { + to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr + } else { + to = '<=' + to } - return Buffer(arg, encodingOrOffset, length) + + return (from + ' ' + to).trim() } -SafeBuffer.alloc = function (size, fill, encoding) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') +// if ANY of the sets match ALL of its comparators, then pass +Range.prototype.test = function (version) { + if (!version) { + return false } - var buf = Buffer(size) - if (fill !== undefined) { - if (typeof encoding === 'string') { - buf.fill(fill, encoding) - } else { - buf.fill(fill) + + if (typeof version === 'string') { + try { + version = new SemVer(version, this.options) + } catch (er) { + return false } - } else { - buf.fill(0) } - return buf -} -SafeBuffer.allocUnsafe = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') + for (var i = 0; i < this.set.length; i++) { + if (testSet(this.set[i], version, this.options)) { + return true + } } - return Buffer(size) + return false } -SafeBuffer.allocUnsafeSlow = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') +function testSet (set, version, options) { + for (var i = 0; i < set.length; i++) { + if (!set[i].test(version)) { + return false + } } - return buffer.SlowBuffer(size) -} - -/***/ }), -/* 907 */ -/***/ (function(module, exports, __webpack_require__) { + if (version.prerelease.length && !options.includePrerelease) { + // Find the set of versions that are allowed to have prereleases + // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 + // That should allow `1.2.3-pr.2` to pass. + // However, `1.2.4-alpha.notready` should NOT be allowed, + // even though it's within the range set by the comparators. + for (i = 0; i < set.length; i++) { + debug(set[i].semver) + if (set[i].semver === ANY) { + continue + } -"use strict"; + if (set[i].semver.prerelease.length > 0) { + var allowed = set[i].semver + if (allowed.major === version.major && + allowed.minor === version.minor && + allowed.patch === version.patch) { + return true + } + } + } -const NestedError = __webpack_require__(908); + // Version has a -pre, but it's not one of the ones we like. + return false + } -class CpFileError extends NestedError { - constructor(message, nested) { - super(message, nested); - Object.assign(this, nested); - this.name = 'CpFileError'; - } + return true } -module.exports = CpFileError; - - -/***/ }), -/* 908 */ -/***/ (function(module, exports, __webpack_require__) { - -var inherits = __webpack_require__(509); - -var NestedError = function (message, nested) { - this.nested = nested; - - if (typeof message !== 'undefined') { - Object.defineProperty(this, 'message', { - value: message, - writable: true, - enumerable: false, - configurable: true - }); - } - - Error.captureStackTrace(this, this.constructor); - var oldStackDescriptor = Object.getOwnPropertyDescriptor(this, 'stack'); - var stackDescriptor = buildStackDescriptor(oldStackDescriptor, nested); - Object.defineProperty(this, 'stack', stackDescriptor); -}; +exports.satisfies = satisfies +function satisfies (version, range, options) { + try { + range = new Range(range, options) + } catch (er) { + return false + } + return range.test(version) +} -function buildStackDescriptor(oldStackDescriptor, nested) { - if (oldStackDescriptor.get) { - return { - get: function () { - var stack = oldStackDescriptor.get.call(this); - return buildCombinedStacks(stack, this.nested); - } - }; - } else { - var stack = oldStackDescriptor.value; - return { - value: buildCombinedStacks(stack, nested) - }; +exports.maxSatisfying = maxSatisfying +function maxSatisfying (versions, range, options) { + var max = null + var maxSV = null + try { + var rangeObj = new Range(range, options) + } catch (er) { + return null + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!max || maxSV.compare(v) === -1) { + // compare(max, v, true) + max = v + maxSV = new SemVer(max, options) + } } + }) + return max } -function buildCombinedStacks(stack, nested) { - if (nested) { - stack += '\nCaused By: ' + nested.stack; +exports.minSatisfying = minSatisfying +function minSatisfying (versions, range, options) { + var min = null + var minSV = null + try { + var rangeObj = new Range(range, options) + } catch (er) { + return null + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!min || minSV.compare(v) === 1) { + // compare(min, v, true) + min = v + minSV = new SemVer(min, options) + } } - return stack; + }) + return min } -inherits(NestedError, Error); -NestedError.prototype.name = 'NestedError'; - - -module.exports = NestedError; - - -/***/ }), -/* 909 */ -/***/ (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 fsP = pify(fs); - -exports.closeSync = fs.closeSync.bind(fs); -exports.createWriteStream = fs.createWriteStream.bind(fs); - -exports.createReadStream = (path, options) => new Promise((resolve, reject) => { - const read = fs.createReadStream(path, options); - - read.once('error', error => { - reject(new CpFileError(`Cannot read from \`${path}\`: ${error.message}`, error)); - }); - - read.once('readable', () => { - resolve(read); - }); - - read.once('end', () => { - resolve(read); - }); -}); +exports.minVersion = minVersion +function minVersion (range, loose) { + range = new Range(range, loose) -exports.stat = path => fsP.stat(path).catch(error => { - throw new CpFileError(`Cannot stat path \`${path}\`: ${error.message}`, error); -}); + var minver = new SemVer('0.0.0') + if (range.test(minver)) { + return minver + } -exports.lstat = path => fsP.lstat(path).catch(error => { - throw new CpFileError(`lstat \`${path}\` failed: ${error.message}`, error); -}); + minver = new SemVer('0.0.0-0') + if (range.test(minver)) { + return minver + } -exports.utimes = (path, atime, mtime) => fsP.utimes(path, atime, mtime).catch(error => { - throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); -}); + minver = null + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i] -exports.chmod = (path, mode) => fsP.chmod(path, mode).catch(error => { - throw new CpFileError(`chmod \`${path}\` failed: ${error.message}`, error); -}); + comparators.forEach(function (comparator) { + // Clone to avoid manipulating the comparator's semver object. + var compver = new SemVer(comparator.semver.version) + switch (comparator.operator) { + case '>': + if (compver.prerelease.length === 0) { + compver.patch++ + } else { + compver.prerelease.push(0) + } + compver.raw = compver.format() + /* fallthrough */ + case '': + case '>=': + if (!minver || gt(minver, compver)) { + minver = compver + } + break + case '<': + case '<=': + /* Ignore maximum versions */ + break + /* istanbul ignore next */ + default: + throw new Error('Unexpected operation: ' + comparator.operator) + } + }) + } -exports.chown = (path, uid, gid) => fsP.chown(path, uid, gid).catch(error => { - throw new CpFileError(`chown \`${path}\` failed: ${error.message}`, error); -}); + if (minver && range.test(minver)) { + return minver + } -exports.openSync = (path, flags, mode) => { - try { - return fs.openSync(path, flags, mode); - } catch (error) { - if (flags.includes('w')) { - throw new CpFileError(`Cannot write to \`${path}\`: ${error.message}`, error); - } + return null +} - throw new CpFileError(`Cannot open \`${path}\`: ${error.message}`, error); - } -}; +exports.validRange = validRange +function validRange (range, options) { + try { + // Return '*' instead of '' so that truthiness works. + // This will throw if it's invalid anyway + return new Range(range, options).range || '*' + } catch (er) { + return null + } +} -// eslint-disable-next-line max-params -exports.readSync = (fileDescriptor, buffer, offset, length, position, path) => { - try { - return fs.readSync(fileDescriptor, buffer, offset, length, position); - } catch (error) { - throw new CpFileError(`Cannot read from \`${path}\`: ${error.message}`, error); - } -}; +// Determine if version is less than all the versions possible in the range +exports.ltr = ltr +function ltr (version, range, options) { + return outside(version, range, '<', options) +} -// eslint-disable-next-line max-params -exports.writeSync = (fileDescriptor, buffer, offset, length, position, path) => { - try { - return fs.writeSync(fileDescriptor, buffer, offset, length, position); - } catch (error) { - throw new CpFileError(`Cannot write to \`${path}\`: ${error.message}`, error); - } -}; +// Determine if version is greater than all the versions possible in the range. +exports.gtr = gtr +function gtr (version, range, options) { + return outside(version, range, '>', options) +} -exports.statSync = path => { - try { - return fs.statSync(path); - } catch (error) { - throw new CpFileError(`stat \`${path}\` failed: ${error.message}`, error); - } -}; +exports.outside = outside +function outside (version, range, hilo, options) { + version = new SemVer(version, options) + range = new Range(range, options) -exports.fstatSync = (fileDescriptor, path) => { - try { - return fs.fstatSync(fileDescriptor); - } catch (error) { - throw new CpFileError(`fstat \`${path}\` failed: ${error.message}`, error); - } -}; + var gtfn, ltefn, ltfn, comp, ecomp + switch (hilo) { + case '>': + gtfn = gt + ltefn = lte + ltfn = lt + comp = '>' + ecomp = '>=' + break + case '<': + gtfn = lt + ltefn = gte + ltfn = gt + comp = '<' + ecomp = '<=' + break + default: + throw new TypeError('Must provide a hilo val of "<" or ">"') + } -exports.futimesSync = (fileDescriptor, atime, mtime, path) => { - try { - return fs.futimesSync(fileDescriptor, atime, mtime, path); - } catch (error) { - throw new CpFileError(`futimes \`${path}\` failed: ${error.message}`, error); - } -}; + // If it satisifes the range it is not outside + if (satisfies(version, range, options)) { + return false + } -exports.utimesSync = (path, atime, mtime) => { - try { - return fs.utimesSync(path, atime, mtime); - } catch (error) { - throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); - } -}; + // From now on, variable terms are as if we're in "gtr" mode. + // but note that everything is flipped for the "ltr" function. -exports.chmodSync = (path, mode) => { - try { - return fs.chmodSync(path, mode); - } catch (error) { - throw new CpFileError(`chmod \`${path}\` failed: ${error.message}`, error); - } -}; + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i] -exports.chownSync = (path, uid, gid) => { - try { - return fs.chownSync(path, uid, gid); - } catch (error) { - throw new CpFileError(`chown \`${path}\` failed: ${error.message}`, error); - } -}; + var high = null + var low = null -exports.makeDir = path => makeDir(path, {fs}).catch(error => { - throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); -}); + comparators.forEach(function (comparator) { + if (comparator.semver === ANY) { + comparator = new Comparator('>=0.0.0') + } + high = high || comparator + low = low || comparator + if (gtfn(comparator.semver, high.semver, options)) { + high = comparator + } else if (ltfn(comparator.semver, low.semver, options)) { + low = comparator + } + }) -exports.makeDirSync = path => { - try { - makeDir.sync(path, {fs}); - } catch (error) { - throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); - } -}; + // If the edge version comparator has a operator then our version + // isn't outside it + if (high.operator === comp || high.operator === ecomp) { + return false + } -if (fs.copyFileSync) { - exports.copyFileSync = (source, destination, flags) => { - try { - fs.copyFileSync(source, destination, flags); - } catch (error) { - throw new CpFileError(`Cannot copy from \`${source}\` to \`${destination}\`: ${error.message}`, error); - } - }; + // If the lowest version comparator has an operator and our version + // is less than it then it isn't higher than the range + if ((!low.operator || low.operator === comp) && + ltefn(version, low.semver)) { + return false + } else if (low.operator === ecomp && ltfn(version, low.semver)) { + return false + } + } + return true } +exports.prerelease = prerelease +function prerelease (version, options) { + var parsed = parse(version, options) + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null +} -/***/ }), -/* 910 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const processFn = (fn, options) => function (...args) { - const P = options.promiseModule; - - return new P((resolve, reject) => { - if (options.multiArgs) { - args.push((...result) => { - if (options.errorFirst) { - if (result[0]) { - reject(result); - } else { - result.shift(); - resolve(result); - } - } else { - resolve(result); - } - }); - } else if (options.errorFirst) { - args.push((error, result) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); - } else { - args.push(resolve); - } - - fn.apply(this, args); - }); -}; - -module.exports = (input, options) => { - options = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, options); +exports.intersects = intersects +function intersects (r1, r2, options) { + r1 = new Range(r1, options) + r2 = new Range(r2, options) + return r1.intersects(r2) +} - const objType = typeof input; - if (!(input !== null && (objType === 'object' || objType === 'function'))) { - throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objType}\``); - } +exports.coerce = coerce +function coerce (version, options) { + if (version instanceof SemVer) { + return version + } - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return options.include ? options.include.some(match) : !options.exclude.some(match); - }; + if (typeof version !== 'string') { + return null + } - let ret; - if (objType === 'function') { - ret = function (...args) { - return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args); - }; - } else { - ret = Object.create(Object.getPrototypeOf(input)); - } + var match = version.match(re[COERCE]) - for (const key in input) { // eslint-disable-line guard-for-in - const property = input[key]; - ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property; - } + if (match == null) { + return null + } - return ret; -}; + return parse(match[1] + + '.' + (match[2] || '0') + + '.' + (match[3] || '0'), options) +} /***/ }), -/* 911 */ +/* 916 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106032,12 +108005,58 @@ module.exports = ProgressEmitter; /***/ }), -/* 912 */ +/* 917 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const blacklist = [ + // # All + '^npm-debug\\.log$', // Error log for npm + '^\\..*\\.swp$', // Swap file for vim state + + // # macOS + '^\\.DS_Store$', // Stores custom folder attributes + '^\\.AppleDouble$', // Stores additional file resources + '^\\.LSOverride$', // Contains the absolute path to the app to be used + '^Icon\\r$', // Custom Finder icon: http://superuser.com/questions/298785/icon-file-on-os-x-desktop + '^\\._.*', // Thumbnail + '^\\.Spotlight-V100(?:$|\\/)', // Directory that might appear on external disk + '\\.Trashes', // File that might appear on external disk + '^__MACOSX$', // Resource fork + + // # Linux + '~$', // Backup file + + // # Windows + '^Thumbs\\.db$', // Image file cache + '^ehthumbs\\.db$', // Folder config file + '^Desktop\\.ini$', // Stores custom folder attributes + '@eaDir$' // Synology Diskstation "hidden" folder where the server stores thumbnails +]; + +exports.re = () => { + throw new Error('`junk.re` was renamed to `junk.regex`'); +}; + +exports.regex = new RegExp(blacklist.join('|')); + +exports.is = filename => exports.regex.test(filename); + +exports.not = filename => !exports.is(filename); + +// TODO: Remove this for the next major release +exports.default = module.exports; + + +/***/ }), +/* 918 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(913); +const NestedError = __webpack_require__(919); class CpyError extends NestedError { constructor(message, nested) { @@ -106051,7 +108070,7 @@ module.exports = CpyError; /***/ }), -/* 913 */ +/* 919 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(29).inherits; @@ -106107,7 +108126,7 @@ module.exports = NestedError; /***/ }), -/* 914 */ +/* 920 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; diff --git a/packages/kbn-pm/package.json b/packages/kbn-pm/package.json index f57365905292b..444d46307b059 100644 --- a/packages/kbn-pm/package.json +++ b/packages/kbn-pm/package.json @@ -39,7 +39,7 @@ "babel-loader": "^8.0.6", "chalk": "^2.4.2", "cmd-shim": "^2.1.0", - "cpy": "^7.3.0", + "cpy": "^8.0.0", "dedent": "^0.7.0", "del": "^5.1.0", "execa": "^3.2.0", @@ -63,8 +63,8 @@ "tempy": "^0.3.0", "typescript": "3.7.2", "unlazy-loader": "^0.1.3", - "webpack": "^4.41.0", - "webpack-cli": "^3.3.9", + "webpack": "^4.41.5", + "webpack-cli": "^3.3.10", "wrap-ansi": "^3.0.1", "write-pkg": "^4.0.0" }, diff --git a/packages/kbn-storybook/package.json b/packages/kbn-storybook/package.json index 6948ae81806eb..73deadba0a619 100644 --- a/packages/kbn-storybook/package.json +++ b/packages/kbn-storybook/package.json @@ -27,6 +27,6 @@ "rxjs": "6.5.2", "serve-static": "1.14.1", "styled-components": "^3", - "webpack": "4.34.0" + "webpack": "^4.41.5" } } \ No newline at end of file diff --git a/packages/kbn-test/src/functional_tests/tasks.js b/packages/kbn-test/src/functional_tests/tasks.js index d50f6a15c2e0b..44b3bd9f2a2c6 100644 --- a/packages/kbn-test/src/functional_tests/tasks.js +++ b/packages/kbn-test/src/functional_tests/tasks.js @@ -59,6 +59,15 @@ const makeSuccessMessage = options => { * @property {string} options.esFrom Optionally run from source instead of snapshot */ export async function runTests(options) { + if (!process.env.KBN_NP_PLUGINS_BUILT) { + const log = options.createLogger(); + log.warning('❗️❗️❗️'); + log.warning( + "Don't forget to use `node scripts/build_new_platform_plugins` to build plugins you plan on testing" + ); + log.warning('❗️❗️❗️'); + } + for (const configPath of options.configs) { const log = options.createLogger(); const opts = { diff --git a/packages/kbn-ui-framework/package.json b/packages/kbn-ui-framework/package.json index b4d9d3dfee03f..4b1286220b80b 100644 --- a/packages/kbn-ui-framework/package.json +++ b/packages/kbn-ui-framework/package.json @@ -33,13 +33,13 @@ "@babel/core": "^7.5.5", "@elastic/eui": "0.0.55", "@kbn/babel-preset": "1.0.0", - "autoprefixer": "9.6.1", + "autoprefixer": "^9.7.4", "babel-loader": "^8.0.6", "brace": "0.11.1", "chalk": "^2.4.2", "chokidar": "3.2.1", "core-js": "^3.2.1", - "css-loader": "^2.1.1", + "css-loader": "^3.4.2", "expose-loader": "^0.7.5", "file-loader": "^4.2.0", "grunt": "1.0.4", @@ -54,7 +54,7 @@ "keymirror": "0.1.1", "moment": "^2.24.0", "node-sass": "^4.9.4", - "postcss": "^7.0.5", + "postcss": "^7.0.26", "postcss-loader": "^3.0.0", "raw-loader": "^3.1.0", "react-dom": "^16.12.0", @@ -64,10 +64,10 @@ "redux": "3.7.2", "redux-thunk": "2.2.0", "regenerator-runtime": "^0.13.3", - "sass-loader": "^7.3.1", + "sass-loader": "^8.0.2", "sinon": "^7.4.2", - "style-loader": "^0.23.1", - "webpack": "^4.41.0", + "style-loader": "^1.1.3", + "webpack": "^4.41.5", "webpack-dev-server": "^3.8.2", "yeoman-generator": "1.1.1", "yo": "2.0.6" diff --git a/packages/kbn-ui-shared-deps/package.json b/packages/kbn-ui-shared-deps/package.json index 47a47449927e4..1c6c85c685a3f 100644 --- a/packages/kbn-ui-shared-deps/package.json +++ b/packages/kbn-ui-shared-deps/package.json @@ -17,7 +17,7 @@ "abortcontroller-polyfill": "^1.3.0", "angular": "^1.7.9", "core-js": "^3.2.1", - "css-loader": "^2.1.1", + "css-loader": "^3.4.2", "custom-event-polyfill": "^0.3.0", "del": "^5.1.0", "jquery": "^3.4.1", @@ -30,7 +30,7 @@ "read-pkg": "^5.2.0", "regenerator-runtime": "^0.13.3", "symbol-observable": "^1.2.0", - "webpack": "4.41.0", + "webpack": "^4.41.5", "whatwg-fetch": "^3.0.0" } } \ No newline at end of file diff --git a/renovate.json5 b/renovate.json5 index 6764ed38ba4cf..f868063142f6b 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -123,6 +123,14 @@ '@types/bluebird', ], }, + { + groupSlug: 'browserslist-useragent', + groupName: 'browserslist-useragent related packages', + packageNames: [ + 'browserslist-useragent', + '@types/browserslist-useragent', + ], + }, { groupSlug: 'chance', groupName: 'chance related packages', diff --git a/scripts/build_new_platform_plugins.js b/scripts/build_new_platform_plugins.js new file mode 100644 index 0000000000000..4d6963144d085 --- /dev/null +++ b/scripts/build_new_platform_plugins.js @@ -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. + */ + +require('@kbn/optimizer/target/cli'); diff --git a/src/cli/cluster/cluster_manager.test.ts b/src/cli/cluster/cluster_manager.test.ts index bd37e854e1691..707778861fb59 100644 --- a/src/cli/cluster/cluster_manager.test.ts +++ b/src/cli/cluster/cluster_manager.test.ts @@ -17,7 +17,24 @@ * under the License. */ +import * as Rx from 'rxjs'; + import { mockCluster } from './cluster_manager.test.mocks'; + +jest.mock('./run_kbn_optimizer', () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires,no-shadow + const Rx = require('rxjs'); + + return { + runKbnOptimizer: () => + new Rx.BehaviorSubject({ + type: 'compiler success', + durSec: 0, + bundles: [], + }), + }; +}); + jest.mock('readline', () => ({ createInterface: jest.fn(() => ({ on: jest.fn(), @@ -26,6 +43,13 @@ jest.mock('readline', () => ({ })), })); +const mockConfig: any = { + get: (key: string) => { + expect(key).toBe('optimize.enabled'); + return false; + }, +}; + import { sample } from 'lodash'; import { ClusterManager } from './cluster_manager'; @@ -51,7 +75,7 @@ describe('CLI cluster manager', () => { }); test('has two workers', () => { - const manager = new ClusterManager({}, {} as any); + const manager = new ClusterManager({}, mockConfig); expect(manager.workers).toHaveLength(2); for (const worker of manager.workers) expect(worker).toBeInstanceOf(Worker); @@ -61,7 +85,7 @@ describe('CLI cluster manager', () => { }); test('delivers broadcast messages to other workers', () => { - const manager = new ClusterManager({}, {} as any); + const manager = new ClusterManager({}, mockConfig); for (const worker of manager.workers) { Worker.prototype.start.call(worker); // bypass the debounced start method @@ -86,92 +110,59 @@ describe('CLI cluster manager', () => { test('correctly configures `BasePathProxy`.', async () => { const basePathProxyMock = { start: jest.fn() }; - new ClusterManager({}, {} as any, basePathProxyMock as any); + new ClusterManager({}, mockConfig, basePathProxyMock as any); expect(basePathProxyMock.start).toHaveBeenCalledWith({ shouldRedirectFromOldBasePath: expect.any(Function), - blockUntil: expect.any(Function), + delayUntil: expect.any(Function), }); }); - describe('proxy is configured with the correct `shouldRedirectFromOldBasePath` and `blockUntil` functions.', () => { + describe('basePathProxy config', () => { let clusterManager: ClusterManager; let shouldRedirectFromOldBasePath: (path: string) => boolean; - let blockUntil: () => Promise; + let delayUntil: () => Rx.Observable; + beforeEach(async () => { const basePathProxyMock = { start: jest.fn() }; - - clusterManager = new ClusterManager({}, {} as any, basePathProxyMock as any); - - jest.spyOn(clusterManager.server, 'on'); - jest.spyOn(clusterManager.server, 'off'); - - [[{ blockUntil, shouldRedirectFromOldBasePath }]] = basePathProxyMock.start.mock.calls; - }); - - test('`shouldRedirectFromOldBasePath()` returns `false` for unknown paths.', () => { - expect(shouldRedirectFromOldBasePath('')).toBe(false); - expect(shouldRedirectFromOldBasePath('some-path/')).toBe(false); - expect(shouldRedirectFromOldBasePath('some-other-path')).toBe(false); + clusterManager = new ClusterManager({}, mockConfig, basePathProxyMock as any); + [[{ delayUntil, shouldRedirectFromOldBasePath }]] = basePathProxyMock.start.mock.calls; }); - test('`shouldRedirectFromOldBasePath()` returns `true` for `app` and other known paths.', () => { - expect(shouldRedirectFromOldBasePath('app/')).toBe(true); - expect(shouldRedirectFromOldBasePath('login')).toBe(true); - expect(shouldRedirectFromOldBasePath('logout')).toBe(true); - expect(shouldRedirectFromOldBasePath('status')).toBe(true); - }); - - test('`blockUntil()` resolves immediately if worker has already crashed.', async () => { - clusterManager.server.crashed = true; - - await expect(blockUntil()).resolves.not.toBeDefined(); - expect(clusterManager.server.on).not.toHaveBeenCalled(); - expect(clusterManager.server.off).not.toHaveBeenCalled(); + describe('shouldRedirectFromOldBasePath()', () => { + test('returns `false` for unknown paths.', () => { + expect(shouldRedirectFromOldBasePath('')).toBe(false); + expect(shouldRedirectFromOldBasePath('some-path/')).toBe(false); + expect(shouldRedirectFromOldBasePath('some-other-path')).toBe(false); + }); + + test('returns `true` for `app` and other known paths.', () => { + expect(shouldRedirectFromOldBasePath('app/')).toBe(true); + expect(shouldRedirectFromOldBasePath('login')).toBe(true); + expect(shouldRedirectFromOldBasePath('logout')).toBe(true); + expect(shouldRedirectFromOldBasePath('status')).toBe(true); + }); }); - test('`blockUntil()` resolves immediately if worker is already listening.', async () => { - clusterManager.server.listening = true; - - await expect(blockUntil()).resolves.not.toBeDefined(); - expect(clusterManager.server.on).not.toHaveBeenCalled(); - expect(clusterManager.server.off).not.toHaveBeenCalled(); - }); - - test('`blockUntil()` resolves when worker crashes.', async () => { - const blockUntilPromise = blockUntil(); - - expect(clusterManager.server.on).toHaveBeenCalledTimes(2); - expect(clusterManager.server.on).toHaveBeenCalledWith('crashed', expect.any(Function)); - - const [, [eventName, onCrashed]] = (clusterManager.server.on as jest.Mock).mock.calls; - // Check event name to make sure we call the right callback, - // in Jest 23 we could use `toHaveBeenNthCalledWith` instead. - expect(eventName).toBe('crashed'); - expect(clusterManager.server.off).not.toHaveBeenCalled(); - - onCrashed(); - await expect(blockUntilPromise).resolves.not.toBeDefined(); - - expect(clusterManager.server.off).toHaveBeenCalledTimes(2); - }); - - test('`blockUntil()` resolves when worker starts listening.', async () => { - const blockUntilPromise = blockUntil(); - - expect(clusterManager.server.on).toHaveBeenCalledTimes(2); - expect(clusterManager.server.on).toHaveBeenCalledWith('listening', expect.any(Function)); - - const [[eventName, onListening]] = (clusterManager.server.on as jest.Mock).mock.calls; - // Check event name to make sure we call the right callback, - // in Jest 23 we could use `toHaveBeenNthCalledWith` instead. - expect(eventName).toBe('listening'); - expect(clusterManager.server.off).not.toHaveBeenCalled(); - - onListening(); - await expect(blockUntilPromise).resolves.not.toBeDefined(); - - expect(clusterManager.server.off).toHaveBeenCalledTimes(2); + describe('delayUntil()', () => { + test('returns an observable which emits when the server and kbnOptimizer are ready and completes', async () => { + clusterManager.serverReady$.next(false); + clusterManager.optimizerReady$.next(false); + clusterManager.kbnOptimizerReady$.next(false); + + const events: Array = []; + delayUntil().subscribe( + () => events.push('next'), + error => events.push(error), + () => events.push('complete') + ); + + clusterManager.serverReady$.next(true); + expect(events).toEqual([]); + + clusterManager.kbnOptimizerReady$.next(true); + expect(events).toEqual(['next', 'complete']); + }); }); }); }); diff --git a/src/cli/cluster/cluster_manager.ts b/src/cli/cluster/cluster_manager.ts index 3fa4bdcbc5fa5..ea4a49dd84d84 100644 --- a/src/cli/cluster/cluster_manager.ts +++ b/src/cli/cluster/cluster_manager.ts @@ -19,22 +19,29 @@ import { resolve } from 'path'; import { format as formatUrl } from 'url'; + import opn from 'opn'; -import { debounce, invoke, bindAll, once, uniq } from 'lodash'; -import * as Rx from 'rxjs'; -import { first, mapTo, filter, map, take } from 'rxjs/operators'; import { REPO_ROOT } from '@kbn/dev-utils'; import { FSWatcher } from 'chokidar'; +import * as Rx from 'rxjs'; +import { startWith, mapTo, filter, map, take, tap } from 'rxjs/operators'; +import { runKbnOptimizer } from './run_kbn_optimizer'; import { LegacyConfig } from '../../core/server/legacy'; import { BasePathProxyServer } from '../../core/server/http'; -// @ts-ignore -import Log from '../log'; +import { Log } from './log'; import { Worker } from './worker'; process.env.kbnWorkerType = 'managr'; +const firstAllTrue = (...sources: Array>) => + Rx.combineLatest(...sources).pipe( + filter(values => values.every(v => v === true)), + take(1), + mapTo(undefined) + ); + export class ClusterManager { public optimizer: Worker; public server: Worker; @@ -42,10 +49,17 @@ export class ClusterManager { private watcher: FSWatcher | null = null; private basePathProxy: BasePathProxyServer | undefined; - private log: any; + private log: Log; private addedCount = 0; private inReplMode: boolean; + // exposed for testing + public readonly serverReady$ = new Rx.ReplaySubject(1); + // exposed for testing + public readonly optimizerReady$ = new Rx.ReplaySubject(1); + // exposed for testing + public readonly kbnOptimizerReady$ = new Rx.ReplaySubject(1); + constructor( opts: Record, config: LegacyConfig, @@ -55,6 +69,23 @@ export class ClusterManager { this.inReplMode = !!opts.repl; this.basePathProxy = basePathProxy; + if (config.get('optimize.enabled') !== false) { + // run @kbn/optimizer and write it's state to kbnOptimizerReady$ + runKbnOptimizer(opts, config) + .pipe( + map(state => state.type === 'compiler success'), + tap({ + error: error => { + this.log.bad('New platform optimizer error', error.stack); + process.exit(1); + }, + }) + ) + .subscribe(this.kbnOptimizerReady$); + } else { + this.kbnOptimizerReady$.next(true); + } + const serverArgv = []; const optimizerArgv = ['--plugins.initialize=false', '--server.autoListen=false']; @@ -86,6 +117,27 @@ export class ClusterManager { })), ]; + // write server status to the serverReady$ subject + Rx.merge( + Rx.fromEvent(this.server, 'starting').pipe(mapTo(false)), + Rx.fromEvent(this.server, 'listening').pipe(mapTo(true)), + Rx.fromEvent(this.server, 'crashed').pipe(mapTo(true)) + ) + .pipe(startWith(this.server.listening || this.server.crashed)) + .subscribe(this.serverReady$); + + // write optimizer status to the optimizerReady$ subject + Rx.merge( + Rx.fromEvent(this.optimizer, 'optimizeStatus'), + Rx.defer(() => { + if (this.optimizer.fork) { + this.optimizer.fork.send({ optimizeReady: '?' }); + } + }) + ) + .pipe(map((msg: any) => msg && !!msg.success)) + .subscribe(this.optimizerReady$); + // broker messages between workers this.workers.forEach(worker => { worker.on('broadcast', msg => { @@ -109,8 +161,6 @@ export class ClusterManager { }); }); - bindAll(this, 'onWatcherAdd', 'onWatcherError', 'onWatcherChange'); - if (opts.open) { this.setupOpen( formatUrl({ @@ -137,11 +187,11 @@ export class ClusterManager { .reduce( (acc, path) => acc.concat( - resolve(path, 'test'), - resolve(path, 'build'), - resolve(path, 'target'), - resolve(path, 'scripts'), - resolve(path, 'docs') + resolve(path, 'test/**'), + resolve(path, 'build/**'), + resolve(path, 'target/**'), + resolve(path, 'scripts/**'), + resolve(path, 'docs/**') ), [] as string[] ); @@ -152,33 +202,36 @@ export class ClusterManager { startCluster() { this.setupManualRestart(); - invoke(this.workers, 'start'); + for (const worker of this.workers) { + worker.start(); + } if (this.basePathProxy) { this.basePathProxy.start({ - blockUntil: this.blockUntil.bind(this), - shouldRedirectFromOldBasePath: this.shouldRedirectFromOldBasePath.bind(this), + delayUntil: () => firstAllTrue(this.serverReady$, this.kbnOptimizerReady$), + + shouldRedirectFromOldBasePath: (path: string) => { + // strip `s/{id}` prefix when checking for need to redirect + if (path.startsWith('s/')) { + path = path + .split('/') + .slice(2) + .join('/'); + } + + const isApp = path.startsWith('app/'); + const isKnownShortPath = ['login', 'logout', 'status'].includes(path); + return isApp || isKnownShortPath; + }, }); } } setupOpen(openUrl: string) { - const serverListening$ = Rx.merge( - Rx.fromEvent(this.server, 'listening').pipe(mapTo(true)), - Rx.fromEvent(this.server, 'fork:exit').pipe(mapTo(false)), - Rx.fromEvent(this.server, 'crashed').pipe(mapTo(false)) - ); - - const optimizeSuccess$ = Rx.fromEvent(this.optimizer, 'optimizeStatus').pipe( - map((msg: any) => !!msg.success) - ); - - Rx.combineLatest(serverListening$, optimizeSuccess$) - .pipe( - filter(([serverListening, optimizeSuccess]) => serverListening && optimizeSuccess), - take(1) - ) + firstAllTrue(this.serverReady$, this.kbnOptimizerReady$, this.optimizerReady$) .toPromise() - .then(() => opn(openUrl)); + .then(() => { + opn(openUrl); + }); } setupWatching(extraPaths: string[], pluginInternalDirsIgnore: string[]) { @@ -187,53 +240,51 @@ export class ClusterManager { // eslint-disable-next-line @typescript-eslint/no-var-requires const { fromRoot } = require('../../core/server/utils'); - const watchPaths = [ - fromRoot('src/core'), - fromRoot('src/legacy/core_plugins'), - fromRoot('src/legacy/server'), - fromRoot('src/legacy/ui'), - fromRoot('src/legacy/utils'), - fromRoot('x-pack/legacy/common'), - fromRoot('x-pack/legacy/plugins'), - fromRoot('x-pack/legacy/server'), - fromRoot('config'), - ...extraPaths, - ].map(path => resolve(path)); + const watchPaths = Array.from( + new Set( + [ + fromRoot('src/core'), + fromRoot('src/legacy/core_plugins'), + fromRoot('src/legacy/server'), + fromRoot('src/legacy/ui'), + fromRoot('src/legacy/utils'), + fromRoot('x-pack/legacy/common'), + fromRoot('x-pack/legacy/plugins'), + fromRoot('x-pack/legacy/server'), + fromRoot('config'), + ...extraPaths, + ].map(path => resolve(path)) + ) + ); const ignorePaths = [ + /[\\\/](\..*|node_modules|bower_components|public|__[a-z0-9_]+__|coverage)[\\\/]/, + /\.test\.(js|ts)$/, + ...pluginInternalDirsIgnore, fromRoot('src/legacy/server/sass/__tmp__'), fromRoot('x-pack/legacy/plugins/reporting/.chromium'), fromRoot('x-pack/legacy/plugins/siem/cypress'), fromRoot('x-pack/legacy/plugins/apm/cypress'), fromRoot('x-pack/legacy/plugins/apm/scripts'), - fromRoot('x-pack/legacy/plugins/canvas/canvas_plugin_src'), // prevents server from restarting twice for Canvas plugin changes + fromRoot('x-pack/legacy/plugins/canvas/canvas_plugin_src'), // prevents server from restarting twice for Canvas plugin changes, + 'plugins/java_languageserver', ]; - this.watcher = chokidar.watch(uniq(watchPaths), { + this.watcher = chokidar.watch(watchPaths, { cwd: fromRoot('.'), - ignored: [ - /[\\\/](\..*|node_modules|bower_components|public|__[a-z0-9_]+__|coverage)[\\\/]/, - /\.test\.(js|ts)$/, - ...pluginInternalDirsIgnore, - ...ignorePaths, - 'plugins/java_languageserver', - ], + ignored: ignorePaths, }) as FSWatcher; this.watcher.on('add', this.onWatcherAdd); this.watcher.on('error', this.onWatcherError); + this.watcher.once('ready', () => { + // start sending changes to workers + this.watcher!.removeListener('add', this.onWatcherAdd); + this.watcher!.on('all', this.onWatcherChange); - this.watcher.on( - 'ready', - once(() => { - // start sending changes to workers - this.watcher!.removeListener('add', this.onWatcherAdd); - this.watcher!.on('all', this.onWatcherChange); - - this.log.good('watching for changes', `(${this.addedCount} files)`); - this.startCluster(); - }) - ); + this.log.good('watching for changes', `(${this.addedCount} files)`); + this.startCluster(); + }); } setupManualRestart() { @@ -249,7 +300,20 @@ export class ClusterManager { let nls = 0; const clear = () => (nls = 0); - const clearSoon = debounce(clear, 2000); + + let clearTimer: number | undefined; + const clearSoon = () => { + clearSoon.cancel(); + clearTimer = setTimeout(() => { + clearTimer = undefined; + clear(); + }); + }; + + clearSoon.cancel = () => { + clearTimeout(clearTimer); + clearTimer = undefined; + }; rl.setPrompt(''); rl.prompt(); @@ -274,41 +338,18 @@ export class ClusterManager { }); } - onWatcherAdd() { + onWatcherAdd = () => { this.addedCount += 1; - } + }; - onWatcherChange(e: any, path: string) { - invoke(this.workers, 'onChange', path); - } + onWatcherChange = (e: any, path: string) => { + for (const worker of this.workers) { + worker.onChange(path); + } + }; - onWatcherError(err: any) { + onWatcherError = (err: any) => { this.log.bad('failed to watch files!\n', err.stack); process.exit(1); // eslint-disable-line no-process-exit - } - - shouldRedirectFromOldBasePath(path: string) { - // strip `s/{id}` prefix when checking for need to redirect - if (path.startsWith('s/')) { - path = path - .split('/') - .slice(2) - .join('/'); - } - - const isApp = path.startsWith('app/'); - const isKnownShortPath = ['login', 'logout', 'status'].includes(path); - return isApp || isKnownShortPath; - } - - blockUntil() { - // Wait until `server` worker either crashes or starts to listen. - if (this.server.listening || this.server.crashed) { - return Promise.resolve(); - } - - return Rx.race(Rx.fromEvent(this.server, 'listening'), Rx.fromEvent(this.server, 'crashed')) - .pipe(first()) - .toPromise(); - } + }; } diff --git a/src/cli/cluster/log.ts b/src/cli/cluster/log.ts new file mode 100644 index 0000000000000..af73059c0758e --- /dev/null +++ b/src/cli/cluster/log.ts @@ -0,0 +1,56 @@ +/* + * 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 Chalk from 'chalk'; + +export class Log { + constructor(private readonly quiet: boolean, private readonly silent: boolean) {} + + good(label: string, ...args: any[]) { + if (this.quiet || this.silent) { + return; + } + + // eslint-disable-next-line no-console + console.log(Chalk.black.bgGreen(` ${label.trim()} `), ...args); + } + + warn(label: string, ...args: any[]) { + if (this.quiet || this.silent) { + return; + } + + // eslint-disable-next-line no-console + console.log(Chalk.black.bgYellow(` ${label.trim()} `), ...args); + } + + bad(label: string, ...args: any[]) { + if (this.silent) { + return; + } + + // eslint-disable-next-line no-console + console.log(Chalk.white.bgRed(` ${label.trim()} `), ...args); + } + + write(label: string, ...args: any[]) { + // eslint-disable-next-line no-console + console.log(` ${label.trim()} `, ...args); + } +} diff --git a/src/cli/cluster/run_kbn_optimizer.ts b/src/cli/cluster/run_kbn_optimizer.ts new file mode 100644 index 0000000000000..e4451331ddaa4 --- /dev/null +++ b/src/cli/cluster/run_kbn_optimizer.ts @@ -0,0 +1,57 @@ +/* + * 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 Chalk from 'chalk'; +import moment from 'moment'; +import { ToolingLog, pickLevelFromFlags, REPO_ROOT } from '@kbn/dev-utils'; +import { OptimizerConfig, Optimizer, logOptimizerState } from '@kbn/optimizer'; + +import { LegacyConfig } from '../../core/server/legacy'; + +export function runKbnOptimizer(opts: Record, config: LegacyConfig) { + const optimizerConfig = OptimizerConfig.create({ + repoRoot: REPO_ROOT, + watch: true, + oss: !!opts.oss, + examples: !!opts.runExamples, + pluginPaths: config.get('plugins.paths'), + }); + + const dim = Chalk.dim('np bld'); + const time = () => moment().format('HH:mm:ss.SSS'); + const toolingLog = new ToolingLog({ + level: pickLevelFromFlags(opts), + writeTo: { + write: chunk => { + const trailingNewLine = chunk[chunk.length - 1] === '\n'; + + process.stdout.write( + chunk + .slice(0, chunk.length - (trailingNewLine ? 1 : 0)) + .split('\n') + .map(line => `${dim} log [${time()}] ${line}`) + .join('\n') + (trailingNewLine ? '\n' : '') + ); + }, + }, + }); + + const optimizer = new Optimizer(optimizerConfig); + return optimizer.run().pipe(logOptimizerState(toolingLog, optimizerConfig)); +} diff --git a/src/cli/cluster/worker.test.ts b/src/cli/cluster/worker.test.ts index 4f9337681e083..e775f71442a77 100644 --- a/src/cli/cluster/worker.test.ts +++ b/src/cli/cluster/worker.test.ts @@ -20,8 +20,8 @@ import { mockCluster } from './cluster_manager.test.mocks'; import { Worker, ClusterWorker } from './worker'; -// @ts-ignore -import Log from '../log'; + +import { Log } from './log'; const workersToShutdown: Worker[] = []; diff --git a/src/cli/cluster/worker.ts b/src/cli/cluster/worker.ts index fb87f1a87654c..c73d3edbf7df7 100644 --- a/src/cli/cluster/worker.ts +++ b/src/cli/cluster/worker.ts @@ -199,6 +199,7 @@ export class Worker extends EventEmitter { } this.fork = cluster.fork(this.env) as ClusterWorker; + this.emit('starting'); this.forkBinder = new BinderFor(this.fork); // when the fork sends a message, comes online, or loses its connection, then react diff --git a/src/cli/command.js b/src/cli/command.js index 06ee87e3198fd..6f083bb2a1fa2 100644 --- a/src/cli/command.js +++ b/src/cli/command.js @@ -18,17 +18,17 @@ */ import _ from 'lodash'; +import Chalk from 'chalk'; import help from './help'; import { Command } from 'commander'; -import { red } from './color'; Command.prototype.error = function(err) { if (err && err.message) err = err.message; console.log( ` -${red(' ERROR ')} ${err} +${Chalk.white.bgRed(' ERROR ')} ${err} ${help(this, ' ')} ` diff --git a/src/cli/serve/serve.js b/src/cli/serve/serve.js index 9cf5691b88399..be3fc319389d7 100644 --- a/src/cli/serve/serve.js +++ b/src/cli/serve/serve.js @@ -195,7 +195,7 @@ export default function(program) { [] ) .option('--plugins ', 'an alias for --plugin-dir', pluginDirCollector) - .option('--optimize', 'Optimize and then stop the server'); + .option('--optimize', 'Run the legacy plugin optimizer and then stop the server'); if (CAN_REPL) { command.option('--repl', 'Run the server with a REPL prompt and access to the server object'); diff --git a/src/core/public/plugins/plugin_loader.test.ts b/src/core/public/plugins/plugin_loader.test.ts index e24be35331f39..e5cbffc3e2d94 100644 --- a/src/core/public/plugins/plugin_loader.test.ts +++ b/src/core/public/plugins/plugin_loader.test.ts @@ -62,7 +62,7 @@ test('`loadPluginBundles` creates a script tag and loads initializer', async () const fakeScriptTag = createdScriptTags[0]; expect(fakeScriptTag.setAttribute).toHaveBeenCalledWith( 'src', - '/bundles/plugin/plugin-a.bundle.js' + '/bundles/plugin/plugin-a/plugin-a.plugin.js' ); expect(fakeScriptTag.setAttribute).toHaveBeenCalledWith('id', 'kbn-plugin-plugin-a'); expect(fakeScriptTag.onload).toBeInstanceOf(Function); @@ -85,7 +85,7 @@ test('`loadPluginBundles` includes the basePath', async () => { const fakeScriptTag = createdScriptTags[0]; expect(fakeScriptTag.setAttribute).toHaveBeenCalledWith( 'src', - '/mybasepath/bundles/plugin/plugin-a.bundle.js' + '/mybasepath/bundles/plugin/plugin-a/plugin-a.plugin.js' ); }); @@ -96,7 +96,7 @@ test('`loadPluginBundles` rejects if script.onerror is called', async () => { fakeScriptTag1.onerror(new Error('Whoa there!')); await expect(loadPromise).rejects.toThrowErrorMatchingInlineSnapshot( - `"Failed to load \\"plugin-a\\" bundle (/bundles/plugin/plugin-a.bundle.js)"` + `"Failed to load \\"plugin-a\\" bundle (/bundles/plugin/plugin-a/plugin-a.plugin.js)"` ); }); @@ -105,7 +105,7 @@ test('`loadPluginBundles` rejects if timeout is reached', async () => { // Override the timeout to 1 ms for testi. loadPluginBundle(addBasePath, 'plugin-a', { timeoutMs: 1 }) ).rejects.toThrowErrorMatchingInlineSnapshot( - `"Timeout reached when loading \\"plugin-a\\" bundle (/bundles/plugin/plugin-a.bundle.js)"` + `"Timeout reached when loading \\"plugin-a\\" bundle (/bundles/plugin/plugin-a/plugin-a.plugin.js)"` ); }); @@ -120,6 +120,6 @@ test('`loadPluginBundles` rejects if bundle does attach an initializer to window fakeScriptTag1.onload(); await expect(loadPromise).rejects.toThrowErrorMatchingInlineSnapshot( - `"Definition of plugin \\"plugin-a\\" should be a function (/bundles/plugin/plugin-a.bundle.js)."` + `"Definition of plugin \\"plugin-a\\" should be a function (/bundles/plugin/plugin-a/plugin-a.plugin.js)."` ); }); diff --git a/src/core/public/plugins/plugin_loader.ts b/src/core/public/plugins/plugin_loader.ts index 776ed7d7c5570..63aba0dde2af8 100644 --- a/src/core/public/plugins/plugin_loader.ts +++ b/src/core/public/plugins/plugin_loader.ts @@ -74,7 +74,7 @@ export const loadPluginBundle: LoadPluginBundle = < const coreWindow = (window as unknown) as CoreWindow; // Assumes that all plugin bundles get put into the bundles/plugins subdirectory - const bundlePath = addBasePath(`/bundles/plugin/${pluginName}.bundle.js`); + const bundlePath = addBasePath(`/bundles/plugin/${pluginName}/${pluginName}.plugin.js`); script.setAttribute('src', bundlePath); script.setAttribute('id', `kbn-plugin-${pluginName}`); script.setAttribute('async', ''); diff --git a/src/core/server/http/base_path_proxy_server.ts b/src/core/server/http/base_path_proxy_server.ts index 276e3955a4678..e418726465efa 100644 --- a/src/core/server/http/base_path_proxy_server.ts +++ b/src/core/server/http/base_path_proxy_server.ts @@ -17,13 +17,17 @@ * under the License. */ -import apm from 'elastic-apm-node'; - -import { ByteSizeValue } from '@kbn/config-schema'; -import { Server, Request } from 'hapi'; import Url from 'url'; import { Agent as HttpsAgent, ServerOptions as TlsOptions } from 'https'; + +import apm from 'elastic-apm-node'; +import { ByteSizeValue } from '@kbn/config-schema'; +import { Server, Request, ResponseToolkit } from 'hapi'; import { sample } from 'lodash'; +import BrowserslistUserAgent from 'browserslist-useragent'; +import * as Rx from 'rxjs'; +import { take } from 'rxjs/operators'; + import { DevConfig } from '../dev'; import { Logger } from '../logging'; import { HttpConfig } from './http_config'; @@ -33,9 +37,37 @@ const alphabet = 'abcdefghijklmnopqrztuvwxyz'.split(''); export interface BasePathProxyServerOptions { shouldRedirectFromOldBasePath: (path: string) => boolean; - blockUntil: () => Promise; + delayUntil: () => Rx.Observable; } +// Before we proxy request to a target port we may want to wait until some +// condition is met (e.g. until target listener is ready). +const checkForBrowserCompat = (log: Logger) => async (request: Request, h: ResponseToolkit) => { + if (!request.headers['user-agent'] || process.env.BROWSERSLIST_ENV === 'production') { + return h.continue; + } + + const matches = BrowserslistUserAgent.matchesUA(request.headers['user-agent'], { + env: 'dev', + allowHigherVersions: true, + ignoreMinor: true, + ignorePath: true, + }); + + if (!matches) { + log.warn(` + Request with user-agent [${request.headers['user-agent']}] + seems like it is coming from a browser that is not supported by the dev browserlist. + + Please run Kibana with the environment variable BROWSERSLIST_ENV=production to enable + support for all production browsers (like IE). + + `); + } + + return h.continue; +}; + export class BasePathProxyServer { private server?: Server; private httpsAgent?: HttpsAgent; @@ -108,7 +140,7 @@ export class BasePathProxyServer { } private setupRoutes({ - blockUntil, + delayUntil, shouldRedirectFromOldBasePath, }: Readonly) { if (this.server === undefined) { @@ -122,6 +154,9 @@ export class BasePathProxyServer { }, method: 'GET', path: '/', + options: { + pre: [checkForBrowserCompat(this.log)], + }, }); this.server.route({ @@ -138,11 +173,14 @@ export class BasePathProxyServer { method: '*', options: { pre: [ + checkForBrowserCompat(this.log), // Before we proxy request to a target port we may want to wait until some // condition is met (e.g. until target listener is ready). async (request, responseToolkit) => { apm.setTransactionName(`${request.method.toUpperCase()} /{basePath}/{kbnPath*}`); - await blockUntil(); + await delayUntil() + .pipe(take(1)) + .toPromise(); return responseToolkit.continue; }, ], @@ -172,10 +210,13 @@ export class BasePathProxyServer { method: '*', options: { pre: [ + checkForBrowserCompat(this.log), // Before we proxy request to a target port we may want to wait until some // condition is met (e.g. until target listener is ready). async (request, responseToolkit) => { - await blockUntil(); + await delayUntil() + .pipe(take(1)) + .toPromise(); return responseToolkit.continue; }, ], diff --git a/src/core/server/legacy/legacy_service.test.ts b/src/core/server/legacy/legacy_service.test.ts index af4db68ee95e1..4d62a562d5311 100644 --- a/src/core/server/legacy/legacy_service.test.ts +++ b/src/core/server/legacy/legacy_service.test.ts @@ -88,7 +88,7 @@ beforeEach(() => { contracts: new Map([['plugin-id', 'plugin-value']]), uiPlugins: { public: new Map([['plugin-id', {} as DiscoveredPlugin]]), - internal: new Map([['plugin-id', { entryPointPath: 'path/to/plugin/public' }]]), + internal: new Map([['plugin-id', { publicTargetDir: 'path/to/target/public' }]]), browserConfigs: new Map(), }, }, diff --git a/src/core/server/plugins/plugins_service.test.ts b/src/core/server/plugins/plugins_service.test.ts index 6768e85c8db17..df618b2c0a706 100644 --- a/src/core/server/plugins/plugins_service.test.ts +++ b/src/core/server/plugins/plugins_service.test.ts @@ -22,6 +22,7 @@ import { mockDiscover, mockPackage } from './plugins_service.test.mocks'; import { resolve, join } from 'path'; import { BehaviorSubject, from } from 'rxjs'; import { schema } from '@kbn/config-schema'; +import { createAbsolutePathSerializer } from '@kbn/dev-utils'; import { ConfigPath, ConfigService, Env } from '../config'; import { rawConfigServiceMock } from '../config/raw_config_service.mock'; @@ -48,6 +49,8 @@ let mockPluginSystem: jest.Mocked; const setupDeps = coreMock.createInternalSetup(); const logger = loggingServiceMock.create(); +expect.addSnapshotSerializer(createAbsolutePathSerializer()); + ['path-1', 'path-2', 'path-3', 'path-4', 'path-5'].forEach(path => { jest.doMock(join(path, 'server'), () => ({}), { virtual: true, @@ -540,10 +543,10 @@ describe('PluginsService', () => { expect(uiPlugins.internal).toMatchInlineSnapshot(` Map { "plugin-1" => Object { - "entryPointPath": "path-1/public", + "publicTargetDir": /path-1/target/public, }, "plugin-2" => Object { - "entryPointPath": "path-2/public", + "publicTargetDir": /path-2/target/public, }, } `); diff --git a/src/core/server/plugins/plugins_service.ts b/src/core/server/plugins/plugins_service.ts index 5a50cf8ea8ba2..427cc19a8614f 100644 --- a/src/core/server/plugins/plugins_service.ts +++ b/src/core/server/plugins/plugins_service.ts @@ -17,6 +17,7 @@ * under the License. */ +import Path from 'path'; import { Observable } from 'rxjs'; import { filter, first, map, mergeMap, tap, toArray } from 'rxjs/operators'; import { CoreService } from '../../types'; @@ -214,7 +215,9 @@ export class PluginsService implements CoreService ({}), - styleSheetPaths: resolve(__dirname, 'public/index.scss'), mappings, savedObjectsManagement: { query: { diff --git a/src/legacy/core_plugins/data/public/index.scss b/src/legacy/core_plugins/data/public/index.scss deleted file mode 100644 index 22877e217279f..0000000000000 --- a/src/legacy/core_plugins/data/public/index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import 'src/legacy/ui/public/styles/styling_constants'; - -@import '../../../../plugins/data/public/index' diff --git a/src/legacy/core_plugins/embeddable_api/index.ts b/src/legacy/core_plugins/embeddable_api/index.ts index 465e13df10bbc..52206e3d0f105 100644 --- a/src/legacy/core_plugins/embeddable_api/index.ts +++ b/src/legacy/core_plugins/embeddable_api/index.ts @@ -17,14 +17,9 @@ * under the License. */ -import { resolve } from 'path'; import { LegacyPluginApi, LegacyPluginSpec, ArrayOrItem } from 'src/legacy/plugin_discovery/types'; // eslint-disable-next-line import/no-default-export export default function(kibana: LegacyPluginApi): ArrayOrItem { - return new kibana.Plugin({ - uiExports: { - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - }, - }); + return new kibana.Plugin({}); } diff --git a/src/legacy/core_plugins/embeddable_api/public/index.scss b/src/legacy/core_plugins/embeddable_api/public/index.scss deleted file mode 100644 index 3f1977b909c31..0000000000000 --- a/src/legacy/core_plugins/embeddable_api/public/index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import 'src/legacy/ui/public/styles/styling_constants'; - -@import '../../../../plugins/embeddable/public/index'; diff --git a/src/legacy/core_plugins/inspector_views/package.json b/src/legacy/core_plugins/inspector_views/package.json deleted file mode 100644 index 74c61c2bcfd2a..0000000000000 --- a/src/legacy/core_plugins/inspector_views/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "inspector_views", - "version": "kibana" -} diff --git a/src/legacy/core_plugins/inspector_views/public/index.scss b/src/legacy/core_plugins/inspector_views/public/index.scss deleted file mode 100644 index d6a076c540f88..0000000000000 --- a/src/legacy/core_plugins/inspector_views/public/index.scss +++ /dev/null @@ -1,4 +0,0 @@ -@import 'src/legacy/ui/public/styles/styling_constants'; - -// Temporary reference -@import '../../../../plugins/inspector/public/views/index'; diff --git a/src/legacy/core_plugins/interpreter/index.ts b/src/legacy/core_plugins/interpreter/index.ts index db6f17a2960a9..9427a2f8a2d0f 100644 --- a/src/legacy/core_plugins/interpreter/index.ts +++ b/src/legacy/core_plugins/interpreter/index.ts @@ -31,7 +31,6 @@ export default function InterpreterPlugin(kibana: any) { injectDefaultVars: server => ({ serverBasePath: server.config().get('server.basePath'), }), - styleSheetPaths: resolve(__dirname, 'public/index.scss'), }, config: (Joi: any) => { return Joi.object({ diff --git a/src/legacy/core_plugins/interpreter/public/index.scss b/src/legacy/core_plugins/interpreter/public/index.scss deleted file mode 100644 index 360f35020764d..0000000000000 --- a/src/legacy/core_plugins/interpreter/public/index.scss +++ /dev/null @@ -1,4 +0,0 @@ -// Import the EUI global scope so we can use EUI constants -@import 'src/legacy/ui/public/styles/_styling_constants'; - -@import '../../../../plugins/expressions/public/index'; diff --git a/src/legacy/core_plugins/navigation/package.json b/src/legacy/core_plugins/navigation/package.json deleted file mode 100644 index 8fddb8e6aeced..0000000000000 --- a/src/legacy/core_plugins/navigation/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "navigation", - "version": "kibana" -} diff --git a/src/legacy/core_plugins/navigation/public/index.scss b/src/legacy/core_plugins/navigation/public/index.scss deleted file mode 100644 index 8f2221eb4d4c7..0000000000000 --- a/src/legacy/core_plugins/navigation/public/index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import 'src/legacy/ui/public/styles/styling_constants'; - -@import '../../../../plugins/navigation/public/top_nav_menu/index'; diff --git a/src/legacy/server/sass/build.js b/src/legacy/server/sass/build.js index 0957d52f46422..3d892ce321c2e 100644 --- a/src/legacy/server/sass/build.js +++ b/src/legacy/server/sass/build.js @@ -56,15 +56,7 @@ const makeAsset = (request, { path, root, boundry, copyRoot, urlRoot }) => { }; export class Build { - constructor({ - log, - sourcePath, - targetPath, - urlImports, - theme, - sourceMap = true, - outputStyle = 'nested', - }) { + constructor({ log, sourcePath, targetPath, urlImports, theme }) { this.log = log; this.sourcePath = sourcePath; this.sourceDir = dirname(this.sourcePath); @@ -73,8 +65,6 @@ export class Build { this.urlImports = urlImports; this.theme = theme; this.includedFiles = [sourcePath]; - this.sourceMap = sourceMap; - this.outputStyle = outputStyle; } /** @@ -97,11 +87,11 @@ export class Build { const rendered = await renderSass({ file: this.sourcePath, outFile: this.targetPath, - sourceMap: this.sourceMap, - outputStyle: this.outputStyle, - sourceMapEmbed: this.sourceMap, - includePaths: [resolve(__dirname, '../../../../node_modules')], importer: this.theme === 'dark' ? DARK_THEME_IMPORTER : undefined, + sourceMap: true, + outputStyle: 'nested', + sourceMapEmbed: true, + includePaths: [resolve(__dirname, '../../../../node_modules')], }); const processor = postcss([autoprefixer]); diff --git a/src/legacy/server/sass/build_all.js b/src/legacy/server/sass/build_all.js index d066e52792ca8..1d3d76d1cb01a 100644 --- a/src/legacy/server/sass/build_all.js +++ b/src/legacy/server/sass/build_all.js @@ -21,7 +21,7 @@ import { resolve } from 'path'; import { Build } from './build'; -export async function buildAll({ styleSheets, log, buildDir, sourceMap, outputStyle }) { +export async function buildAll({ styleSheets, log, buildDir }) { const bundles = await Promise.all( styleSheets.map(async styleSheet => { if (!styleSheet.localPath.endsWith('.scss')) { @@ -31,8 +31,6 @@ export async function buildAll({ styleSheets, log, buildDir, sourceMap, outputSt const bundle = new Build({ sourcePath: styleSheet.localPath, log, - sourceMap, - outputStyle, theme: styleSheet.theme, targetPath: resolve(buildDir, styleSheet.publicPath), urlImports: styleSheet.urlImports, diff --git a/src/legacy/ui/ui_exports/ui_export_defaults.js b/src/legacy/ui/ui_exports/ui_export_defaults.js index a62ebdc25ca2c..888cd52bf3ba2 100644 --- a/src/legacy/ui/ui_exports/ui_export_defaults.js +++ b/src/legacy/ui/ui_exports/ui_export_defaults.js @@ -30,9 +30,6 @@ export const UI_EXPORT_DEFAULTS = { ui: resolve(ROOT, 'src/legacy/ui/public'), __kibanaCore__$: resolve(ROOT, 'src/core/public'), test_harness: resolve(ROOT, 'src/test_harness/public'), - querystring: 'querystring-browser', - moment$: resolve(ROOT, 'webpackShims/moment'), - 'moment-timezone$': resolve(ROOT, 'webpackShims/moment-timezone'), }, styleSheetPaths: ['light', 'dark'].map(theme => ({ diff --git a/src/legacy/ui/ui_render/bootstrap/template.js.hbs b/src/legacy/ui/ui_render/bootstrap/template.js.hbs index 72dd97ff58642..94f6c4223b8c4 100644 --- a/src/legacy/ui/ui_render/bootstrap/template.js.hbs +++ b/src/legacy/ui/ui_render/bootstrap/template.js.hbs @@ -1,5 +1,6 @@ var kbnCsp = JSON.parse(document.querySelector('kbn-csp').getAttribute('data')); window.__kbnStrictCsp__ = kbnCsp.strictCsp; +window.__kbnDarkMode__ = {{darkMode}}; if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { var legacyBrowserError = document.getElementById('kbn_legacy_browser_error'); @@ -14,10 +15,12 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { window.onload = function () { var files = [ '{{dllBundlePath}}/vendors_runtime.bundle.dll.js', - {{#each dllJsChunks}} - '{{this}}', - {{/each}} - '{{regularBundlePath}}/kbn-ui-shared-deps/{{sharedDepsFilename}}', + [ + {{#each dllJsChunks}} + '{{this}}', + {{/each}} + '{{regularBundlePath}}/kbn-ui-shared-deps/{{sharedDepsFilename}}', + ], '{{regularBundlePath}}/commons.bundle.js', '{{regularBundlePath}}/{{appId}}.bundle.js' ]; @@ -57,6 +60,28 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { document.head.appendChild(dom); } + function loadJs(file, cb) { + var dom = document.createElement('script'); + + dom.setAttribute('async', ''); + dom.addEventListener('error', failure); + dom.setAttribute('src', file); + dom.addEventListener('load', cb); + document.head.appendChild(dom); + } + + function loadJsInParallel(files, cb) { + var pending = files.length; + for (var i = 0; i < files.length; i++) { + loadJs(files[i], function () { + pending = pending - 1; + if (pending === 0) { + cb(); + } + }) + } + } + {{#each styleSheetPaths}} loadStyleSheet('{{this}}'); {{/each}} @@ -64,14 +89,11 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { (function next() { var file = files.shift(); if (!file) return; - - var dom = document.createElement('script'); - - dom.setAttribute('async', ''); - dom.addEventListener('error', failure); - dom.setAttribute('src', file); - dom.addEventListener('load', next); - document.head.appendChild(dom); + if (typeof file === 'string') { + loadJs(file, next); + } else { + loadJsInParallel(file, next); + } }()); }; } diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js index 4158af19bd858..21c10bb20962f 100644 --- a/src/legacy/ui/ui_render/ui_render_mixin.js +++ b/src/legacy/ui/ui_render/ui_render_mixin.js @@ -142,6 +142,7 @@ export function uiRenderMixin(kbnServer, server, config) { dllJsChunks, styleSheetPaths, sharedDepsFilename: UiSharedDeps.distFilename, + darkMode, }, }); diff --git a/src/optimize/base_optimizer.js b/src/optimize/base_optimizer.js index efff7f0aa2b46..fbf746d5e89f8 100644 --- a/src/optimize/base_optimizer.js +++ b/src/optimize/base_optimizer.js @@ -39,6 +39,7 @@ import { PUBLIC_PATH_PLACEHOLDER } from './public_path_placeholder'; const POSTCSS_CONFIG_PATH = require.resolve('./postcss.config'); const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset'); const ISTANBUL_PRESET_PATH = require.resolve('@kbn/babel-preset/istanbul_preset'); +const EMPTY_MODULE_PATH = require.resolve('./intentionally_empty_module.js'); const BABEL_EXCLUDE_RE = [/[\/\\](webpackShims|node_modules|bower_components)[\/\\]/]; const STATS_WARNINGS_FILTER = new RegExp( [ @@ -62,7 +63,6 @@ export default class BaseOptimizer { constructor(opts) { this.logWithMetadata = opts.logWithMetadata || (() => null); this.uiBundles = opts.uiBundles; - this.newPlatformPluginInfo = opts.newPlatformPluginInfo; this.profile = opts.profile || false; this.workers = opts.workers; @@ -147,7 +147,7 @@ export default class BaseOptimizer { return 1; } - return Math.max(1, Math.min(cpus.length - 1, 7)); + return Math.max(1, Math.min(cpus.length - 1, 3)); } getThreadLoaderPoolConfig() { @@ -247,7 +247,6 @@ export default class BaseOptimizer { cache: true, entry: { ...this.uiBundles.toWebpackEntries(), - ...this._getDiscoveredPluginEntryPoints(), light_theme: [require.resolve('../legacy/ui/public/styles/bootstrap_light.less')], dark_theme: [require.resolve('../legacy/ui/public/styles/bootstrap_dark.less')], }, @@ -261,12 +260,6 @@ export default class BaseOptimizer { sourceMapFilename: '[file].map', publicPath: PUBLIC_PATH_PLACEHOLDER, devtoolModuleFilenameTemplate: '[absolute-resource-path]', - - // When the entry point is loaded, assign it's exported `plugin` - // value to a key on the global `__kbnBundles__` object. - // NOTE: Only actually used by new platform plugins - library: ['__kbnBundles__', '[name]'], - libraryExport: 'plugin', }, optimization: { @@ -307,6 +300,11 @@ export default class BaseOptimizer { filename: '[name].style.css', }), + // ignore scss imports in new-platform code that finds its way into legacy bundles + new webpack.NormalModuleReplacementPlugin(/\.scss$/, resource => { + resource.request = EMPTY_MODULE_PATH; + }), + // replace imports for `uiExports/*` modules with a synthetic module // created by create_ui_exports_module.js new webpack.NormalModuleReplacementPlugin(/^uiExports\//, resource => { @@ -395,7 +393,11 @@ export default class BaseOptimizer { 'node_modules', fromRoot('node_modules'), ], - alias: this.uiBundles.getAliases(), + alias: { + ...this.uiBundles.getAliases(), + tinymath: require.resolve('tinymath/lib/tinymath.es5.js'), + querystring: require.resolve('querystring-browser'), + }, }, performance: { @@ -523,17 +525,6 @@ export default class BaseOptimizer { ); } - _getDiscoveredPluginEntryPoints() { - // New platform plugin entry points - return [...this.newPlatformPluginInfo.entries()].reduce( - (entryPoints, [pluginId, pluginInfo]) => { - entryPoints[`plugin/${pluginId}`] = pluginInfo.entryPointPath; - return entryPoints; - }, - {} - ); - } - getPresets() { return IS_CODE_COVERAGE ? [ISTANBUL_PRESET_PATH, BABEL_PRESET_PATH] : [BABEL_PRESET_PATH]; } diff --git a/src/optimize/bundles_route/__tests__/fixtures/plugin/no_placeholder/no_placeholder.plugin.js b/src/optimize/bundles_route/__tests__/fixtures/plugin/no_placeholder/no_placeholder.plugin.js new file mode 100644 index 0000000000000..519e301113ff5 --- /dev/null +++ b/src/optimize/bundles_route/__tests__/fixtures/plugin/no_placeholder/no_placeholder.plugin.js @@ -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. + */ + +module.exports = 'BAR'; diff --git a/src/optimize/bundles_route/__tests__/fixtures/plugin/placeholder/placeholder.plugin.js b/src/optimize/bundles_route/__tests__/fixtures/plugin/placeholder/placeholder.plugin.js new file mode 100644 index 0000000000000..8c959f9b4779f --- /dev/null +++ b/src/optimize/bundles_route/__tests__/fixtures/plugin/placeholder/placeholder.plugin.js @@ -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. + */ + +module.exports = '__REPLACE_WITH_PUBLIC_PATH__/FOO'; diff --git a/src/optimize/bundles_route/bundles_route.js b/src/optimize/bundles_route/bundles_route.js index f0261d44e0347..0c2e98b5acd63 100644 --- a/src/optimize/bundles_route/bundles_route.js +++ b/src/optimize/bundles_route/bundles_route.js @@ -21,6 +21,7 @@ import { isAbsolute, extname } from 'path'; import LruCache from 'lru-cache'; import * as UiSharedDeps from '@kbn/ui-shared-deps'; import { createDynamicAssetResponse } from './dynamic_asset_response'; +import { assertIsNpUiPluginPublicDirs } from '../np_ui_plugin_public_dirs'; /** * Creates the routes that serves files from `bundlesPath` or from @@ -29,6 +30,7 @@ import { createDynamicAssetResponse } from './dynamic_asset_response'; * PUBLIC_PATH_PLACEHOLDER and replaces them with `publicPath`. * * @param {Object} options + * @property {Array<{id,path}>} options.npUiPluginPublicDirs array of ids and paths that should be served for new platform plugins * @property {string} options.regularBundlesPath * @property {string} options.dllBundlesPath * @property {string} options.basePublicPath @@ -40,11 +42,13 @@ export function createBundlesRoute({ dllBundlesPath, basePublicPath, builtCssPath, + npUiPluginPublicDirs = [], }) { // rather than calculate the fileHash on every request, we - // provide a cache object to `createDynamicAssetResponse()` that + // provide a cache object to `resolveDynamicAssetResponse()` that // will store the 100 most recently used hashes. const fileHashCache = new LruCache(100); + assertIsNpUiPluginPublicDirs(npUiPluginPublicDirs); if (typeof regularBundlesPath !== 'string' || !isAbsolute(regularBundlesPath)) { throw new TypeError( @@ -73,6 +77,14 @@ export function createBundlesRoute({ UiSharedDeps.distDir, fileHashCache ), + ...npUiPluginPublicDirs.map(({ id, path }) => + buildRouteForBundles( + `${basePublicPath}/bundles/plugin/${id}/`, + `/bundles/plugin/${id}/`, + path, + fileHashCache + ) + ), buildRouteForBundles( `${basePublicPath}/bundles/`, '/bundles/', diff --git a/src/optimize/index.js b/src/optimize/index.js index 83825e5a8f386..b7b9f7712358a 100644 --- a/src/optimize/index.js +++ b/src/optimize/index.js @@ -21,6 +21,8 @@ import FsOptimizer from './fs_optimizer'; import { createBundlesRoute } from './bundles_route'; import { DllCompiler } from './dynamic_dll_plugin'; import { fromRoot } from '../core/server/utils'; +import { getNpUiPluginPublicDirs } from './np_ui_plugin_public_dirs'; + export default async (kbnServer, server, config) => { if (!config.get('optimize.enabled')) return; @@ -37,13 +39,14 @@ export default async (kbnServer, server, config) => { return await kbnServer.mixin(require('./watch/watch')); } - const { newPlatform, uiBundles } = kbnServer; + const { uiBundles } = kbnServer; server.route( createBundlesRoute({ regularBundlesPath: uiBundles.getWorkingDir(), dllBundlesPath: DllCompiler.getRawDllConfig().outputPath, basePublicPath: config.get('server.basePath'), builtCssPath: fromRoot('built_assets/css'), + npUiPluginPublicDirs: getNpUiPluginPublicDirs(kbnServer), }) ); @@ -64,7 +67,6 @@ export default async (kbnServer, server, config) => { const optimizer = new FsOptimizer({ logWithMetadata: (tags, message, metadata) => server.logWithMetadata(tags, message, metadata), uiBundles, - newPlatformPluginInfo: newPlatform.__internals.uiPlugins.internal, profile: config.get('optimize.profile'), sourceMaps: config.get('optimize.sourceMaps'), workers: config.get('optimize.workers'), diff --git a/src/optimize/intentionally_empty_module.js b/src/optimize/intentionally_empty_module.js new file mode 100644 index 0000000000000..9880b336e76e5 --- /dev/null +++ b/src/optimize/intentionally_empty_module.js @@ -0,0 +1,18 @@ +/* + * 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. + */ diff --git a/src/legacy/core_plugins/navigation/index.ts b/src/optimize/np_ui_plugin_public_dirs.js similarity index 53% rename from src/legacy/core_plugins/navigation/index.ts rename to src/optimize/np_ui_plugin_public_dirs.js index 32d5f040760c6..de05fd2b863b8 100644 --- a/src/legacy/core_plugins/navigation/index.ts +++ b/src/optimize/np_ui_plugin_public_dirs.js @@ -17,26 +17,28 @@ * under the License. */ -import { resolve } from 'path'; -import { Legacy } from '../../../../kibana'; +export function getNpUiPluginPublicDirs(kbnServer) { + return Array.from(kbnServer.newPlatform.__internals.uiPlugins.internal.entries()).map( + ([id, { publicTargetDir }]) => ({ + id, + path: publicTargetDir, + }) + ); +} -// eslint-disable-next-line import/no-default-export -export default function NavigationPlugin(kibana: any) { - const config: Legacy.PluginSpecOptions = { - id: 'navigation', - require: [], - publicDir: resolve(__dirname, 'public'), - config: (Joi: any) => { - return Joi.object({ - enabled: Joi.boolean().default(true), - }).default(); - }, - init: (server: Legacy.Server) => ({}), - uiExports: { - injectDefaultVars: () => ({}), - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - }, - }; +export function isNpUiPluginPublicDirs(something) { + return ( + Array.isArray(something) && + something.every( + s => typeof s === 'object' && s && typeof s.id === 'string' && typeof s.path === 'string' + ) + ); +} - return new kibana.Plugin(config); +export function assertIsNpUiPluginPublicDirs(something) { + if (!isNpUiPluginPublicDirs(something)) { + throw new TypeError( + 'npUiPluginPublicDirs must be an array of objects with string `id` and `path` properties' + ); + } } diff --git a/src/optimize/watch/optmzr_role.js b/src/optimize/watch/optmzr_role.js index ed1c51f933eaa..a31ef7229e5da 100644 --- a/src/optimize/watch/optmzr_role.js +++ b/src/optimize/watch/optmzr_role.js @@ -23,6 +23,7 @@ import WatchServer from './watch_server'; import WatchOptimizer, { STATUS } from './watch_optimizer'; import { DllCompiler } from '../dynamic_dll_plugin'; import { WatchCache } from './watch_cache'; +import { getNpUiPluginPublicDirs } from '../np_ui_plugin_public_dirs'; export default async (kbnServer, kibanaHapiServer, config) => { const logWithMetadata = (tags, message, metadata) => @@ -31,7 +32,6 @@ export default async (kbnServer, kibanaHapiServer, config) => { const watchOptimizer = new WatchOptimizer({ logWithMetadata, uiBundles: kbnServer.uiBundles, - newPlatformPluginInfo: kbnServer.newPlatform.__internals.uiPlugins.internal, profile: config.get('optimize.profile'), sourceMaps: config.get('optimize.sourceMaps'), workers: config.get('optimize.workers'), @@ -48,7 +48,8 @@ export default async (kbnServer, kibanaHapiServer, config) => { config.get('optimize.watchHost'), config.get('optimize.watchPort'), config.get('server.basePath'), - watchOptimizer + watchOptimizer, + getNpUiPluginPublicDirs(kbnServer) ); watchOptimizer.status$.subscribe({ diff --git a/src/optimize/watch/watch_optimizer.js b/src/optimize/watch/watch_optimizer.js index a0595816f6a65..6c20f21c7768e 100644 --- a/src/optimize/watch/watch_optimizer.js +++ b/src/optimize/watch/watch_optimizer.js @@ -106,7 +106,7 @@ export default class WatchOptimizer extends BaseOptimizer { }); } - bindToServer(server, basePath) { + bindToServer(server, basePath, npUiPluginPublicDirs) { // pause all requests received while the compiler is running // and continue once an outcome is reached (aborting the request // with an error if it was a failure). @@ -117,6 +117,7 @@ export default class WatchOptimizer extends BaseOptimizer { server.route( createBundlesRoute({ + npUiPluginPublicDirs: npUiPluginPublicDirs, regularBundlesPath: this.compiler.outputPath, dllBundlesPath: DllCompiler.getRawDllConfig().outputPath, basePublicPath: basePath, diff --git a/src/optimize/watch/watch_server.js b/src/optimize/watch/watch_server.js index f21db0de61824..74a96dc8aea6e 100644 --- a/src/optimize/watch/watch_server.js +++ b/src/optimize/watch/watch_server.js @@ -21,9 +21,10 @@ import { Server } from 'hapi'; import { registerHapiPlugins } from '../../legacy/server/http/register_hapi_plugins'; export default class WatchServer { - constructor(host, port, basePath, optimizer) { + constructor(host, port, basePath, optimizer, npUiPluginPublicDirs) { this.basePath = basePath; this.optimizer = optimizer; + this.npUiPluginPublicDirs = npUiPluginPublicDirs; this.server = new Server({ host: host, port: port, @@ -34,7 +35,7 @@ export default class WatchServer { async init() { await this.optimizer.init(); - this.optimizer.bindToServer(this.server, this.basePath); + this.optimizer.bindToServer(this.server, this.basePath, this.npUiPluginPublicDirs); await this.server.start(); } } diff --git a/src/plugins/dashboard_embeddable_container/public/index.ts b/src/plugins/dashboard_embeddable_container/public/index.ts index 73597525105db..cd0b7d4157fa8 100644 --- a/src/plugins/dashboard_embeddable_container/public/index.ts +++ b/src/plugins/dashboard_embeddable_container/public/index.ts @@ -17,6 +17,8 @@ * under the License. */ +import './_index.scss'; + import { PluginInitializerContext } from '../../../core/public'; import { DashboardEmbeddableContainerPublicPlugin } from './plugin'; diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index 19ba246ce02dd..7bf5ae3e26fbb 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -17,6 +17,8 @@ * under the License. */ +import './_index.scss'; + import { PluginInitializerContext } from '../../../core/public'; import * as autocomplete from './autocomplete'; diff --git a/src/plugins/data/public/ui/filter_bar/filter_editor/_index.scss b/src/plugins/data/public/ui/filter_bar/filter_editor/_index.scss index 21ba32ec6a6fe..3d416aade9a53 100644 --- a/src/plugins/data/public/ui/filter_bar/filter_editor/_index.scss +++ b/src/plugins/data/public/ui/filter_bar/filter_editor/_index.scss @@ -1 +1 @@ -@import 'filter_editor'; \ No newline at end of file +@import 'filter_editor'; diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index 583b21ddfa433..8fb8c0f6c7ead 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -17,6 +17,8 @@ * under the License. */ +import './_index.scss'; + import { PluginInitializerContext } from 'src/core/public'; import { EmbeddablePublicPlugin } from './plugin'; diff --git a/src/plugins/expressions/public/index.ts b/src/plugins/expressions/public/index.ts index 951d643c9df68..3b6316379314e 100644 --- a/src/plugins/expressions/public/index.ts +++ b/src/plugins/expressions/public/index.ts @@ -17,6 +17,8 @@ * under the License. */ +import './_index.scss'; + import { PluginInitializerContext } from '../../../core/public'; import { ExpressionsPublicPlugin } from './plugin'; diff --git a/src/plugins/inspector/public/index.ts b/src/plugins/inspector/public/index.ts index ea3985563118b..d81bb0b99ed2c 100644 --- a/src/plugins/inspector/public/index.ts +++ b/src/plugins/inspector/public/index.ts @@ -17,6 +17,8 @@ * under the License. */ +import './views/_index.scss'; + import { PluginInitializerContext } from '../../../core/public'; import { InspectorPublicPlugin } from './plugin'; diff --git a/src/plugins/navigation/public/index.ts b/src/plugins/navigation/public/index.ts index 1c0a36c597ce7..f2dc3b9a84349 100644 --- a/src/plugins/navigation/public/index.ts +++ b/src/plugins/navigation/public/index.ts @@ -17,6 +17,8 @@ * under the License. */ +import './top_nav_menu/_index.scss'; + import { PluginInitializerContext } from '../../../core/public'; export function plugin(initializerContext: PluginInitializerContext) { return new NavigationPublicPlugin(initializerContext); diff --git a/test/functional/services/dashboard/add_panel.js b/test/functional/services/dashboard/add_panel.js index e390fd918eaee..91e7c15c4f1d9 100644 --- a/test/functional/services/dashboard/add_panel.js +++ b/test/functional/services/dashboard/add_panel.js @@ -54,14 +54,23 @@ export function DashboardAddPanelProvider({ getService, getPageObjects }) { async addEveryEmbeddableOnCurrentPage() { log.debug('addEveryEmbeddableOnCurrentPage'); const itemList = await testSubjects.find('savedObjectFinderItemList'); - const embeddableRows = await itemList.findAllByCssSelector('li'); const embeddableList = []; - for (let i = 0; i < embeddableRows.length; i++) { - embeddableList.push(await embeddableRows[i].getVisibleText()); - await embeddableRows[i].click(); - await PageObjects.common.closeToast(); - } - log.debug(`Added ${embeddableRows.length} embeddables`); + await retry.try(async () => { + const embeddableRows = await itemList.findAllByCssSelector('li'); + for (let i = 0; i < embeddableRows.length; i++) { + const name = await embeddableRows[i].getVisibleText(); + + if (embeddableList.includes(name)) { + // already added this one + continue; + } + + await embeddableRows[i].click(); + await PageObjects.common.closeToast(); + embeddableList.push(name); + } + }); + log.debug(`Added ${embeddableList.length} embeddables`); return embeddableList; } diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 643964999017f..24f7c19bd6419 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -62,8 +62,8 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider return JSON.parse(document.querySelector('kbn-injected-metadata')!.getAttribute('data')!) .legacyMetadata.uiSettings.user; }); - const exists = (selector: string) => testSubjects.exists(selector, { timeout: 2000 }); - const findLoadingMessage = () => testSubjects.find('kbnLoadingMessage', 5000); + const exists = (selector: string) => testSubjects.exists(selector); + const findLoadingMessage = () => testSubjects.find('kbnLoadingMessage'); describe('rendering service', () => { it('renders "core" application', async () => { diff --git a/test/scripts/jenkins_build_kibana.sh b/test/scripts/jenkins_build_kibana.sh index 2605655ed7e7a..1f7f021d961ce 100755 --- a/test/scripts/jenkins_build_kibana.sh +++ b/test/scripts/jenkins_build_kibana.sh @@ -2,6 +2,12 @@ source src/dev/ci_setup/setup_env.sh +echo " -> building new platform plugins" +node scripts/build_new_platform_plugins \ + --oss \ + --scan-dir "$KIBANA_DIR/test/plugin_functional/plugins" \ + --verbose; + echo " -> downloading es snapshot" node scripts/es snapshot --license=oss --download-only; diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh index 20b12b302cb39..016c7cfbec6ba 100755 --- a/test/scripts/jenkins_xpack_build_kibana.sh +++ b/test/scripts/jenkins_xpack_build_kibana.sh @@ -3,6 +3,11 @@ cd "$KIBANA_DIR" source src/dev/ci_setup/setup_env.sh +echo " -> building new platform plugins" +node scripts/build_new_platform_plugins \ + --scan-dir "$XPACK_DIR/test/plugin_functional/plugins" \ + --verbose; + echo " -> downloading es snapshot" node scripts/es snapshot --download-only; diff --git a/vars/kibanaPipeline.groovy b/vars/kibanaPipeline.groovy index 5c6be70514c61..f888710254baf 100644 --- a/vars/kibanaPipeline.groovy +++ b/vars/kibanaPipeline.groovy @@ -58,6 +58,7 @@ def getPostBuildWorker(name, closure) { "TEST_ES_URL=http://elastic:changeme@localhost:${esPort}", "TEST_ES_TRANSPORT_PORT=${esTransportPort}", "IS_PIPELINE_JOB=1", + "KBN_NP_PLUGINS_BUILT=true", ]) { closure() } diff --git a/x-pack/index.js b/x-pack/index.js index 83a7b5540334f..9068ca279d1ba 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -9,10 +9,8 @@ import { graph } from './legacy/plugins/graph'; import { monitoring } from './legacy/plugins/monitoring'; import { reporting } from './legacy/plugins/reporting'; import { security } from './legacy/plugins/security'; -import { searchprofiler } from './legacy/plugins/searchprofiler'; import { ml } from './legacy/plugins/ml'; import { tilemap } from './legacy/plugins/tilemap'; -import { watcher } from './legacy/plugins/watcher'; import { grokdebugger } from './legacy/plugins/grokdebugger'; import { dashboardMode } from './legacy/plugins/dashboard_mode'; import { logstash } from './legacy/plugins/logstash'; @@ -52,10 +50,8 @@ module.exports = function(kibana) { reporting(kibana), spaces(kibana), security(kibana), - searchprofiler(kibana), ml(kibana), tilemap(kibana), - watcher(kibana), grokdebugger(kibana), dashboardMode(kibana), logstash(kibana), diff --git a/x-pack/legacy/plugins/apm/cypress/package.json b/x-pack/legacy/plugins/apm/cypress/package.json index ef8955fcbd1b0..59f76ba250ad7 100644 --- a/x-pack/legacy/plugins/apm/cypress/package.json +++ b/x-pack/legacy/plugins/apm/cypress/package.json @@ -16,6 +16,6 @@ "p-limit": "^2.2.1", "ts-loader": "^6.1.0", "typescript": "3.7.2", - "webpack": "^4.40.2" + "webpack": "^4.41.5" } } diff --git a/x-pack/legacy/plugins/canvas/shareable_runtime/webpack.config.js b/x-pack/legacy/plugins/canvas/shareable_runtime/webpack.config.js index c711f9510a10b..0ce722eb90d43 100644 --- a/x-pack/legacy/plugins/canvas/shareable_runtime/webpack.config.js +++ b/x-pack/legacy/plugins/canvas/shareable_runtime/webpack.config.js @@ -99,16 +99,19 @@ module.exports = { { loader: 'css-loader', options: { - modules: true, - localIdentName: '[name]__[local]___[hash:base64:5]', - camelCase: true, + modules: { + localIdentName: '[name]__[local]___[hash:base64:5]', + }, + localsConvention: 'camelCase', sourceMap: !isProd, }, }, { loader: 'postcss-loader', options: { - path: path.resolve(KIBANA_ROOT, 'src/optimize/postcss.config.js'), + config: { + path: path.resolve(KIBANA_ROOT, 'src/optimize/postcss.config.js'), + }, }, }, { diff --git a/x-pack/legacy/plugins/searchprofiler/index.ts b/x-pack/legacy/plugins/searchprofiler/index.ts deleted file mode 100644 index fab2e43847348..0000000000000 --- a/x-pack/legacy/plugins/searchprofiler/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { resolve } from 'path'; - -// TODO: -// Until we can process SCSS in new platform, this part of Searchprofiler -// legacy must remain here. - -export const searchprofiler = (kibana: any) => { - const publicSrc = resolve(__dirname, 'public'); - - return new kibana.Plugin({ - require: ['elasticsearch', 'xpack_main'], - id: 'searchprofiler', - configPrefix: 'xpack.searchprofiler', - publicDir: publicSrc, - - uiExports: { - styleSheetPaths: `${publicSrc}/index.scss`, - }, - init() {}, - }); -}; diff --git a/x-pack/legacy/plugins/searchprofiler/public/index.scss b/x-pack/legacy/plugins/searchprofiler/public/index.scss deleted file mode 100644 index e04e81c023196..0000000000000 --- a/x-pack/legacy/plugins/searchprofiler/public/index.scss +++ /dev/null @@ -1,12 +0,0 @@ -// Import the EUI global scope so we can use EUI constants -@import 'src/legacy/ui/public/styles/_styling_constants'; - -// Search profiler plugin styles - -// Prefix all styles with "prfDevTool" to avoid conflicts. -// Examples -// prfDevTool__ -// prfDevTool__cell -// prfDevTool__shardDetails - -@import 'styles/index'; diff --git a/x-pack/legacy/plugins/security/public/index.scss b/x-pack/legacy/plugins/security/public/index.scss index 187ad5231534d..0050d01a52493 100644 --- a/x-pack/legacy/plugins/security/public/index.scss +++ b/x-pack/legacy/plugins/security/public/index.scss @@ -7,14 +7,9 @@ // secChart__legend--small // secChart__legend-isLoading -$secFormWidth: 460px; - // Public components @import './components/index'; // Public views @import './views/index'; -// Styles of Kibana Platform plugin -@import '../../../../plugins/security/public/index'; - diff --git a/x-pack/legacy/plugins/watcher/index.ts b/x-pack/legacy/plugins/watcher/index.ts deleted file mode 100644 index fdf9ba1bad6e4..0000000000000 --- a/x-pack/legacy/plugins/watcher/index.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ -import { resolve } from 'path'; - -const pluginDefinition = { - id: 'watcher', - configPrefix: 'xpack.watcher', - publicDir: resolve(__dirname, 'public'), - require: ['kibana'], - uiExports: { - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - }, - init(server: any) {}, -}; - -export const watcher = (kibana: any) => new kibana.Plugin(pluginDefinition); diff --git a/x-pack/package.json b/x-pack/package.json index ad0be351483f6..77e4cfe8da609 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -153,7 +153,7 @@ "react-docgen-typescript-loader": "^3.1.1", "react-test-renderer": "^16.12.0", "rxjs-marbles": "^5.0.3", - "sass-loader": "^7.3.1", + "sass-loader": "^8.0.2", "sass-resources-loader": "^2.0.1", "simple-git": "1.116.0", "sinon": "^7.4.2", @@ -345,7 +345,7 @@ "uuid": "3.3.2", "venn.js": "0.2.20", "vscode-languageserver": "^5.2.1", - "webpack": "4.41.0", + "webpack": "^4.41.5", "wellknown": "^0.5.0", "xml2js": "^0.4.22", "xregexp": "4.2.4" diff --git a/x-pack/plugins/searchprofiler/public/README.md b/x-pack/plugins/searchprofiler/public/README.md deleted file mode 100644 index 3cf79162b3965..0000000000000 --- a/x-pack/plugins/searchprofiler/public/README.md +++ /dev/null @@ -1,3 +0,0 @@ -## Please note - -See x-pack/legacy/plugins/searchprofiler/public for styles. diff --git a/x-pack/plugins/searchprofiler/public/index.ts b/x-pack/plugins/searchprofiler/public/index.ts index 3d77f703b42cd..33952a747018e 100644 --- a/x-pack/plugins/searchprofiler/public/index.ts +++ b/x-pack/plugins/searchprofiler/public/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import './styles/_index.scss'; import { PluginInitializerContext } from 'src/core/public'; import { SearchProfilerUIPlugin } from './plugin'; diff --git a/x-pack/legacy/plugins/searchprofiler/public/styles/_index.scss b/x-pack/plugins/searchprofiler/public/styles/_index.scss similarity index 100% rename from x-pack/legacy/plugins/searchprofiler/public/styles/_index.scss rename to x-pack/plugins/searchprofiler/public/styles/_index.scss diff --git a/x-pack/legacy/plugins/searchprofiler/public/styles/_mixins.scss b/x-pack/plugins/searchprofiler/public/styles/_mixins.scss similarity index 100% rename from x-pack/legacy/plugins/searchprofiler/public/styles/_mixins.scss rename to x-pack/plugins/searchprofiler/public/styles/_mixins.scss diff --git a/x-pack/legacy/plugins/searchprofiler/public/styles/components/_highlight_details_flyout.scss b/x-pack/plugins/searchprofiler/public/styles/components/_highlight_details_flyout.scss similarity index 100% rename from x-pack/legacy/plugins/searchprofiler/public/styles/components/_highlight_details_flyout.scss rename to x-pack/plugins/searchprofiler/public/styles/components/_highlight_details_flyout.scss diff --git a/x-pack/legacy/plugins/searchprofiler/public/styles/components/_percentage_badge.scss b/x-pack/plugins/searchprofiler/public/styles/components/_percentage_badge.scss similarity index 100% rename from x-pack/legacy/plugins/searchprofiler/public/styles/components/_percentage_badge.scss rename to x-pack/plugins/searchprofiler/public/styles/components/_percentage_badge.scss diff --git a/x-pack/legacy/plugins/searchprofiler/public/styles/components/_profile_tree.scss b/x-pack/plugins/searchprofiler/public/styles/components/_profile_tree.scss similarity index 100% rename from x-pack/legacy/plugins/searchprofiler/public/styles/components/_profile_tree.scss rename to x-pack/plugins/searchprofiler/public/styles/components/_profile_tree.scss diff --git a/x-pack/legacy/plugins/searchprofiler/public/styles/containers/_main.scss b/x-pack/plugins/searchprofiler/public/styles/containers/_main.scss similarity index 100% rename from x-pack/legacy/plugins/searchprofiler/public/styles/containers/_main.scss rename to x-pack/plugins/searchprofiler/public/styles/containers/_main.scss diff --git a/x-pack/legacy/plugins/searchprofiler/public/styles/containers/_profile_query_editor.scss b/x-pack/plugins/searchprofiler/public/styles/containers/_profile_query_editor.scss similarity index 100% rename from x-pack/legacy/plugins/searchprofiler/public/styles/containers/_profile_query_editor.scss rename to x-pack/plugins/searchprofiler/public/styles/containers/_profile_query_editor.scss diff --git a/x-pack/plugins/security/public/_index.scss b/x-pack/plugins/security/public/_index.scss index 9fa81bad7c3f4..1bdb8cc178fdf 100644 --- a/x-pack/plugins/security/public/_index.scss +++ b/x-pack/plugins/security/public/_index.scss @@ -1,2 +1,4 @@ +$secFormWidth: 460px; + // Management styles @import './management/index'; diff --git a/x-pack/plugins/security/public/index.ts b/x-pack/plugins/security/public/index.ts index 336ec37d76a1b..e298130e3a727 100644 --- a/x-pack/plugins/security/public/index.ts +++ b/x-pack/plugins/security/public/index.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import './_index.scss'; import { PluginInitializer } from 'src/core/public'; import { SecurityPlugin, SecurityPluginSetup, SecurityPluginStart } from './plugin'; diff --git a/x-pack/legacy/plugins/watcher/public/index.scss b/x-pack/plugins/watcher/public/index.scss similarity index 80% rename from x-pack/legacy/plugins/watcher/public/index.scss rename to x-pack/plugins/watcher/public/index.scss index 33ebf21326c7b..101db14aee9e6 100644 --- a/x-pack/legacy/plugins/watcher/public/index.scss +++ b/x-pack/plugins/watcher/public/index.scss @@ -1,6 +1,3 @@ -// Import the EUI global scope so we can use EUI constants -@import 'src/legacy/ui/public/styles/_styling_constants'; - // Watcher plugin styles // Prefix all styles with "watcher" to avoid conflicts. diff --git a/x-pack/plugins/watcher/public/index.ts b/x-pack/plugins/watcher/public/index.ts index ff635579316e5..783668285e74a 100644 --- a/x-pack/plugins/watcher/public/index.ts +++ b/x-pack/plugins/watcher/public/index.ts @@ -3,6 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ + +import './index.scss'; import { WatcherUIPlugin } from './plugin'; export const plugin = () => new WatcherUIPlugin(); diff --git a/yarn.lock b/yarn.lock index 3563ee3fc2733..60ffa6144125b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4087,6 +4087,11 @@ resolved "https://registry.yarnpkg.com/@types/angular/-/angular-1.6.56.tgz#20124077bd44061e018c7283c0bb83f4b00322dd" integrity sha512-HxtqilvklZ7i6XOaiP7uIJIrFXEVEhfbSY45nfv2DeBRngncI58Y4ZOUMiUkcT8sqgLL1ablmbfylChUg7A3GA== +"@types/anymatch@*": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" + integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== + "@types/archiver@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-3.0.0.tgz#c0a53e0ed3b7aef626ce683d081d7821d8c638b4" @@ -4199,6 +4204,11 @@ resolved "https://registry.yarnpkg.com/@types/boom/-/boom-7.2.1.tgz#a21e21ba08cc49d17b26baef98e1a77ee4d6cdb0" integrity sha512-kOiap+kSa4DPoookJXQGQyKy1rjZ55tgfKAh9F0m1NUdukkcwVzpSnXPMH42a5L+U++ugdQlh/xFJu/WAdr1aw== +"@types/browserslist-useragent@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/browserslist-useragent/-/browserslist-useragent-3.0.0.tgz#d425c9818182ce71ce53866798cee9c7d41d6e53" + integrity sha512-ZBvKzg3yyWNYEkwxAzdmUzp27sFvw+1m080/+2lwrt+eltNefn1f4fnpMyrjOla31p8zLleCYqQXw+3EETfn0w== + "@types/caseless@*": version "0.12.2" resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" @@ -4674,6 +4684,14 @@ "@types/node" "*" rxjs "^6.5.1" +"@types/loader-utils@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@types/loader-utils/-/loader-utils-1.1.3.tgz#82b9163f2ead596c68a8c03e450fbd6e089df401" + integrity sha512-euKGFr2oCB3ASBwG39CYJMR3N9T0nanVqXdiH7Zu/Nqddt6SmFRxytq/i2w9LQYNQekEtGBz+pE3qG6fQTNvRg== + dependencies: + "@types/node" "*" + "@types/webpack" "*" + "@types/lodash.clonedeep@^4.5.4": version "4.5.4" resolved "https://registry.yarnpkg.com/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.4.tgz#2515c5f08bc95afebfb597711871b0497f5d7da7" @@ -5064,13 +5082,6 @@ dependencies: "@types/normalize-package-data" "*" -"@types/recompose@^0.30.5": - version "0.30.5" - resolved "https://registry.yarnpkg.com/@types/recompose/-/recompose-0.30.5.tgz#09890e3c504546b38193479e610e427ac0888393" - integrity sha512-PEQvFmudB9n0+ZvD8l7lh0olGAWmVAuVwCM4eotzWouH8/Kcr8/EcZyLhYILqoTlqzi6ey/3kbKQzJ/h3KkyXw== - dependencies: - "@types/react" "*" - "@types/recompose@^0.30.6": version "0.30.6" resolved "https://registry.yarnpkg.com/@types/recompose/-/recompose-0.30.6.tgz#f6ffae2008b84df916ed6633751f9287f344ea3e" @@ -5132,6 +5143,11 @@ resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47" integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg== +"@types/source-list-map@*": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" + integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== + "@types/stack-utils@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" @@ -5197,6 +5213,11 @@ dependencies: "@types/superagent" "*" +"@types/tapable@*": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" + integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== + "@types/tar-fs@^1.16.1": version "1.16.1" resolved "https://registry.yarnpkg.com/@types/tar-fs/-/tar-fs-1.16.1.tgz#6e3fba276c173e365ae91e55f7b797a0e64298e5" @@ -5252,6 +5273,13 @@ resolved "https://registry.yarnpkg.com/@types/type-detect/-/type-detect-4.0.1.tgz#3b0f5ac82ea630090cbf57c57a1bf5a63a29b9b6" integrity sha512-0+S1S9Iq0oJ9w9IaBC5W/z1WsPNDUIAJG+THGmqR4vUAxUPCzIY+dApTvyGsaBUWjafTDL0Dg8Z9+iRuk3/BQA== +"@types/uglify-js@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" + integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ== + dependencies: + source-map "^0.6.1" + "@types/undertaker-registry@*": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/undertaker-registry/-/undertaker-registry-1.0.1.tgz#4306d4a03d7acedb974b66530832b90729e1d1da" @@ -5319,6 +5347,27 @@ resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.14.1.tgz#0d8a53f308f017c53a5ddc3d07f4d6fa76b790d7" integrity sha512-0Ki9jAAhKDSuLDXOIMADg54Hu60SuBTEsWaJGGy5cV+SSUQ63J2a+RrYYGrErzz39fXzTibhKrAQJAb8M7PNcA== +"@types/webpack-sources@*": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" + integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== + dependencies: + "@types/node" "*" + "@types/source-list-map" "*" + source-map "^0.6.1" + +"@types/webpack@*", "@types/webpack@^4.4.31", "@types/webpack@^4.41.3": + version "4.41.3" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.3.tgz#30c2251db1d69a45bbffd79c0577dd9baf50e7ba" + integrity sha512-dH+BZ6pHBZFrXpnif0YU/PbmUq3lQrvRPnqkxsciSIzvG/DE+Vm/Wrjn56T7V3+B5ryQa5fw0oGnHL8tk4ll6w== + dependencies: + "@types/anymatch" "*" + "@types/node" "*" + "@types/tapable" "*" + "@types/uglify-js" "*" + "@types/webpack-sources" "*" + source-map "^0.6.0" + "@types/wrap-ansi@^2.0.15": version "2.0.15" resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-2.0.15.tgz#87affc11a46864cb6853b642e89363633d544aa7" @@ -5684,11 +5733,6 @@ accepts@~1.3.7: mime-types "~2.1.24" negotiator "0.6.2" -acorn-dynamic-import@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz#482210140582a36b83c3e342e1cfebcaa9240948" - integrity sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw== - acorn-globals@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" @@ -5763,11 +5807,6 @@ acorn@^6.0.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.1.tgz#7d25ae05bb8ad1f9b699108e1094ecd7884adc1f" integrity sha512-jPTiwtOxaHNaAPg/dmrJ/beuzLRnXtB0kQPQ8JpotKJgTB6rX6c8mlf315941pyjBSaPg8NHXS9fhP4u17DpGA== -acorn@^6.0.5: - version "6.4.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784" - integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw== - acorn@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" @@ -6949,18 +6988,18 @@ autobind-decorator@^1.3.4: resolved "https://registry.yarnpkg.com/autobind-decorator/-/autobind-decorator-1.4.3.tgz#4c96ffa77b10622ede24f110f5dbbf56691417d1" integrity sha1-TJb/p3sQYi7eJPEQ9du/VmkUF9E= -autoprefixer@9.6.1, autoprefixer@^9.4.9: - version "9.6.1" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.6.1.tgz#51967a02d2d2300bb01866c1611ec8348d355a47" - integrity sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw== +autoprefixer@^9.4.9, autoprefixer@^9.7.4: + version "9.7.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.4.tgz#f8bf3e06707d047f0641d87aee8cfb174b2a5378" + integrity sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g== dependencies: - browserslist "^4.6.3" - caniuse-lite "^1.0.30000980" + browserslist "^4.8.3" + caniuse-lite "^1.0.30001020" chalk "^2.4.2" normalize-range "^0.1.2" num2fraction "^1.2.2" - postcss "^7.0.17" - postcss-value-parser "^4.0.0" + postcss "^7.0.26" + postcss-value-parser "^4.0.2" await-event@^2.1.0: version "2.1.0" @@ -7682,11 +7721,6 @@ big-time@2.x.x: resolved "https://registry.yarnpkg.com/big-time/-/big-time-2.0.1.tgz#68c7df8dc30f97e953f25a67a76ac9713c16c9de" integrity sha1-aMffjcMPl+lT8lpnp2rJcTwWyd4= -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== - big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -8141,6 +8175,15 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" +browserslist-useragent@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/browserslist-useragent/-/browserslist-useragent-3.0.2.tgz#f0e209b2742baa5de0e451b52e678e8b4402617c" + integrity sha512-/UPzK9xZnk5mwwWx4wcuBKAKx/mD3MNY8sUuZ2NPqnr4RVFWZogX+8mOP0cQEYo8j78sHk0hiDNaVXZ1U3hM9A== + dependencies: + browserslist "^4.6.6" + semver "^6.3.0" + useragent "^2.3.0" + browserslist@4.6.6: version "4.6.6" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.6.tgz#6e4bf467cde520bc9dbdf3747dafa03531cec453" @@ -8150,14 +8193,14 @@ browserslist@4.6.6: electron-to-chromium "^1.3.191" node-releases "^1.1.25" -browserslist@^4.6.0, browserslist@^4.6.3: - version "4.6.4" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.4.tgz#fd0638b3f8867fec2c604ed0ed9300379f8ec7c2" - integrity sha512-ErJT8qGfRt/VWHSr1HeqZzz50DvxHtr1fVL1m5wf20aGrG8e1ce8fpZ2EjZEfs09DDZYSvtRaDlMpWslBf8Low== +browserslist@^4.6.0, browserslist@^4.6.6, browserslist@^4.8.3: + version "4.8.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.5.tgz#691af4e327ac877b25e7a3f7ee869c4ef36cdea3" + integrity sha512-4LMHuicxkabIB+n9874jZX/az1IaZ5a+EUuvD7KFOu9x/Bd5YHyO0DIz2ls/Kl8g0ItS4X/ilEgf4T1Br0lgSg== dependencies: - caniuse-lite "^1.0.30000981" - electron-to-chromium "^1.3.188" - node-releases "^1.1.25" + caniuse-lite "^1.0.30001022" + electron-to-chromium "^1.3.338" + node-releases "^1.1.46" bser@^2.0.0: version "2.0.0" @@ -8341,7 +8384,7 @@ cacache@^12.0.2: unique-filename "^1.1.1" y18n "^4.0.0" -cacache@^13.0.0: +cacache@^13.0.1: version "13.0.1" resolved "https://registry.yarnpkg.com/cacache/-/cacache-13.0.1.tgz#a8000c21697089082f85287a1aec6e382024a71c" integrity sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w== @@ -8546,11 +8589,6 @@ camelcase@^5.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.0.0.tgz#03295527d58bd3cd4aa75363f35b2e8d97be2f42" integrity sha512-faqwZqnWxbxn+F1d399ygeamQNy3lPp/H9H6rNrqYh4FSVCtcY+3cub1MxA8o9mDd55mM8Aghuu/kuyYA6VTsA== -camelcase@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.2.0.tgz#e7522abda5ed94cc0489e1b8466610e88404cf45" - integrity sha512-IXFsBS2pC+X0j0N/GE7Dm7j3bsEBp+oTpb7F50dwEVX7rf3IgwO9XatnegTsDtniKCUtEJH4fSU6Asw7uoVLfQ== - camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -8566,10 +8604,10 @@ can-use-dom@^0.1.0: resolved "https://registry.yarnpkg.com/can-use-dom/-/can-use-dom-0.1.0.tgz#22cc4a34a0abc43950f42c6411024a3f6366b45a" integrity sha1-IsxKNKCrxDlQ9CxkEQJKP2NmtFo= -caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000984: - version "1.0.30001016" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz#16ea48d7d6e8caf3cad3295c2d746fe38c4e7f66" - integrity sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA== +caniuse-lite@^1.0.30000984, caniuse-lite@^1.0.30001020, caniuse-lite@^1.0.30001022: + version "1.0.30001022" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001022.tgz#9eeffe580c3a8f110b7b1742dcf06a395885e4c6" + integrity sha512-FjwPPtt/I07KyLPkBQ0g7/XuZg6oUkYBVnPHNj3VHJbOjmmJ/GdSo/GUY6MwINEQvjhP6WZVbX8Tvms8xh0D5A== capture-exit@^2.0.0: version "2.0.0" @@ -8929,7 +8967,7 @@ chroma-js@^2.0.4: dependencies: cross-env "^6.0.3" -chrome-trace-event@^1.0.0, chrome-trace-event@^1.0.2: +chrome-trace-event@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== @@ -9025,6 +9063,14 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.1.0.tgz#9e7fec7f3f8340a2ab4f127c80273085e8fbbdd0" integrity sha512-uQWrpRm+iZZUCAp7ZZJQbd4Za9I3AjR/3YTjmcnAtkauaIm/T5CT6U8zVI6e60T6OANqBFAzuR9/HB3NzuZCRA== +clean-webpack-plugin@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/clean-webpack-plugin/-/clean-webpack-plugin-3.0.0.tgz#a99d8ec34c1c628a4541567aa7b457446460c62b" + integrity sha512-MciirUH5r+cYLGCOL5JX/ZLzOZbVr1ot3Fw+KcvbhUb6PM+yycqd9ZhIlcigQ5gl+XhppNmw3bEFuaaMNyLj3A== + dependencies: + "@types/webpack" "^4.4.31" + del "^4.1.1" + cli-boxes@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" @@ -9966,7 +10012,7 @@ cosmiconfig@^5.2.0: js-yaml "^3.13.1" parse-json "^4.0.0" -cp-file@^6.1.0, cp-file@^6.2.0: +cp-file@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-6.2.0.tgz#40d5ea4a1def2a9acdd07ba5c0b0246ef73dc10d" integrity sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA== @@ -9977,15 +10023,28 @@ cp-file@^6.1.0, cp-file@^6.2.0: pify "^4.0.1" safe-buffer "^5.0.1" -cpy@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/cpy/-/cpy-7.3.0.tgz#62f2847986b4ff9d029710568a49e9a9ab5a210e" - integrity sha512-auvDu6h/J+cO1uqV40ymL/VoPM0+qPpNGaNttTzkYVXO/+GeynuyAK/MwFcWgU/P82ezcZw7RaN34CIIWajKLA== +cp-file@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" + integrity sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw== dependencies: - arrify "^1.0.1" - cp-file "^6.1.0" + graceful-fs "^4.1.2" + make-dir "^3.0.0" + nested-error-stacks "^2.0.0" + p-event "^4.1.0" + +cpy@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/cpy/-/cpy-8.0.0.tgz#8195db0db19a9ea6aa4f229784cbf3e3f53c3158" + integrity sha512-iTjLUqtVr45e17GFAyxA0lqFinbGMblMCTtAqrPzT/IETNtDuyyhDDk8weEZ08MiCc6EcuyNq2KtGH5J2BIAoQ== + dependencies: + arrify "^2.0.1" + cp-file "^7.0.0" globby "^9.2.0" + is-glob "^4.0.1" + junk "^3.1.0" nested-error-stacks "^2.1.0" + p-all "^2.1.0" crc32-stream@^3.0.1: version "3.0.1" @@ -10263,40 +10322,23 @@ css-in-js-utils@^2.0.0: hyphenate-style-name "^1.0.2" isobject "^3.0.1" -css-loader@2.1.1, css-loader@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-2.1.1.tgz#d8254f72e412bb2238bb44dd674ffbef497333ea" - integrity sha512-OcKJU/lt232vl1P9EEDamhoO9iKY3tIjY5GU+XDLblAykTdgs6Ux9P1hTHve8nFKy5KPpOXOsVI/hIwi3841+w== - dependencies: - camelcase "^5.2.0" - icss-utils "^4.1.0" - loader-utils "^1.2.3" - normalize-path "^3.0.0" - postcss "^7.0.14" - postcss-modules-extract-imports "^2.0.0" - postcss-modules-local-by-default "^2.0.6" - postcss-modules-scope "^2.1.0" - postcss-modules-values "^2.0.0" - postcss-value-parser "^3.3.0" - schema-utils "^1.0.0" - -css-loader@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.2.0.tgz#bb570d89c194f763627fcf1f80059c6832d009b2" - integrity sha512-QTF3Ud5H7DaZotgdcJjGMvyDj5F3Pn1j/sC6VBEOVp94cbwqyIBdcs/quzj4MC1BKQSrTpQznegH/5giYbhnCQ== +css-loader@^3.0.0, css-loader@^3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.4.2.tgz#d3fdb3358b43f233b78501c5ed7b1c6da6133202" + integrity sha512-jYq4zdZT0oS0Iykt+fqnzVLRIeiPWhka+7BqPn+oSIpWJAHak5tmB/WZrJ2a21JhCeFyNnnlroSl8c+MtVndzA== dependencies: camelcase "^5.3.1" cssesc "^3.0.0" icss-utils "^4.1.1" loader-utils "^1.2.3" normalize-path "^3.0.0" - postcss "^7.0.17" + postcss "^7.0.23" postcss-modules-extract-imports "^2.0.0" postcss-modules-local-by-default "^3.0.2" - postcss-modules-scope "^2.1.0" + postcss-modules-scope "^2.1.1" postcss-modules-values "^3.0.0" - postcss-value-parser "^4.0.0" - schema-utils "^2.0.0" + postcss-value-parser "^4.0.2" + schema-utils "^2.6.0" css-select-base-adapter@^0.1.1: version "0.1.1" @@ -11894,15 +11936,10 @@ elasticsearch@^16.4.0, elasticsearch@^16.5.0: chalk "^1.0.0" lodash "^4.17.10" -electron-to-chromium@^1.3.188: - version "1.3.190" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.190.tgz#5bf599519983bfffd9d4387817039a3ed7ca085f" - integrity sha512-cs9WnTnGBGnYYVFMCtLmr9jXNTOkdp95RLz5VhwzDn7dErg1Lnt9o4d01gEH69XlmRKWUr91Yu1hA+Hi8qW0PA== - -electron-to-chromium@^1.3.191: - version "1.3.246" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.246.tgz#38c30a380398b293f39a19d4346f18e2cb376b72" - integrity sha512-CzR7VM16UmZQVgd5I5qu/rx0e67l6FF17rpJD2kRFX9n1ygHFIS+TV9DO55MSZKBGVuQ0Ph1JLLTFEReCKU6nQ== +electron-to-chromium@^1.3.191, electron-to-chromium@^1.3.338: + version "1.3.340" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.340.tgz#5d4fe78e984d4211194cf5a52e08069543da146f" + integrity sha512-hRFBAglhcj5iVYH+o8QU0+XId1WGoc0VGowJB1cuJAt3exHGrivZvWeAO5BRgBZqwZtwxjm8a5MQeGoT/Su3ww== elegant-spinner@^1.0.1: version "1.0.1" @@ -12612,7 +12649,7 @@ eslint-rule-composer@^0.3.0: resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== -eslint-scope@^4.0.0, eslint-scope@^4.0.3: +eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== @@ -13701,16 +13738,7 @@ finalhandler@~1.1.2: statuses "~1.5.0" unpipe "~1.0.0" -find-cache-dir@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.0.0.tgz#4c1faed59f45184530fb9d7fa123a4d04a98472d" - integrity sha512-LDUY6V1Xs5eFskUVYtIwatojt6+9xC9Chnlk/jYOOvn3FAFfSaWddxahDGyNHh0b2dMXa6YW2m0tk8TdVaXHlA== - dependencies: - commondir "^1.0.1" - make-dir "^1.0.0" - pkg-dir "^3.0.0" - -find-cache-dir@^2.1.0: +find-cache-dir@^2.0.0, find-cache-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== @@ -13719,10 +13747,10 @@ find-cache-dir@^2.1.0: make-dir "^2.0.0" pkg-dir "^3.0.0" -find-cache-dir@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.0.0.tgz#cd4b7dd97b7185b7e17dbfe2d6e4115ee3eeb8fc" - integrity sha512-t7ulV1fmbxh5G9l/492O1p5+EBbr3uwpt6odhFTMc+nWyhmbloe+ja9BZ8pIBtqFWhOmCWVjx+pTW4zDkFoclw== +find-cache-dir@^3.0.0, find-cache-dir@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.2.0.tgz#e7fe44c1abc1299f516146e563108fd1006c1874" + integrity sha512-1JKclkYYsf1q9WIJKLZa9S9muC+08RIjzAlLrK4QcYLJMS6mk9yombQ9qf+zJ7H9LS800k0s44L4sDq9VYzqyg== dependencies: commondir "^1.0.1" make-dir "^3.0.0" @@ -16320,11 +16348,6 @@ iconv-lite@^0.5.0: dependencies: safer-buffer ">= 2.1.2 < 3" -icss-replace-symbols@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" - integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= - icss-utils@^4.0.0, icss-utils@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" @@ -16332,13 +16355,6 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" -icss-utils@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.0.tgz#339dbbffb9f8729a243b701e1c29d4cc58c52f0e" - integrity sha512-3DEun4VOeMvSczifM3F2cKQrDQ5Pj6WKhkOq6HD4QTnDUAq8MQRxy5TX6Sy1iY6WPBe4gQ3p5vTECjbIkglkkQ== - dependencies: - postcss "^7.0.14" - idx@^2.5.6: version "2.5.6" resolved "https://registry.yarnpkg.com/idx/-/idx-2.5.6.tgz#1f824595070100ae9ad585c86db08dc74f83a59d" @@ -16772,16 +16788,11 @@ internal-ip@^4.3.0: default-gateway "^4.2.0" ipaddr.js "^1.9.0" -interpret@1.2.0, interpret@^1.1.0, interpret@^1.2.0: +interpret@1.2.0, interpret@^1.0.0, interpret@^1.1.0, interpret@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== -interpret@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.1.0.tgz#7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614" - integrity sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ= - intl-format-cache@^2.0.5, intl-format-cache@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/intl-format-cache/-/intl-format-cache-2.1.0.tgz#04a369fecbfad6da6005bae1f14333332dcf9316" @@ -17342,10 +17353,10 @@ is-path-inside@^2.1.0: dependencies: path-is-inside "^1.0.2" -is-path-inside@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.1.tgz#7417049ed551d053ab82bba3fdd6baa6b3a81e89" - integrity sha512-CKstxrctq1kUesU6WhtZDbYKzzYBuRH0UYInAVrkc/EYdB9ltbfE0gOoayG9nhohG6447sOOVGhHqsdmBvkbNg== +is-path-inside@^3.0.1, is-path-inside@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" + integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: version "1.1.0" @@ -17623,7 +17634,7 @@ isstream@0.1.x, isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul-instrumenter-loader@3.0.1: +istanbul-instrumenter-loader@3.0.1, istanbul-instrumenter-loader@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz#9957bd59252b373fae5c52b7b5188e6fde2a0949" integrity sha512-a5SPObZgS0jB/ixaKSMdn6n/gXSrK2S6q/UfRJBT3e6gQmVjwZROTODQsYW5ZNwOu78hG62Y3fWlebaVOL0C+w== @@ -18438,11 +18449,6 @@ json3@^3.3.2: resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" integrity sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= -json5@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -18614,6 +18620,11 @@ jszip@^3.1.5: readable-stream "~2.3.6" set-immediate-shim "~1.0.1" +junk@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" + integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== + just-curry-it@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/just-curry-it/-/just-curry-it-3.1.0.tgz#ab59daed308a58b847ada166edd0a2d40766fbc5" @@ -19280,12 +19291,12 @@ load-source-map@^1.0.0: semver "^5.3.0" source-map "^0.5.6" -loader-runner@^2.3.0, loader-runner@^2.3.1, loader-runner@^2.4.0: +loader-runner@^2.3.1, loader-runner@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== -loader-utils@1.2.3, loader-utils@^1.0.4, loader-utils@^1.2.3: +loader-utils@1.2.3, loader-utils@^1.0.0, loader-utils@^1.0.2, loader-utils@^1.0.4, loader-utils@^1.1.0, loader-utils@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== @@ -19294,15 +19305,6 @@ loader-utils@1.2.3, loader-utils@^1.0.4, loader-utils@^1.2.3: emojis-list "^2.0.0" json5 "^1.0.1" -loader-utils@^1.0.0, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" - integrity sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0= - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - locate-path@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" @@ -19371,7 +19373,7 @@ lodash.clone@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" integrity sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y= -lodash.clonedeep@^4.3.2, lodash.clonedeep@^4.5.0: +lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= @@ -19516,11 +19518,6 @@ lodash.merge@^4.4.0, lodash.merge@^4.6.1: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.mergewith@^4.6.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" - integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== - lodash.omit@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" @@ -20203,10 +20200,10 @@ memoizerific@^1.11.3: memory-fs@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" integrity sha1-8rslNovBIeORwlIN6Slpyu4KApA= -memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1: +memory-fs@^0.4.0, memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= @@ -20310,7 +20307,7 @@ microevent.ts@~0.1.1: resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g== -micromatch@3.1.10, micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8: +micromatch@3.1.10, micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -20947,10 +20944,10 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.10.0, nan@^2.9.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" - integrity sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA== +nan@^2.13.2, nan@^2.9.2: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== nano-css@^5.2.1: version "5.2.1" @@ -21282,7 +21279,7 @@ node-jose@1.1.0: util "^0.11.0" vm-browserify "0.0.4" -node-libs-browser@^2.0.0, node-libs-browser@^2.2.1: +node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== @@ -21343,17 +21340,17 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-releases@^1.1.25: - version "1.1.25" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.25.tgz#0c2d7dbc7fed30fbe02a9ee3007b8c90bf0133d3" - integrity sha512-fI5BXuk83lKEoZDdH3gRhtsNgh05/wZacuXkgbiYkceE7+QIMXOg98n9ZV7mz27B+kFHnqHcUpscZZlGRSmTpQ== +node-releases@^1.1.25, node-releases@^1.1.46: + version "1.1.47" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.47.tgz#c59ef739a1fd7ecbd9f0b7cf5b7871e8a8b591e4" + integrity sha512-k4xjVPx5FpwBUj0Gw7uvFOTF4Ep8Hok1I6qjwL3pLfwe7Y0REQSAqOwwv9TWBCUtMHxcXfY4PgRLRozcChvTcA== dependencies: - semver "^5.3.0" + semver "^6.3.0" -node-sass@^4.9.4: - version "4.9.4" - resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.9.4.tgz#349bd7f1c89422ffe7e1e4b60f2055a69fbc5512" - integrity sha512-MXyurANsUoE4/6KmfMkwGcBzAnJQ5xJBGW7Ei6ea8KnUKuzHr/SguVBIi3uaUAHtZCPUYkvlJ3Ef5T5VAwVpaA== +node-sass@^4.13.0, node-sass@^4.9.4: + version "4.13.1" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.13.1.tgz#9db5689696bb2eec2c32b98bfea4c7a2e992d0a3" + integrity sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw== dependencies: async-foreach "^0.1.3" chalk "^1.1.1" @@ -21362,12 +21359,10 @@ node-sass@^4.9.4: get-stdin "^4.0.1" glob "^7.0.3" in-publish "^2.0.0" - lodash.assign "^4.2.0" - lodash.clonedeep "^4.3.2" - lodash.mergewith "^4.6.0" + lodash "^4.17.15" meow "^3.7.0" mkdirp "^0.5.1" - nan "^2.10.0" + nan "^2.13.2" node-gyp "^3.8.0" npmlog "^4.0.0" request "^2.88.0" @@ -22149,6 +22144,13 @@ output-file-sync@^2.0.0: is-plain-obj "^1.1.0" mkdirp "^0.5.1" +p-all@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-all/-/p-all-2.1.0.tgz#91419be56b7dee8fe4c5db875d55e0da084244a0" + integrity sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA== + dependencies: + p-map "^2.0.0" + p-any@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/p-any/-/p-any-1.1.0.tgz#1d03835c7eed1e34b8e539c47b7b60d0d015d4e1" @@ -22178,6 +22180,13 @@ p-each-series@^1.0.0: dependencies: p-reduce "^1.0.0" +p-event@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.1.0.tgz#e92bb866d7e8e5b732293b1c8269d38e9982bf8e" + integrity sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA== + dependencies: + p-timeout "^2.0.1" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -23047,7 +23056,7 @@ postcss-load-config@^2.0.0: cosmiconfig "^4.0.0" import-cwd "^2.0.0" -postcss-loader@3.0.0, postcss-loader@^3.0.0: +postcss-loader@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-3.0.0.tgz#6b97943e47c72d845fa9e03f273773d4e8dd6c2d" integrity sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA== @@ -23064,15 +23073,6 @@ postcss-modules-extract-imports@^2.0.0: dependencies: postcss "^7.0.5" -postcss-modules-local-by-default@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-2.0.6.tgz#dd9953f6dd476b5fd1ef2d8830c8929760b56e63" - integrity sha512-oLUV5YNkeIBa0yQl7EYnxMgy4N6noxmiwZStaEJUSe2xPMcdNc8WmBQuQCx18H5psYbVxz8zoHk0RAAYZXP9gA== - dependencies: - postcss "^7.0.6" - postcss-selector-parser "^6.0.0" - postcss-value-parser "^3.3.1" - postcss-modules-local-by-default@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915" @@ -23083,22 +23083,14 @@ postcss-modules-local-by-default@^3.0.2: postcss-selector-parser "^6.0.2" postcss-value-parser "^4.0.0" -postcss-modules-scope@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb" - integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A== +postcss-modules-scope@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.1.tgz#33d4fc946602eb5e9355c4165d68a10727689dba" + integrity sha512-OXRUPecnHCg8b9xWvldG/jUpRIGPNRka0r4D4j0ESUU2/5IOnpsjfPPmDprM3Ih8CgZ8FXjWqaniK5v4rWt3oQ== dependencies: postcss "^7.0.6" postcss-selector-parser "^6.0.0" -postcss-modules-values@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-2.0.0.tgz#479b46dc0c5ca3dc7fa5270851836b9ec7152f64" - integrity sha512-Ki7JZa7ff1N3EIMlPnGTZfUMe69FFwiQPnVSXC9mnn3jozCRBYIxiZd44yJOV2AmabOo4qFf8s0dC/+lweG7+w== - dependencies: - icss-replace-symbols "^1.1.0" - postcss "^7.0.6" - postcss-modules-values@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10" @@ -23134,7 +23126,7 @@ postcss-url@^8.0.0: postcss "^7.0.2" xxhashjs "^0.2.1" -postcss-value-parser@^3.3.0, postcss-value-parser@^3.3.1: +postcss-value-parser@^3.3.0: version "3.3.1" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== @@ -23158,19 +23150,10 @@ postcss-values-parser@^1.5.0: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.17, postcss@^7.0.2, postcss@^7.0.5, postcss@^7.0.6: - version "7.0.17" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f" - integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ== - dependencies: - chalk "^2.4.2" - source-map "^0.6.1" - supports-color "^6.1.0" - -postcss@^7.0.16: - version "7.0.21" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.21.tgz#06bb07824c19c2021c5d056d5b10c35b989f7e17" - integrity sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ== +postcss@^7.0.0, postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.2, postcss@^7.0.23, postcss@^7.0.26, postcss@^7.0.5, postcss@^7.0.6: + version "7.0.26" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587" + integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA== dependencies: chalk "^2.4.2" source-map "^0.6.1" @@ -26306,15 +26289,15 @@ sass-lint@^1.12.1: path-is-absolute "^1.0.0" util "^0.10.3" -sass-loader@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.3.1.tgz#a5bf68a04bcea1c13ff842d747150f7ab7d0d23f" - integrity sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA== +sass-loader@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-8.0.2.tgz#debecd8c3ce243c76454f2e8290482150380090d" + integrity sha512-7o4dbSK8/Ol2KflEmSco4jTjQoV988bM82P9CZdmo9hR3RLnvNc0ufMNdMrB0caq38JQ/FgF4/7RcbcfKzxoFQ== dependencies: clone-deep "^4.0.1" - loader-utils "^1.0.1" - neo-async "^2.5.0" - pify "^4.0.1" + loader-utils "^1.2.3" + neo-async "^2.6.1" + schema-utils "^2.6.1" semver "^6.3.0" sass-lookup@^3.0.0: @@ -26386,18 +26369,10 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" -schema-utils@^2.0.0, schema-utils@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.1.0.tgz#940363b6b1ec407800a22951bdcc23363c039393" - integrity sha512-g6SViEZAfGNrToD82ZPUjq52KUPDYc+fN5+g6Euo5mLokl/9Yx14z0Cu4RR1m55HtBXejO0sBt+qw79axN+Fiw== - dependencies: - ajv "^6.1.0" - ajv-keywords "^3.1.0" - -schema-utils@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.4.1.tgz#e89ade5d056dc8bcaca377574bb4a9c4e1b8be56" - integrity sha512-RqYLpkPZX5Oc3fw/kHHHyP56fg5Y+XBpIpV8nCg0znIALfq3OH+Ea9Hfeac9BAMwG5IICltiZ0vxFvJQONfA5w== +schema-utils@^2.0.0, schema-utils@^2.0.1, schema-utils@^2.4.1, schema-utils@^2.5.0, schema-utils@^2.6.0, schema-utils@^2.6.1, schema-utils@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.6.4.tgz#a27efbf6e4e78689d91872ee3ccfa57d7bdd0f53" + integrity sha512-VNjcaUxVnEeun6B2fiiUDjXXBtD4ZSH7pdbfIu1pOFwgptDPLMo/z9jr4sUfsjFVPqDCEin/F7IYlq7/E6yDbQ== dependencies: ajv "^6.10.2" ajv-keywords "^3.4.1" @@ -26424,7 +26399,7 @@ screenfull@^5.0.0: resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.0.0.tgz#5c2010c0e84fd4157bf852877698f90b8cbe96f6" integrity sha512-yShzhaIoE9OtOhWVyBBffA6V98CDCoyHTsp8228blmqYy1Z5bddzE/4FPiJKlr8DVR4VBiiUyfPzIQPIYDkeMA== -script-loader@0.7.2: +script-loader@0.7.2, script-loader@^0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/script-loader/-/script-loader-0.7.2.tgz#2016db6f86f25f5cf56da38915d83378bb166ba7" integrity sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA== @@ -26595,7 +26570,7 @@ sentence-case@^2.1.0: no-case "^2.2.0" upper-case-first "^1.1.2" -serialize-javascript@^1.7.0, serialize-javascript@^2.1.0, serialize-javascript@^2.1.1, serialize-javascript@^2.1.2: +serialize-javascript@^1.7.0, serialize-javascript@^2.1.1, serialize-javascript@^2.1.2: version "2.1.1" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-2.1.1.tgz#952907a04a3e3a75af7f73d92d15e233862048b2" integrity sha512-MPLPRpD4FNqWq9tTIjYG5LesFouDhdyH0EPY3gVK4DRD5+g4aDqdNSzLIwceulo3Yj+PL1bPh6laE5+H6LTcrQ== @@ -27960,7 +27935,7 @@ style-it@^2.1.3: dependencies: react-lib-adler32 "^1.0.3" -style-loader@0.23.1, style-loader@^0.23.1: +style-loader@^0.23.1: version "0.23.1" resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-0.23.1.tgz#cb9154606f3e771ab6c4ab637026a1049174d925" integrity sha512-XK+uv9kWwhZMZ1y7mysB+zoihsEj4wneFWAS5qoiLwzW0WzSqMrrsIy+a3zkQJq0ipFtBpX5W3MqyRIBF/WFGg== @@ -27968,6 +27943,14 @@ style-loader@0.23.1, style-loader@^0.23.1: loader-utils "^1.1.0" schema-utils "^1.0.0" +style-loader@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-1.1.3.tgz#9e826e69c683c4d9bf9db924f85e9abb30d5e200" + integrity sha512-rlkH7X/22yuwFYK357fMN/BxYOorfnfq0eD7+vqlemSK4wEcejFF1dg4zxP0euBW8NrYx2WZzZ8PPFevr7D+Kw== + dependencies: + loader-utils "^1.2.3" + schema-utils "^2.6.4" + styled-components@^3: version "3.4.10" resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-3.4.10.tgz#9a654c50ea2b516c36ade57ddcfa296bf85c96e1" @@ -28458,7 +28441,7 @@ term-size@^1.2.0: dependencies: execa "^0.7.0" -terser-webpack-plugin@^1.1.0: +terser-webpack-plugin@^1.2.4, terser-webpack-plugin@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz#5ecaf2dbdc5fb99745fd06791f46fc9ddb1c9a7c" integrity sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA== @@ -28473,39 +28456,24 @@ terser-webpack-plugin@^1.1.0: webpack-sources "^1.4.0" worker-farm "^1.7.0" -terser-webpack-plugin@^1.2.4, terser-webpack-plugin@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.1.tgz#61b18e40eaee5be97e771cdbb10ed1280888c2b4" - integrity sha512-ZXmmfiwtCLfz8WKZyYUuuHf3dMYEjg8NrjHMb0JqHVHVOSkzp3cW2/XG1fP3tRhqEqSzMwzzRQGtAPbs4Cncxg== - dependencies: - cacache "^12.0.2" - find-cache-dir "^2.1.0" - is-wsl "^1.1.0" - schema-utils "^1.0.0" - serialize-javascript "^1.7.0" - source-map "^0.6.1" - terser "^4.1.2" - webpack-sources "^1.4.0" - worker-farm "^1.7.0" - terser-webpack-plugin@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.1.2.tgz#2b9b8147a6f18918348200800cf9560c50f701bb" - integrity sha512-MF/C4KABwqYOfRDi87f7gG07GP7Wj/kyiX938UxIGIO6l5mkh8XJL7xtS0hX/CRdVQaZI7ThGUPZbznrCjsGpg== + version "2.3.2" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.3.2.tgz#6d3d1b0590c8f729bfbaeb7fb2528b8b62db4c74" + integrity sha512-SmvB/6gtEPv+CJ88MH5zDOsZdKXPS/Uzv2//e90+wM1IHFUhsguPKEILgzqrM1nQ4acRXN/SV4Obr55SXC+0oA== dependencies: - cacache "^13.0.0" - find-cache-dir "^3.0.0" + cacache "^13.0.1" + find-cache-dir "^3.2.0" jest-worker "^24.9.0" - schema-utils "^2.4.1" - serialize-javascript "^2.1.0" + schema-utils "^2.6.1" + serialize-javascript "^2.1.2" source-map "^0.6.1" - terser "^4.3.4" + terser "^4.4.3" webpack-sources "^1.4.3" -terser@^4.1.2, terser@^4.3.4: - version "4.6.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.1.tgz#913e35e0d38a75285a7913ba01d753c4089ebdbd" - integrity sha512-w0f2OWFD7ka3zwetgVAhNMeyzEbj39ht2Tb0qKflw9PmW9Qbo5tjTh01QJLkhO9t9RDDQYvk+WXqpECI2C6i2A== +terser@^4.1.2, terser@^4.4.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.6.3.tgz#e33aa42461ced5238d352d2df2a67f21921f8d87" + integrity sha512-Lw+ieAXmY69d09IIc/yqeBqXpEQIpDGZqT34ui1QWXIUpR2RjbqEkT8X7Lgex19hslSqcWM5iMN2kM11eMsESQ== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -30121,6 +30089,15 @@ url-loader@2.2.0, url-loader@^2.0.1: mime "^2.4.4" schema-utils "^2.4.1" +url-loader@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-2.3.0.tgz#e0e2ef658f003efb8ca41b0f3ffbf76bab88658b" + integrity sha512-goSdg8VY+7nPZKUEChZSEtW5gjbS66USIGCeSJ1OVOJ7Yfuh/36YxCwMi5HVEJh6mqUYOoy3NJ0vlOMrWsSHog== + dependencies: + loader-utils "^1.2.3" + mime "^2.4.4" + schema-utils "^2.5.0" + url-parse-lax@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" @@ -30187,7 +30164,7 @@ user-home@^2.0.0: dependencies: os-homedir "^1.0.0" -useragent@2.3.0: +useragent@2.3.0, useragent@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972" integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw== @@ -31030,7 +31007,7 @@ warning@^4.0.2, warning@^4.0.3: dependencies: loose-envify "^1.0.0" -watchpack@^1.5.0, watchpack@^1.6.0: +watchpack@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA== @@ -31070,10 +31047,10 @@ webidl-conversions@^4.0.1, webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== -webpack-cli@^3.3.9: - version "3.3.9" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.9.tgz#79c27e71f94b7fe324d594ab64a8e396b9daa91a" - integrity sha512-xwnSxWl8nZtBl/AFJCOn9pG7s5CYUYdZxmmukv+fAHLcBIHM36dImfpQg3WfShZXeArkWlf6QRw24Klcsv8a5A== +webpack-cli@^3.3.10: + version "3.3.10" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.10.tgz#17b279267e9b4fb549023fae170da8e6e766da13" + integrity sha512-u1dgND9+MXaEt74sJR4PR7qkPxXUSQ0RXYq8x1L6Jg1MYVEmGPrH6Ah6C4arD4r0J1P5HKjRqpab36k0eIzPqg== dependencies: chalk "2.4.2" cross-spawn "6.0.5" @@ -31175,7 +31152,7 @@ webpack-log@^2.0.0: ansi-colors "^3.0.0" uuid "^3.3.2" -webpack-merge@4.2.2: +webpack-merge@4.2.2, webpack-merge@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.2.2.tgz#a27c52ea783d1398afd2087f547d7b9d2f43634d" integrity sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g== @@ -31190,7 +31167,7 @@ webpack-sources@^1.1.0: source-list-map "^2.0.0" source-map "~0.6.1" -webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: +webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack-sources@^1.4.3: version "1.4.3" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== @@ -31198,40 +31175,10 @@ webpack-sources@^1.3.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1, webpack- source-list-map "^2.0.0" source-map "~0.6.1" -webpack@4.34.0: - version "4.34.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.34.0.tgz#a4c30129482f7b4ece4c0842002dedf2b56fab58" - integrity sha512-ry2IQy1wJjOefLe1uJLzn5tG/DdIKzQqNlIAd2L84kcaADqNvQDTBlo8UcCNyDaT5FiaB+16jhAkb63YeG3H8Q== - dependencies: - "@webassemblyjs/ast" "1.8.5" - "@webassemblyjs/helper-module-context" "1.8.5" - "@webassemblyjs/wasm-edit" "1.8.5" - "@webassemblyjs/wasm-parser" "1.8.5" - acorn "^6.0.5" - acorn-dynamic-import "^4.0.0" - ajv "^6.1.0" - ajv-keywords "^3.1.0" - chrome-trace-event "^1.0.0" - enhanced-resolve "^4.1.0" - eslint-scope "^4.0.0" - json-parse-better-errors "^1.0.2" - loader-runner "^2.3.0" - loader-utils "^1.1.0" - memory-fs "~0.4.1" - micromatch "^3.1.8" - mkdirp "~0.5.0" - neo-async "^2.5.0" - node-libs-browser "^2.0.0" - schema-utils "^1.0.0" - tapable "^1.1.0" - terser-webpack-plugin "^1.1.0" - watchpack "^1.5.0" - webpack-sources "^1.3.0" - -webpack@4.41.0, webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.0: - version "4.41.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.0.tgz#db6a254bde671769f7c14e90a1a55e73602fc70b" - integrity sha512-yNV98U4r7wX1VJAj5kyMsu36T8RPPQntcb5fJLOsMz/pt/WrKC0Vp1bAlqPLkA1LegSwQwf6P+kAbyhRKVQ72g== +webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.5: + version "4.41.5" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.41.5.tgz#3210f1886bce5310e62bb97204d18c263341b77c" + integrity sha512-wp0Co4vpyumnp3KlkmpM5LWuzvZYayDwM2n17EHFr4qxBBbRokC7DJawPJC7TfSFZ9HZ6GsdH40EBj4UV0nmpw== dependencies: "@webassemblyjs/ast" "1.8.5" "@webassemblyjs/helper-module-context" "1.8.5" @@ -31253,7 +31200,7 @@ webpack@4.41.0, webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.0: node-libs-browser "^2.2.1" schema-utils "^1.0.0" tapable "^1.1.3" - terser-webpack-plugin "^1.4.1" + terser-webpack-plugin "^1.4.3" watchpack "^1.6.0" webpack-sources "^1.4.1" From ac62e68ac8fdf761a8c59996c6a370ebacfdc435 Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 27 Jan 2020 14:26:37 -0700 Subject: [PATCH 02/83] only inspect workers if configured to do so --- packages/kbn-optimizer/src/cli.ts | 10 +++++++- .../basic_optimization.test.ts.snap | 1 + packages/kbn-optimizer/src/observe_worker.ts | 25 +++++++++++++------ packages/kbn-optimizer/src/optimizer.ts | 2 +- .../src/optimizer_config.test.ts | 7 ++++++ .../kbn-optimizer/src/optimizer_config.ts | 11 ++++++-- 6 files changed, 44 insertions(+), 12 deletions(-) diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts index 3710d736e7a0f..87efd7dc63ff3 100644 --- a/packages/kbn-optimizer/src/cli.ts +++ b/packages/kbn-optimizer/src/cli.ts @@ -54,6 +54,11 @@ run( throw createFlagError('expected --profile to have no value'); } + const inspectWorkers = flags['inspect-workers'] ?? false; + if (typeof inspectWorkers !== 'boolean') { + throw createFlagError('expected --no-inspect-workers to have no value'); + } + const maxWorkerCount = flags.workers ? Number.parseInt(String(flags.workers), 10) : undefined; if (maxWorkerCount !== undefined && (!Number.isFinite(maxWorkerCount) || maxWorkerCount < 1)) { throw createFlagError('expected --workers to be a number greater than 0'); @@ -75,6 +80,7 @@ run( examples, profileWebpack, extraPluginScanDirs, + inspectWorkers, }); await new Optimizer(config) @@ -84,10 +90,11 @@ run( }, { flags: { - boolean: ['watch', 'oss', 'examples', 'dist', 'profile'], + boolean: ['watch', 'oss', 'examples', 'dist', 'profile', 'inspect-workers'], string: ['workers', 'scan-dir'], default: { examples: true, + 'inspect-workers': true, }, help: ` --watch run the optimizer in watch mode @@ -97,6 +104,7 @@ run( --no-examples don't build the example plugins --dist build new platform plugins in a way that is suitable for inclusion in the Kibana distributable --scan-dir add a directory to the list of directories scanned for plugins (specify as many times as necessary) + --no-inspect-workers when inspecting the parent process, don't inspect the workers `, }, } diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap index 1e135c6fc9888..52ff5f25f556d 100644 --- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap +++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap @@ -27,6 +27,7 @@ OptimizerConfig { "moduleCounts": Object {}, }, }, + "inspectWorkers": false, "watch": false, "workers": Array [ Object { diff --git a/packages/kbn-optimizer/src/observe_worker.ts b/packages/kbn-optimizer/src/observe_worker.ts index ed67204ebbbea..8b95b0ce3b370 100644 --- a/packages/kbn-optimizer/src/observe_worker.ts +++ b/packages/kbn-optimizer/src/observe_worker.ts @@ -25,6 +25,7 @@ import * as Rx from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; import { isWorkerMessage, WorkerMessage, WorkerConfig } from './common'; +import { OptimizerConfig } from './optimizer_config'; export interface WorkerStdio { type: 'worker stdio'; @@ -57,15 +58,20 @@ if (inspectFlagIndex !== -1) { } } -function usingWorkerProc(config: WorkerConfig, user: (proc: ChildProcess) => Rx.Observable) { +function usingWorkerProc( + config: OptimizerConfig, + worker: WorkerConfig, + fn: (proc: ChildProcess) => Rx.Observable +) { return Rx.using( (): ProcResource => { - const proc = fork(require.resolve('./worker/run_worker'), [JSON.stringify(config)], { + const proc = fork(require.resolve('./worker/run_worker'), [JSON.stringify(worker)], { stdio: ['ignore', 'pipe', 'pipe', 'ipc'], - execArgv: inspectFlag ? [`${inspectFlag}=${inspectPortCounter++}`] : [], + execArgv: + inspectFlag && config.inspectWorkers ? [`${inspectFlag}=${inspectPortCounter++}`] : [], env: { ...process.env, - BROWSERSLIST_ENV: config.dist ? 'production' : process.env.BROWSERSLIST_ENV || 'dev', + BROWSERSLIST_ENV: worker.dist ? 'production' : process.env.BROWSERSLIST_ENV || 'dev', }, }); @@ -79,7 +85,7 @@ function usingWorkerProc(config: WorkerConfig, user: (proc: ChildProcess) => resource => { const { proc } = resource as ProcResource; - return user(proc); + return fn(proc); } ); } @@ -106,8 +112,11 @@ function observeStdio$(stream: Readable, name: WorkerStdio['stream']) { ); } -export function observeWorker(config: WorkerConfig): Rx.Observable { - return usingWorkerProc(config, proc => { +export function observeWorker( + config: OptimizerConfig, + worker: WorkerConfig +): Rx.Observable { + return usingWorkerProc(config, worker, proc => { let lastMessage: WorkerMessage; return Rx.merge( @@ -143,7 +152,7 @@ export function observeWorker(config: WorkerConfig): Rx.Observable observeWorker(config)), + mergeMap(worker => observeWorker(this.config, worker)), closure(msg$ => { let prevSummaryType: OptimizerStateSummary['type'] | undefined; let startTime = Date.now(); diff --git a/packages/kbn-optimizer/src/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer_config.test.ts index 9b69a9edcb33e..811326ed8fef0 100644 --- a/packages/kbn-optimizer/src/optimizer_config.test.ts +++ b/packages/kbn-optimizer/src/optimizer_config.test.ts @@ -98,6 +98,7 @@ describe('OptimizerConfig::parseOptions()', () => { ).toMatchInlineSnapshot(` Object { "dist": false, + "inspectWorkers": false, "maxWorkerCount": 2, "optimizerCachePath": /data/.kbn-optimizer-cache.json, "pluginPaths": Array [], @@ -120,6 +121,7 @@ describe('OptimizerConfig::parseOptions()', () => { ).toMatchInlineSnapshot(` Object { "dist": false, + "inspectWorkers": false, "maxWorkerCount": 2, "optimizerCachePath": false, "pluginPaths": Array [], @@ -142,6 +144,7 @@ describe('OptimizerConfig::parseOptions()', () => { ).toMatchInlineSnapshot(` Object { "dist": false, + "inspectWorkers": false, "maxWorkerCount": 2, "optimizerCachePath": /data/.kbn-optimizer-cache.json, "pluginPaths": Array [], @@ -165,6 +168,7 @@ describe('OptimizerConfig::parseOptions()', () => { ).toMatchInlineSnapshot(` Object { "dist": false, + "inspectWorkers": false, "maxWorkerCount": 2, "optimizerCachePath": /data/.kbn-optimizer-cache.json, "pluginPaths": Array [], @@ -186,6 +190,7 @@ describe('OptimizerConfig::parseOptions()', () => { ).toMatchInlineSnapshot(` Object { "dist": false, + "inspectWorkers": false, "maxWorkerCount": 2, "optimizerCachePath": /data/.kbn-optimizer-cache.json, "pluginPaths": Array [], @@ -236,6 +241,7 @@ describe('OptimizerConfig::create()', () => { pluginScanDirs: Symbol('parsed plugin scan dirs'), repoRoot: Symbol('parsed repo root'), watch: Symbol('parsed watch'), + inspectWorkers: Symbol('parsed inspect workers'), })); }); @@ -253,6 +259,7 @@ describe('OptimizerConfig::create()', () => { "saveBundleModuleCount": [MockFunction], "setState": [MockFunction], }, + "inspectWorkers": Symbol(parsed inspect workers), "watch": Symbol(parsed watch), "workers": Array [ Symbol(worker config 1), diff --git a/packages/kbn-optimizer/src/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer_config.ts index 24f957ea406ec..edd245a32a0c3 100644 --- a/packages/kbn-optimizer/src/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer_config.ts @@ -39,6 +39,8 @@ interface Options { dist?: boolean; /** enable webpack profiling, writes stats.json files to the root of each plugin's output dir */ profileWebpack?: boolean; + /** set to true to inspecting workers when the parent process is being inspected */ + inspectWorkers?: boolean; /** include only oss plugins in default scan dirs */ oss?: boolean; @@ -61,6 +63,7 @@ interface ParsedOptions { dist: boolean; pluginPaths: string[]; pluginScanDirs: string[]; + inspectWorkers: boolean; } export class OptimizerConfig { @@ -70,6 +73,7 @@ export class OptimizerConfig { const dist = !!options.dist; const examples = !!options.examples; const profileWebpack = !!options.profileWebpack; + const inspectWorkers = !!options.inspectWorkers; const repoRoot = options.repoRoot; if (!Path.isAbsolute(repoRoot)) { @@ -122,6 +126,7 @@ export class OptimizerConfig { optimizerCachePath, pluginScanDirs, pluginPaths, + inspectWorkers, }; } @@ -148,7 +153,8 @@ export class OptimizerConfig { cache, bundles, workers.map(w => w.config), - options.watch + options.watch, + options.inspectWorkers ); } @@ -156,6 +162,7 @@ export class OptimizerConfig { public readonly cache: OptimizerCache, public readonly bundles: BundleDefinition[], public readonly workers: WorkerConfig[], - public readonly watch: boolean + public readonly watch: boolean, + public readonly inspectWorkers: boolean ) {} } From 2112fb1354f5497a62c5e5bd39622fe60636b418 Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 27 Jan 2020 16:05:26 -0700 Subject: [PATCH 03/83] [navigation] use an index.scss file --- src/plugins/navigation/public/index.scss | 1 + src/plugins/navigation/public/index.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 src/plugins/navigation/public/index.scss diff --git a/src/plugins/navigation/public/index.scss b/src/plugins/navigation/public/index.scss new file mode 100644 index 0000000000000..4734a2915c620 --- /dev/null +++ b/src/plugins/navigation/public/index.scss @@ -0,0 +1 @@ +@import "top_nav_menu/index"; diff --git a/src/plugins/navigation/public/index.ts b/src/plugins/navigation/public/index.ts index f2dc3b9a84349..5afc91c4445e8 100644 --- a/src/plugins/navigation/public/index.ts +++ b/src/plugins/navigation/public/index.ts @@ -17,7 +17,7 @@ * under the License. */ -import './top_nav_menu/_index.scss'; +import './index.scss'; import { PluginInitializerContext } from '../../../core/public'; export function plugin(initializerContext: PluginInitializerContext) { From 2b3a2a030d20fd4fadddf180c323ebac2ac9e708 Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 27 Jan 2020 19:46:51 -0700 Subject: [PATCH 04/83] add yarn.lock symlink --- packages/kbn-optimizer/yarn.lock | 1 + 1 file changed, 1 insertion(+) create mode 120000 packages/kbn-optimizer/yarn.lock diff --git a/packages/kbn-optimizer/yarn.lock b/packages/kbn-optimizer/yarn.lock new file mode 120000 index 0000000000000..3f82ebc9cdbae --- /dev/null +++ b/packages/kbn-optimizer/yarn.lock @@ -0,0 +1 @@ +../../yarn.lock \ No newline at end of file From 13d700bcbf75c1a45794216d029835aecb371c06 Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 27 Jan 2020 20:44:30 -0700 Subject: [PATCH 05/83] set pluginScanDirs in test so fixtures stay consistent --- packages/kbn-optimizer/src/log_optimizer_state.test.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/src/log_optimizer_state.test.ts b/packages/kbn-optimizer/src/log_optimizer_state.test.ts index 5a97d90e34466..bcc65b4d1472e 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.test.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.test.ts @@ -17,6 +17,8 @@ * under the License. */ +import Path from 'path'; + import * as Rx from 'rxjs'; import { toArray } from 'rxjs/operators'; import { REPO_ROOT, ToolingLog, ToolingLogCollectingWriter } from '@kbn/dev-utils'; @@ -33,6 +35,7 @@ it('produces expected messages and mirrors state updates downstream', async () = const config = OptimizerConfig.create({ repoRoot: REPO_ROOT, maxWorkerCount: 2, + pluginScanDirs: [Path.resolve(__dirname, './__fixtures__/mock_repo/plugins')], }); const stateUpdates: OptimizerState[] = [ @@ -111,7 +114,7 @@ it('produces expected messages and mirrors state updates downstream', async () = expect(logWriter.messages).toMatchInlineSnapshot(` Array [ - " info ⚙️ building 28 bundles using 2 workers", + " info ⚙️ building 2 bundles using 2 workers", " warn ⚙️ worker stderr something from stderr", " warn ⚙️ worker stdout something from stdout", " sill [foo] state = \\"running\\"", From edc362aab13cb361cfd5461e7e03d2d43e07baea Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 28 Jan 2020 00:59:56 -0700 Subject: [PATCH 06/83] cleanup helpers a little --- packages/kbn-optimizer/src/common/index.ts | 1 + .../{closure.ts => common/rxjs_helpers.ts} | 29 ++++++++++---- packages/kbn-optimizer/src/optimizer.ts | 5 +-- .../src/worker/block_legacy_code_plugin.ts | 38 +------------------ .../kbn-optimizer/src/worker/run_worker.ts | 22 +++++------ .../src/worker/webpack_helpers.ts | 35 +++++++++++++++++ 6 files changed, 71 insertions(+), 59 deletions(-) rename packages/kbn-optimizer/src/{closure.ts => common/rxjs_helpers.ts} (54%) diff --git a/packages/kbn-optimizer/src/common/index.ts b/packages/kbn-optimizer/src/common/index.ts index 5f56fa41734a1..9a9ae739dcde1 100644 --- a/packages/kbn-optimizer/src/common/index.ts +++ b/packages/kbn-optimizer/src/common/index.ts @@ -21,3 +21,4 @@ export * from './bundle_definition'; export * from './worker_config'; export * from './worker_messages'; export * from './compiler_messages'; +export * from './rxjs_helpers'; diff --git a/packages/kbn-optimizer/src/closure.ts b/packages/kbn-optimizer/src/common/rxjs_helpers.ts similarity index 54% rename from packages/kbn-optimizer/src/closure.ts rename to packages/kbn-optimizer/src/common/rxjs_helpers.ts index 38b3412f773df..0430b507ae15f 100644 --- a/packages/kbn-optimizer/src/closure.ts +++ b/packages/kbn-optimizer/src/common/rxjs_helpers.ts @@ -18,23 +18,38 @@ */ import * as Rx from 'rxjs'; +import { mergeMap } from 'rxjs/operators'; type Operator = (source: Rx.Observable) => Rx.Observable; +type MapFn = (item: T1, index: number) => T2; /** - * Wrap an operator chain in a closure so that is can have some local state + * Wrap an operator chain in a closure so that is can have some local + * state. The `fn` is called each time the final observable is + * subscribed so the pipeline/closure is setup for each subscription. * - * This could also be done with new Rx.Obseravble(...) but that gives - * the closure access to the subscriber, and I often wish I didn't have - * access to such a powerful/dangerous object. - * - * Using closure makes sure that only operators are used so errors + * This helper was created to avoid exposing the subscriber when all + * it is needed for is subscribing to an internal obseravble. Using + * `closure()` makes sure that only operators are used so errors * and subscriptions are managed correctly without worry. */ -export const closure = (fn: Operator): Operator => { +export const pipeClosure = (fn: Operator): Operator => { return (source: Rx.Observable) => { return new Rx.Observable(subscriber => { return fn(source).subscribe(subscriber); }); }; }; + +/** + * An operator like map(), but undefined values are filered out automatically + * with TypeScript support. For some reason TS doesn't have great support for + * filter's without defining an explicit type assertion in the signature of + * the filter. + */ +export const maybeMap = (fn: MapFn): Operator => { + return mergeMap((item, index) => { + const result = fn(item, index); + return result === undefined ? [] : [result]; + }); +}; diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index e290daacd6c56..3654b96898291 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -23,8 +23,7 @@ import { createFailError } from '@kbn/dev-utils'; import { observeWorker, WorkerStdio } from './observe_worker'; import { OptimizerConfig } from './optimizer_config'; -import { CompilerState, WorkerMessage } from './common'; -import { closure } from './closure'; +import { CompilerState, WorkerMessage, pipeClosure } from './common'; export interface OptimizerStateSummary { type: CompilerState['type']; @@ -58,7 +57,7 @@ export class Optimizer { run() { return Rx.from(this.config.workers).pipe( mergeMap(worker => observeWorker(this.config, worker)), - closure(msg$ => { + pipeClosure(msg$ => { let prevSummaryType: OptimizerStateSummary['type'] | undefined; let startTime = Date.now(); const compilerStates: CompilerState[] = []; diff --git a/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts b/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts index 24814674aeb32..638b3e821277a 100644 --- a/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts +++ b/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts @@ -23,44 +23,10 @@ import webpack from 'webpack'; import isPathInside from 'is-path-inside'; import { BundleDefinition } from '../common'; +import { WebpackResolveData } from './webpack_helpers'; const ANY_LEGACY_DIR = `${Path.sep}legacy${Path.sep}`; -interface ResolveData { - /** compilation context */ - context: string; - /** full request (with loaders) */ - request: string; - dependencies: [ - { - module: unknown; - weak: boolean; - optional: boolean; - loc: unknown; - request: string; - userRequest: string; - } - ]; - /** absolute path, but probably includes loaders in some cases */ - userRequest: string; - /** string from source code */ - rawRequest: string; - loaders: unknown; - /** absolute path to file, but probablt includes loaders in some cases */ - resource: string; - /** module type */ - type: string | 'javascript/auto'; - - resourceResolveData: { - context: { - /** absolute path to the file that issued the request */ - issuer: string; - }; - /** absolute path to the resolved file */ - path: string; - }; -} - export class BlockLegacyCodePlugin { constructor(private readonly def: BundleDefinition) {} @@ -68,7 +34,7 @@ export class BlockLegacyCodePlugin { compiler.hooks.normalModuleFactory.tap(BlockLegacyCodePlugin.name, normalModuleFactory => { normalModuleFactory.hooks.afterResolve.tap( BlockLegacyCodePlugin.name, - (resolveData: ResolveData) => { + (resolveData: WebpackResolveData) => { const { rawRequest, resourceResolveData: { context, path }, diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts index 082a1adad3595..9f7b6ce32ff5b 100644 --- a/packages/kbn-optimizer/src/worker/run_worker.ts +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -26,7 +26,7 @@ import webpack, { Stats } from 'webpack'; import * as Rx from 'rxjs'; import { mergeMap, map, mapTo, takeUntil } from 'rxjs/operators'; -import { CompilerMessages, WorkerMessages } from '../common'; +import { CompilerMessages, WorkerMessages, maybeMap } from '../common'; import { getWebpackConfig } from './webpack.config'; import { isFailureStats, failedStatsToErrorMessage } from './webpack_helpers'; import { @@ -119,10 +119,10 @@ const observeCompiler = ( * is about to be started, so we shouldn't send complete quite yet */ const complete$ = Rx.fromEventPattern(cb => done.tap(PLUGIN_NAME, cb)).pipe( - mergeMap(stats => { + maybeMap(stats => { // @ts-ignore not included in types, but it is real https://github.com/webpack/webpack/blob/ab4fa8ddb3f433d286653cd6af7e3aad51168649/lib/Watching.js#L58 if (stats.compilation.needAdditionalPass) { - return []; + return undefined; } if (workerConfig.profileWebpack) { @@ -134,18 +134,14 @@ const observeCompiler = ( } if (isFailureStats(stats)) { - return [ - compilerMsgs.compilerFailure({ - failure: failedStatsToErrorMessage(stats), - }), - ]; + return compilerMsgs.compilerFailure({ + failure: failedStatsToErrorMessage(stats), + }); } - return [ - compilerMsgs.compilerSuccess({ - moduleCount: stats.compilation.modules.length, - }), - ]; + return compilerMsgs.compilerSuccess({ + moduleCount: stats.compilation.modules.length, + }); }) ); diff --git a/packages/kbn-optimizer/src/worker/webpack_helpers.ts b/packages/kbn-optimizer/src/worker/webpack_helpers.ts index 65e728db0cc6b..ea68f79de00bf 100644 --- a/packages/kbn-optimizer/src/worker/webpack_helpers.ts +++ b/packages/kbn-optimizer/src/worker/webpack_helpers.ts @@ -64,3 +64,38 @@ export function failedStatsToErrorMessage(stats: webpack.Stats) { return `Optimizations failure.\n${details.split('\n').join('\n ')}`; } + +export interface WebpackResolveData { + /** compilation context */ + context: string; + /** full request (with loaders) */ + request: string; + dependencies: [ + { + module: unknown; + weak: boolean; + optional: boolean; + loc: unknown; + request: string; + userRequest: string; + } + ]; + /** absolute path, but probably includes loaders in some cases */ + userRequest: string; + /** string from source code */ + rawRequest: string; + loaders: unknown; + /** absolute path to file, but probablt includes loaders in some cases */ + resource: string; + /** module type */ + type: string | 'javascript/auto'; + + resourceResolveData: { + context: { + /** absolute path to the file that issued the request */ + issuer: string; + }; + /** absolute path to the resolved file */ + path: string; + }; +} From 9089c2071e5b7d4ba4394d242a771521139dd8dd Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 28 Jan 2020 01:49:17 -0700 Subject: [PATCH 07/83] fix type error --- packages/kbn-optimizer/src/log_optimizer_state.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index 35a8144f4b590..14a3f7cf30ea8 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -23,11 +23,10 @@ import { filter } from 'rxjs/operators'; import { OptimizerConfig } from './optimizer_config'; import { OptimizerState, OptimizerStateSummary } from './optimizer'; -import { CompilerState } from './common'; -import { closure } from './closure'; +import { CompilerState, pipeClosure } from './common'; export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { - return closure(source => { + return pipeClosure(source => { const bundleStates = new Map(); log.info( From 7a85b6d8e22fed5ba42ca8830e966276861491d5 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 28 Jan 2020 10:34:02 -0700 Subject: [PATCH 08/83] support KBN_OPTIMIZER_MAX_WORKERS for limiting workers via env --- packages/kbn-optimizer/src/optimizer_config.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/kbn-optimizer/src/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer_config.ts index edd245a32a0c3..ead02e48490fb 100644 --- a/packages/kbn-optimizer/src/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer_config.ts @@ -102,8 +102,9 @@ export class OptimizerConfig { throw new TypeError('pluginPaths must all be absolute paths'); } - const maxWorkerCount = - options.maxWorkerCount ?? Math.max(Math.ceil(Math.max(Os.cpus()?.length, 1) / 3), 2); + const maxWorkerCount = process.env.KBN_OPTIMIZER_MAX_WORKERS + ? parseInt(process.env.KBN_OPTIMIZER_MAX_WORKERS, 10) + : options.maxWorkerCount ?? Math.max(Math.ceil(Math.max(Os.cpus()?.length, 1) / 3), 2); if (typeof maxWorkerCount !== 'number' || !Number.isFinite(maxWorkerCount)) { throw new TypeError('worker count must be a number'); } From 58afee8addca1fb3fb197cf61d4841310647a8ea Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 28 Jan 2020 10:37:55 -0700 Subject: [PATCH 09/83] test support for KBN_OPTIMIZER_MAX_WORKERS --- .../src/optimizer_config.test.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/kbn-optimizer/src/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer_config.test.ts index 811326ed8fef0..500016832cbff 100644 --- a/packages/kbn-optimizer/src/optimizer_config.test.ts +++ b/packages/kbn-optimizer/src/optimizer_config.test.ts @@ -35,6 +35,7 @@ jest.spyOn(Os, 'cpus').mockReturnValue(['foo'] as any); expect.addSnapshotSerializer(createAbsolutePathSerializer()); beforeEach(() => { + delete process.env.KBN_OPTIMIZER_MAX_WORKERS; jest.clearAllMocks(); }); @@ -203,6 +204,26 @@ describe('OptimizerConfig::parseOptions()', () => { "watch": false, } `); + + process.env.KBN_OPTIMIZER_MAX_WORKERS = '100'; + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + pluginScanDirs: [], + }) + ).toMatchInlineSnapshot(` + Object { + "dist": false, + "inspectWorkers": false, + "maxWorkerCount": 100, + "optimizerCachePath": /data/.kbn-optimizer-cache.json, + "pluginPaths": Array [], + "pluginScanDirs": Array [], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); }); }); From 39b7a9663bf40bd31d8d0f3d0ab780bde5c7af87 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 28 Jan 2020 11:02:26 -0700 Subject: [PATCH 10/83] expand the available memory for workers when only running one or two --- packages/kbn-optimizer/src/observe_worker.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/kbn-optimizer/src/observe_worker.ts b/packages/kbn-optimizer/src/observe_worker.ts index 8b95b0ce3b370..ca7663ccbf957 100644 --- a/packages/kbn-optimizer/src/observe_worker.ts +++ b/packages/kbn-optimizer/src/observe_worker.ts @@ -67,8 +67,12 @@ function usingWorkerProc( (): ProcResource => { const proc = fork(require.resolve('./worker/run_worker'), [JSON.stringify(worker)], { stdio: ['ignore', 'pipe', 'pipe', 'ipc'], - execArgv: - inspectFlag && config.inspectWorkers ? [`${inspectFlag}=${inspectPortCounter++}`] : [], + execArgv: [ + ...(inspectFlag && config.inspectWorkers + ? [`${inspectFlag}=${inspectPortCounter++}`] + : []), + ...(config.workers.length <= 2 ? ['--max-old-space-size=2048'] : []), + ], env: { ...process.env, BROWSERSLIST_ENV: worker.dist ? 'production' : process.env.BROWSERSLIST_ENV || 'dev', From c70177d8604e0caf50fbd3a8e17f0f605e8ff230 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 28 Jan 2020 11:08:43 -0700 Subject: [PATCH 11/83] add docs about KBN_OPTIMIZER_MAX_WORKERS environment variable --- packages/kbn-optimizer/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/kbn-optimizer/README.md b/packages/kbn-optimizer/README.md index 65ce1637faea4..9986976f6b4b2 100644 --- a/packages/kbn-optimizer/README.md +++ b/packages/kbn-optimizer/README.md @@ -18,6 +18,8 @@ To make front-end code easier to debug the optimizer uses the `BROWSERSLIST_ENV= The `@kbn/optimizer` is automatically executed from the dev cli, the Kibana build scripts, and in CI. If you're running Kibana locally in some other way you might need to build the plugins manually, which you can do by running `node scripts/build_new_platform_plugins` (pass `--help` for options). +You can limit the number of workers the optimizer uses in all of these places by setting the `KBN_OPTIMIZER_MAX_WORKERS` environment variable. You might want to do this if your system struggles to keep up while the optimizer is getting started and building all plugins as fast as possible. Setting `KBN_OPTIMIZER_MAX_WORKERS=1` will cause the optimizer to take the longest amount of time but will have the smallest impact on other components of your system. + ## API To run the optimizer from code, you can import the [`Optimizer`][Optimizer] and [`OptimizerConfig`][OptimizerConfig] classes. Create an [`OptimizerConfig`][OptimizerConfig] instance by calling it's static `create()` method with some options, then pass it to the [`Optimizer`][Optimizer] constructor. Calling `Optimizer#run()` will return an observable of [`OptimizerState`][Optimizer] objects, which are either bits of stdio from the workers or [`OptimizerStateSummary`][Optimizer] objects. You can use the [`logOptimizerState()`][LogOptimizerState] helper to write the relevant bits of state to a tooling log. From 3dea8ae4a34971b103178faf911b53597a9418f1 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 28 Jan 2020 16:55:51 -0700 Subject: [PATCH 12/83] fix README link --- packages/kbn-optimizer/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/README.md b/packages/kbn-optimizer/README.md index 9986976f6b4b2..011bf393f780d 100644 --- a/packages/kbn-optimizer/README.md +++ b/packages/kbn-optimizer/README.md @@ -49,7 +49,7 @@ await optimizer .toPromise(); ``` -This is essentially what we're doing in [`the build_new_platform_plugins script`][Cli] and the new [build system task][BuildTask]. +This is essentially what we're doing in [`script/build_new_platform_plugins`][Cli] and the new [build system task][BuildTask]. ## Internals From 9ad75493672139cb90ab9d72abbd898cc5fe1c76 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 15:46:24 -0700 Subject: [PATCH 13/83] update kbn/pm dist --- packages/kbn-pm/dist/index.js | 60505 ++++++++++++++++---------------- 1 file changed, 30059 insertions(+), 30446 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 8d17d285dce21..dd17b59555f61 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__(705); +/* harmony import */ var _production__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(703); /* 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__(690); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(689); /* 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__(687); -/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(688); +/* harmony import */ var _run__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(686); +/* harmony import */ var _watch__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(687); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -4497,7 +4497,7 @@ exports.pickLevelFromFlags = tooling_log_1.pickLevelFromFlags; exports.ToolingLogCollectingWriter = tooling_log_1.ToolingLogCollectingWriter; var serializers_1 = __webpack_require__(420); exports.createAbsolutePathSerializer = serializers_1.createAbsolutePathSerializer; -var certs_1 = __webpack_require__(422); +var certs_1 = __webpack_require__(445); exports.CA_CERT_PATH = certs_1.CA_CERT_PATH; exports.ES_KEY_PATH = certs_1.ES_KEY_PATH; exports.ES_CERT_PATH = certs_1.ES_CERT_PATH; @@ -4509,13 +4509,13 @@ exports.KBN_KEY_PATH = certs_1.KBN_KEY_PATH; exports.KBN_CERT_PATH = certs_1.KBN_CERT_PATH; exports.KBN_P12_PATH = certs_1.KBN_P12_PATH; exports.KBN_P12_PASSWORD = certs_1.KBN_P12_PASSWORD; -var run_1 = __webpack_require__(423); +var run_1 = __webpack_require__(446); exports.run = run_1.run; exports.createFailError = run_1.createFailError; exports.createFlagError = run_1.createFlagError; exports.combineErrors = run_1.combineErrors; exports.isFailError = run_1.isFailError; -var repo_root_1 = __webpack_require__(428); +var repo_root_1 = __webpack_require__(422); exports.REPO_ROOT = repo_root_1.REPO_ROOT; var kbn_client_1 = __webpack_require__(451); exports.KbnClient = kbn_client_1.KbnClient; @@ -36959,7 +36959,8 @@ exports.createAbsolutePathSerializer = absolute_path_serializer_1.createAbsolute * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -function createAbsolutePathSerializer(rootPath) { +const repo_root_1 = __webpack_require__(422); +function createAbsolutePathSerializer(rootPath = repo_root_1.REPO_ROOT) { return { print: (value) => value.replace(rootPath, '').replace(/\\/g, '/'), test: (value) => typeof value === 'string' && value.startsWith(rootPath), @@ -36974,79 +36975,6 @@ exports.createAbsolutePathSerializer = createAbsolutePathSerializer; "use strict"; -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -const path_1 = __webpack_require__(16); -exports.CA_CERT_PATH = path_1.resolve(__dirname, '../certs/ca.crt'); -exports.ES_KEY_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.key'); -exports.ES_CERT_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.crt'); -exports.ES_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.p12'); -exports.ES_P12_PASSWORD = 'storepass'; -exports.ES_EMPTYPASSWORD_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch_emptypassword.p12'); -exports.ES_NOPASSWORD_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch_nopassword.p12'); -exports.KBN_KEY_PATH = path_1.resolve(__dirname, '../certs/kibana.key'); -exports.KBN_CERT_PATH = path_1.resolve(__dirname, '../certs/kibana.crt'); -exports.KBN_P12_PATH = path_1.resolve(__dirname, '../certs/kibana.p12'); -exports.KBN_P12_PASSWORD = 'storepass'; - - -/***/ }), -/* 423 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -var run_1 = __webpack_require__(424); -exports.run = run_1.run; -var fail_1 = __webpack_require__(425); -exports.createFailError = fail_1.createFailError; -exports.createFlagError = fail_1.createFlagError; -exports.combineErrors = fail_1.combineErrors; -exports.isFailError = fail_1.isFailError; - - -/***/ }), -/* 424 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -37067,678 +36995,166 @@ exports.isFailError = fail_1.isFailError; */ Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = __webpack_require__(36); -// @ts-ignore @types are outdated and module is super simple -const exit_hook_1 = tslib_1.__importDefault(__webpack_require__(348)); -const tooling_log_1 = __webpack_require__(415); -const fail_1 = __webpack_require__(425); -const flags_1 = __webpack_require__(426); -const proc_runner_1 = __webpack_require__(37); -async function run(fn, options = {}) { - var _a; - const flags = flags_1.getFlags(process.argv.slice(2), options); - if (flags.help) { - process.stderr.write(flags_1.getHelp(options)); - process.exit(1); - } - const log = new tooling_log_1.ToolingLog({ - level: tooling_log_1.pickLevelFromFlags(flags), - writeTo: process.stdout, - }); - process.on('unhandledRejection', error => { - log.error('UNHANDLED PROMISE REJECTION'); - log.error(error); - process.exit(1); - }); - const handleErrorWithoutExit = (error) => { - if (fail_1.isFailError(error)) { - log.error(error.message); - if (error.showHelp) { - log.write(flags_1.getHelp(options)); - } - process.exitCode = error.exitCode; - } - else { - log.error('UNHANDLED ERROR'); - log.error(error); - process.exitCode = 1; - } - }; - const doCleanup = () => { - const tasks = cleanupTasks.slice(0); - cleanupTasks.length = 0; - for (const task of tasks) { - try { - task(); - } - catch (error) { - handleErrorWithoutExit(error); - } - } - }; - const unhookExit = exit_hook_1.default(doCleanup); - const cleanupTasks = [unhookExit]; +const path_1 = tslib_1.__importDefault(__webpack_require__(16)); +const fs_1 = tslib_1.__importDefault(__webpack_require__(23)); +const load_json_file_1 = tslib_1.__importDefault(__webpack_require__(423)); +const isKibanaDir = (dir) => { try { - if (!((_a = options.flags) === null || _a === void 0 ? void 0 : _a.allowUnexpected) && flags.unexpected.length) { - throw fail_1.createFlagError(`Unknown flag(s) "${flags.unexpected.join('", "')}"`); - } - try { - await proc_runner_1.withProcRunner(log, async (procRunner) => { - await fn({ - log, - flags, - procRunner, - addCleanupTask: (task) => cleanupTasks.push(task), - }); - }); - } - finally { - doCleanup(); + const path = path_1.default.resolve(dir, 'package.json'); + const json = load_json_file_1.default.sync(path); + if (json && typeof json === 'object' && 'name' in json && json.name === 'kibana') { + return true; } } catch (error) { - handleErrorWithoutExit(error); - process.exit(); + if (error && error.code === 'ENOENT') { + return false; + } + throw error; + } +}; +// search for the kibana directory, since this file is moved around it might +// not be where we think but should always be a relatively close parent +// of this directory +const startDir = fs_1.default.realpathSync(__dirname); +const { root: rootDir } = path_1.default.parse(startDir); +let cursor = startDir; +while (true) { + if (isKibanaDir(cursor)) { + break; + } + const parent = path_1.default.dirname(cursor); + if (parent === rootDir) { + throw new Error(`unable to find kibana directory from ${startDir}`); } + cursor = parent; } -exports.run = run; +exports.REPO_ROOT = cursor; /***/ }), -/* 425 */ +/* 423 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -const util_1 = __webpack_require__(29); -const FAIL_TAG = Symbol('fail error'); -function createFailError(reason, options = {}) { - const { exitCode = 1, showHelp = false } = options; - return Object.assign(new Error(reason), { - exitCode, - showHelp, - [FAIL_TAG]: true, - }); -} -exports.createFailError = createFailError; -function createFlagError(reason) { - return createFailError(reason, { - showHelp: true, - }); -} -exports.createFlagError = createFlagError; -function isFailError(error) { - return Boolean(error && error[FAIL_TAG]); -} -exports.isFailError = isFailError; -function combineErrors(errors) { - if (errors.length === 1) { - return errors[0]; - } - const exitCode = errors - .filter(isFailError) - .reduce((acc, error) => Math.max(acc, error.exitCode), 1); - const showHelp = errors.some(error => isFailError(error) && error.showHelp); - const message = errors.reduce((acc, error) => { - if (isFailError(error)) { - return acc + '\n' + error.message; - } - return acc + `\nUNHANDLED ERROR\n${util_1.inspect(error)}`; - }, ''); - return createFailError(`${errors.length} errors:\n${message}`, { - exitCode, - showHelp, - }); -} -exports.combineErrors = combineErrors; - - -/***/ }), -/* 426 */ -/***/ (function(module, exports, __webpack_require__) { +const path = __webpack_require__(16); +const {promisify} = __webpack_require__(29); +const fs = __webpack_require__(424); +const stripBom = __webpack_require__(428); +const parseJson = __webpack_require__(429); -"use strict"; +const parse = (data, filePath, options = {}) => { + data = stripBom(data); -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -const tslib_1 = __webpack_require__(36); -const path_1 = __webpack_require__(16); -const dedent_1 = tslib_1.__importDefault(__webpack_require__(14)); -const getopts_1 = tslib_1.__importDefault(__webpack_require__(427)); -function getFlags(argv, options) { - const unexpectedNames = new Set(); - const flagOpts = options.flags || {}; - const { verbose, quiet, silent, debug, help, _, ...others } = getopts_1.default(argv, { - string: flagOpts.string, - boolean: [...(flagOpts.boolean || []), 'verbose', 'quiet', 'silent', 'debug', 'help'], - alias: { - ...(flagOpts.alias || {}), - v: 'verbose', - }, - default: flagOpts.default, - unknown: (name) => { - unexpectedNames.add(name); - return flagOpts.guessTypesForUnexpectedFlags; - }, - }); - const unexpected = []; - for (const unexpectedName of unexpectedNames) { - const matchingArgv = []; - iterArgv: for (const [i, v] of argv.entries()) { - for (const prefix of ['--', '-']) { - if (v.startsWith(prefix)) { - // -/--name=value - if (v.startsWith(`${prefix}${unexpectedName}=`)) { - matchingArgv.push(v); - continue iterArgv; - } - // -/--name (value possibly follows) - if (v === `${prefix}${unexpectedName}`) { - matchingArgv.push(v); - // value follows -/--name - if (argv.length > i + 1 && !argv[i + 1].startsWith('-')) { - matchingArgv.push(argv[i + 1]); - } - continue iterArgv; - } - } - } - // special case for `--no-{flag}` disabling of boolean flags - if (v === `--no-${unexpectedName}`) { - matchingArgv.push(v); - continue iterArgv; - } - // special case for shortcut flags formatted as `-abc` where `a`, `b`, - // and `c` will be three separate unexpected flags - if (unexpectedName.length === 1 && - v[0] === '-' && - v[1] !== '-' && - !v.includes('=') && - v.includes(unexpectedName)) { - matchingArgv.push(`-${unexpectedName}`); - continue iterArgv; - } - } - if (matchingArgv.length) { - unexpected.push(...matchingArgv); - } - else { - throw new Error(`unable to find unexpected flag named "${unexpectedName}"`); - } - } - return { - verbose, - quiet, - silent, - debug, - help, - _, - unexpected, - ...others, - }; -} -exports.getFlags = getFlags; -function getHelp(options) { - var _a, _b; - const usage = options.usage || `node ${path_1.relative(process.cwd(), process.argv[1])}`; - const optionHelp = (dedent_1.default(((_b = (_a = options) === null || _a === void 0 ? void 0 : _a.flags) === null || _b === void 0 ? void 0 : _b.help) || '') + - '\n' + - dedent_1.default ` - --verbose, -v Log verbosely - --debug Log debug messages (less than verbose) - --quiet Only log errors - --silent Don't log anything - --help Show this message - `) - .split('\n') - .filter(Boolean) - .join('\n '); - return ` - ${usage} + if (typeof options.beforeParse === 'function') { + data = options.beforeParse(data); + } - ${dedent_1.default(options.description || 'Runs a dev task') - .split('\n') - .join('\n ')} + return parseJson(data, options.reviver, path.relative(process.cwd(), filePath)); +}; - Options: - ${optionHelp + '\n\n'}`; -} -exports.getHelp = getHelp; +module.exports = async (filePath, options) => parse(await promisify(fs.readFile)(filePath, 'utf8'), filePath, options); +module.exports.sync = (filePath, options) => parse(fs.readFileSync(filePath, 'utf8'), filePath, options); /***/ }), -/* 427 */ +/* 424 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - - -const EMPTYARR = [] -const SHORTSPLIT = /$|[!-@[-`{-~][\s\S]*/g -const isArray = Array.isArray - -const parseValue = function(any) { - if (any === "") return "" - if (any === "false") return false - const maybe = Number(any) - return maybe * 0 === 0 ? maybe : any -} +var fs = __webpack_require__(23) +var polyfills = __webpack_require__(425) +var legacy = __webpack_require__(426) +var clone = __webpack_require__(427) -const parseAlias = function(aliases) { - let out = {}, - key, - alias, - prev, - len, - any, - i, - k +var queue = [] - for (key in aliases) { - any = aliases[key] - alias = out[key] = isArray(any) ? any : [any] +var util = __webpack_require__(29) - for (i = 0, len = alias.length; i < len; i++) { - prev = out[alias[i]] = [key] +function noop () {} - for (k = 0; k < len; k++) { - if (i !== k) prev.push(alias[k]) - } - } +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 out +if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { + process.on('exit', function() { + debug(queue) + __webpack_require__(30).equal(queue.length, 0) + }) } -const parseDefault = function(aliases, defaults) { - let out = {}, - key, - alias, - value, - len, - i +module.exports = patch(clone(fs)) +if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { + module.exports = patch(fs) + fs.__patched = true; +} - for (key in defaults) { - value = defaults[key] - alias = aliases[key] +// Always patch fs.close/closeSync, because we want 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. +module.exports.close = (function (fs$close) { return function (fd, cb) { + return fs$close.call(fs, fd, function (err) { + if (!err) + retry() - out[key] = value + if (typeof cb === 'function') + cb.apply(this, arguments) + }) +}})(fs.close) - if (alias === undefined) { - aliases[key] = EMPTYARR - } else { - for (i = 0, len = alias.length; i < len; i++) { - out[alias[i]] = value - } - } - } +module.exports.closeSync = (function (fs$closeSync) { return function (fd) { + // Note that graceful-fs also retries when fs.closeSync() fails. + // Looks like a bug to me, although it's probably a harmless one. + var rval = fs$closeSync.apply(fs, arguments) + retry() + return rval +}})(fs.closeSync) - return out +// Only patch fs once, otherwise we'll run into a memory leak if +// graceful-fs is loaded multiple times, such as in test environments that +// reset the loaded modules between tests. +// We look for the string `graceful-fs` from the comment above. This +// way we are not adding any extra properties and it will detect if older +// versions of graceful-fs are installed. +if (!/\bgraceful-fs\b/.test(fs.closeSync.toString())) { + fs.closeSync = module.exports.closeSync; + fs.close = module.exports.close; } -const parseOptions = function(aliases, options, value) { - let out = {}, - key, - alias, - len, - end, - i, - k - - if (options !== undefined) { - for (i = 0, len = options.length; i < len; i++) { - key = options[i] - alias = aliases[key] +function patch (fs) { + // Everything that references the open() function needs to be in here + polyfills(fs) + fs.gracefulify = patch + fs.FileReadStream = ReadStream; // Legacy name. + fs.FileWriteStream = WriteStream; // Legacy name. + 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 - out[key] = value + return go$readFile(path, options, cb) - if (alias === undefined) { - aliases[key] = EMPTYARR - } else { - for (k = 0, end = alias.length; k < end; k++) { - out[alias[k]] = value + 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() } - } - } - } - - return out -} - -const write = function(out, key, value, aliases, unknown) { - let i, - prev, - alias = aliases[key], - len = alias === undefined ? -1 : alias.length - - if (len >= 0 || unknown === undefined || unknown(key)) { - prev = out[key] - - if (prev === undefined) { - out[key] = value - } else { - if (isArray(prev)) { - prev.push(value) - } else { - out[key] = [prev, value] - } - } - - for (i = 0; i < len; i++) { - out[alias[i]] = out[key] - } - } -} - -const getopts = function(argv, opts) { - let unknown = (opts = opts || {}).unknown, - aliases = parseAlias(opts.alias), - strings = parseOptions(aliases, opts.string, ""), - values = parseDefault(aliases, opts.default), - bools = parseOptions(aliases, opts.boolean, false), - stopEarly = opts.stopEarly, - _ = [], - out = { _ }, - i = 0, - k = 0, - len = argv.length, - key, - arg, - end, - match, - value - - for (; i < len; i++) { - arg = argv[i] - - if (arg[0] !== "-" || arg === "-") { - if (stopEarly) while (i < len) _.push(argv[i++]) - else _.push(arg) - } else if (arg === "--") { - while (++i < len) _.push(argv[i]) - } else if (arg[1] === "-") { - end = arg.indexOf("=", 2) - if (arg[2] === "n" && arg[3] === "o" && arg[4] === "-") { - key = arg.slice(5, end >= 0 ? end : undefined) - value = false - } else if (end >= 0) { - key = arg.slice(2, end) - value = - bools[key] !== undefined || - (strings[key] === undefined - ? parseValue(arg.slice(end + 1)) - : arg.slice(end + 1)) - } else { - key = arg.slice(2) - value = - bools[key] !== undefined || - (len === i + 1 || argv[i + 1][0] === "-" - ? strings[key] === undefined - ? true - : "" - : strings[key] === undefined - ? parseValue(argv[++i]) - : argv[++i]) - } - write(out, key, value, aliases, unknown) - } else { - SHORTSPLIT.lastIndex = 2 - match = SHORTSPLIT.exec(arg) - end = match.index - value = match[0] - - for (k = 1; k < end; k++) { - write( - out, - (key = arg[k]), - k + 1 < end - ? strings[key] === undefined || - arg.substring(k + 1, (k = end)) + value - : value === "" - ? len === i + 1 || argv[i + 1][0] === "-" - ? strings[key] === undefined || "" - : bools[key] !== undefined || - (strings[key] === undefined ? parseValue(argv[++i]) : argv[++i]) - : bools[key] !== undefined || - (strings[key] === undefined ? parseValue(value) : value), - aliases, - unknown - ) - } - } - } - - for (key in values) if (out[key] === undefined) out[key] = values[key] - for (key in bools) if (out[key] === undefined) out[key] = false - for (key in strings) if (out[key] === undefined) out[key] = "" - - return out -} - -module.exports = getopts - - -/***/ }), -/* 428 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* - * 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. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -const tslib_1 = __webpack_require__(36); -const path_1 = tslib_1.__importDefault(__webpack_require__(16)); -const fs_1 = tslib_1.__importDefault(__webpack_require__(23)); -const load_json_file_1 = tslib_1.__importDefault(__webpack_require__(429)); -const isKibanaDir = (dir) => { - try { - const path = path_1.default.resolve(dir, 'package.json'); - const json = load_json_file_1.default.sync(path); - if (json && typeof json === 'object' && 'name' in json && json.name === 'kibana') { - return true; - } - } - catch (error) { - if (error && error.code === 'ENOENT') { - return false; - } - throw error; - } -}; -// search for the kibana directory, since this file is moved around it might -// not be where we think but should always be a relatively close parent -// of this directory -const startDir = fs_1.default.realpathSync(__dirname); -const { root: rootDir } = path_1.default.parse(startDir); -let cursor = startDir; -while (true) { - if (isKibanaDir(cursor)) { - break; - } - const parent = path_1.default.dirname(cursor); - if (parent === rootDir) { - throw new Error(`unable to find kibana directory from ${startDir}`); - } - cursor = parent; -} -exports.REPO_ROOT = cursor; - - -/***/ }), -/* 429 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const path = __webpack_require__(16); -const {promisify} = __webpack_require__(29); -const fs = __webpack_require__(430); -const stripBom = __webpack_require__(434); -const parseJson = __webpack_require__(435); - -const parse = (data, filePath, options = {}) => { - data = stripBom(data); - - if (typeof options.beforeParse === 'function') { - data = options.beforeParse(data); - } - - return parseJson(data, options.reviver, path.relative(process.cwd(), filePath)); -}; - -module.exports = async (filePath, options) => parse(await promisify(fs.readFile)(filePath, 'utf8'), filePath, options); -module.exports.sync = (filePath, options) => parse(fs.readFileSync(filePath, 'utf8'), filePath, options); - - -/***/ }), -/* 430 */ -/***/ (function(module, exports, __webpack_require__) { - -var fs = __webpack_require__(23) -var polyfills = __webpack_require__(431) -var legacy = __webpack_require__(432) -var clone = __webpack_require__(433) - -var queue = [] - -var util = __webpack_require__(29) - -function noop () {} - -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) - } - -if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { - process.on('exit', function() { - debug(queue) - __webpack_require__(30).equal(queue.length, 0) - }) -} - -module.exports = patch(clone(fs)) -if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { - module.exports = patch(fs) - fs.__patched = true; -} - -// Always patch fs.close/closeSync, because we want 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. -module.exports.close = (function (fs$close) { return function (fd, cb) { - return fs$close.call(fs, fd, function (err) { - if (!err) - retry() - - if (typeof cb === 'function') - cb.apply(this, arguments) - }) -}})(fs.close) - -module.exports.closeSync = (function (fs$closeSync) { return function (fd) { - // Note that graceful-fs also retries when fs.closeSync() fails. - // Looks like a bug to me, although it's probably a harmless one. - var rval = fs$closeSync.apply(fs, arguments) - retry() - return rval -}})(fs.closeSync) - -// Only patch fs once, otherwise we'll run into a memory leak if -// graceful-fs is loaded multiple times, such as in test environments that -// reset the loaded modules between tests. -// We look for the string `graceful-fs` from the comment above. This -// way we are not adding any extra properties and it will detect if older -// versions of graceful-fs are installed. -if (!/\bgraceful-fs\b/.test(fs.closeSync.toString())) { - fs.closeSync = module.exports.closeSync; - fs.close = module.exports.close; -} - -function patch (fs) { - // Everything that references the open() function needs to be in here - polyfills(fs) - fs.gracefulify = patch - fs.FileReadStream = ReadStream; // Legacy name. - fs.FileWriteStream = WriteStream; // Legacy name. - 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) - - 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() - } - }) + }) } } @@ -37928,7 +37344,7 @@ function retry () { /***/ }), -/* 431 */ +/* 425 */ /***/ (function(module, exports, __webpack_require__) { var constants = __webpack_require__(25) @@ -38263,7 +37679,7 @@ function patch (fs) { /***/ }), -/* 432 */ +/* 426 */ /***/ (function(module, exports, __webpack_require__) { var Stream = __webpack_require__(27).Stream @@ -38387,7 +37803,7 @@ function legacy (fs) { /***/ }), -/* 433 */ +/* 427 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38413,7 +37829,7 @@ function clone (obj) { /***/ }), -/* 434 */ +/* 428 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38435,15 +37851,15 @@ module.exports = string => { /***/ }), -/* 435 */ +/* 429 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const errorEx = __webpack_require__(436); -const fallback = __webpack_require__(438); -const {default: LinesAndColumns} = __webpack_require__(439); -const {codeFrameColumns} = __webpack_require__(440); +const errorEx = __webpack_require__(430); +const fallback = __webpack_require__(432); +const {default: LinesAndColumns} = __webpack_require__(433); +const {codeFrameColumns} = __webpack_require__(434); const JSONError = errorEx('JSONError', { fileName: errorEx.append('in %s'), @@ -38492,14 +37908,14 @@ module.exports = (string, reviver, filename) => { /***/ }), -/* 436 */ +/* 430 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var isArrayish = __webpack_require__(437); +var isArrayish = __webpack_require__(431); var errorEx = function errorEx(name, properties) { if (!name || name.constructor !== String) { @@ -38632,7 +38048,7 @@ module.exports = errorEx; /***/ }), -/* 437 */ +/* 431 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38649,7 +38065,7 @@ module.exports = function isArrayish(obj) { /***/ }), -/* 438 */ +/* 432 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38688,7 +38104,7 @@ function parseJson (txt, reviver, context) { /***/ }), -/* 439 */ +/* 433 */ /***/ (function(__webpack_module__, __webpack_exports__, __webpack_require__) { "use strict"; @@ -38752,7 +38168,7 @@ var LinesAndColumns = (function () { /***/ }), -/* 440 */ +/* 434 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38765,7 +38181,7 @@ exports.codeFrameColumns = codeFrameColumns; exports.default = _default; function _highlight() { - const data = _interopRequireWildcard(__webpack_require__(441)); + const data = _interopRequireWildcard(__webpack_require__(435)); _highlight = function () { return data; @@ -38931,7 +38347,7 @@ function _default(rawLines, lineNumber, colNumber, opts = {}) { } /***/ }), -/* 441 */ +/* 435 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -38945,7 +38361,7 @@ exports.getChalk = getChalk; exports.default = highlight; function _jsTokens() { - const data = _interopRequireWildcard(__webpack_require__(442)); + const data = _interopRequireWildcard(__webpack_require__(436)); _jsTokens = function () { return data; @@ -38955,7 +38371,7 @@ function _jsTokens() { } function _esutils() { - const data = _interopRequireDefault(__webpack_require__(443)); + const data = _interopRequireDefault(__webpack_require__(437)); _esutils = function () { return data; @@ -38965,7 +38381,7 @@ function _esutils() { } function _chalk() { - const data = _interopRequireDefault(__webpack_require__(447)); + const data = _interopRequireDefault(__webpack_require__(441)); _chalk = function () { return data; @@ -39066,7 +38482,7 @@ function highlight(code, options = {}) { } /***/ }), -/* 442 */ +/* 436 */ /***/ (function(module, exports) { // Copyright 2014, 2015, 2016, 2017, 2018 Simon Lydell @@ -39095,7 +38511,7 @@ exports.matchToToken = function(match) { /***/ }), -/* 443 */ +/* 437 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -39126,15 +38542,15 @@ exports.matchToToken = function(match) { (function () { 'use strict'; - exports.ast = __webpack_require__(444); - exports.code = __webpack_require__(445); - exports.keyword = __webpack_require__(446); + exports.ast = __webpack_require__(438); + exports.code = __webpack_require__(439); + exports.keyword = __webpack_require__(440); }()); /* vim: set sw=4 ts=4 et tw=80 : */ /***/ }), -/* 444 */ +/* 438 */ /***/ (function(module, exports) { /* @@ -39284,7 +38700,7 @@ exports.matchToToken = function(match) { /***/ }), -/* 445 */ +/* 439 */ /***/ (function(module, exports) { /* @@ -39425,7 +38841,7 @@ exports.matchToToken = function(match) { /***/ }), -/* 446 */ +/* 440 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -39455,7 +38871,7 @@ exports.matchToToken = function(match) { (function () { 'use strict'; - var code = __webpack_require__(445); + var code = __webpack_require__(439); function isStrictModeReservedWordES6(id) { switch (id) { @@ -39596,16 +39012,16 @@ exports.matchToToken = function(match) { /***/ }), -/* 447 */ +/* 441 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const escapeStringRegexp = __webpack_require__(3); -const ansiStyles = __webpack_require__(448); -const stdoutColor = __webpack_require__(449).stdout; +const ansiStyles = __webpack_require__(442); +const stdoutColor = __webpack_require__(443).stdout; -const template = __webpack_require__(450); +const template = __webpack_require__(444); const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); @@ -39831,7 +39247,7 @@ module.exports.default = module.exports; // For TypeScript /***/ }), -/* 448 */ +/* 442 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40004,7 +39420,7 @@ Object.defineProperty(module, 'exports', { /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 449 */ +/* 443 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40146,7 +39562,7 @@ module.exports = { /***/ }), -/* 450 */ +/* 444 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40281,7 +39697,7 @@ module.exports = (chalk, tmp) => { /***/ }), -/* 451 */ +/* 445 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40305,14 +39721,22 @@ module.exports = (chalk, tmp) => { * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -var kbn_client_1 = __webpack_require__(452); -exports.KbnClient = kbn_client_1.KbnClient; -var kbn_client_requester_1 = __webpack_require__(453); -exports.uriencode = kbn_client_requester_1.uriencode; +const path_1 = __webpack_require__(16); +exports.CA_CERT_PATH = path_1.resolve(__dirname, '../certs/ca.crt'); +exports.ES_KEY_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.key'); +exports.ES_CERT_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.crt'); +exports.ES_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch.p12'); +exports.ES_P12_PASSWORD = 'storepass'; +exports.ES_EMPTYPASSWORD_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch_emptypassword.p12'); +exports.ES_NOPASSWORD_P12_PATH = path_1.resolve(__dirname, '../certs/elasticsearch_nopassword.p12'); +exports.KBN_KEY_PATH = path_1.resolve(__dirname, '../certs/kibana.key'); +exports.KBN_CERT_PATH = path_1.resolve(__dirname, '../certs/kibana.crt'); +exports.KBN_P12_PATH = path_1.resolve(__dirname, '../certs/kibana.p12'); +exports.KBN_P12_PASSWORD = 'storepass'; /***/ }), -/* 452 */ +/* 446 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -40336,50 +39760,627 @@ exports.uriencode = kbn_client_requester_1.uriencode; * under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); -const kbn_client_requester_1 = __webpack_require__(453); -const kbn_client_status_1 = __webpack_require__(495); -const kbn_client_plugins_1 = __webpack_require__(496); -const kbn_client_version_1 = __webpack_require__(497); -const kbn_client_saved_objects_1 = __webpack_require__(498); -const kbn_client_ui_settings_1 = __webpack_require__(499); -class KbnClient { - /** - * Basic Kibana server client that implements common behaviors for talking - * to the Kibana server from dev tooling. - * - * @param log ToolingLog - * @param kibanaUrls Array of kibana server urls to send requests to - * @param uiSettingDefaults Map of uiSetting values that will be merged with all uiSetting resets - */ - constructor(log, kibanaUrls, uiSettingDefaults) { - this.log = log; - this.kibanaUrls = kibanaUrls; - this.uiSettingDefaults = uiSettingDefaults; - this.requester = new kbn_client_requester_1.KbnClientRequester(this.log, this.kibanaUrls); - this.status = new kbn_client_status_1.KbnClientStatus(this.requester); - this.plugins = new kbn_client_plugins_1.KbnClientPlugins(this.status); - this.version = new kbn_client_version_1.KbnClientVersion(this.status); - this.savedObjects = new kbn_client_saved_objects_1.KbnClientSavedObjects(this.log, this.requester); - this.uiSettings = new kbn_client_ui_settings_1.KbnClientUiSettings(this.log, this.requester, this.uiSettingDefaults); - if (!kibanaUrls.length) { - throw new Error('missing Kibana urls'); +var run_1 = __webpack_require__(447); +exports.run = run_1.run; +var fail_1 = __webpack_require__(448); +exports.createFailError = fail_1.createFailError; +exports.createFlagError = fail_1.createFlagError; +exports.combineErrors = fail_1.combineErrors; +exports.isFailError = fail_1.isFailError; + + +/***/ }), +/* 447 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const tslib_1 = __webpack_require__(36); +// @ts-ignore @types are outdated and module is super simple +const exit_hook_1 = tslib_1.__importDefault(__webpack_require__(348)); +const tooling_log_1 = __webpack_require__(415); +const fail_1 = __webpack_require__(448); +const flags_1 = __webpack_require__(449); +const proc_runner_1 = __webpack_require__(37); +async function run(fn, options = {}) { + var _a; + const flags = flags_1.getFlags(process.argv.slice(2), options); + if (flags.help) { + process.stderr.write(flags_1.getHelp(options)); + process.exit(1); + } + const log = new tooling_log_1.ToolingLog({ + level: tooling_log_1.pickLevelFromFlags(flags), + writeTo: process.stdout, + }); + process.on('unhandledRejection', error => { + log.error('UNHANDLED PROMISE REJECTION'); + log.error(error); + process.exit(1); + }); + const handleErrorWithoutExit = (error) => { + if (fail_1.isFailError(error)) { + log.error(error.message); + if (error.showHelp) { + log.write(flags_1.getHelp(options)); + } + process.exitCode = error.exitCode; + } + else { + log.error('UNHANDLED ERROR'); + log.error(error); + process.exitCode = 1; + } + }; + const doCleanup = () => { + const tasks = cleanupTasks.slice(0); + cleanupTasks.length = 0; + for (const task of tasks) { + try { + task(); + } + catch (error) { + handleErrorWithoutExit(error); + } + } + }; + const unhookExit = exit_hook_1.default(doCleanup); + const cleanupTasks = [unhookExit]; + try { + if (!((_a = options.flags) === null || _a === void 0 ? void 0 : _a.allowUnexpected) && flags.unexpected.length) { + throw fail_1.createFlagError(`Unknown flag(s) "${flags.unexpected.join('", "')}"`); + } + try { + await proc_runner_1.withProcRunner(log, async (procRunner) => { + await fn({ + log, + flags, + procRunner, + addCleanupTask: (task) => cleanupTasks.push(task), + }); + }); + } + finally { + doCleanup(); } } - /** - * Make a direct request to the Kibana server - */ - async request(options) { - return await this.requester.request(options); + catch (error) { + handleErrorWithoutExit(error); + process.exit(); } - resolveUrl(relativeUrl) { - return this.requester.resolveUrl(relativeUrl); +} +exports.run = run; + + +/***/ }), +/* 448 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const util_1 = __webpack_require__(29); +const FAIL_TAG = Symbol('fail error'); +function createFailError(reason, options = {}) { + const { exitCode = 1, showHelp = false } = options; + return Object.assign(new Error(reason), { + exitCode, + showHelp, + [FAIL_TAG]: true, + }); +} +exports.createFailError = createFailError; +function createFlagError(reason) { + return createFailError(reason, { + showHelp: true, + }); +} +exports.createFlagError = createFlagError; +function isFailError(error) { + return Boolean(error && error[FAIL_TAG]); +} +exports.isFailError = isFailError; +function combineErrors(errors) { + if (errors.length === 1) { + return errors[0]; } + const exitCode = errors + .filter(isFailError) + .reduce((acc, error) => Math.max(acc, error.exitCode), 1); + const showHelp = errors.some(error => isFailError(error) && error.showHelp); + const message = errors.reduce((acc, error) => { + if (isFailError(error)) { + return acc + '\n' + error.message; + } + return acc + `\nUNHANDLED ERROR\n${util_1.inspect(error)}`; + }, ''); + return createFailError(`${errors.length} errors:\n${message}`, { + exitCode, + showHelp, + }); } -exports.KbnClient = KbnClient; +exports.combineErrors = combineErrors; /***/ }), -/* 453 */ +/* 449 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const tslib_1 = __webpack_require__(36); +const path_1 = __webpack_require__(16); +const dedent_1 = tslib_1.__importDefault(__webpack_require__(14)); +const getopts_1 = tslib_1.__importDefault(__webpack_require__(450)); +function getFlags(argv, options) { + const unexpectedNames = new Set(); + const flagOpts = options.flags || {}; + const { verbose, quiet, silent, debug, help, _, ...others } = getopts_1.default(argv, { + string: flagOpts.string, + boolean: [...(flagOpts.boolean || []), 'verbose', 'quiet', 'silent', 'debug', 'help'], + alias: { + ...(flagOpts.alias || {}), + v: 'verbose', + }, + default: flagOpts.default, + unknown: (name) => { + unexpectedNames.add(name); + return flagOpts.guessTypesForUnexpectedFlags; + }, + }); + const unexpected = []; + for (const unexpectedName of unexpectedNames) { + const matchingArgv = []; + iterArgv: for (const [i, v] of argv.entries()) { + for (const prefix of ['--', '-']) { + if (v.startsWith(prefix)) { + // -/--name=value + if (v.startsWith(`${prefix}${unexpectedName}=`)) { + matchingArgv.push(v); + continue iterArgv; + } + // -/--name (value possibly follows) + if (v === `${prefix}${unexpectedName}`) { + matchingArgv.push(v); + // value follows -/--name + if (argv.length > i + 1 && !argv[i + 1].startsWith('-')) { + matchingArgv.push(argv[i + 1]); + } + continue iterArgv; + } + } + } + // special case for `--no-{flag}` disabling of boolean flags + if (v === `--no-${unexpectedName}`) { + matchingArgv.push(v); + continue iterArgv; + } + // special case for shortcut flags formatted as `-abc` where `a`, `b`, + // and `c` will be three separate unexpected flags + if (unexpectedName.length === 1 && + v[0] === '-' && + v[1] !== '-' && + !v.includes('=') && + v.includes(unexpectedName)) { + matchingArgv.push(`-${unexpectedName}`); + continue iterArgv; + } + } + if (matchingArgv.length) { + unexpected.push(...matchingArgv); + } + else { + throw new Error(`unable to find unexpected flag named "${unexpectedName}"`); + } + } + return { + verbose, + quiet, + silent, + debug, + help, + _, + unexpected, + ...others, + }; +} +exports.getFlags = getFlags; +function getHelp(options) { + var _a, _b; + const usage = options.usage || `node ${path_1.relative(process.cwd(), process.argv[1])}`; + const optionHelp = (dedent_1.default(((_b = (_a = options) === null || _a === void 0 ? void 0 : _a.flags) === null || _b === void 0 ? void 0 : _b.help) || '') + + '\n' + + dedent_1.default ` + --verbose, -v Log verbosely + --debug Log debug messages (less than verbose) + --quiet Only log errors + --silent Don't log anything + --help Show this message + `) + .split('\n') + .filter(Boolean) + .join('\n '); + return ` + ${usage} + + ${dedent_1.default(options.description || 'Runs a dev task') + .split('\n') + .join('\n ')} + + Options: + ${optionHelp + '\n\n'}`; +} +exports.getHelp = getHelp; + + +/***/ }), +/* 450 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const EMPTYARR = [] +const SHORTSPLIT = /$|[!-@[-`{-~][\s\S]*/g +const isArray = Array.isArray + +const parseValue = function(any) { + if (any === "") return "" + if (any === "false") return false + const maybe = Number(any) + return maybe * 0 === 0 ? maybe : any +} + +const parseAlias = function(aliases) { + let out = {}, + key, + alias, + prev, + len, + any, + i, + k + + for (key in aliases) { + any = aliases[key] + alias = out[key] = isArray(any) ? any : [any] + + for (i = 0, len = alias.length; i < len; i++) { + prev = out[alias[i]] = [key] + + for (k = 0; k < len; k++) { + if (i !== k) prev.push(alias[k]) + } + } + } + + return out +} + +const parseDefault = function(aliases, defaults) { + let out = {}, + key, + alias, + value, + len, + i + + for (key in defaults) { + value = defaults[key] + alias = aliases[key] + + out[key] = value + + if (alias === undefined) { + aliases[key] = EMPTYARR + } else { + for (i = 0, len = alias.length; i < len; i++) { + out[alias[i]] = value + } + } + } + + return out +} + +const parseOptions = function(aliases, options, value) { + let out = {}, + key, + alias, + len, + end, + i, + k + + if (options !== undefined) { + for (i = 0, len = options.length; i < len; i++) { + key = options[i] + alias = aliases[key] + + out[key] = value + + if (alias === undefined) { + aliases[key] = EMPTYARR + } else { + for (k = 0, end = alias.length; k < end; k++) { + out[alias[k]] = value + } + } + } + } + + return out +} + +const write = function(out, key, value, aliases, unknown) { + let i, + prev, + alias = aliases[key], + len = alias === undefined ? -1 : alias.length + + if (len >= 0 || unknown === undefined || unknown(key)) { + prev = out[key] + + if (prev === undefined) { + out[key] = value + } else { + if (isArray(prev)) { + prev.push(value) + } else { + out[key] = [prev, value] + } + } + + for (i = 0; i < len; i++) { + out[alias[i]] = out[key] + } + } +} + +const getopts = function(argv, opts) { + let unknown = (opts = opts || {}).unknown, + aliases = parseAlias(opts.alias), + strings = parseOptions(aliases, opts.string, ""), + values = parseDefault(aliases, opts.default), + bools = parseOptions(aliases, opts.boolean, false), + stopEarly = opts.stopEarly, + _ = [], + out = { _ }, + i = 0, + k = 0, + len = argv.length, + key, + arg, + end, + match, + value + + for (; i < len; i++) { + arg = argv[i] + + if (arg[0] !== "-" || arg === "-") { + if (stopEarly) while (i < len) _.push(argv[i++]) + else _.push(arg) + } else if (arg === "--") { + while (++i < len) _.push(argv[i]) + } else if (arg[1] === "-") { + end = arg.indexOf("=", 2) + if (arg[2] === "n" && arg[3] === "o" && arg[4] === "-") { + key = arg.slice(5, end >= 0 ? end : undefined) + value = false + } else if (end >= 0) { + key = arg.slice(2, end) + value = + bools[key] !== undefined || + (strings[key] === undefined + ? parseValue(arg.slice(end + 1)) + : arg.slice(end + 1)) + } else { + key = arg.slice(2) + value = + bools[key] !== undefined || + (len === i + 1 || argv[i + 1][0] === "-" + ? strings[key] === undefined + ? true + : "" + : strings[key] === undefined + ? parseValue(argv[++i]) + : argv[++i]) + } + write(out, key, value, aliases, unknown) + } else { + SHORTSPLIT.lastIndex = 2 + match = SHORTSPLIT.exec(arg) + end = match.index + value = match[0] + + for (k = 1; k < end; k++) { + write( + out, + (key = arg[k]), + k + 1 < end + ? strings[key] === undefined || + arg.substring(k + 1, (k = end)) + value + : value === "" + ? len === i + 1 || argv[i + 1][0] === "-" + ? strings[key] === undefined || "" + : bools[key] !== undefined || + (strings[key] === undefined ? parseValue(argv[++i]) : argv[++i]) + : bools[key] !== undefined || + (strings[key] === undefined ? parseValue(value) : value), + aliases, + unknown + ) + } + } + } + + for (key in values) if (out[key] === undefined) out[key] = values[key] + for (key in bools) if (out[key] === undefined) out[key] = false + for (key in strings) if (out[key] === undefined) out[key] = "" + + return out +} + +module.exports = getopts + + +/***/ }), +/* 451 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +var kbn_client_1 = __webpack_require__(452); +exports.KbnClient = kbn_client_1.KbnClient; +var kbn_client_requester_1 = __webpack_require__(453); +exports.uriencode = kbn_client_requester_1.uriencode; + + +/***/ }), +/* 452 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* + * 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. + */ +Object.defineProperty(exports, "__esModule", { value: true }); +const kbn_client_requester_1 = __webpack_require__(453); +const kbn_client_status_1 = __webpack_require__(495); +const kbn_client_plugins_1 = __webpack_require__(496); +const kbn_client_version_1 = __webpack_require__(497); +const kbn_client_saved_objects_1 = __webpack_require__(498); +const kbn_client_ui_settings_1 = __webpack_require__(499); +class KbnClient { + /** + * Basic Kibana server client that implements common behaviors for talking + * to the Kibana server from dev tooling. + * + * @param log ToolingLog + * @param kibanaUrls Array of kibana server urls to send requests to + * @param uiSettingDefaults Map of uiSetting values that will be merged with all uiSetting resets + */ + constructor(log, kibanaUrls, uiSettingDefaults) { + this.log = log; + this.kibanaUrls = kibanaUrls; + this.uiSettingDefaults = uiSettingDefaults; + this.requester = new kbn_client_requester_1.KbnClientRequester(this.log, this.kibanaUrls); + this.status = new kbn_client_status_1.KbnClientStatus(this.requester); + this.plugins = new kbn_client_plugins_1.KbnClientPlugins(this.status); + this.version = new kbn_client_version_1.KbnClientVersion(this.status); + this.savedObjects = new kbn_client_saved_objects_1.KbnClientSavedObjects(this.log, this.requester); + this.uiSettings = new kbn_client_ui_settings_1.KbnClientUiSettings(this.log, this.requester, this.uiSettingDefaults); + if (!kibanaUrls.length) { + throw new Error('missing Kibana urls'); + } + } + /** + * Make a direct request to the Kibana server + */ + async request(options) { + return await this.requester.request(options); + } + resolveUrl(relativeUrl) { + return this.requester.resolveUrl(relativeUrl); + } +} +exports.KbnClient = KbnClient; + + +/***/ }), +/* 453 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -43034,28 +43035,21 @@ module.exports = require("tty"); const os = __webpack_require__(11); const hasFlag = __webpack_require__(12); -const {env} = process; +const env = process.env; let forceColor; if (hasFlag('no-color') || hasFlag('no-colors') || - hasFlag('color=false') || - hasFlag('color=never')) { - forceColor = 0; + hasFlag('color=false')) { + forceColor = false; } else if (hasFlag('color') || hasFlag('colors') || hasFlag('color=true') || hasFlag('color=always')) { - forceColor = 1; + forceColor = true; } if ('FORCE_COLOR' in env) { - if (env.FORCE_COLOR === true || env.FORCE_COLOR === 'true') { - forceColor = 1; - } else if (env.FORCE_COLOR === false || env.FORCE_COLOR === 'false') { - forceColor = 0; - } else { - forceColor = env.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env.FORCE_COLOR, 10), 3); - } + forceColor = env.FORCE_COLOR.length === 0 || parseInt(env.FORCE_COLOR, 10) !== 0; } function translateLevel(level) { @@ -43072,7 +43066,7 @@ function translateLevel(level) { } function supportsColor(stream) { - if (forceColor === 0) { + if (forceColor === false) { return 0; } @@ -43086,15 +43080,11 @@ function supportsColor(stream) { return 2; } - if (stream && !stream.isTTY && forceColor === undefined) { + if (stream && !stream.isTTY && forceColor !== true) { return 0; } - const min = forceColor || 0; - - if (env.TERM === 'dumb') { - return min; - } + const min = forceColor ? 1 : 0; if (process.platform === 'win32') { // Node.js 7.5.0 is the first version of Node.js to include a patch to @@ -43155,6 +43145,10 @@ function supportsColor(stream) { return 1; } + if (env.TERM === 'dumb') { + return min; + } + return min; } @@ -46624,11 +46618,9 @@ 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); } @@ -46640,28 +46632,24 @@ try { 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 - } - }) - } + 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 - } + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor } } @@ -47870,10 +47858,10 @@ module.exports.sync = options => { "use strict"; -const errorEx = __webpack_require__(436); -const fallback = __webpack_require__(438); -const {default: LinesAndColumns} = __webpack_require__(439); -const {codeFrameColumns} = __webpack_require__(440); +const errorEx = __webpack_require__(430); +const fallback = __webpack_require__(432); +const {default: LinesAndColumns} = __webpack_require__(433); +const {codeFrameColumns} = __webpack_require__(434); const JSONError = errorEx('JSONError', { fileName: errorEx.append('in %s'), @@ -68976,7 +68964,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__(676); +/* harmony import */ var ora__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(675); /* 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__); @@ -69084,13 +69072,13 @@ const CleanCommand = { const {promisify} = __webpack_require__(29); const path = __webpack_require__(16); const globby = __webpack_require__(589); -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 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 rimrafP = promisify(rimraf); @@ -69212,11 +69200,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__(592); -const fastGlob = __webpack_require__(597); -const dirGlob = __webpack_require__(663); -const gitignore = __webpack_require__(665); -const {FilterStream, UniqueStream} = __webpack_require__(668); +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 DEFAULT_FILTER = () => false; @@ -69518,4341 +69506,4257 @@ function pauseStreams (streams, options) { /* 592 */ /***/ (function(module, exports, __webpack_require__) { -// 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. +"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; -module.exports = glob -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 +/***/ }), +/* 593 */ +/***/ (function(module, exports, __webpack_require__) { -var once = __webpack_require__(385) +"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; -function glob (pattern, options, cb) { - if (typeof options === 'function') cb = options, options = {} - if (!options) options = {} - if (options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return globSync(pattern, options) - } +/***/ }), +/* 594 */ +/***/ (function(module, exports, __webpack_require__) { - return new Glob(pattern, options, cb) -} +"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; -glob.sync = globSync -var GlobSync = glob.GlobSync = globSync.GlobSync -// old api surface -glob.glob = glob +/***/ }), +/* 595 */ +/***/ (function(module, exports, __webpack_require__) { -function extend (origin, add) { - if (add === null || typeof add !== 'object') { - return origin - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function flatten(items) { + return items.reduce((collection, item) => [].concat(collection, item), []); +} +exports.flatten = flatten; - var keys = Object.keys(add) - var i = keys.length - while (i--) { - origin[keys[i]] = add[keys[i]] - } - return origin -} -glob.hasMagic = function (pattern, options_) { - var options = extend({}, options_) - options.noprocess = true +/***/ }), +/* 596 */ +/***/ (function(module, exports, __webpack_require__) { - var g = new Glob(pattern, options) - var set = g.minimatch.set +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function isEnoentCodeError(error) { + return error.code === 'ENOENT'; +} +exports.isEnoentCodeError = isEnoentCodeError; - if (!pattern) - return false - if (set.length > 1) - return true +/***/ }), +/* 597 */ +/***/ (function(module, exports, __webpack_require__) { - for (var j = 0; j < set[0].length; j++) { - if (typeof set[0][j] !== 'string') - 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; - return false -} -glob.Glob = Glob -inherits(Glob, EE) -function Glob (pattern, options, cb) { - if (typeof options === 'function') { - cb = options - options = null - } +/***/ }), +/* 598 */ +/***/ (function(module, exports, __webpack_require__) { - if (options && options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return new GlobSync(pattern, options) - } +"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 (!(this instanceof Glob)) - return new Glob(pattern, options, cb) - setopts(this, pattern, options) - this._didRealPath = false +/***/ }), +/* 599 */ +/***/ (function(module, exports, __webpack_require__) { - // process each pattern in the minimatch set - var n = this.minimatch.set.length +"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; - // 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) - if (typeof cb === 'function') { - cb = once(cb) - this.on('error', cb) - this.on('end', function (matches) { - cb(null, matches) - }) - } +/***/ }), +/* 600 */ +/***/ (function(module, exports, __webpack_require__) { - var self = this - this._processing = 0 +"use strict"; - this._emitQueue = [] - this._processQueue = [] - this.paused = false - if (this.noprocess) - return this +var isGlob = __webpack_require__(601); +var pathPosixDirname = __webpack_require__(16).posix.dirname; +var isWin32 = __webpack_require__(11).platform() === 'win32'; - if (n === 0) - return done() +var slash = '/'; +var backslash = /\\/g; +var enclosure = /[\{\[].*[\/]*.*[\}\]]$/; +var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; +var escaped = /\\([\*\?\|\[\]\(\)\{\}])/g; - var sync = true - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false, done) +module.exports = function globParent(str) { + // flip windows path separators + if (isWin32 && str.indexOf(slash) < 0) { + str = str.replace(backslash, slash); } - sync = false - function done () { - --self._processing - if (self._processing <= 0) { - if (sync) { - process.nextTick(function () { - self._finish() - }) - } else { - self._finish() - } - } + // special case for strings ending in enclosure containing path separator + if (enclosure.test(str)) { + str += slash; } -} -Glob.prototype._finish = function () { - assert(this instanceof Glob) - if (this.aborted) - return + // preserves full path in case of trailing path separator + str += 'a'; - if (this.realpath && !this._didRealpath) - return this._realpath() + // remove path parts that are globby + do { + str = pathPosixDirname(str); + } while (isGlob(str) || globby.test(str)); - common.finish(this) - this.emit('end', this.found) -} + // remove escape chars and return result + return str.replace(escaped, '$1'); +}; -Glob.prototype._realpath = function () { - if (this._didRealpath) - return - this._didRealpath = true +/***/ }), +/* 601 */ +/***/ (function(module, exports, __webpack_require__) { - var n = this.matches.length - if (n === 0) - return this._finish() +/*! + * is-glob + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ - var self = this - for (var i = 0; i < this.matches.length; i++) - this._realpathSet(i, next) +var isExtglob = __webpack_require__(602); +var chars = { '{': '}', '(': ')', '[': ']'}; +var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; +var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; - function next () { - if (--n === 0) - self._finish() +module.exports = function isGlob(str, options) { + if (typeof str !== 'string' || str === '') { + return false; } -} -Glob.prototype._realpathSet = function (index, cb) { - var matchset = this.matches[index] - if (!matchset) - return cb() + if (isExtglob(str)) { + return true; + } - var found = Object.keys(matchset) - var self = this - var n = found.length + var regex = strictRegex; + var match; - if (n === 0) - return cb() + // optionally relax regex + if (options && options.strict === false) { + regex = relaxedRegex; + } - 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 + while ((match = regex.exec(str))) { + if (match[2]) return true; + var idx = match.index + match[0].length; - if (--n === 0) { - self.matches[index] = set - cb() + // 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; } - }) - }) -} - -Glob.prototype._mark = function (p) { - return common.mark(this, p) -} - -Glob.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} - -Glob.prototype.abort = function () { - this.aborted = true - this.emit('abort') -} + } -Glob.prototype.pause = function () { - if (!this.paused) { - this.paused = true - this.emit('pause') + str = str.slice(idx); } -} + 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]) - } - } - } -} -Glob.prototype._process = function (pattern, index, inGlobStar, cb) { - assert(this instanceof Glob) - assert(typeof cb === 'function') +/***/ }), +/* 602 */ +/***/ (function(module, exports) { - if (this.aborted) - return +/*! + * is-extglob + * + * Copyright (c) 2014-2016, Jon Schlinkert. + * Licensed under the MIT License. + */ - this._processing++ - if (this.paused) { - this._processQueue.push([pattern, index, inGlobStar, cb]) - return +module.exports = function isExtglob(str) { + if (typeof str !== 'string' || str === '') { + 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 ++ + var match; + while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { + if (match[2]) return true; + str = str.slice(match.index + match[0].length); } - // 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, cb) - return + return false; +}; - 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 - } +/***/ }), +/* 603 */ +/***/ (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 - var abs = this._makeAbs(read) +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 === './'); - //if ignored, skip _processing - if (childrenIgnored(this, read)) - return cb() +/** + * 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 + */ - 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) -} +const micromatch = (list, patterns, options) => { + patterns = [].concat(patterns); + list = [].concat(list); -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) - }) -} + let omit = new Set(); + let keep = new Set(); + let items = new Set(); + let negatives = 0; -Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + let onResult = state => { + items.add(state.output); + if (options && options.onResult) { + options.onResult(state); + } + }; - // if the abs isn't a dir, then nothing can match! - if (!entries) - return 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++; - // 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) === '.' + for (let item of list) { + let matched = isMatch(item, 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) + let match = negated ? !matched.isMatch : matched.isMatch; + if (!match) continue; + + if (negated) { + omit.add(matched.output); } else { - m = e.match(pn) + omit.delete(matched.output); + keep.add(matched.output); } - if (m) - matchedEntries.push(e) } } - //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) - - 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 - } + let result = negatives === patterns.length ? [...items] : [...keep]; + let matches = result.filter(item => !omit.has(item)); - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) - } - this._emitMatch(index, e) + if (options && matches.length === 0) { + if (options.failglob === true) { + throw new Error(`No matches found for "${patterns.join(', ')}"`); } - // 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 + if (options.nonull === true || options.nullglob === true) { + return options.unescape ? patterns.map(p => p.replace(/\\/g, '')) : patterns; } - this._process([e].concat(remain), index, inGlobStar, cb) - } - cb() -} - -Glob.prototype._emitMatch = function (index, e) { - if (this.aborted) - return - - if (isIgnored(this, e)) - return - - if (this.paused) { - this._emitQueue.push([index, e]) - return } - var abs = isAbsolute(e) ? e : this._makeAbs(e) - - if (this.mark) - e = this._mark(e) + return matches; +}; - if (this.absolute) - e = abs +/** + * Backwards compatibility + */ - if (this.matches[index][e]) - return +micromatch.match = micromatch; - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - 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 + */ - this.matches[index][e] = true +micromatch.matcher = (pattern, options) => picomatch(pattern, options); - var st = this.statCache[abs] - if (st) - this.emit('stat', e, st) +/** + * 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 + */ - this.emit('match', e) -} +micromatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); -Glob.prototype._readdirInGlobStar = function (abs, cb) { - if (this.aborted) - return +/** + * Backwards compatibility + */ - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false, cb) +micromatch.any = micromatch.isMatch; - var lstatkey = 'lstat\0' + abs - var self = this - var lstatcb = inflight(lstatkey, lstatcb_) +/** + * 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 + */ - if (lstatcb) - fs.lstat(abs, lstatcb) +micromatch.not = (list, patterns, options = {}) => { + patterns = [].concat(patterns).map(String); + let result = new Set(); + let items = []; - function lstatcb_ (er, lstat) { - if (er && er.code === 'ENOENT') - return cb() + let onResult = state => { + if (options.onResult) options.onResult(state); + items.push(state.output); + }; - var isSym = lstat && lstat.isSymbolicLink() - self.symlinks[abs] = isSym + let matches = micromatch(list, patterns, { ...options, onResult }); - // 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) + for (let item of items) { + if (!matches.includes(item)) { + result.add(item); + } } -} + return [...result]; +}; -Glob.prototype._readdir = function (abs, inGlobStar, cb) { - if (this.aborted) - return +/** + * 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 + */ - cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) - if (!cb) - return +micromatch.contains = (str, pattern, options) => { + if (typeof str !== 'string') { + throw new TypeError(`Expected a string: "${util.inspect(str)}"`); + } - //console.error('RD %j %j', +inGlobStar, abs) - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs, cb) + if (Array.isArray(pattern)) { + return pattern.some(p => micromatch.contains(str, p, options)); + } - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return cb() + if (typeof pattern === 'string') { + if (isEmptyString(str) || isEmptyString(pattern)) { + return false; + } - if (Array.isArray(c)) - return cb(null, c) + if (str.includes(pattern) || (str.startsWith('./') && str.slice(2).includes(pattern))) { + return true; + } } - 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) - } -} + return micromatch.isMatch(str, pattern, { ...options, contains: true }); +}; -Glob.prototype._readdirEntries = function (abs, entries, cb) { - if (this.aborted) - return +/** + * 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 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 - } +micromatch.matchKeys = (obj, patterns, options) => { + if (!utils.isObject(obj)) { + throw new TypeError('Expected the first argument to be an object'); } + let keys = micromatch(Object.keys(obj), patterns, options); + let res = {}; + for (let key of keys) res[key] = obj[key]; + return res; +}; - this.cache[abs] = entries - return cb(null, entries) -} - -Glob.prototype._readdirError = function (f, er, cb) { - if (this.aborted) - return - - // 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 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 + */ - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break +micromatch.some = (list, patterns, options) => { + let items = [].concat(list); - 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 + for (let pattern of [].concat(patterns)) { + let isMatch = picomatch(String(pattern), options); + if (items.some(item => isMatch(item))) { + return true; + } } + return false; +}; - return cb() -} - -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) - }) -} - - -Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - //console.error('pgs2', prefix, remain[0], entries) - - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return cb() - - // 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) - - // 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 +/** + * 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 + */ - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true, cb) +micromatch.every = (list, patterns, options) => { + let items = [].concat(list); - var below = gspref.concat(entries[i], remain) - this._process(below, index, true, cb) + for (let pattern of [].concat(patterns)) { + let isMatch = picomatch(String(pattern), options); + if (!items.every(item => isMatch(item))) { + return false; + } } + return true; +}; - cb() -} - -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() +/** + * 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 + */ - 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 += '/' - } +micromatch.all = (str, patterns, options) => { + if (typeof str !== 'string') { + throw new TypeError(`Expected a string: "${util.inspect(str)}"`); } - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') + return [].concat(patterns).every(p => picomatch(p, options)(str)); +}; - // Mark this as a match - this._emitMatch(index, prefix) - 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 + */ -// Returns either 'DIR', 'FILE', or false -Glob.prototype._stat = function (f, cb) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' +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 (f.length > this.maxLength) - return cb() + if (match) { + return match.slice(1).map(v => v === void 0 ? '' : v); + } +}; - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] +/** + * 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 + */ - if (Array.isArray(c)) - c = 'DIR' +micromatch.makeRe = (...args) => picomatch.makeRe(...args); - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return cb(null, c) +/** + * 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 + */ - if (needDir && c === 'FILE') - return cb() +micromatch.scan = (...args) => picomatch.scan(...args); - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } +/** + * 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 + */ - 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) +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 res; +}; - var self = this - var statcb = inflight('stat\0' + abs, lstatcb_) - if (statcb) - fs.lstat(abs, statcb) - - 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) - } - } -} +/** + * 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 + */ -Glob.prototype._stat2 = function (f, abs, er, stat, cb) { - if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { - this.statCache[abs] = false - return cb() +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); +}; - var needDir = f.slice(-1) === '/' - this.statCache[abs] = stat - - if (abs.slice(-1) === '/' && stat && !stat.isDirectory()) - return cb(null, false, stat) +/** + * Expand braces + */ - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' - this.cache[abs] = this.cache[abs] || c +micromatch.braceExpand = (pattern, options) => { + if (typeof pattern !== 'string') throw new TypeError('Expected a string'); + return micromatch.braces(pattern, { ...options, expand: true }); +}; - if (needDir && c === 'FILE') - return cb() +/** + * Expose micromatch + */ - return cb(null, c, stat) -} +module.exports = micromatch; /***/ }), -/* 593 */ +/* 604 */ /***/ (function(module, exports, __webpack_require__) { -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); -} +"use strict"; -/***/ }), -/* 594 */ -/***/ (function(module, exports) { +const stringify = __webpack_require__(605); +const compile = __webpack_require__(607); +const expand = __webpack_require__(611); +const parse = __webpack_require__(612); -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 +/** + * 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 + */ + +const braces = (input, options = {}) => { + let output = []; + + 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)); } -} + if (options && options.expand === true && options.nodupes === true) { + output = [...new Set(output)]; + } + return output; +}; -/***/ }), -/* 595 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * 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 + */ -module.exports = globSync -globSync.GlobSync = GlobSync +braces.parse = (input, options = {}) => parse(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 - -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') - - return new GlobSync(pattern, options).found -} - -function GlobSync (pattern, options) { - if (!pattern) - throw new Error('must provide pattern') - - 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') - - if (!(this instanceof GlobSync)) - return new GlobSync(pattern, options) +/** + * 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 + */ - setopts(this, pattern, options) +braces.stringify = (input, options = {}) => { + if (typeof input === 'string') { + return stringify(braces.parse(input, options), options); + } + return stringify(input, options); +}; - if (this.noprocess) - return this +/** + * 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 + */ - 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) +braces.compile = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); } - this._finish() -} + return compile(input, options); +}; -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 - } - } - }) +/** + * 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 + */ + +braces.expand = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); } - common.finish(this) -} + let result = expand(input, options); -GlobSync.prototype._process = function (pattern, index, inGlobStar) { - assert(this instanceof GlobSync) + // filter out empty strings if specified + if (options.noempty === true) { + result = result.filter(Boolean); + } - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === 'string') { - n ++ + // filter out duplicates if specified + if (options.nodupes === true) { + result = [...new Set(result)]; } - // 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 + return result; +}; - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break +/** + * 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 + */ - 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 +braces.create = (input, options = {}) => { + if (input === '' || input.length < 3) { + return [input]; } - var remain = pattern.slice(n) + return options.expand !== true + ? braces.compile(input, options) + : braces.expand(input, options); +}; - // 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 +/** + * Expose "braces" + */ - var abs = this._makeAbs(read) +module.exports = braces; - //if ignored, skip processing - if (childrenIgnored(this, read)) - return - 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) -} +/***/ }), +/* 605 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; -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 +const utils = __webpack_require__(606); - // 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) === '.' +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 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 (node.value) { + if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) { + return '\\' + node.value; } - if (m) - matchedEntries.push(e) + return node.value; } - } - - 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) - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix.slice(-1) !== '/') - e = prefix + '/' + e - else - e = prefix + e - } + if (node.value) { + return node.value; + } - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) + if (node.nodes) { + for (let child of node.nodes) { + output += stringify(child); } - this._emitMatch(index, e) } - // This was the last one, and no stats were needed - return - } + return output; + }; - // 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) - } -} + return stringify(ast); +}; -GlobSync.prototype._emitMatch = function (index, e) { - if (isIgnored(this, e)) - return - var abs = this._makeAbs(e) +/***/ }), +/* 606 */ +/***/ (function(module, exports, __webpack_require__) { - if (this.mark) - e = this._mark(e) +"use strict"; - if (this.absolute) { - e = abs + +exports.isInteger = num => { + if (typeof num === 'number') { + return Number.isInteger(num); + } + if (typeof num === 'string' && num.trim() !== '') { + return Number.isInteger(Number(num)); } + return false; +}; - if (this.matches[index][e]) - return +/** + * Find a node of the given type + */ - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } +exports.find = (node, type) => node.nodes.find(node => node.type === type); - this.matches[index][e] = true +/** + * Find a node of the given type + */ - if (this.stat) - this._stat(e) -} +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 + */ -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) +exports.escapeNode = (block, n = 0, type) => { + let node = block.nodes[n]; + if (!node) return; - 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 ((type && node.type === type) || node.type === 'open' || node.type === 'close') { + if (node.escaped !== true) { + node.value = '\\' + node.value; + node.escaped = true; } } +}; - var isSym = lstat && lstat.isSymbolicLink() - this.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()) - this.cache[abs] = 'FILE' - else - entries = this._readdir(abs, false) - - return entries -} - -GlobSync.prototype._readdir = function (abs, inGlobStar) { - var entries +/** + * Returns true if the given brace node should be enclosed in literal braces + */ - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs) +exports.encloseBrace = node => { + if (node.type !== 'brace') return false; + if ((node.commas >> 0 + node.ranges >> 0) === 0) { + node.invalid = true; + return true; + } + return false; +}; - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return null +/** + * Returns true if a brace node is invalid. + */ - if (Array.isArray(c)) - return c +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; } - - try { - return this._readdirEntries(abs, fs.readdirSync(abs)) - } catch (er) { - this._readdirError(abs, er) - return null + if (block.open !== true || block.close !== true) { + block.invalid = true; + return true; } -} + return false; +}; -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 - } - } +/** + * Returns true if a node is an open or close node + */ - this.cache[abs] = entries +exports.isOpenOrClose = node => { + if (node.type === 'open' || node.type === 'close') { + return true; + } + return node.open === true || node.close === true; +}; - // mark and cache dir-ness - return entries -} +/** + * Reduce an array of text nodes. + */ -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 +exports.reduce = nodes => nodes.reduce((acc, node) => { + if (node.type === 'text') acc.push(node.value); + if (node.type === 'range') node.type = 'text'; + return acc; +}, []); - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break +/** + * Flatten an array + */ - 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 - } -} +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; +}; -GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { - var entries = this._readdir(abs, inGlobStar) +/***/ }), +/* 607 */ +/***/ (function(module, exports, __webpack_require__) { - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return +"use strict"; - // 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) - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false) +const fill = __webpack_require__(608); +const utils = __webpack_require__(606); - var len = entries.length - var isSym = this.symlinks[abs] +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 it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return + if (node.isOpen === true) { + return prefix + node.value; + } + if (node.isClose === true) { + return prefix + node.value; + } - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue + if (node.type === 'open') { + return invalid ? (prefix + node.value) : '('; + } - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true) + if (node.type === 'close') { + return invalid ? (prefix + node.value) : ')'; + } - var below = gspref.concat(entries[i], remain) - this._process(below, index, true) - } -} + if (node.type === 'comma') { + return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|'); + } -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) + if (node.value) { + return node.value; + } - if (!this.matches[index]) - this.matches[index] = Object.create(null) + if (node.nodes && node.ranges > 0) { + let args = utils.reduce(node.nodes); + let range = fill(...args, { ...options, wrap: false, toRegex: true }); - // If it doesn't exist, then just mark the lack of results - if (!exists) - return + if (range.length !== 0) { + return args.length > 1 && range.length > 1 ? `(${range})` : range; + } + } - 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 += '/' + if (node.nodes) { + for (let child of node.nodes) { + output += walk(child, node); + } } - } + return output; + }; - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') + return walk(ast); +}; - // Mark this as a match - this._emitMatch(index, prefix) -} +module.exports = compile; -// Returns either 'DIR', 'FILE', or false -GlobSync.prototype._stat = function (f) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' - if (f.length > this.maxLength) - return false +/***/ }), +/* 608 */ +/***/ (function(module, exports, __webpack_require__) { - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] +"use strict"; +/*! + * fill-range + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Licensed under the MIT License. + */ - if (Array.isArray(c)) - c = 'DIR' - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return c - if (needDir && c === 'FILE') - return false +const util = __webpack_require__(29); +const toRegexRange = __webpack_require__(609); - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } +const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); - 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 transform = toNumber => { + return value => toNumber === true ? Number(value) : String(value); +}; - if (lstat && lstat.isSymbolicLink()) { - try { - stat = fs.statSync(abs) - } catch (er) { - stat = lstat - } - } else { - stat = lstat - } - } +const isValidValue = value => { + return typeof value === 'number' || (typeof value === 'string' && value !== ''); +}; - this.statCache[abs] = stat +const isNumber = num => Number.isInteger(+num); - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' +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; +}; - this.cache[abs] = this.cache[abs] || c +const stringify = (start, end, options) => { + if (typeof start === 'string' || typeof end === 'string') { + return true; + } + return options.stringify === true; +}; - if (needDir && c === 'FILE') - 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; +}; - return c -} +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; +}; -GlobSync.prototype._mark = function (p) { - return common.mark(this, p) -} +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); -GlobSync.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} + let prefix = options.capture ? '' : '?:'; + let positives = ''; + let negatives = ''; + let result; + if (parts.positives.length) { + positives = parts.positives.join('|'); + } -/***/ }), -/* 596 */ -/***/ (function(module, exports, __webpack_require__) { + if (parts.negatives.length) { + negatives = `-(${prefix}${parts.negatives.join('|')})`; + } -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 + if (positives && negatives) { + result = `${positives}|${negatives}`; + } else { + result = positives || negatives; + } -function ownProp (obj, field) { - return Object.prototype.hasOwnProperty.call(obj, field) -} + if (options.wrap) { + return `(${prefix}${result})`; + } -var path = __webpack_require__(16) -var minimatch = __webpack_require__(505) -var isAbsolute = __webpack_require__(511) -var Minimatch = minimatch.Minimatch + return result; +}; -function alphasorti (a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()) -} +const toRange = (a, b, isNumbers, options) => { + if (isNumbers) { + return toRegexRange(a, b, { wrap: false, ...options }); + } -function alphasort (a, b) { - return a.localeCompare(b) -} + let start = String.fromCharCode(a); + if (a === b) return start; -function setupIgnores (self, options) { - self.ignore = options.ignore || [] + let stop = String.fromCharCode(b); + return `[${start}-${stop}]`; +}; - if (!Array.isArray(self.ignore)) - self.ignore = [self.ignore] +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); +}; - if (self.ignore.length) { - self.ignore = self.ignore.map(ignoreMap) +const rangeError = (...args) => { + return new RangeError('Invalid range arguments: ' + util.inspect(...args)); +}; + +const invalidRange = (start, end, options) => { + if (options.strictRanges === true) throw rangeError([start, end]); + return []; +}; + +const invalidStep = (step, options) => { + if (options.strictRanges === true) { + throw new TypeError(`Expected step "${step}" to be a number`); } -} + return []; +}; -// 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 }) +const fillNumbers = (start, end, step = 1, options = {}) => { + let a = Number(start); + let b = Number(end); + + if (!Number.isInteger(a) || !Number.isInteger(b)) { + if (options.strictRanges === true) throw rangeError([start, end]); + return []; } - return { - matcher: new Minimatch(pattern, { dot: true }), - gmatcher: gmatcher + // fix negative zero + if (a === 0) a = 0; + if (b === 0) b = 0; + + let descending = a > b; + let startString = String(start); + let endString = String(end); + let stepString = String(step); + step = Math.max(Math.abs(step), 1); + + 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 (options.toRegex && step === 1) { + return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options); } -} -function setopts (self, pattern, options) { - if (!options) - options = {} + let parts = { negatives: [], positives: [] }; + let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num)); + let range = []; + let index = 0; - // base-matching: just use globstar for that. - if (options.matchBase && -1 === pattern.indexOf("/")) { - if (options.noglobstar) { - throw new Error("base matching requires globstar") + while (descending ? a >= b : a <= b) { + if (options.toRegex === true && step > 1) { + push(a); + } else { + range.push(pad(format(a, index), maxLen, toNumber)); } - pattern = "**/" + pattern + a = descending ? a - step : a + step; + index++; } - 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) + if (options.toRegex === true) { + return step > 1 + ? toSequence(parts, options) + : toRegex(range, null, { wrap: false, ...options }); + } - setupIgnores(self, options) + return range; +}; - 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 +const fillLetters = (start, end, step = 1, options = {}) => { + if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) { + return invalidRange(start, end, options); } - self.root = options.root || path.resolve(self.cwd, "/") - self.root = path.resolve(self.root) - if (process.platform === "win32") - self.root = self.root.replace(/\\/g, "/") - // 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 format = options.transform || (val => String.fromCharCode(val)); + let a = `${start}`.charCodeAt(0); + let b = `${end}`.charCodeAt(0); - // disable comments and negation in Minimatch. - // Note that they are not supported in Glob itself anyway. - options.nonegate = true - options.nocomment = true + let descending = a > b; + let min = Math.min(a, b); + let max = Math.max(a, b); - self.minimatch = new Minimatch(pattern, options) - self.options = self.minimatch.options -} + if (options.toRegex && step === 1) { + return toRange(min, max, false, options); + } -function finish (self) { - var nou = self.nounique - var all = nou ? [] : Object.create(null) + let range = []; + let index = 0; - 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 - }) - } + while (descending ? a >= b : a <= b) { + range.push(format(a, index)); + a = descending ? a - step : a + step; + index++; } - if (!nou) - all = Object.keys(all) + if (options.toRegex === true) { + return toRegex(range, null, { wrap: false, options }); + } - if (!self.nosort) - all = all.sort(self.nocase ? alphasorti : alphasort) + return range; +}; - // 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 - }) - } +const fill = (start, end, step, options = {}) => { + if (end == null && isValidValue(start)) { + return [start]; } - if (self.ignore.length) - all = all.filter(function(m) { - return !isIgnored(self, m) - }) + if (!isValidValue(start) || !isValidValue(end)) { + return invalidRange(start, end, options); + } - self.found = all -} + if (typeof step === 'function') { + return fill(start, end, 1, { transform: step }); + } -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) === '/' + if (isObject(step)) { + return fill(start, end, 0, step); + } - if (isDir && !slash) - m += '/' - else if (!isDir && slash) - m = m.slice(0, -1) + let opts = { ...options }; + if (opts.capture === true) opts.wrap = true; + step = step || opts.step || 1; - if (m !== p) { - var mabs = makeAbs(self, m) - self.statCache[mabs] = self.statCache[abs] - self.cache[mabs] = self.cache[abs] - } + if (!isNumber(step)) { + if (step != null && !isObject(step)) return invalidStep(step, opts); + return fill(start, end, 1, step); } - return m -} - -// 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) + if (isNumber(start) && isNumber(end)) { + return fillNumbers(start, end, step, opts); } - if (process.platform === 'win32') - abs = abs.replace(/\\/g, '/') + return fillLetters(start, end, Math.max(Math.abs(step), 1), opts); +}; - return abs -} +module.exports = fill; -// 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 self.ignore.some(function(item) { - return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) - }) -} +/***/ }), +/* 609 */ +/***/ (function(module, exports, __webpack_require__) { -function childrenIgnored (self, path) { - if (!self.ignore.length) - return false +"use strict"; +/*! + * to-regex-range + * + * Copyright (c) 2015-present, Jon Schlinkert. + * Released under the MIT License. + */ - return self.ignore.some(function(item) { - return !!(item.gmatcher && item.gmatcher.match(path)) - }) -} -/***/ }), -/* 597 */ -/***/ (function(module, exports, __webpack_require__) { +const isNumber = __webpack_require__(610); -"use strict"; - -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; +const toRegexRange = (min, max, options) => { + if (isNumber(min) === false) { + throw new TypeError('toRegexRange: expected the first argument to be a number'); + } + if (max === void 0 || min === max) { + return String(min); + } -/***/ }), -/* 598 */ -/***/ (function(module, exports, __webpack_require__) { + if (isNumber(max) === false) { + throw new TypeError('toRegexRange: expected the second argument to be a number.'); + } -"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; + let opts = { relaxZeros: true, ...options }; + if (typeof opts.strictZeros === 'boolean') { + opts.relaxZeros = opts.strictZeros === false; + } + 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; -/***/ }), -/* 599 */ -/***/ (function(module, exports, __webpack_require__) { + if (toRegexRange.cache.hasOwnProperty(cacheKey)) { + return toRegexRange.cache[cacheKey].result; + } -"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; + let a = Math.min(min, max); + let b = Math.max(min, max); + if (Math.abs(a - b) === 1) { + let result = min + '|' + max; + if (opts.capture) { + return `(${result})`; + } + if (opts.wrap === false) { + return result; + } + return `(?:${result})`; + } -/***/ }), -/* 600 */ -/***/ (function(module, exports, __webpack_require__) { + let isPadded = hasPadding(min) || hasPadding(max); + let state = { min, max, a, b }; + let positives = []; + let negatives = []; -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function flatten(items) { - return items.reduce((collection, item) => [].concat(collection, item), []); -} -exports.flatten = flatten; + 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; + } -/***/ }), -/* 601 */ -/***/ (function(module, exports, __webpack_require__) { + if (b >= 0) { + positives = splitToPatterns(a, b, state, opts); + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -function isEnoentCodeError(error) { - return error.code === 'ENOENT'; -} -exports.isEnoentCodeError = isEnoentCodeError; + 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})`; + } -/***/ }), -/* 602 */ -/***/ (function(module, exports, __webpack_require__) { + toRegexRange.cache[cacheKey] = state; + return state.result; +}; -"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; +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; -/***/ }), -/* 603 */ -/***/ (function(module, exports, __webpack_require__) { + let stop = countNines(min, nines); + let stops = new Set([max]); -"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; + while (min <= stop && stop <= max) { + stops.add(stop); + nines += 1; + stop = countNines(min, nines); + } + stop = countZeros(max + 1, zeros) - 1; -/***/ }), -/* 604 */ -/***/ (function(module, exports, __webpack_require__) { + while (min < stop && stop <= max) { + stops.add(stop); + zeros += 1; + stop = countZeros(max + 1, zeros) - 1; + } -"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; + stops = [...stops]; + stops.sort(compare); + return stops; +} +/** + * Convert a range to a regex pattern + * @param {Number} `start` + * @param {Number} `stop` + * @return {String} + */ -/***/ }), -/* 605 */ -/***/ (function(module, exports, __webpack_require__) { +function rangeToPattern(start, stop, options) { + if (start === stop) { + return { pattern: start, count: [], digits: 0 }; + } -"use strict"; + 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]; -var isGlob = __webpack_require__(606); -var pathPosixDirname = __webpack_require__(16).posix.dirname; -var isWin32 = __webpack_require__(11).platform() === 'win32'; + if (startDigit === stopDigit) { + pattern += startDigit; -var slash = '/'; -var backslash = /\\/g; -var enclosure = /[\{\[].*[\/]*.*[\}\]]$/; -var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; -var escaped = /\\([\*\?\|\[\]\(\)\{\}])/g; + } else if (startDigit !== '0' || stopDigit !== '9') { + pattern += toCharacterClass(startDigit, stopDigit, options); -module.exports = function globParent(str) { - // flip windows path separators - if (isWin32 && str.indexOf(slash) < 0) { - str = str.replace(backslash, slash); + } else { + count++; + } } - // special case for strings ending in enclosure containing path separator - if (enclosure.test(str)) { - str += slash; + if (count) { + pattern += options.shorthand === true ? '\\d' : '[0-9]'; } - // preserves full path in case of trailing path separator - str += 'a'; - - // remove path parts that are globby - do { - str = pathPosixDirname(str); - } while (isGlob(str) || globby.test(str)); + return { pattern, count: [count], digits }; +} - // remove escape chars and return result - return str.replace(escaped, '$1'); -}; +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 = ''; -/***/ }), -/* 606 */ -/***/ (function(module, exports, __webpack_require__) { + if (!tok.isPadded && prev && prev.pattern === obj.pattern) { + if (prev.count.length > 1) { + prev.count.pop(); + } -/*! - * is-glob - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ + prev.count.push(obj.count[0]); + prev.string = prev.pattern + toQuantifier(prev.count); + start = max + 1; + continue; + } -var isExtglob = __webpack_require__(607); -var chars = { '{': '}', '(': ')', '[': ']'}; -var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; -var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; + if (tok.isPadded) { + zeros = padZeros(max, tok, options); + } -module.exports = function isGlob(str, options) { - if (typeof str !== 'string' || str === '') { - return false; + obj.string = zeros + obj.pattern + toQuantifier(obj.count); + tokens.push(obj); + start = max + 1; + prev = obj; } - if (isExtglob(str)) { - return true; - } + return tokens; +} - var regex = strictRegex; - var match; +function filterPatterns(arr, comparison, prefix, intersection, options) { + let result = []; - // optionally relax regex - if (options && options.strict === false) { - regex = relaxedRegex; - } + for (let ele of arr) { + let { string } = ele; - while ((match = regex.exec(str))) { - if (match[2]) return true; - var idx = match.index + match[0].length; + // only push if _both_ are negative... + if (!intersection && !contains(comparison, 'string', string)) { + result.push(prefix + string); + } - // 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; - } + // or _both_ are positive + if (intersection && contains(comparison, 'string', string)) { + result.push(prefix + string); } + } + return result; +} - str = str.slice(idx); +/** + * 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)); +} + +function countZeros(integer, zeros) { + return integer - (integer % Math.pow(10, zeros)); +} + +function toQuantifier(digits) { + let [start = 0, stop = ''] = digits; + if (stop || start > 1) { + return `{${start + (stop ? ',' + stop : '')}}`; } - return false; -}; + return ''; +} + +function toCharacterClass(a, b, options) { + return `[${a}${(b - a === 1) ? '' : '-'}${b}]`; +} + +function hasPadding(str) { + return /^-?(0+)\d/.test(str); +} + +function padZeros(value, tok, options) { + if (!tok.isPadded) { + return value; + } + + let diff = Math.abs(tok.maxLen - String(value).length); + let relax = options.relaxZeros !== 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}}`; + } + } +} + +/** + * Cache + */ + +toRegexRange.cache = {}; +toRegexRange.clearCache = () => (toRegexRange.cache = {}); + +/** + * Expose `toRegexRange` + */ + +module.exports = toRegexRange; /***/ }), -/* 607 */ -/***/ (function(module, exports) { +/* 610 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; /*! - * is-extglob + * is-number * - * Copyright (c) 2014-2016, Jon Schlinkert. - * Licensed under the MIT License. + * Copyright (c) 2014-present, Jon Schlinkert. + * Released under the MIT License. */ -module.exports = function isExtglob(str) { - if (typeof str !== 'string' || str === '') { - return false; - } - var match; - while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { - if (match[2]) return true; - str = str.slice(match.index + match[0].length); - } +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; }; /***/ }), -/* 608 */ +/* 611 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -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 === './'); +const fill = __webpack_require__(608); +const stringify = __webpack_require__(605); +const utils = __webpack_require__(606); -/** - * 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 - */ +const append = (queue = '', stash = '', enclose = false) => { + let result = []; -const micromatch = (list, patterns, options) => { - patterns = [].concat(patterns); - list = [].concat(list); + queue = [].concat(queue); + stash = [].concat(stash); - let omit = new Set(); - let keep = new Set(); - let items = new Set(); - let negatives = 0; + if (!stash.length) return queue; + if (!queue.length) { + return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; + } - let onResult = state => { - items.add(state.output); - if (options && options.onResult) { - options.onResult(state); + 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); +}; - 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++; +const expand = (ast, options = {}) => { + let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit; - for (let item of list) { - let matched = isMatch(item, true); + let walk = (node, parent = {}) => { + node.queue = []; - let match = negated ? !matched.isMatch : matched.isMatch; - if (!match) continue; + let p = parent; + let q = parent.queue; - if (negated) { - omit.add(matched.output); - } else { - omit.delete(matched.output); - keep.add(matched.output); - } + while (p.type !== 'brace' && p.type !== 'root' && p.parent) { + p = p.parent; + q = p.queue; } - } - - let result = negatives === patterns.length ? [...items] : [...keep]; - let matches = result.filter(item => !omit.has(item)); - if (options && matches.length === 0) { - if (options.failglob === true) { - throw new Error(`No matches found for "${patterns.join(', ')}"`); + if (node.invalid || node.dollar) { + q.push(append(q.pop(), stringify(node, options))); + return; } - if (options.nonull === true || options.nullglob === true) { - return options.unescape ? patterns.map(p => p.replace(/\\/g, '')) : patterns; + if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { + q.push(append(q.pop(), ['{}'])); + return; } - } - return matches; -}; + if (node.nodes && node.ranges > 0) { + let args = utils.reduce(node.nodes); -/** - * Backwards compatibility - */ + 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.'); + } -micromatch.match = micromatch; + let range = fill(...args, options); + if (range.length === 0) { + range = stringify(node, options); + } -/** - * 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 - */ + q.push(append(q.pop(), range)); + node.nodes = []; + return; + } -micromatch.matcher = (pattern, options) => picomatch(pattern, options); + let enclose = utils.encloseBrace(node); + let queue = node.queue; + let block = node; -/** - * 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 - */ + while (block.type !== 'brace' && block.type !== 'root' && block.parent) { + block = block.parent; + queue = block.queue; + } -micromatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); + for (let i = 0; i < node.nodes.length; i++) { + let child = node.nodes[i]; -/** - * Backwards compatibility - */ + if (child.type === 'comma' && node.type === 'brace') { + if (i === 1) queue.push(''); + queue.push(''); + continue; + } -micromatch.any = micromatch.isMatch; + if (child.type === 'close') { + q.push(append(q.pop(), queue, enclose)); + 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 - */ + if (child.value && child.type !== 'open') { + queue.push(append(queue.pop(), child.value)); + continue; + } -micromatch.not = (list, patterns, options = {}) => { - patterns = [].concat(patterns).map(String); - let result = new Set(); - let items = []; + if (child.nodes) { + walk(child, node); + } + } - let onResult = state => { - if (options.onResult) options.onResult(state); - items.push(state.output); + return queue; }; - let matches = micromatch(list, patterns, { ...options, onResult }); - - for (let item of items) { - if (!matches.includes(item)) { - result.add(item); - } - } - return [...result]; + return utils.flatten(walk(ast)); }; -/** - * 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 - */ +module.exports = expand; -micromatch.contains = (str, pattern, options) => { - if (typeof str !== 'string') { - throw new TypeError(`Expected a string: "${util.inspect(str)}"`); - } - if (Array.isArray(pattern)) { - return pattern.some(p => micromatch.contains(str, p, options)); - } +/***/ }), +/* 612 */ +/***/ (function(module, exports, __webpack_require__) { - if (typeof pattern === 'string') { - if (isEmptyString(str) || isEmptyString(pattern)) { - return false; - } +"use strict"; - if (str.includes(pattern) || (str.startsWith('./') && str.slice(2).includes(pattern))) { - return true; - } - } - return micromatch.isMatch(str, pattern, { ...options, contains: true }); -}; +const stringify = __webpack_require__(605); /** - * 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 + * Constants */ -micromatch.matchKeys = (obj, patterns, options) => { - if (!utils.isObject(obj)) { - throw new TypeError('Expected the first argument to be an object'); - } - let keys = micromatch(Object.keys(obj), patterns, options); - let res = {}; - for (let key of keys) res[key] = obj[key]; - return res; -}; +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); /** - * 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 + * parse */ -micromatch.some = (list, patterns, options) => { - let items = [].concat(list); +const parse = (input, options = {}) => { + if (typeof input !== 'string') { + throw new TypeError('Expected a string'); + } - for (let pattern of [].concat(patterns)) { - let isMatch = picomatch(String(pattern), options); - if (items.some(item => isMatch(item))) { - return true; - } + 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})`); } - 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 - */ + 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 = {}; -micromatch.every = (list, patterns, options) => { - let items = [].concat(list); + /** + * Helpers + */ - for (let pattern of [].concat(patterns)) { - let isMatch = picomatch(String(pattern), options); - if (!items.every(item => isMatch(item))) { - return false; + const advance = () => input[index++]; + const push = node => { + if (node.type === 'text' && prev.type === 'dot') { + prev.type = 'text'; } - } - return true; -}; -/** - * 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 - */ - -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 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 - */ - -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 (prev && prev.type === 'text' && node.type === 'text') { + prev.value += node.value; + return; + } - if (match) { - return match.slice(1).map(v => v === void 0 ? '' : v); - } -}; + block.nodes.push(node); + node.parent = block; + node.prev = prev; + prev = node; + return node; + }; -/** - * 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 - */ + push({ type: 'bos' }); -micromatch.makeRe = (...args) => picomatch.makeRe(...args); + while (index < length) { + block = stack[stack.length - 1]; + value = advance(); -/** - * 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 - */ + /** + * Invalid chars + */ -micromatch.scan = (...args) => picomatch.scan(...args); + if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { + continue; + } -/** - * 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 - */ + /** + * Escaped chars + */ -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)); + if (value === CHAR_BACKSLASH) { + push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); + continue; } - } - 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 - */ + /** + * Right square bracket (literal): ']' + */ -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); -}; + if (value === CHAR_RIGHT_SQUARE_BRACKET) { + push({ type: 'text', value: '\\' + value }); + continue; + } -/** - * Expand braces - */ + /** + * Left square bracket: '[' + */ -micromatch.braceExpand = (pattern, options) => { - if (typeof pattern !== 'string') throw new TypeError('Expected a string'); - return micromatch.braces(pattern, { ...options, expand: true }); -}; + if (value === CHAR_LEFT_SQUARE_BRACKET) { + brackets++; -/** - * Expose micromatch - */ + let closed = true; + let next; -module.exports = micromatch; + while (index < length && (next = advance())) { + value += next; + if (next === CHAR_LEFT_SQUARE_BRACKET) { + brackets++; + continue; + } -/***/ }), -/* 609 */ -/***/ (function(module, exports, __webpack_require__) { + if (next === CHAR_BACKSLASH) { + value += advance(); + continue; + } -"use strict"; + if (next === CHAR_RIGHT_SQUARE_BRACKET) { + brackets--; + if (brackets === 0) { + break; + } + } + } -const stringify = __webpack_require__(610); -const compile = __webpack_require__(612); -const expand = __webpack_require__(616); -const parse = __webpack_require__(617); + push({ type: 'text', value }); + continue; + } -/** - * 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 - */ + /** + * Parentheses + */ -const braces = (input, options = {}) => { - let output = []; + if (value === CHAR_LEFT_PARENTHESES) { + block = push({ type: 'paren', nodes: [] }); + stack.push(block); + push({ type: 'text', value }); + continue; + } - 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); + 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; } - } else { - output = [].concat(braces.create(input, options)); - } - if (options && options.expand === true && options.nodupes === true) { - output = [...new Set(output)]; - } - return output; -}; + /** + * Quotes: '|"|` + */ -/** - * 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 (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { + let open = value; + let next; -braces.parse = (input, options = {}) => parse(input, options); + if (options.keepQuotes !== true) { + value = ''; + } -/** - * 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 (index < length && (next = advance())) { + if (next === CHAR_BACKSLASH) { + value += next + advance(); + continue; + } -braces.stringify = (input, options = {}) => { - if (typeof input === 'string') { - return stringify(braces.parse(input, options), options); - } - return stringify(input, options); -}; + if (next === open) { + if (options.keepQuotes === true) value += next; + break; + } -/** - * 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 - */ + value += next; + } -braces.compile = (input, options = {}) => { - if (typeof input === 'string') { - input = braces.parse(input, options); - } - return compile(input, options); -}; + push({ type: 'text', value }); + continue; + } -/** - * 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 - */ + /** + * Left curly brace: '{' + */ -braces.expand = (input, options = {}) => { - if (typeof input === 'string') { - input = braces.parse(input, options); - } + if (value === CHAR_LEFT_CURLY_BRACE) { + depth++; - let result = expand(input, options); + 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: [] + }; - // filter out empty strings if specified - if (options.noempty === true) { - result = result.filter(Boolean); - } + block = push(brace); + stack.push(block); + push({ type: 'open', value }); + continue; + } - // filter out duplicates if specified - if (options.nodupes === true) { - result = [...new Set(result)]; - } + /** + * Right curly brace: '}' + */ - return result; -}; + if (value === CHAR_RIGHT_CURLY_BRACE) { + if (block.type !== 'brace') { + push({ type: 'text', value }); + 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 - */ + let type = 'close'; + block = stack.pop(); + block.close = true; -braces.create = (input, options = {}) => { - if (input === '' || input.length < 3) { - return [input]; - } + push({ type, value }); + depth--; - return options.expand !== true - ? braces.compile(input, options) - : braces.expand(input, options); -}; + block = stack[stack.length - 1]; + continue; + } -/** - * Expose "braces" - */ + /** + * Comma: ',' + */ -module.exports = braces; + 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; + } -/***/ }), -/* 610 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Dot: '.' + */ -"use strict"; + if (value === CHAR_DOT && depth > 0 && block.commas === 0) { + let siblings = block.nodes; + if (depth === 0 || siblings.length === 0) { + push({ type: 'text', value }); + continue; + } -const utils = __webpack_require__(611); + if (prev.type === 'dot') { + block.range = []; + prev.value += value; + prev.type = 'range'; -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 (block.nodes.length !== 3 && block.nodes.length !== 5) { + block.invalid = true; + block.ranges = 0; + prev.type = 'text'; + continue; + } - if (node.value) { - if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) { - return '\\' + node.value; + block.ranges++; + block.args = []; + continue; } - return node.value; - } - if (node.value) { - return node.value; - } + if (prev.type === 'range') { + siblings.pop(); - if (node.nodes) { - for (let child of node.nodes) { - output += stringify(child); + let before = siblings[siblings.length - 1]; + before.value += prev.value + value; + prev = before; + block.ranges--; + continue; } - } - return output; - }; - - return stringify(ast); -}; - + push({ type: 'dot', value }); + continue; + } -/***/ }), -/* 611 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Text + */ -"use strict"; + push({ type: 'text', value }); + } + // Mark imbalanced braces and brackets as invalid + do { + block = stack.pop(); -exports.isInteger = num => { - if (typeof num === 'number') { - return Number.isInteger(num); - } - if (typeof num === 'string' && num.trim() !== '') { - return Number.isInteger(Number(num)); - } - return false; -}; + 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; + } + }); -/** - * Find a node of the given type - */ + // 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); -exports.find = (node, type) => node.nodes.find(node => node.type === type); + push({ type: 'eos' }); + return ast; +}; -/** - * Find a node of the given type - */ +module.exports = parse; -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 - */ +/***/ }), +/* 613 */ +/***/ (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 - */ +module.exports = { + MAX_LENGTH: 1024 * 64, -exports.encloseBrace = node => { - if (node.type !== 'brace') return false; - if ((node.commas >> 0 + node.ranges >> 0) === 0) { - node.invalid = true; - return true; - } - return false; -}; + // Digits + CHAR_0: '0', /* 0 */ + CHAR_9: '9', /* 9 */ -/** - * Returns true if a brace node is invalid. - */ + // Alphabet chars. + CHAR_UPPERCASE_A: 'A', /* A */ + CHAR_LOWERCASE_A: 'a', /* a */ + CHAR_UPPERCASE_Z: 'Z', /* Z */ + CHAR_LOWERCASE_Z: 'z', /* z */ -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; -}; + CHAR_LEFT_PARENTHESES: '(', /* ( */ + CHAR_RIGHT_PARENTHESES: ')', /* ) */ -/** - * Returns true if a node is an open or close node - */ + CHAR_ASTERISK: '*', /* * */ -exports.isOpenOrClose = node => { - if (node.type === 'open' || node.type === 'close') { - return true; - } - return node.open === true || node.close === true; + // 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 */ }; -/** - * Reduce an array of text nodes. - */ -exports.reduce = nodes => nodes.reduce((acc, node) => { - if (node.type === 'text') acc.push(node.value); - if (node.type === 'range') node.type = 'text'; - return acc; -}, []); +/***/ }), +/* 614 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Flatten an array - */ +"use strict"; -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 = __webpack_require__(615); /***/ }), -/* 612 */ +/* 615 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fill = __webpack_require__(613); -const utils = __webpack_require__(611); +const path = __webpack_require__(16); +const scan = __webpack_require__(616); +const parse = __webpack_require__(619); +const utils = __webpack_require__(617); -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 = ''; +/** + * 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 + */ - if (node.isOpen === true) { - return prefix + node.value; - } - if (node.isClose === true) { - return prefix + node.value; - } +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 (node.type === 'open') { - return invalid ? (prefix + node.value) : '('; - } + if (typeof glob !== 'string' || glob === '') { + throw new TypeError('Expected pattern to be a non-empty string'); + } - if (node.type === 'close') { - return invalid ? (prefix + node.value) : ')'; - } + let opts = options || {}; + let posix = utils.isWindows(options); + let regex = picomatch.makeRe(glob, options, false, true); + let state = regex.state; + delete regex.state; - if (node.type === 'comma') { - return node.prev.type === 'comma' ? '' : (invalid ? node.value : '|'); - } + let isIgnored = () => false; + if (opts.ignore) { + let ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; + isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); + } - if (node.value) { - return node.value; + 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 (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); - let range = fill(...args, { ...options, wrap: false, toRegex: true }); + if (isMatch === false) { + result.isMatch = false; + return returnObject ? result : false; + } - if (range.length !== 0) { - return args.length > 1 && range.length > 1 ? `(${range})` : range; + if (isIgnored(input)) { + if (typeof opts.onIgnore === 'function') { + opts.onIgnore(result); } + result.isMatch = false; + return returnObject ? result : false; } - if (node.nodes) { - for (let child of node.nodes) { - output += walk(child, node); - } + if (typeof opts.onMatch === 'function') { + opts.onMatch(result); } - return output; + return returnObject ? result : true; }; - return walk(ast); -}; - -module.exports = compile; - + if (returnState) { + matcher.state = state; + } -/***/ }), -/* 613 */ -/***/ (function(module, exports, __webpack_require__) { + return matcher; +}; -"use strict"; -/*! - * fill-range +/** + * Test `input` with the given `regex`. This is used by the main + * `picomatch()` function to test the input string. * - * Copyright (c) 2014-present, Jon Schlinkert. - * Licensed under the MIT License. + * ```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 */ +picomatch.test = (input, regex, options, { glob, posix } = {}) => { + if (typeof input !== 'string') { + throw new TypeError('Expected input to be a string'); + } + if (input === '') { + return { isMatch: false, output: '' }; + } -const util = __webpack_require__(29); -const toRegexRange = __webpack_require__(614); + let opts = options || {}; + let format = opts.format || (posix ? utils.toPosixSlashes : null); + let match = input === glob; + let output = (match && format) ? format(input) : input; -const isObject = val => val !== null && typeof val === 'object' && !Array.isArray(val); + if (match === false) { + output = format ? format(input) : input; + match = output === glob; + } -const transform = toNumber => { - return value => toNumber === true ? Number(value) : String(value); -}; + 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); + } + } -const isValidValue = value => { - return typeof value === 'number' || (typeof value === 'string' && value !== ''); + return { isMatch: !!match, match, output }; }; -const isNumber = num => Number.isInteger(+num); +/** + * 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 + */ -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; +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)); }; -const stringify = (start, end, options) => { - if (typeof start === 'string' || typeof end === 'string') { - return true; - } - return options.stringify === true; -}; +/** + * 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 + */ -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; -}; +picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); -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; -}; +/** + * 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 + */ -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); +picomatch.parse = (glob, options) => parse(glob, options); - let prefix = options.capture ? '' : '?:'; - let positives = ''; - let negatives = ''; - let result; +/** + * 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 + */ - if (parts.positives.length) { - positives = parts.positives.join('|'); +picomatch.scan = (input, options) => scan(input, options); + +/** + * 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 + */ + +picomatch.makeRe = (input, options, returnOutput = false, returnState = false) => { + if (!input || typeof input !== 'string') { + throw new TypeError('Expected a non-empty string'); } - if (parts.negatives.length) { - negatives = `-(${prefix}${parts.negatives.join('|')})`; + 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 (positives && negatives) { - result = `${positives}|${negatives}`; - } else { - result = positives || negatives; + if (opts.fastpaths !== false && (input[0] === '.' || input[0] === '*')) { + output = parse.fastpaths(input, options); } - if (options.wrap) { - return `(${prefix}${result})`; + if (output === void 0) { + state = picomatch.parse(input, options); + state.prefix = prefix + (state.prefix || ''); + output = state.output; } - return result; -}; + if (returnOutput === true) { + return output; + } -const toRange = (a, b, isNumbers, options) => { - if (isNumbers) { - return toRegexRange(a, b, { wrap: false, ...options }); + let source = `${prepend}(?:${output})${append}`; + if (state && state.negated === true) { + source = `^(?!${source}).*$`; } - let start = String.fromCharCode(a); - if (a === b) return start; + let regex = picomatch.toRegex(source, options); + if (returnState === true) { + regex.state = state; + } - let stop = String.fromCharCode(b); - return `[${start}-${stop}]`; + return regex; }; -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); -}; - -const rangeError = (...args) => { - return new RangeError('Invalid range arguments: ' + util.inspect(...args)); -}; - -const invalidRange = (start, end, options) => { - if (options.strictRanges === true) throw rangeError([start, end]); - return []; -}; +/** + * 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 + */ -const invalidStep = (step, options) => { - if (options.strictRanges === true) { - throw new TypeError(`Expected step "${step}" to be a number`); +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 /$^/; } - return []; }; -const fillNumbers = (start, end, step = 1, options = {}) => { - let a = Number(start); - let b = Number(end); +/** + * Picomatch constants. + * @return {Object} + */ - if (!Number.isInteger(a) || !Number.isInteger(b)) { - if (options.strictRanges === true) throw rangeError([start, end]); - return []; - } +picomatch.constants = __webpack_require__(618); - // fix negative zero - if (a === 0) a = 0; - if (b === 0) b = 0; +/** + * Expose "picomatch" + */ - let descending = a > b; - let startString = String(start); - let endString = String(end); - let stepString = String(step); - step = Math.max(Math.abs(step), 1); +module.exports = picomatch; - 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 (options.toRegex && step === 1) { - return toRange(toMaxLen(start, maxLen), toMaxLen(end, maxLen), true, options); - } +/***/ }), +/* 616 */ +/***/ (function(module, exports, __webpack_require__) { - let parts = { negatives: [], positives: [] }; - let push = num => parts[num < 0 ? 'negatives' : 'positives'].push(Math.abs(num)); - let range = []; - let index = 0; +"use strict"; - 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 (options.toRegex === true) { - return step > 1 - ? toSequence(parts, options) - : toRegex(range, null, { wrap: false, ...options }); - } +const utils = __webpack_require__(617); - return range; +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 fillLetters = (start, end, step = 1, options = {}) => { - if ((!isNumber(start) && start.length > 1) || (!isNumber(end) && end.length > 1)) { - return invalidRange(start, end, options); - } +/** + * 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 + */ +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 format = options.transform || (val => String.fromCharCode(val)); - let a = `${start}`.charCodeAt(0); - let b = `${end}`.charCodeAt(0); + let braceEscaped = false; - let descending = a > b; - let min = Math.min(a, b); - let max = Math.max(a, b); + let eos = () => index >= length; + let advance = () => { + prev = code; + return input.charCodeAt(++index); + }; - if (options.toRegex && step === 1) { - return toRange(min, max, false, options); - } + while (index < length) { + code = advance(); + let next; - let range = []; - let index = 0; + if (code === CHAR_BACKWARD_SLASH) { + backslashes = true; + next = advance(); - while (descending ? a >= b : a <= b) { - range.push(format(a, index)); - a = descending ? a - step : a + step; - index++; - } + if (next === CHAR_LEFT_CURLY_BRACE) { + braceEscaped = true; + } + continue; + } - if (options.toRegex === true) { - return toRegex(range, null, { wrap: false, options }); - } + if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) { + braces++; - return range; -}; + while (!eos() && (next = advance())) { + if (next === CHAR_BACKWARD_SLASH) { + backslashes = true; + next = advance(); + continue; + } -const fill = (start, end, step, options = {}) => { - if (end == null && isValidValue(start)) { - return [start]; - } + if (next === CHAR_LEFT_CURLY_BRACE) { + braces++; + continue; + } - if (!isValidValue(start) || !isValidValue(end)) { - return invalidRange(start, end, options); - } + if (!braceEscaped && next === CHAR_DOT && (next = advance()) === CHAR_DOT) { + isGlob = true; + break; + } - if (typeof step === 'function') { - return fill(start, end, 1, { transform: step }); - } + if (!braceEscaped && next === CHAR_COMMA) { + isGlob = true; + break; + } - if (isObject(step)) { - return fill(start, end, 0, step); - } + if (next === CHAR_RIGHT_CURLY_BRACE) { + braces--; + if (braces === 0) { + braceEscaped = false; + break; + } + } + } + } - let opts = { ...options }; - if (opts.capture === true) opts.wrap = true; - step = step || opts.step || 1; + if (code === CHAR_FORWARD_SLASH) { + if (prev === CHAR_DOT && index === (start + 1)) { + start += 2; + continue; + } - if (!isNumber(step)) { - if (step != null && !isObject(step)) return invalidStep(step, opts); - return fill(start, end, 1, step); - } + lastIndex = index + 1; + continue; + } - if (isNumber(start) && isNumber(end)) { - return fillNumbers(start, end, step, opts); - } + if (code === CHAR_ASTERISK) { + isGlob = true; + break; + } - return fillLetters(start, end, Math.max(Math.abs(step), 1), opts); -}; + if (code === CHAR_ASTERISK || code === CHAR_QUESTION_MARK) { + isGlob = true; + break; + } -module.exports = fill; + if (code === CHAR_LEFT_SQUARE_BRACKET) { + while (!eos() && (next = advance())) { + if (next === CHAR_BACKWARD_SLASH) { + backslashes = true; + next = advance(); + continue; + } + if (next === CHAR_RIGHT_SQUARE_BRACKET) { + isGlob = true; + break; + } + } + } -/***/ }), -/* 614 */ -/***/ (function(module, exports, __webpack_require__) { + let isExtglobChar = code === CHAR_PLUS + || code === CHAR_AT + || code === CHAR_EXCLAMATION_MARK; -"use strict"; -/*! - * to-regex-range - * - * Copyright (c) 2015-present, Jon Schlinkert. - * Released under the MIT License. - */ + if (isExtglobChar && input.charCodeAt(index + 1) === CHAR_LEFT_PARENTHESES) { + isGlob = true; + break; + } + if (code === CHAR_EXCLAMATION_MARK && index === start) { + negated = true; + start++; + continue; + } + if (code === CHAR_LEFT_PARENTHESES) { + while (!eos() && (next = advance())) { + if (next === CHAR_BACKWARD_SLASH) { + backslashes = true; + next = advance(); + continue; + } -const isNumber = __webpack_require__(615); + if (next === CHAR_RIGHT_PARENTHESES) { + isGlob = true; + break; + } + } + } -const toRegexRange = (min, max, options) => { - if (isNumber(min) === false) { - throw new TypeError('toRegexRange: expected the first argument to be a number'); + if (isGlob) { + break; + } } - if (max === void 0 || min === max) { - return String(min); - } + let prefix = ''; + let orig = input; + let base = input; + let glob = ''; - if (isNumber(max) === false) { - throw new TypeError('toRegexRange: expected the second argument to be a number.'); + if (start > 0) { + prefix = input.slice(0, start); + input = input.slice(start); + lastIndex -= start; } - let opts = { relaxZeros: true, ...options }; - if (typeof opts.strictZeros === 'boolean') { - opts.relaxZeros = opts.strictZeros === false; + 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; } - 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 (toRegexRange.cache.hasOwnProperty(cacheKey)) { - return toRegexRange.cache[cacheKey].result; + if (base && base !== '' && base !== '/' && base !== input) { + if (isPathSeparator(base.charCodeAt(base.length - 1))) { + base = base.slice(0, -1); + } } - let a = Math.min(min, max); - let b = Math.max(min, max); + if (opts.unescape === true) { + if (glob) glob = utils.removeBackslashes(glob); - if (Math.abs(a - b) === 1) { - let result = min + '|' + max; - if (opts.capture) { - return `(${result})`; - } - if (opts.wrap === false) { - return result; + if (base && backslashes === true) { + base = utils.removeBackslashes(base); } - return `(?:${result})`; } - let isPadded = hasPadding(min) || hasPadding(max); - let state = { min, max, a, b }; - let positives = []; - let negatives = []; + return { prefix, input: orig, base, glob, negated, isGlob }; +}; - 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; - } +/***/ }), +/* 617 */ +/***/ (function(module, exports, __webpack_require__) { - if (b >= 0) { - positives = splitToPatterns(a, b, state, opts); - } +"use strict"; - 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})`; - } +const path = __webpack_require__(16); +const win32 = process.platform === 'win32'; +const { + REGEX_SPECIAL_CHARS, + REGEX_SPECIAL_CHARS_GLOBAL, + REGEX_REMOVE_BACKSLASH +} = __webpack_require__(618); - toRegexRange.cache[cacheKey] = state; - return state.result; -}; +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, '/'); -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('|'); +exports.removeBackslashes = str => { + return str.replace(REGEX_REMOVE_BACKSLASH, match => { + return match === '\\' ? '' : match; + }); } -function splitToRanges(min, max) { - let nines = 1; - let zeros = 1; - - let stop = countNines(min, nines); - let stops = new Set([max]); +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; +}; - while (min <= stop && stop <= max) { - stops.add(stop); - nines += 1; - stop = countNines(min, nines); +exports.isWindows = options => { + if (options && typeof options.windows === 'boolean') { + return options.windows; } + return win32 === true || path.sep === '\\'; +}; - stop = countZeros(max + 1, zeros) - 1; +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); +}; - while (min < stop && stop <= max) { - stops.add(stop); - zeros += 1; - stop = countZeros(max + 1, zeros) - 1; - } - stops = [...stops]; - stops.sort(compare); - return stops; -} +/***/ }), +/* 618 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const path = __webpack_require__(16); +const WIN_SLASH = '\\\\/'; +const WIN_NO_SLASH = `[^${WIN_SLASH}]`; /** - * Convert a range to a regex pattern - * @param {Number} `start` - * @param {Number} `stop` - * @return {String} + * Posix glob regex */ -function rangeToPattern(start, stop, options) { - if (start === stop) { - return { pattern: start, count: [], digits: 0 }; - } +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}*?`; - let zipped = zip(start, stop); - let digits = zipped.length; - let pattern = ''; - let count = 0; +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 +}; - for (let i = 0; i < digits; i++) { - let [startDigit, stopDigit] = zipped[i]; +/** + * Windows glob regex + */ - if (startDigit === stopDigit) { - pattern += startDigit; +const WINDOWS_CHARS = { + ...POSIX_CHARS, - } else if (startDigit !== '0' || stopDigit !== '9') { - pattern += toCharacterClass(startDigit, stopDigit, options); + 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}]|$)` +}; - } else { - count++; - } - } +/** + * POSIX Bracket Regex + */ - if (count) { - pattern += options.shorthand === true ? '\\d' : '[0-9]'; - } +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' +}; - return { pattern, count: [count], digits }; -} +module.exports = { + MAX_LENGTH: 1024 * 64, + POSIX_REGEX_SOURCE, -function splitToPatterns(min, max, tok, options) { - let ranges = splitToRanges(min, max); - let tokens = []; - let start = min; - let prev; + // 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, - for (let i = 0; i < ranges.length; i++) { - let max = ranges[i]; - let obj = rangeToPattern(String(start), String(max), options); - let zeros = ''; + // Replace globs with equivalent patterns to reduce parsing time. + REPLACEMENTS: { + '***': '*', + '**/**': '**', + '**/**/**': '**' + }, - if (!tok.isPadded && prev && prev.pattern === obj.pattern) { - if (prev.count.length > 1) { - prev.count.pop(); - } + // Digits + CHAR_0: 48, /* 0 */ + CHAR_9: 57, /* 9 */ - prev.count.push(obj.count[0]); - prev.string = prev.pattern + toQuantifier(prev.count); - start = max + 1; - continue; - } + // Alphabet chars. + CHAR_UPPERCASE_A: 65, /* A */ + CHAR_LOWERCASE_A: 97, /* a */ + CHAR_UPPERCASE_Z: 90, /* Z */ + CHAR_LOWERCASE_Z: 122, /* z */ - if (tok.isPadded) { - zeros = padZeros(max, tok, options); - } + CHAR_LEFT_PARENTHESES: 40, /* ( */ + CHAR_RIGHT_PARENTHESES: 41, /* ) */ - obj.string = zeros + obj.pattern + toQuantifier(obj.count); - tokens.push(obj); - start = max + 1; - prev = obj; - } + CHAR_ASTERISK: 42, /* * */ - return tokens; -} + // 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 */ -function filterPatterns(arr, comparison, prefix, intersection, options) { - let result = []; + SEP: path.sep, - for (let ele of arr) { - let { string } = ele; + /** + * Create EXTGLOB_CHARS + */ - // only push if _both_ are negative... - if (!intersection && !contains(comparison, 'string', string)) { - result.push(prefix + string); - } + 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: ')' } + }; + }, - // or _both_ are positive - if (intersection && contains(comparison, 'string', string)) { - result.push(prefix + string); - } + /** + * Create GLOB_CHARS + */ + + globChars(win32) { + return win32 === true ? WINDOWS_CHARS : POSIX_CHARS; } - 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; -} +/***/ }), +/* 619 */ +/***/ (function(module, exports, __webpack_require__) { -function compare(a, b) { - return a > b ? 1 : b > a ? -1 : 0; -} +"use strict"; -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)); -} +const utils = __webpack_require__(617); +const constants = __webpack_require__(618); -function countZeros(integer, zeros) { - return integer - (integer % Math.pow(10, zeros)); -} +/** + * Constants + */ -function toQuantifier(digits) { - let [start = 0, stop = ''] = digits; - if (stop || start > 1) { - return `{${start + (stop ? ',' + stop : '')}}`; - } - return ''; -} +const { + MAX_LENGTH, + POSIX_REGEX_SOURCE, + REGEX_NON_SPECIAL_CHAR, + REGEX_SPECIAL_CHARS_BACKREF, + REPLACEMENTS +} = constants; -function toCharacterClass(a, b, options) { - return `[${a}${(b - a === 1) ? '' : '-'}${b}]`; -} +/** + * Helpers + */ -function hasPadding(str) { - return /^-?(0+)\d/.test(str); -} +const expandRange = (args, options) => { + if (typeof options.expandRange === 'function') { + return options.expandRange(...args, options); + } -function padZeros(value, tok, options) { - if (!tok.isPadded) { - return value; + args.sort(); + let value = `[${args.join('-')}]`; + + try { + /* eslint-disable no-new */ + new RegExp(value); + } catch (ex) { + return args.map(v => utils.escapeRegex(v)).join('..'); } - let diff = Math.abs(tok.maxLen - String(value).length); - let relax = options.relaxZeros !== false; + return 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}}`; - } +const negate = state => { + let count = 1; + + while (state.peek() === '!' && (state.peek(2) !== '(' || state.peek(3) === '?')) { + state.advance(); + state.start++; + count++; } -} -/** - * Cache - */ + if (count % 2 === 0) { + return false; + } -toRegexRange.cache = {}; -toRegexRange.clearCache = () => (toRegexRange.cache = {}); + state.negated = true; + state.start++; + return true; +}; /** - * Expose `toRegexRange` + * Create the message for a syntax error */ -module.exports = toRegexRange; - - -/***/ }), -/* 615 */ -/***/ (function(module, exports, __webpack_require__) { +const syntaxError = (type, char) => { + return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; +}; -"use strict"; -/*! - * is-number - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Released under the MIT License. +/** + * 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; -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); + 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}`); } - return false; -}; - -/***/ }), -/* 616 */ -/***/ (function(module, exports, __webpack_require__) { + let bos = { type: 'bos', value: '', output: opts.prepend || '' }; + let tokens = [bos]; -"use strict"; + 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 fill = __webpack_require__(613); -const stringify = __webpack_require__(610); -const utils = __webpack_require__(611); + 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 append = (queue = '', stash = '', enclose = false) => { - let result = []; + const globstar = (opts) => { + return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; + }; - queue = [].concat(queue); - stash = [].concat(stash); + let nodot = opts.dot ? '' : NO_DOT; + let star = opts.bash === true ? globstar(opts) : STAR; + let qmarkNoDot = opts.dot ? QMARK : QMARK_NO_DOT; - if (!stash.length) return queue; - if (!queue.length) { - return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; + if (opts.capture) { + star = `(${star})`; } - 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)); - } - } + // minimatch options support + if (typeof opts.noext === 'boolean') { + opts.noextglob = opts.noext; } - return utils.flatten(result); -}; -const expand = (ast, options = {}) => { - let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit; + let state = { + index: -1, + start: 0, + consumed: '', + output: '', + backtrack: false, + brackets: 0, + braces: 0, + parens: 0, + quotes: 0, + tokens + }; - let walk = (node, parent = {}) => { - node.queue = []; + let extglobs = []; + let stack = []; + let prev = bos; + let value; - let p = parent; - let q = parent.queue; + /** + * Tokenizing helpers + */ - while (p.type !== 'brace' && p.type !== 'root' && p.parent) { - p = p.parent; - q = p.queue; - } + 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 || ''; + }; - if (node.invalid || node.dollar) { - q.push(append(q.pop(), stringify(node, options))); - return; - } + const increment = type => { + state[type]++; + stack.push(type); + }; - if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { - q.push(append(q.pop(), ['{}'])); - return; - } + const decrement = type => { + state[type]--; + stack.pop(); + }; - if (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); + /** + * 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. + */ - 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.'); + 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; } + } - let range = fill(...args, options); - if (range.length === 0) { - range = stringify(node, options); - } + if (extglobs.length && tok.type !== 'paren' && !EXTGLOB_CHARS[tok.value]) { + extglobs[extglobs.length - 1].inner += tok.value; + } - q.push(append(q.pop(), range)); - node.nodes = []; + if (tok.value || tok.output) append(tok); + if (prev && prev.type === 'text' && tok.type === 'text') { + prev.value += tok.value; return; } - let enclose = utils.encloseBrace(node); - let queue = node.queue; - let block = node; + tok.prev = prev; + tokens.push(tok); + prev = tok; + }; - while (block.type !== 'brace' && block.type !== 'root' && block.parent) { - block = block.parent; - queue = block.queue; - } + const extglobOpen = (type, value) => { + let token = { ...EXTGLOB_CHARS[value], conditions: 1, inner: '' }; - for (let i = 0; i < node.nodes.length; i++) { - let child = node.nodes[i]; + token.prev = prev; + token.parens = state.parens; + token.output = state.output; + let output = (opts.capture ? '(' : '') + token.open; - if (child.type === 'comma' && node.type === 'brace') { - if (i === 1) queue.push(''); - queue.push(''); - continue; - } + push({ type, value, output: state.output ? '' : ONE_CHAR }); + push({ type: 'paren', extglob: true, value: advance(), output }); + increment('parens'); + extglobs.push(token); + }; - if (child.type === 'close') { - q.push(append(q.pop(), queue, enclose)); - continue; + 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 (child.value && child.type !== 'open') { - queue.push(append(queue.pop(), child.value)); - continue; + if (extglobStar !== star || eos() || /^\)+$/.test(input.slice(state.index + 1))) { + output = token.close = ')$))' + extglobStar; } - if (child.nodes) { - walk(child, node); + if (token.prev.type === 'bos' && eos()) { + state.negatedExtglob = true; } } - return queue; + push({ type: 'paren', extglob: true, value, output }); + decrement('parens'); }; - return utils.flatten(walk(ast)); -}; - -module.exports = expand; + 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; + } -/***/ }), -/* 617 */ -/***/ (function(module, exports, __webpack_require__) { + 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); + } -"use strict"; + if (first === '.') { + return DOT_LITERAL.repeat(chars.length); + } + if (first === '*') { + if (esc) { + return esc + first + (rest ? star : ''); + } + return star; + } + return esc ? m : '\\' + m; + }); -const stringify = __webpack_require__(610); + if (backslashes === true) { + if (opts.unescape === true) { + output = output.replace(/\\/g, ''); + } else { + output = output.replace(/\\+/g, m => { + return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : ''); + }); + } + } -/** - * Constants - */ + state.output = output; + return state; + } -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); + /** + * Tokenize input until we reach end-of-string + */ -/** - * parse - */ + while (!eos()) { + value = advance(); -const parse = (input, options = {}) => { - if (typeof input !== 'string') { - throw new TypeError('Expected a string'); - } + if (value === '\u0000') { + continue; + } - 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})`); - } + /** + * Escaped characters + */ - 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 = {}; + if (value === '\\') { + let next = peek(); - /** - * Helpers - */ + if (next === '/' && opts.bash !== true) { + continue; + } - const advance = () => input[index++]; - const push = node => { - if (node.type === 'text' && prev.type === 'dot') { - prev.type = 'text'; - } + if (next === '.' || next === ';') { + continue; + } - if (prev && prev.type === 'text' && node.type === 'text') { - prev.value += node.value; - return; - } + if (!next) { + value += '\\'; + push({ type: 'text', value }); + continue; + } - block.nodes.push(node); - node.parent = block; - node.prev = prev; - prev = node; - return node; - }; + // collapse slashes to reduce potential for exploits + let match = /^\\+/.exec(input.slice(state.index + 1)); + let slashes = 0; - push({ type: 'bos' }); + if (match && match[0].length > 2) { + slashes = match[0].length; + state.index += slashes; + if (slashes % 2 !== 0) { + value += '\\'; + } + } - while (index < length) { - block = stack[stack.length - 1]; - value = advance(); + if (opts.unescape === true) { + value = advance() || ''; + } else { + value += advance() || ''; + } + + if (state.brackets === 0) { + push({ type: 'text', value }); + continue; + } + } /** - * Invalid chars + * If we're inside a regex character class, continue + * until we reach the closing bracket. */ - if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { + 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; } /** - * Escaped chars + * If we're inside a quoted string, continue + * until we reach the closing double quote. */ - if (value === CHAR_BACKSLASH) { - push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); + if (state.quotes === 1 && value !== '"') { + value = utils.escapeRegex(value); + prev.value += value; + append({ value }); continue; } /** - * Right square bracket (literal): ']' + * Double quotes */ - if (value === CHAR_RIGHT_SQUARE_BRACKET) { - push({ type: 'text', value: '\\' + value }); + if (value === '"') { + state.quotes = state.quotes === 1 ? 0 : 1; + if (opts.keepQuotes === true) { + push({ type: 'text', value }); + } continue; } /** - * Left square bracket: '[' + * Parentheses */ - if (value === CHAR_LEFT_SQUARE_BRACKET) { - brackets++; - - let closed = true; - let next; - - while (index < length && (next = advance())) { - value += next; - - if (next === CHAR_LEFT_SQUARE_BRACKET) { - brackets++; - continue; - } - - if (next === CHAR_BACKSLASH) { - value += advance(); - continue; - } + if (value === '(') { + push({ type: 'paren', value }); + increment('parens'); + continue; + } - if (next === CHAR_RIGHT_SQUARE_BRACKET) { - brackets--; + if (value === ')') { + if (state.parens === 0 && opts.strictBrackets === true) { + throw new SyntaxError(syntaxError('opening', '(')); + } - if (brackets === 0) { - break; - } - } + let extglob = extglobs[extglobs.length - 1]; + if (extglob && state.parens === extglob.parens + 1) { + extglobClose(extglobs.pop()); + continue; } - push({ type: 'text', value }); + push({ type: 'paren', value, output: state.parens ? ')' : '\\)' }); + decrement('parens'); continue; } /** - * Parentheses + * Brackets */ - if (value === CHAR_LEFT_PARENTHESES) { - block = push({ type: 'paren', nodes: [] }); - stack.push(block); - push({ type: 'text', value }); + 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 === CHAR_RIGHT_PARENTHESES) { - if (block.type !== 'paren') { - push({ type: 'text', value }); + if (value === ']') { + if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) { + push({ type: 'text', value, output: '\\' + value }); continue; } - block = stack.pop(); - push({ type: 'text', value }); - block = stack[stack.length - 1]; + + 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; } /** - * Quotes: '|"|` + * Braces */ - if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { - let open = value; - let next; + if (value === '{' && opts.nobrace !== true) { + push({ type: 'brace', value, output: '(' }); + increment('braces'); + continue; + } - if (options.keepQuotes !== true) { - value = ''; + if (value === '}') { + if (opts.nobrace === true || state.braces === 0) { + push({ type: 'text', value, output: '\\' + value }); + continue; } - while (index < length && (next = advance())) { - if (next === CHAR_BACKSLASH) { - value += next + advance(); - continue; - } + let output = ')'; - if (next === open) { - if (options.keepQuotes === true) value += next; - break; + 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); + } } - value += next; + 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; } /** - * Left curly brace: '{' + * Commas */ - if (value === CHAR_LEFT_CURLY_BRACE) { - depth++; + if (value === ',') { + let output = value; - 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: [] - }; + if (state.braces > 0 && stack[stack.length - 1] === 'braces') { + output = '|'; + } - block = push(brace); - stack.push(block); - push({ type: 'open', value }); + push({ type: 'comma', value, output }); continue; } /** - * Right curly brace: '}' + * Slashes */ - if (value === CHAR_RIGHT_CURLY_BRACE) { - if (block.type !== 'brace') { - push({ type: 'text', value }); + 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; } - let type = 'close'; - block = stack.pop(); - block.close = true; - - push({ type, value }); - depth--; - - block = stack[stack.length - 1]; + push({ type: 'slash', value, output: SLASH_LITERAL }); continue; } /** - * Comma: ',' + * Dots */ - 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) }]; + 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: 'comma', value }); - block.commas++; + push({ type: 'dot', value, output: DOT_LITERAL }); continue; } /** - * Dot: '.' + * Question marks */ - 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 (value === '?') { + if (prev && prev.type === 'paren') { + let next = peek(); + let output = value; - if (prev.type === 'dot') { - block.range = []; - prev.value += value; - prev.type = 'range'; + if (next === '<' && !utils.supportsLookbehinds()) { + throw new Error('Node.js v10 or higher is required for regex lookbehinds'); + } - if (block.nodes.length !== 3 && block.nodes.length !== 5) { - block.invalid = true; - block.ranges = 0; - prev.type = 'text'; - continue; + if (prev.value === '(' && !/[!=<:]/.test(next) || (next === '<' && !/[!=]/.test(peek(2)))) { + output = '\\' + value; } - block.ranges++; - block.args = []; + push({ type: 'text', value, output }); continue; } - if (prev.type === 'range') { - siblings.pop(); + if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + extglobOpen('qmark', value); + continue; + } - let before = siblings[siblings.length - 1]; - before.value += prev.value + value; - prev = before; - block.ranges--; + if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) { + push({ type: 'qmark', value, output: QMARK_NO_DOT }); continue; } - push({ type: 'dot', value }); + push({ type: 'qmark', value, output: QMARK }); continue; } /** - * Text + * Exclamation */ - 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; + if (value === '!') { + if (opts.noextglob !== true && peek() === '(') { + if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) { + extglobOpen('negate', value); + continue; } - }); + } - // 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); + if (opts.nonegate !== true && state.index === 0) { + negate(state); + continue; + } } - } while (stack.length > 0); - push({ type: 'eos' }); - return ast; -}; + /** + * Plus + */ -module.exports = parse; + 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; + } -/***/ }), -/* 618 */ -/***/ (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 + */ -module.exports = { - MAX_LENGTH: 1024 * 64, + if (value === '@') { + if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + push({ type: 'at', value, output: '' }); + continue; + } - // Digits - CHAR_0: '0', /* 0 */ - CHAR_9: '9', /* 9 */ + push({ type: 'text', value }); + continue; + } - // Alphabet chars. - CHAR_UPPERCASE_A: 'A', /* A */ - CHAR_LOWERCASE_A: 'a', /* a */ - CHAR_UPPERCASE_Z: 'Z', /* Z */ - CHAR_LOWERCASE_Z: 'z', /* z */ + /** + * Plain text + */ - CHAR_LEFT_PARENTHESES: '(', /* ( */ - CHAR_RIGHT_PARENTHESES: ')', /* ) */ + if (value !== '*') { + if (value === '$' || value === '^') { + value = '\\' + value; + } - CHAR_ASTERISK: '*', /* * */ + let match = REGEX_NON_SPECIAL_CHAR.exec(input.slice(state.index + 1)); + if (match) { + value += match[0]; + state.index += match[0].length; + } - // 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 */ -}; + push({ type: 'text', value }); + continue; + } + /** + * Stars + */ -/***/ }), -/* 619 */ -/***/ (function(module, exports, __webpack_require__) { + 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; + } -"use strict"; + if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { + extglobOpen('star', value); + continue; + } + if (prev.type === 'star') { + if (opts.noglobstar === true) { + state.consumed += value; + continue; + } -module.exports = __webpack_require__(620); + 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; + } -/***/ }), -/* 620 */ -/***/ (function(module, exports, __webpack_require__) { + 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; + } -"use strict"; + // 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; + } -const path = __webpack_require__(16); -const scan = __webpack_require__(621); -const parse = __webpack_require__(624); -const utils = __webpack_require__(622); + 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; -/** - * 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 - */ + prev.type = 'globstar'; + prev.output = globstar(opts) + '|$)'; + prev.value += value; -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; + state.output += prior.output + prev.output; + state.consumed += value; + continue; } - return false; - }; - } - if (typeof glob !== 'string' || glob === '') { - throw new TypeError('Expected pattern to be a non-empty string'); - } + let next = peek(); + if (prior.type === 'slash' && prior.prev.type !== 'bos' && next === '/') { + let end = peek(2) !== void 0 ? '|$' : ''; - let opts = options || {}; - let posix = utils.isWindows(options); - let regex = picomatch.makeRe(glob, options, false, true); - let state = regex.state; - delete regex.state; + state.output = state.output.slice(0, -(prior.output + prev.output).length); + prior.output = '(?:' + prior.output; - let isIgnored = () => false; - if (opts.ignore) { - let ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; - isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); - } + prev.type = 'globstar'; + prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`; + prev.value += value; - 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 }; + state.output += prior.output + prev.output; + state.consumed += value + advance(); - if (typeof opts.onResult === 'function') { - opts.onResult(result); - } + push({ type: 'slash', value, output: '' }); + continue; + } - if (isMatch === false) { - result.isMatch = false; - return returnObject ? result : false; + 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; } - if (isIgnored(input)) { - if (typeof opts.onIgnore === 'function') { - opts.onIgnore(result); + 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; } - result.isMatch = false; - return returnObject ? result : false; + push(token); + continue; } - if (typeof opts.onMatch === 'function') { - opts.onMatch(result); + if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) { + token.output = value; + push(token); + continue; } - return returnObject ? result : true; - }; - if (returnState) { - matcher.state = state; - } + 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; - return matcher; -}; + } else if (opts.dot === true) { + state.output += NO_DOTS_SLASH; + prev.output += NO_DOTS_SLASH; -/** - * 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 - */ + } else { + state.output += nodot; + prev.output += nodot; + } -picomatch.test = (input, regex, options, { glob, posix } = {}) => { - if (typeof input !== 'string') { - throw new TypeError('Expected input to be a string'); + if (peek() !== '*') { + state.output += ONE_CHAR; + prev.output += ONE_CHAR; + } + } + + push(token); } - if (input === '') { - return { isMatch: false, output: '' }; + while (state.brackets > 0) { + if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']')); + state.output = utils.escapeLast(state.output, '['); + decrement('brackets'); } - let opts = options || {}; - let format = opts.format || (posix ? utils.toPosixSlashes : null); - let match = input === glob; - let output = (match && format) ? format(input) : input; + while (state.parens > 0) { + if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')')); + state.output = utils.escapeLast(state.output, '('); + decrement('parens'); + } - if (match === false) { - output = format ? format(input) : input; - match = output === glob; + while (state.braces > 0) { + if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}')); + state.output = utils.escapeLast(state.output, '{'); + decrement('braces'); } - 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); - } + if (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) { + push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` }); } - return { isMatch: !!match, match, output }; -}; + // rebuild the output if we had to backtrack at any point + if (state.backtrack === true) { + state.output = ''; -/** - * 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 - */ + for (let token of state.tokens) { + state.output += token.output != null ? token.output : token.value; -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)); + if (token.suffix) { + state.output += token.suffix; + } + } + } + + return state; }; /** - * 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 + * 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. */ -picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); +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}`); + } -/** - * 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 - */ + input = REPLACEMENTS[input] || input; + let win32 = utils.isWindows(options); -picomatch.parse = (glob, options) => parse(glob, 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); -/** - * 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 - */ + 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; -picomatch.scan = (input, options) => scan(input, options); + if (opts.capture) { + star = `(${star})`; + } -/** - * 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 - */ + const globstar = (opts) => { + return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; + }; -picomatch.makeRe = (input, options, returnOutput = false, returnState = false) => { - if (!input || typeof input !== 'string') { - throw new TypeError('Expected a non-empty string'); - } + const create = str => { + switch (str) { + case '*': + return `${nodot}${ONE_CHAR}${star}`; - let opts = options || {}; - let prepend = opts.contains ? '' : '^'; - let append = opts.contains ? '' : '$'; - let state = { negated: false, fastpaths: true }; - let prefix = ''; - let output; + case '.*': + return `${DOT_LITERAL}${ONE_CHAR}${star}`; - if (input.startsWith('./')) { - input = input.slice(2); - prefix = state.prefix = './'; - } + case '*.*': + return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; - if (opts.fastpaths !== false && (input[0] === '.' || input[0] === '*')) { - output = parse.fastpaths(input, options); - } + case '*/*': + return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`; - if (output === void 0) { - state = picomatch.parse(input, options); - state.prefix = prefix + (state.prefix || ''); - output = state.output; - } + case '**': + return nodot + globstar(opts); - if (returnOutput === true) { - return output; - } + case '**/*': + return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`; - let source = `${prepend}(?:${output})${append}`; - if (state && state.negated === true) { - source = `^(?!${source}).*$`; - } + case '**/*.*': + return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; - let regex = picomatch.toRegex(source, options); - if (returnState === true) { - regex.state = state; - } + case '**/.*': + return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`; - return regex; -}; + default: { + let match = /^(.*?)\.(\w+)$/.exec(str); + if (!match) return; -/** - * 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 - */ + let source = create(match[1], options); + if (!source) return; -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 /$^/; + return source + DOT_LITERAL + match[2]; + } + } + }; + + let output = create(input); + if (output && opts.strictSlashes !== true) { + output += `${SLASH_LITERAL}?`; } + + return output; }; -/** - * Picomatch constants. - * @return {Object} - */ +module.exports = parse; -picomatch.constants = __webpack_require__(623); -/** - * Expose "picomatch" - */ +/***/ }), +/* 620 */ +/***/ (function(module, exports, __webpack_require__) { -module.exports = picomatch; +"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; /***/ }), @@ -73860,6813 +73764,5051 @@ module.exports = picomatch; /***/ (function(module, exports, __webpack_require__) { "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; -const utils = __webpack_require__(622); - -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); - -const isPathSeparator = code => { - return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; -}; +/***/ }), +/* 622 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * 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 - */ +"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; -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; +/***/ }), +/* 623 */ +/***/ (function(module, exports, __webpack_require__) { - let eos = () => index >= length; - let advance = () => { - prev = code; - return input.charCodeAt(++index); - }; +"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); +} - while (index < length) { - code = advance(); - let next; - if (code === CHAR_BACKWARD_SLASH) { - backslashes = true; - next = advance(); +/***/ }), +/* 624 */ +/***/ (function(module, exports, __webpack_require__) { - if (next === CHAR_LEFT_CURLY_BRACE) { - braceEscaped = true; - } - continue; - } +"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 (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) { - braces++; - while (!eos() && (next = advance())) { - if (next === CHAR_BACKWARD_SLASH) { - backslashes = true; - next = advance(); - continue; - } +/***/ }), +/* 625 */ +/***/ (function(module, exports, __webpack_require__) { - if (next === CHAR_LEFT_CURLY_BRACE) { - braces++; - continue; - } +"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 (!braceEscaped && next === CHAR_DOT && (next = advance()) === CHAR_DOT) { - isGlob = true; - break; - } - if (!braceEscaped && next === CHAR_COMMA) { - isGlob = true; - break; - } +/***/ }), +/* 626 */ +/***/ (function(module, exports, __webpack_require__) { - if (next === CHAR_RIGHT_CURLY_BRACE) { - braces--; - if (braces === 0) { - braceEscaped = false; - break; - } - } - } - } +"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 (code === CHAR_FORWARD_SLASH) { - if (prev === CHAR_DOT && index === (start + 1)) { - start += 2; - continue; - } - lastIndex = index + 1; - continue; - } +/***/ }), +/* 627 */ +/***/ (function(module, exports, __webpack_require__) { - if (code === CHAR_ASTERISK) { - isGlob = true; - break; - } +"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; - 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; - } +/***/ }), +/* 628 */ +/***/ (function(module, exports, __webpack_require__) { - if (next === CHAR_RIGHT_SQUARE_BRACKET) { - isGlob = true; - break; - } - } - } +"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); +} - let isExtglobChar = code === CHAR_PLUS - || code === CHAR_AT - || code === CHAR_EXCLAMATION_MARK; - if (isExtglobChar && input.charCodeAt(index + 1) === CHAR_LEFT_PARENTHESES) { - isGlob = true; - break; - } +/***/ }), +/* 629 */ +/***/ (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 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); +} - 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; - } - } - } +/***/ }), +/* 630 */ +/***/ (function(module, exports, __webpack_require__) { - if (isGlob) { - break; - } - } +"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; - let prefix = ''; - let orig = input; - let base = input; - let glob = ''; - if (start > 0) { - prefix = input.slice(0, start); - input = input.slice(start); - lastIndex -= start; - } +/***/ }), +/* 631 */ +/***/ (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; +"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); +} + + +/***/ }), +/* 632 */ +/***/ (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) { + +module.exports = runParallel + +function runParallel (tasks, cb) { + var results, pending, keys + var isSync = true + + if (Array.isArray(tasks)) { + results = [] + pending = tasks.length } else { - base = input; + keys = Object.keys(tasks) + results = {} + pending = keys.length } - if (base && base !== '' && base !== '/' && base !== input) { - if (isPathSeparator(base.charCodeAt(base.length - 1))) { - base = base.slice(0, -1); + function done (err) { + function end () { + if (cb) cb(err, results) + cb = null } + if (isSync) process.nextTick(end) + else end() } - if (opts.unescape === true) { - if (glob) glob = utils.removeBackslashes(glob); - - if (base && backslashes === true) { - base = utils.removeBackslashes(base); + function each (i, err, result) { + results[i] = result + if (--pending === 0 || err) { + done(err) } } - return { prefix, input: orig, base, glob, negated, isGlob }; -}; + 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 +} /***/ }), -/* 622 */ +/* 634 */ /***/ (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); -const path = __webpack_require__(16); -const win32 = process.platform === 'win32'; -const { - REGEX_SPECIAL_CHARS, - REGEX_SPECIAL_CHARS_GLOBAL, - REGEX_REMOVE_BACKSLASH -} = __webpack_require__(623); +/***/ }), +/* 635 */ +/***/ (function(module, exports, __webpack_require__) { -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, '/'); +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const fs = __webpack_require__(636); +exports.fs = fs; -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; - } - return false; -}; +/***/ }), +/* 636 */ +/***/ (function(module, exports, __webpack_require__) { -exports.isWindows = options => { - if (options && typeof options.windows === 'boolean') { - return options.windows; - } - return win32 === true || path.sep === '\\'; -}; +"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; -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); -}; + +/***/ }), +/* 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; /***/ }), -/* 623 */ +/* 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; -const path = __webpack_require__(16); -const WIN_SLASH = '\\\\/'; -const WIN_NO_SLASH = `[^${WIN_SLASH}]`; +/***/ }), +/* 639 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Posix glob regex - */ +"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; -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 -}; +/***/ }), +/* 640 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Windows glob regex - */ +"use strict"; -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 - */ +var reusify = __webpack_require__(641) -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' -}; +function fastqueue (context, worker, concurrency) { + if (typeof context === 'function') { + concurrency = worker + worker = context + context = null + } -module.exports = { - MAX_LENGTH: 1024 * 64, - POSIX_REGEX_SOURCE, + var cache = reusify(Task) + var queueHead = null + var queueTail = null + var _running = 0 - // 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, + 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 + } - // Replace globs with equivalent patterns to reduce parsing time. - REPLACEMENTS: { - '***': '*', - '**/**': '**', - '**/**/**': '**' - }, + return self - // Digits - CHAR_0: 48, /* 0 */ - CHAR_9: 57, /* 9 */ + function running () { + return _running + } - // Alphabet chars. - CHAR_UPPERCASE_A: 65, /* A */ - CHAR_LOWERCASE_A: 97, /* a */ - CHAR_UPPERCASE_Z: 90, /* Z */ - CHAR_LOWERCASE_Z: 122, /* z */ + function pause () { + self.paused = true + } - CHAR_LEFT_PARENTHESES: 40, /* ( */ - CHAR_RIGHT_PARENTHESES: 41, /* ) */ + function length () { + var current = queueHead + var counter = 0 - CHAR_ASTERISK: 42, /* * */ + while (current) { + current = current.next + counter++ + } - // 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 */ + return counter + } - SEP: path.sep, + function resume () { + if (!self.paused) return + self.paused = false + for (var i = 0; i < self.concurrency; i++) { + _running++ + release() + } + } - /** - * Create EXTGLOB_CHARS - */ + function idle () { + return _running === 0 && self.length() === 0 + } - 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: ')' } - }; - }, + function push (value, done) { + var current = cache.get() - /** - * Create GLOB_CHARS - */ + current.context = context + current.release = release + current.value = value + current.callback = done || noop - globChars(win32) { - return win32 === true ? WINDOWS_CHARS : POSIX_CHARS; + 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() -/***/ }), -/* 624 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; + 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) + } + } -const utils = __webpack_require__(622); -const constants = __webpack_require__(623); + 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() + } + } -/** - * Constants - */ + function kill () { + queueHead = null + queueTail = null + self.drain = noop + } -const { - MAX_LENGTH, - POSIX_REGEX_SOURCE, - REGEX_NON_SPECIAL_CHAR, - REGEX_SPECIAL_CHARS_BACKREF, - REPLACEMENTS -} = constants; + function killAndDrain () { + queueHead = null + queueTail = null + self.drain() + self.drain = noop + } +} -/** - * Helpers - */ +function noop () {} -const expandRange = (args, options) => { - if (typeof options.expandRange === 'function') { - return options.expandRange(...args, options); - } +function Task () { + this.value = null + this.callback = noop + this.next = null + this.release = noop + this.context = null - args.sort(); - let value = `[${args.join('-')}]`; + var self = this - try { - /* eslint-disable no-new */ - new RegExp(value); - } catch (ex) { - return args.map(v => utils.escapeRegex(v)).join('..'); + 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) } +} - return value; -}; +module.exports = fastqueue -const negate = state => { - let count = 1; - while (state.peek() === '!' && (state.peek(2) !== '(' || state.peek(3) === '?')) { - state.advance(); - state.start++; - count++; - } +/***/ }), +/* 641 */ +/***/ (function(module, exports, __webpack_require__) { - if (count % 2 === 0) { - return false; - } +"use strict"; - state.negated = true; - state.start++; - return true; -}; -/** - * Create the message for a syntax error - */ +function reusify (Constructor) { + var head = new Constructor() + var tail = head -const syntaxError = (type, char) => { - return `Missing ${type}: "${char}" - use "\\\\${char}" to match literal characters`; -}; + function get () { + var current = head -/** - * Parse the given input string. - * @param {String} input - * @param {Object} options - * @return {Object} - */ + if (current.next) { + head = current.next + } else { + head = new Constructor() + tail = head + } -const parse = (input, options) => { - if (typeof input !== 'string') { - throw new TypeError('Expected a string'); + current.next = null + + return current } - input = REPLACEMENTS[input] || input; + function release (obj) { + tail.next = obj + tail = obj + } - 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}`); + return { + get: get, + release: release } +} - let bos = { type: 'bos', value: '', output: opts.prepend || '' }; - let tokens = [bos]; +module.exports = reusify - 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); +/***/ }), +/* 642 */ +/***/ (function(module, exports, __webpack_require__) { - 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; +"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; - 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; +/***/ }), +/* 643 */ +/***/ (function(module, exports, __webpack_require__) { - if (opts.capture) { - star = `(${star})`; - } +"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; - // 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 - }; +/***/ }), +/* 644 */ +/***/ (function(module, exports, __webpack_require__) { - let extglobs = []; - let stack = []; - let prev = bos; - let value; +"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; - /** - * 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 || ''; - }; +/***/ }), +/* 645 */ +/***/ (function(module, exports, __webpack_require__) { - const increment = type => { - state[type]++; - stack.push(type); - }; +"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; - 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. - */ +/***/ }), +/* 646 */ +/***/ (function(module, exports, __webpack_require__) { - 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; - } - } +"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; - 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; - } +/***/ }), +/* 647 */ +/***/ (function(module, exports, __webpack_require__) { - tok.prev = prev; - tokens.push(tok); - prev = tok; - }; +"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; - 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; +/***/ }), +/* 648 */ +/***/ (function(module, exports, __webpack_require__) { - push({ type, value, output: state.output ? '' : ONE_CHAR }); - push({ type: 'paren', extglob: true, value: advance(), output }); - increment('parens'); - extglobs.push(token); - }; +"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; - const extglobClose = token => { - let output = token.close + (opts.capture ? ')' : ''); - if (token.type === 'negate') { - let extglobStar = star; +/***/ }), +/* 649 */ +/***/ (function(module, exports, __webpack_require__) { - if (token.inner && token.inner.length > 1 && token.inner.includes('/')) { - extglobStar = globstar(opts); - } +"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; - if (extglobStar !== star || eos() || /^\)+$/.test(input.slice(state.index + 1))) { - output = token.close = ')$))' + extglobStar; - } - if (token.prev.type === 'bos' && eos()) { - state.negatedExtglob = true; - } - } +/***/ }), +/* 650 */ +/***/ (function(module, exports, __webpack_require__) { - push({ type: 'paren', extglob: true, value, output }); - decrement('parens'); - }; +"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; - 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; - } +/***/ }), +/* 651 */ +/***/ (function(module, exports, __webpack_require__) { - 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); - } +"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; - if (first === '.') { - return DOT_LITERAL.repeat(chars.length); - } - if (first === '*') { - if (esc) { - return esc + first + (rest ? star : ''); - } - return star; - } - return esc ? m : '\\' + m; - }); +/***/ }), +/* 652 */ +/***/ (function(module, exports, __webpack_require__) { - if (backslashes === true) { - if (opts.unescape === true) { - output = output.replace(/\\/g, ''); - } else { - output = output.replace(/\\+/g, m => { - return m.length % 2 === 0 ? '\\\\' : (m ? '\\' : ''); - }); - } - } +"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; - state.output = output; - return state; - } - /** - * Tokenize input until we reach end-of-string - */ +/***/ }), +/* 653 */ +/***/ (function(module, exports, __webpack_require__) { - while (!eos()) { - value = advance(); +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __webpack_require__(594); +class EntryTransformer { + constructor(_settings) { + this._settings = _settings; + } + getTransformer() { + return (entry) => this._transform(entry); + } + _transform(entry) { + let filepath = entry.path; + if (this._settings.absolute) { + filepath = utils.path.makeAbsolute(this._settings.cwd, filepath); + filepath = utils.path.unixify(filepath); + } + if (this._settings.markDirectories && entry.dirent.isDirectory()) { + filepath += '/'; + } + if (!this._settings.objectMode) { + return filepath; + } + return Object.assign({}, entry, { path: filepath }); + } +} +exports.default = EntryTransformer; - if (value === '\u0000') { - continue; - } - /** - * Escaped characters - */ +/***/ }), +/* 654 */ +/***/ (function(module, exports, __webpack_require__) { - if (value === '\\') { - let next = peek(); +"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; - if (next === '/' && opts.bash !== true) { - continue; - } - if (next === '.' || next === ';') { - continue; - } +/***/ }), +/* 655 */ +/***/ (function(module, exports, __webpack_require__) { - if (!next) { - value += '\\'; - push({ type: 'text', value }); - continue; - } +"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; - // 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 += '\\'; - } - } +/***/ }), +/* 656 */ +/***/ (function(module, exports, __webpack_require__) { - if (opts.unescape === true) { - value = advance() || ''; - } else { - value += advance() || ''; - } +"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; - if (state.brackets === 0) { - push({ type: 'text', value }); - continue; - } - } - /** - * If we're inside a regex character class, continue - * until we reach the closing bracket. - */ +/***/ }), +/* 657 */ +/***/ (function(module, exports, __webpack_require__) { - 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; +"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; - 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; - } - } - } - } +/***/ }), +/* 658 */ +/***/ (function(module, exports, __webpack_require__) { - if ((value === '[' && peek() !== ':') || (value === '-' && peek() === ']')) { - value = '\\' + value; - } +"use strict"; - if (value === ']' && (prev.value === '[' || prev.value === '[^')) { - value = '\\' + value; - } +const path = __webpack_require__(16); +const pathType = __webpack_require__(659); - if (opts.posix === true && value === '!' && prev.value === '[') { - value = '^'; - } +const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; - prev.value += value; - append({ value }); - continue; - } +const getPath = (filepath, cwd) => { + const pth = filepath[0] === '!' ? filepath.slice(1) : filepath; + return path.isAbsolute(pth) ? pth : path.join(cwd, pth); +}; - /** - * If we're inside a quoted string, continue - * until we reach the closing double quote. - */ +const addExtensions = (file, extensions) => { + if (path.extname(file)) { + return `**/${file}`; + } - if (state.quotes === 1 && value !== '"') { - value = utils.escapeRegex(value); - prev.value += value; - append({ value }); - continue; - } + return `**/${file}.${getExtensions(extensions)}`; +}; - /** - * Double quotes - */ +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 (value === '"') { - state.quotes = state.quotes === 1 ? 0 : 1; - if (opts.keepQuotes === true) { - push({ type: 'text', value }); - } - continue; - } + if (options.extensions && !Array.isArray(options.extensions)) { + throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof options.extensions}\``); + } - /** - * Parentheses - */ + if (options.files && options.extensions) { + return options.files.map(x => path.posix.join(directory, addExtensions(x, options.extensions))); + } - if (value === '(') { - push({ type: 'paren', value }); - increment('parens'); - continue; - } + if (options.files) { + return options.files.map(x => path.posix.join(directory, `**/${x}`)); + } - if (value === ')') { - if (state.parens === 0 && opts.strictBrackets === true) { - throw new SyntaxError(syntaxError('opening', '(')); - } + if (options.extensions) { + return [path.posix.join(directory, `**/*.${getExtensions(options.extensions)}`)]; + } - let extglob = extglobs[extglobs.length - 1]; - if (extglob && state.parens === extglob.parens + 1) { - extglobClose(extglobs.pop()); - continue; - } + return [path.posix.join(directory, '**')]; +}; - push({ type: 'paren', value, output: state.parens ? ')' : '\\)' }); - decrement('parens'); - continue; - } +module.exports = async (input, options) => { + options = { + cwd: process.cwd(), + ...options + }; - /** - * Brackets - */ + if (typeof options.cwd !== 'string') { + throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); + } - if (value === '[') { - if (opts.nobracket === true || !input.slice(state.index + 1).includes(']')) { - if (opts.nobracket !== true && opts.strictBrackets === true) { - throw new SyntaxError(syntaxError('closing', ']')); - } + 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; + })); - value = '\\' + value; - } else { - increment('brackets'); - } + return [].concat.apply([], globs); // eslint-disable-line prefer-spread +}; - push({ type: 'bracket', value }); - continue; - } +module.exports.sync = (input, options) => { + options = { + cwd: process.cwd(), + ...options + }; - if (value === ']') { - if (opts.nobracket === true || (prev && prev.type === 'bracket' && prev.value.length === 1)) { - push({ type: 'text', value, output: '\\' + value }); - continue; - } + if (typeof options.cwd !== 'string') { + throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof options.cwd}\``); + } - if (state.brackets === 0) { - if (opts.strictBrackets === true) { - throw new SyntaxError(syntaxError('opening', '[')); - } + const globs = [].concat(input).map(x => pathType.isDirectorySync(getPath(x, options.cwd)) ? getGlob(x, options) : x); - push({ type: 'text', value, output: '\\' + value }); - continue; - } + return [].concat.apply([], globs); // eslint-disable-line prefer-spread +}; - decrement('brackets'); - let prevValue = prev.value.slice(1); - if (prev.posix !== true && prevValue[0] === '^' && !prevValue.includes('/')) { - value = '/' + value; - } +/***/ }), +/* 659 */ +/***/ (function(module, exports, __webpack_require__) { - prev.value += value; - append({ value }); +"use strict"; - // when literal brackets are explicitly disabled - // assume we should match with a regex character class - if (opts.literalBrackets === false || utils.hasRegexChars(prevValue)) { - continue; - } +const {promisify} = __webpack_require__(29); +const fs = __webpack_require__(23); - let escaped = utils.escapeRegex(prev.value); - state.output = state.output.slice(0, -prev.value.length); +async function isType(fsStatType, statsMethodName, filePath) { + if (typeof filePath !== 'string') { + throw new TypeError(`Expected a string, got ${typeof filePath}`); + } - // 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; - } + try { + const stats = await promisify(fs[fsStatType])(filePath); + return stats[statsMethodName](); + } catch (error) { + if (error.code === 'ENOENT') { + return false; + } - // when the user specifies nothing, try to match both - prev.value = `(${capture}${escaped}|${prev.value})`; - state.output += prev.value; - continue; - } + throw error; + } +} - /** - * Braces - */ +function isTypeSync(fsStatType, statsMethodName, filePath) { + if (typeof filePath !== 'string') { + throw new TypeError(`Expected a string, got ${typeof filePath}`); + } - if (value === '{' && opts.nobrace !== true) { - push({ type: 'brace', value, output: '(' }); - increment('braces'); - continue; - } + try { + return fs[fsStatType](filePath)[statsMethodName](); + } catch (error) { + if (error.code === 'ENOENT') { + return false; + } - if (value === '}') { - if (opts.nobrace === true || state.braces === 0) { - push({ type: 'text', value, output: '\\' + value }); - continue; - } + throw error; + } +} - let output = ')'; +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'); - 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); - } - } +/***/ }), +/* 660 */ +/***/ (function(module, exports, __webpack_require__) { - output = expandRange(range, opts); - state.backtrack = true; - } +"use strict"; - push({ type: 'brace', value, output }); - decrement('braces'); - continue; - } +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); - /** - * Pipes - */ +const DEFAULT_IGNORE = [ + '**/node_modules/**', + '**/flow-typed/**', + '**/coverage/**', + '**/.git' +]; - if (value === '|') { - if (extglobs.length > 0) { - extglobs[extglobs.length - 1].conditions++; - } - push({ type: 'text', value }); - continue; - } +const readFileP = promisify(fs.readFile); - /** - * Commas - */ +const mapGitIgnorePatternTo = base => ignore => { + if (ignore.startsWith('!')) { + return '!' + path.posix.join(base, ignore.slice(1)); + } - if (value === ',') { - let output = value; + return path.posix.join(base, ignore); +}; - if (state.braces > 0 && stack[stack.length - 1] === 'braces') { - output = '|'; - } +const parseGitIgnore = (content, options) => { + const base = slash(path.relative(options.cwd, path.dirname(options.fileName))); - push({ type: 'comma', value, output }); - continue; - } + return content + .split(/\r?\n/) + .filter(Boolean) + .filter(line => !line.startsWith('#')) + .map(mapGitIgnorePatternTo(base)); +}; - /** - * Slashes - */ +const reduceIgnore = files => { + return files.reduce((ignores, file) => { + ignores.add(parseGitIgnore(file.content, { + cwd: file.cwd, + fileName: file.filePath + })); + return ignores; + }, gitIgnore()); +}; - 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; - } +const ensureAbsolutePathForCwd = (cwd, p) => { + if (path.isAbsolute(p)) { + if (p.startsWith(cwd)) { + return p; + } - push({ type: 'slash', value, output: SLASH_LITERAL }); - continue; - } + throw new Error(`Path ${p} is not in cwd ${cwd}`); + } - /** - * Dots - */ + return path.join(cwd, p); +}; - 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; - } +const getIsIgnoredPredecate = (ignores, cwd) => { + return p => ignores.ignores(slash(path.relative(cwd, ensureAbsolutePathForCwd(cwd, p)))); +}; - push({ type: 'dot', value, output: DOT_LITERAL }); - continue; - } +const getFile = async (file, cwd) => { + const filePath = path.join(cwd, file); + const content = await readFileP(filePath, 'utf8'); - /** - * Question marks - */ + return { + cwd, + filePath, + content + }; +}; - if (value === '?') { - if (prev && prev.type === 'paren') { - let next = peek(); - let output = value; +const getFileSync = (file, cwd) => { + const filePath = path.join(cwd, file); + const content = fs.readFileSync(filePath, 'utf8'); - if (next === '<' && !utils.supportsLookbehinds()) { - throw new Error('Node.js v10 or higher is required for regex lookbehinds'); - } + return { + cwd, + filePath, + content + }; +}; - if (prev.value === '(' && !/[!=<:]/.test(next) || (next === '<' && !/[!=]/.test(peek(2)))) { - output = '\\' + value; - } +const normalizeOptions = ({ + ignore = [], + cwd = process.cwd() +} = {}) => { + return {ignore, cwd}; +}; - push({ type: 'text', value, output }); - continue; - } +module.exports = async options => { + options = normalizeOptions(options); - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('qmark', value); - continue; - } + const paths = await fastGlob('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }); - if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) { - push({ type: 'qmark', value, output: QMARK_NO_DOT }); - continue; - } + const files = await Promise.all(paths.map(file => getFile(file, options.cwd))); + const ignores = reduceIgnore(files); - push({ type: 'qmark', value, output: QMARK }); - continue; - } + return getIsIgnoredPredecate(ignores, options.cwd); +}; - /** - * Exclamation - */ +module.exports.sync = options => { + options = normalizeOptions(options); - if (value === '!') { - if (opts.noextglob !== true && peek() === '(') { - if (peek(2) !== '?' || !/[!=<:]/.test(peek(3))) { - extglobOpen('negate', value); - continue; - } - } + const paths = fastGlob.sync('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }); - if (opts.nonegate !== true && state.index === 0) { - negate(state); - continue; - } - } + const files = paths.map(file => getFileSync(file, options.cwd)); + const ignores = reduceIgnore(files); - /** - * Plus - */ + return getIsIgnoredPredecate(ignores, options.cwd); +}; - 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; - } +/***/ }), +/* 661 */ +/***/ (function(module, exports) { - // use regex behavior inside parens - if (state.parens > 0 && opts.regex !== false) { - push({ type: 'plus', value }); - continue; - } +// A simple implementation of make-array +function makeArray (subject) { + return Array.isArray(subject) + ? subject + : [subject] +} - push({ type: 'plus', value: PLUS_LITERAL }); - continue; - } +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 = /^\.*\/|^\.+$/ - /** - * Plain text - */ +const SLASH = '/' +const KEY_IGNORE = typeof Symbol !== 'undefined' + ? Symbol.for('node-ignore') + /* istanbul ignore next */ + : 'node-ignore' - if (value === '@') { - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - push({ type: 'at', value, output: '' }); - continue; - } +const define = (object, key, value) => + Object.defineProperty(object, key, {value}) - push({ type: 'text', value }); - continue; - } +const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g - /** - * Plain text - */ +// 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 (value !== '*') { - if (value === '$' || value === '^') { - value = '\\' + value; - } +// > 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` - let match = REGEX_NON_SPECIAL_CHAR.exec(input.slice(state.index + 1)); - if (match) { - value += match[0]; - state.index += match[0].length; - } +// '`foo/`' should not continue with the '`..`' +const DEFAULT_REPLACER_PREFIX = [ - push({ type: 'text', value }); - continue; - } + // > Trailing spaces are ignored unless they are quoted with backslash ("\") + [ + // (a\ ) -> (a ) + // (a ) -> (a) + // (a \ ) -> (a ) + /\\?\s+$/, + match => match.indexOf('\\') === 0 + ? ' ' + : '' + ], - /** - * Stars - */ + // replace (\ ) with ' ' + [ + /\\\s/g, + () => ' ' + ], - 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; - } + // Escape metacharacters + // which is written down by users but means special for regular expressions. - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('star', value); - continue; - } + // > 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 (prev.type === 'star') { - if (opts.noglobstar === true) { - state.consumed += value; - continue; - } + [ + // > [abc] matches any character inside the brackets + // > (in this case a, b, or c); + /\[([^\]/]*)($|\])/g, + (match, p1, p2) => p2 === ']' + ? `[${sanitizeRange(p1)}]` + : `\\${match}` + ], - 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'); + [ + // > a question mark (?) matches a single character + /(?!\\)\?/g, + () => '[^/]' + ], - if (opts.bash === true && (!isStart || (!eos() && peek() !== '/'))) { - push({ type: 'star', value, output: '' }); - continue; - } + // leading slash + [ - 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; - } + // > 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 + /^\//, + () => '^' + ], - // 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; - } + // replace special metacharacter slash after the leading slash + [ + /\//g, + () => '\\/' + ], - if (prior.type === 'bos' && eos()) { - prev.type = 'globstar'; - prev.value += value; - prev.output = globstar(opts); - state.output = prev.output; - state.consumed += value; - continue; - } + [ + // > 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 '\\*' + /^\^*\\\*\\\*\\\//, - 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; + // '**/foo' <-> 'foo' + () => '^(?:.*\\/)?' + ] +] - prev.type = 'globstar'; - prev.output = globstar(opts) + '|$)'; - prev.value += value; +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 + ? '(?:^|\\/)' - state.output += prior.output + prev.output; - state.consumed += value; - continue; - } + // > Otherwise, Git treats the pattern as a shell glob suitable for + // > consumption by fnmatch(3) + : '^' + } + ], - let next = peek(); - if (prior.type === 'slash' && prior.prev.type !== 'bos' && next === '/') { - let end = peek(2) !== void 0 ? '|$' : ''; + // two globstars + [ + // Use lookahead assertions so that we could match more than one `'/**'` + /\\\/\\\*\\\*(?=\\\/|$)/g, - state.output = state.output.slice(0, -(prior.output + prev.output).length); - prior.output = '(?:' + prior.output; + // Zero, one or several directories + // should not use '*', or it will be replaced by the next replacer - prev.type = 'globstar'; - prev.output = `${globstar(opts)}${SLASH_LITERAL}|${SLASH_LITERAL}${end})`; - prev.value += value; + // Check if it is not the last `'/**'` + (_, index, str) => index + 6 < str.length - state.output += prior.output + prev.output; - state.consumed += value + advance(); + // 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. + // '/**/' + ? '(?:\\/[^\\/]+)*' - push({ type: 'slash', value, output: '' }); - continue; - } + // case: /** + // > A trailing `"/**"` matches everything inside. - 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; - } + // #21: everything inside but it should not include the current folder + : '\\/.+' + ], - // remove single star from output - state.output = state.output.slice(0, -prev.output.length); + // intermediate wildcards + [ + // Never replace escaped '*' + // ignore rule '\*' will match the path '*' - // reset previous token to globstar - prev.type = 'globstar'; - prev.output = globstar(opts); - prev.value += value; + // 'abc.*/' -> go + // 'abc.*' -> skip this rule + /(^|[^\\]+)\\\*(?=.+)/g, - // reset output with globstar - state.output += prev.output; - state.consumed += value; - continue; - } + // '*.js' matches '.js' + // '*.js' doesn't match 'abc' + (_, p1) => `${p1}[^\\/]*` + ], - let token = { type: 'star', value, output: star }; + // trailing wildcard + [ + /(\^|\\\/)?\\\*$/, + (_, p1) => { + const prefix = p1 + // '\^': + // '/*' does not match '' + // '/*' does not match everything - if (opts.bash === true) { - token.output = '.*?'; - if (prev.type === 'bos' || prev.type === 'slash') { - token.output = nodot + token.output; - } - push(token); - continue; - } + // '\\\/': + // 'abc/*' does not match 'abc/' + ? `${p1}[^/]+` - if (prev && (prev.type === 'bracket' || prev.type === 'paren') && opts.regex === true) { - token.output = value; - push(token); - continue; + // 'a*' matches 'a' + // 'a*' matches 'aa' + : '[^/]*' + + return `${prefix}(?=$|\\/$)` } + ], - 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; + [ + // unescape + /\\\\\\/g, + () => '\\' + ] +] - } else if (opts.dot === true) { - state.output += NO_DOTS_SLASH; - prev.output += NO_DOTS_SLASH; +const POSITIVE_REPLACERS = [ + ...DEFAULT_REPLACER_PREFIX, - } else { - state.output += nodot; - prev.output += nodot; - } + // 'f' + // matches + // - /f(end) + // - /f/ + // - (start)f(end) + // - (start)f/ + // doesn't match + // - oof + // - foo + // pseudo: + // -> (^|/)f(/|$) - if (peek() !== '*') { - state.output += ONE_CHAR; - prev.output += ONE_CHAR; - } - } + // ending + [ + // 'js' will not match 'js.' + // 'ab' will not match 'abc' + /(?:[^*/])$/, - push(token); - } + // 'js*' will not match 'a.js' + // 'js/' will not match 'a.js' + // 'js' will match 'a.js' and 'a.js/' + match => `${match}(?=$|\\/)` + ], - while (state.brackets > 0) { - if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ']')); - state.output = utils.escapeLast(state.output, '['); - decrement('brackets'); - } + ...DEFAULT_REPLACER_SUFFIX +] - while (state.parens > 0) { - if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', ')')); - state.output = utils.escapeLast(state.output, '('); - decrement('parens'); - } +const NEGATIVE_REPLACERS = [ + ...DEFAULT_REPLACER_PREFIX, - while (state.braces > 0) { - if (opts.strictBrackets === true) throw new SyntaxError(syntaxError('closing', '}')); - state.output = utils.escapeLast(state.output, '{'); - decrement('braces'); - } + // #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 (opts.strictSlashes !== true && (prev.type === 'star' || prev.type === 'bracket')) { - push({ type: 'maybe_slash', value: '', output: `${SLASH_LITERAL}?` }); - } + // eg: + // ['node_modules/*', '!node_modules'] + // should ignore `node_modules/a.js` + [ + /(?:[^*])$/, + match => `${match}(?=$|\\/$)` + ], - // rebuild the output if we had to backtrack at any point - if (state.backtrack === true) { - state.output = ''; + ...DEFAULT_REPLACER_SUFFIX +] - for (let token of state.tokens) { - state.output += token.output != null ? token.output : token.value; +// A simple cache, because an ignore rule only has only one certain meaning +const regexCache = Object.create(null) - if (token.suffix) { - state.output += token.suffix; - } - } +// @param {pattern} +const makeRegex = (pattern, negative, ignorecase) => { + const r = regexCache[pattern] + if (r) { + return r } - return state; -}; + const replacers = negative + ? NEGATIVE_REPLACERS + : POSITIVE_REPLACERS -/** - * 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. - */ + const source = replacers.reduce( + (prev, current) => prev.replace(current[0], current[1].bind(pattern)), + pattern + ) -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}`); + 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 } +} - input = REPLACEMENTS[input] || input; - let win32 = utils.isWindows(options); +const createRule = (pattern, ignorecase) => { + const origin = pattern + let negative = false - // 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); + // > An optional prefix "!" which negates the pattern; + if (pattern.indexOf('!') === 0) { + negative = true + pattern = pattern.substr(1) + } - 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; + 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, '#') - if (opts.capture) { - star = `(${star})`; + const regex = makeRegex(pattern, negative, ignorecase) + + return new IgnoreRule( + origin, + pattern, + negative, + regex + ) +} + +const throwError = (message, Ctor) => { + throw new Ctor(message) +} + +const checkPath = (path, originalPath, doThrow) => { + if (!isString(path)) { + return doThrow( + `path must be a string, but got \`${originalPath}\``, + TypeError + ) } - const globstar = (opts) => { - return `(${capture}(?:(?!${START_ANCHOR}${opts.dot ? DOTS_SLASH : DOT_LITERAL}).)*?)`; - }; + // We don't know if we should ignore '', so throw + if (!path) { + return doThrow(`path must not be empty`, TypeError) + } - const create = str => { - switch (str) { - case '*': - return `${nodot}${ONE_CHAR}${star}`; + // 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 + ) + } - case '.*': - return `${DOT_LITERAL}${ONE_CHAR}${star}`; + return true +} - case '*.*': - return `${nodot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; +const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path) - case '*/*': - return `${nodot}${star}${SLASH_LITERAL}${ONE_CHAR}${slashDot}${star}`; +checkPath.isNotRelative = isNotRelative +checkPath.convert = p => p - case '**': - return nodot + globstar(opts); +class Ignore { + constructor ({ + ignorecase = true + } = {}) { + this._rules = [] + this._ignorecase = ignorecase + define(this, KEY_IGNORE, true) + this._initCache() + } - case '**/*': - return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${ONE_CHAR}${star}`; + _initCache () { + this._ignoreCache = Object.create(null) + this._testCache = Object.create(null) + } - case '**/*.*': - return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${slashDot}${star}${DOT_LITERAL}${ONE_CHAR}${star}`; + _addPattern (pattern) { + // #32 + if (pattern && pattern[KEY_IGNORE]) { + this._rules = this._rules.concat(pattern._rules) + this._added = true + return + } - case '**/.*': - return `(?:${nodot}${globstar(opts)}${SLASH_LITERAL})?${DOT_LITERAL}${ONE_CHAR}${star}`; + if (checkPattern(pattern)) { + const rule = createRule(pattern, this._ignorecase) + this._added = true + this._rules.push(rule) + } + } - default: { - let match = /^(.*?)\.(\w+)$/.exec(str); - if (!match) return; + // @param {Array | string | Ignore} pattern + add (pattern) { + this._added = false - let source = create(match[1], options); - if (!source) return; + makeArray( + isString(pattern) + ? splitPattern(pattern) + : pattern + ).forEach(this._addPattern, this) - return source + DOT_LITERAL + match[2]; + // Some rules have just added to the ignore, + // making the behavior changed. + if (this._added) { + this._initCache() + } + + return this + } + + // legacy + addPattern (pattern) { + return this.add(pattern) + } + + // | ignored : unignored + // negative | 0:0 | 0:1 | 1:0 | 1:1 + // -------- | ------- | ------- | ------- | -------- + // 0 | TEST | TEST | SKIP | X + // 1 | TESTIF | SKIP | TEST | X + + // - SKIP: always skip + // - TEST: always test + // - TESTIF: only test if checkUnignored + // - X: that never happen + + // @param {boolean} whether should check if the path is unignored, + // setting `checkUnignored` to `false` could reduce additional + // path matching. + + // @returns {TestResult} true if a file is ignored + _testOne (path, checkUnignored) { + let ignored = false + let unignored = false + + this._rules.forEach(rule => { + const {negative} = rule + if ( + unignored === negative && ignored !== unignored + || negative && !ignored && !unignored && !checkUnignored + ) { + return + } + + const matched = rule.regex.test(path) + + if (matched) { + ignored = !negative + unignored = negative } + }) + + return { + ignored, + unignored } - }; + } - let output = create(input); - if (output && opts.strictSlashes !== true) { - output += `${SLASH_LITERAL}?`; + // @returns {TestResult} + _test (originalPath, cache, checkUnignored, slices) { + const path = originalPath + // Supports nullable path + && checkPath.convert(originalPath) + + checkPath(path, originalPath, throwError) + + return this._t(path, cache, checkUnignored, slices) } - return output; -}; + _t (path, cache, checkUnignored, slices) { + if (path in cache) { + return cache[path] + } -module.exports = parse; + if (!slices) { + // path/to/a.js + // ['path', 'to', 'a.js'] + slices = path.split(SLASH) + } + slices.pop() -/***/ }), -/* 625 */ -/***/ (function(module, exports, __webpack_require__) { + // If the path has no parent directory, just test it + if (!slices.length) { + return cache[path] = this._testOne(path, checkUnignored) + } -"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; + const parent = this._t( + slices.join(SLASH) + SLASH, + cache, + checkUnignored, + slices + ) + // 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) + } -/***/ }), -/* 626 */ -/***/ (function(module, exports, __webpack_require__) { + ignores (path) { + return this._test(path, this._ignoreCache, false).ignored + } -"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; + createFilter () { + return path => !this.ignores(path) + } + filter (paths) { + return makeArray(paths).filter(this.createFilter()) + } -/***/ }), -/* 627 */ -/***/ (function(module, exports, __webpack_require__) { + // @returns {TestResult} + test (path) { + return this._test(path, this._testCache, true) + } +} -"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; +const factory = options => new Ignore(options) +const returnFalse = () => false -/***/ }), -/* 628 */ -/***/ (function(module, exports, __webpack_require__) { +const isPathValid = path => + checkPath(path && checkPath.convert(path), path, returnFalse) -"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); -} +factory.isPathValid = isPathValid +// Fixes typescript +factory.default = factory -/***/ }), -/* 629 */ -/***/ (function(module, exports, __webpack_require__) { +module.exports = factory -"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); -} +// 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, '/') + + checkPath.convert = makePosix + + // '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) +} /***/ }), -/* 630 */ +/* 662 */ /***/ (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; + +module.exports = path => { + const isExtendedLengthPath = /^\\\\\?\\/.test(path); + const hasNonAscii = /[^\u0000-\u0080]+/.test(path); // eslint-disable-line no-control-regex + + if (isExtendedLengthPath || hasNonAscii) { + return path; + } + + return path.replace(/\\/g, '/'); +}; /***/ }), -/* 631 */ +/* 663 */ /***/ (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; +const {Transform} = __webpack_require__(27); -/***/ }), -/* 633 */ -/***/ (function(module, exports, __webpack_require__) { +class ObjectTransform extends Transform { + constructor() { + super({ + objectMode: true + }); + } +} -"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); -} +class FilterStream extends ObjectTransform { + constructor(filter) { + super(); + this._filter = filter; + } + _transform(data, encoding, callback) { + if (this._filter(data)) { + this.push(data); + } -/***/ }), -/* 634 */ -/***/ (function(module, exports, __webpack_require__) { + callback(); + } +} -"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); -} +class UniqueStream extends ObjectTransform { + constructor() { + super(); + this._pushed = new Set(); + } + _transform(data, encoding, callback) { + if (!this._pushed.has(data)) { + this.push(data); + this._pushed.add(data); + } -/***/ }), -/* 635 */ -/***/ (function(module, exports, __webpack_require__) { + callback(); + } +} -"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; +module.exports = { + FilterStream, + UniqueStream +}; /***/ }), -/* 636 */ +/* 664 */ /***/ (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); -} - +var fs = __webpack_require__(23) +var polyfills = __webpack_require__(665) +var legacy = __webpack_require__(666) +var clone = __webpack_require__(667) -/***/ }), -/* 637 */ -/***/ (function(module, exports, __webpack_require__) { +var util = __webpack_require__(29) -"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); -} +/* istanbul ignore next - node 0.x polyfill */ +var gracefulQueue +var previousSymbol +/* 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' +} -/***/ }), -/* 638 */ -/***/ (function(module, exports) { +function noop () {} -module.exports = runParallel +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) + } -function runParallel (tasks, cb) { - var results, pending, keys - var isSync = true +// 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 + } + }) - if (Array.isArray(tasks)) { - results = [] - pending = tasks.length - } else { - keys = Object.keys(tasks) - results = {} - pending = keys.length - } + // 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() + } - function done (err) { - function end () { - if (cb) cb(err, results) - cb = null + if (typeof cb === 'function') + cb.apply(this, arguments) + }) } - if (isSync) process.nextTick(end) - else end() - } - function each (i, err, result) { - results[i] = result - if (--pending === 0 || err) { - done(err) + Object.defineProperty(close, previousSymbol, { + value: fs$close + }) + return close + })(fs.close) + + fs.closeSync = (function (fs$closeSync) { + function closeSync (fd) { + // This function uses the graceful-fs shared queue + fs$closeSync.apply(fs, arguments) + retry() } - } - if (!pending) { - // empty - done(null) - } else if (keys) { - // object - keys.forEach(function (key) { - tasks[key](function (err, result) { each(key, err, result) }) + Object.defineProperty(closeSync, previousSymbol, { + value: fs$closeSync }) - } else { - // array - tasks.forEach(function (task, i) { - task(function (err, result) { each(i, err, result) }) + return closeSync + })(fs.closeSync) + + if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { + process.on('exit', function() { + debug(global[gracefulQueue]) + __webpack_require__(30).equal(global[gracefulQueue].length, 0) }) } - - isSync = false } +module.exports = patch(clone(fs)) +if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { + module.exports = patch(fs) + fs.__patched = true; +} -/***/ }), -/* 639 */ -/***/ (function(module, exports, __webpack_require__) { +function patch (fs) { + // Everything that references the open() function needs to be in here + polyfills(fs) + fs.gracefulify = patch -"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); + 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) -/***/ }), -/* 640 */ -/***/ (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"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(641); -exports.fs = fs; + var fs$writeFile = fs.writeFile + fs.writeFile = writeFile + function writeFile (path, data, options, cb) { + if (typeof options === 'function') + cb = options, options = null + return go$writeFile(path, data, options, cb) -/***/ }), -/* 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; - + 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() + } + }) + } + } -/***/ }), -/* 644 */ -/***/ (function(module, exports, __webpack_require__) { + 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 -"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; + return go$appendFile(path, data, options, cb) + 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() + } + }) + } + } -/***/ }), -/* 645 */ -/***/ (function(module, exports, __webpack_require__) { + 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) -"use strict"; + return go$readdir(args) + function go$readdir$cb (err, files) { + if (files && files.sort) + files.sort() -var reusify = __webpack_require__(646) + if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) + enqueue([go$readdir, [args]]) -function fastqueue (context, worker, concurrency) { - if (typeof context === 'function') { - concurrency = worker - worker = context - context = null + else { + if (typeof cb === 'function') + cb.apply(this, arguments) + retry() + } + } } - 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 + function go$readdir (args) { + return fs$readdir.apply(fs, args) } - return self - - function running () { - return _running + if (process.version.substr(0, 4) === 'v0.8') { + var legStreams = legacy(fs) + ReadStream = legStreams.ReadStream + WriteStream = legStreams.WriteStream } - function pause () { - self.paused = true + var fs$ReadStream = fs.ReadStream + if (fs$ReadStream) { + ReadStream.prototype = Object.create(fs$ReadStream.prototype) + ReadStream.prototype.open = ReadStream$open } - function length () { - var current = queueHead - var counter = 0 - - while (current) { - current = current.next - counter++ - } - - return counter + var fs$WriteStream = fs.WriteStream + if (fs$WriteStream) { + WriteStream.prototype = Object.create(fs$WriteStream.prototype) + WriteStream.prototype.open = WriteStream$open } - function resume () { - if (!self.paused) return - self.paused = false - for (var i = 0; i < self.concurrency; i++) { - _running++ - release() - } - } + 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 + }) - function idle () { - return _running === 0 && self.length() === 0 - } + // 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 + }) - function push (value, done) { - var current = cache.get() + function ReadStream (path, options) { + if (this instanceof ReadStream) + return fs$ReadStream.apply(this, arguments), this + else + return ReadStream.apply(Object.create(ReadStream.prototype), arguments) + } - current.context = context - current.release = release - current.value = value - current.callback = done || noop + function ReadStream$open () { + var that = this + open(that.path, that.flags, that.mode, function (err, fd) { + if (err) { + if (that.autoClose) + that.destroy() - if (_running === self.concurrency || self.paused) { - if (queueTail) { - queueTail.next = current - queueTail = current + that.emit('error', err) } else { - queueHead = current - queueTail = current - self.saturated() + that.fd = fd + that.emit('open', fd) + that.read() } - } 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 WriteStream (path, options) { + if (this instanceof WriteStream) + return fs$WriteStream.apply(this, arguments), this + else + return WriteStream.apply(Object.create(WriteStream.prototype), arguments) } - 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() - } + 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 { - _running-- + that.fd = fd + that.emit('open', fd) } - } else if (--_running === 0) { - self.drain() - } + }) } - function kill () { - queueHead = null - queueTail = null - self.drain = noop + function createReadStream (path, options) { + return new fs.ReadStream(path, options) } - function killAndDrain () { - queueHead = null - queueTail = null - self.drain() - self.drain = noop + function createWriteStream (path, options) { + return new fs.WriteStream(path, options) } -} - -function noop () {} -function Task () { - this.value = null - this.callback = noop - this.next = null - this.release = noop - this.context = null + var fs$open = fs.open + fs.open = open + function open (path, flags, mode, cb) { + if (typeof mode === 'function') + cb = mode, mode = null - var self = this + return go$open(path, flags, mode, cb) - 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) + 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() + } + }) + } } + + return fs } -module.exports = fastqueue +function enqueue (elem) { + debug('ENQUEUE', elem[0].name, elem[1]) + global[gracefulQueue].push(elem) +} + +function retry () { + var elem = global[gracefulQueue].shift() + if (elem) { + debug('RETRY', elem[0].name, elem[1]) + elem[0].apply(null, elem[1]) + } +} /***/ }), -/* 646 */ +/* 665 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +var constants = __webpack_require__(25) +var origCwd = process.cwd +var cwd = null -function reusify (Constructor) { - var head = new Constructor() - var tail = head +var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform - function get () { - var current = head +process.cwd = function() { + if (!cwd) + cwd = origCwd.call(process) + return cwd +} +try { + process.cwd() +} catch (er) {} - if (current.next) { - head = current.next - } else { - head = new Constructor() - tail = head - } +var chdir = process.chdir +process.chdir = function(d) { + cwd = null + chdir.call(process, d) +} - current.next = null +module.exports = patch - return current - } +function patch (fs) { + // (re-)implement some things that are known busted or missing. - function release (obj) { - tail.next = obj - tail = obj + // 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) } - return { - get: get, - release: release + // lutimes implementation, or no-op + if (!fs.lutimes) { + patchLutimes(fs) } -} -module.exports = reusify + // 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. + fs.chown = chownFix(fs.chown) + fs.fchown = chownFix(fs.fchown) + fs.lchown = chownFix(fs.lchown) -/***/ }), -/* 647 */ -/***/ (function(module, exports, __webpack_require__) { + fs.chmod = chmodFix(fs.chmod) + fs.fchmod = chmodFix(fs.fchmod) + fs.lchmod = chmodFix(fs.lchmod) -"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 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; - } - getTransformer() { - return (entry) => this._transform(entry); - } - _transform(entry) { - let filepath = entry.path; - if (this._settings.absolute) { - filepath = utils.path.makeAbsolute(this._settings.cwd, filepath); - filepath = utils.path.unixify(filepath); - } - if (this._settings.markDirectories && entry.dirent.isDirectory()) { - filepath += '/'; - } - if (!this._settings.objectMode) { - return filepath; - } - return Object.assign({}, entry, { path: filepath }); - } -} -exports.default = EntryTransformer; - - -/***/ }), -/* 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"; - -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); -}; - - -/***/ }), -/* 666 */ -/***/ (function(module, exports) { - -// 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, '#') - - const regex = makeRegex(pattern, negative, ignorecase) - - return new IgnoreRule( - origin, - pattern, - negative, - regex - ) -} - -const throwError = (message, Ctor) => { - throw new Ctor(message) -} - -const checkPath = (path, originalPath, doThrow) => { - if (!isString(path)) { - return doThrow( - `path must be a string, but got \`${originalPath}\``, - TypeError - ) - } - - // 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 - ) - } - - return true -} - -const isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path) - -checkPath.isNotRelative = isNotRelative -checkPath.convert = p => p - -class Ignore { - constructor ({ - ignorecase = true - } = {}) { - this._rules = [] - this._ignorecase = ignorecase - define(this, KEY_IGNORE, true) - this._initCache() - } - - _initCache () { - this._ignoreCache = Object.create(null) - this._testCache = Object.create(null) - } - - _addPattern (pattern) { - // #32 - if (pattern && pattern[KEY_IGNORE]) { - this._rules = this._rules.concat(pattern._rules) - this._added = true - return - } - - if (checkPattern(pattern)) { - const rule = createRule(pattern, this._ignorecase) - this._added = true - this._rules.push(rule) - } - } - - // @param {Array | string | Ignore} pattern - add (pattern) { - this._added = false - - makeArray( - isString(pattern) - ? splitPattern(pattern) - : pattern - ).forEach(this._addPattern, this) - - // Some rules have just added to the ignore, - // making the behavior changed. - if (this._added) { - this._initCache() - } - - return this - } - - // legacy - addPattern (pattern) { - return this.add(pattern) - } - - // | ignored : unignored - // negative | 0:0 | 0:1 | 1:0 | 1:1 - // -------- | ------- | ------- | ------- | -------- - // 0 | TEST | TEST | SKIP | X - // 1 | TESTIF | SKIP | TEST | X - - // - SKIP: always skip - // - TEST: always test - // - TESTIF: only test if checkUnignored - // - X: that never happen - - // @param {boolean} whether should check if the path is unignored, - // setting `checkUnignored` to `false` could reduce additional - // path matching. - - // @returns {TestResult} true if a file is ignored - _testOne (path, checkUnignored) { - let ignored = false - let unignored = false - - this._rules.forEach(rule => { - const {negative} = rule - if ( - unignored === negative && ignored !== unignored - || negative && !ignored && !unignored && !checkUnignored - ) { - return - } - - const matched = rule.regex.test(path) - - if (matched) { - ignored = !negative - unignored = negative - } - }) - - return { - ignored, - unignored - } - } - - // @returns {TestResult} - _test (originalPath, cache, checkUnignored, slices) { - const path = originalPath - // Supports nullable path - && checkPath.convert(originalPath) - - checkPath(path, originalPath, throwError) - - return this._t(path, cache, checkUnignored, slices) - } - - _t (path, cache, checkUnignored, slices) { - if (path in cache) { - return cache[path] - } - - if (!slices) { - // path/to/a.js - // ['path', 'to', 'a.js'] - slices = path.split(SLASH) - } - - slices.pop() - - // If the path has no parent directory, just test it - if (!slices.length) { - return cache[path] = this._testOne(path, checkUnignored) - } - - const parent = this._t( - slices.join(SLASH) + SLASH, - cache, - checkUnignored, - slices - ) - - // 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) - } - - ignores (path) { - return this._test(path, this._ignoreCache, false).ignored - } - - 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) - } -} - -const factory = options => new Ignore(options) - -const returnFalse = () => false - -const isPathValid = path => - checkPath(path && checkPath.convert(path), path, returnFalse) - -factory.isPathValid = isPathValid - -// Fixes typescript -factory.default = factory - -module.exports = factory - -// 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, '/') - - checkPath.convert = makePosix - - // '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) -} - - -/***/ }), -/* 667 */ -/***/ (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 - - if (isExtendedLengthPath || hasNonAscii) { - return path; - } - - return path.replace(/\\/g, '/'); -}; - - -/***/ }), -/* 668 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const {Transform} = __webpack_require__(27); - -class ObjectTransform extends Transform { - constructor() { - super({ - objectMode: true - }); - } -} - -class FilterStream extends ObjectTransform { - constructor(filter) { - super(); - this._filter = filter; - } - - _transform(data, encoding, callback) { - if (this._filter(data)) { - this.push(data); - } - - callback(); - } -} - -class UniqueStream extends ObjectTransform { - constructor() { - super(); - this._pushed = new Set(); - } - - _transform(data, encoding, callback) { - if (!this._pushed.has(data)) { - this.push(data); - this._pushed.add(data); - } - - callback(); - } -} - -module.exports = { - FilterStream, - UniqueStream -}; - - -/***/ }), -/* 669 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const path = __webpack_require__(16); - -module.exports = path_ => { - let cwd = process.cwd(); - - path_ = path.resolve(path_); - - if (process.platform === 'win32') { - cwd = cwd.toLowerCase(); - path_ = path_.toLowerCase(); - } - - return path_ === cwd; -}; - - -/***/ }), -/* 670 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const path = __webpack_require__(16); - -module.exports = (childPath, parentPath) => { - childPath = path.resolve(childPath); - parentPath = path.resolve(parentPath); - - if (process.platform === 'win32') { - childPath = childPath.toLowerCase(); - parentPath = parentPath.toLowerCase(); - } - - if (childPath === parentPath) { - return false; - } - - childPath += path.sep; - parentPath += path.sep; - - return childPath.startsWith(parentPath); -}; - - -/***/ }), -/* 671 */ -/***/ (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__(592) -} catch (_err) { - // treat glob as optional. -} - -const defaultGlobOpts = { - nosort: true, - silent: true -} - -// for EMFILE handling -let timeout = 0 - -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] - }) - - 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 rimraf = (p, options, cb) => { - if (typeof options === 'function') { - cb = options - options = {} - } - - 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') - - defaults(options) - - let busyTries = 0 - let errState = null - let n = 0 - - const next = (er) => { - errState = errState || er - if (--n === 0) - cb(errState) - } - - const afterGlob = (er, results) => { - if (er) - return cb(er) - - n = results.length - if (n === 0) - return cb() - - 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) - } - - // this one won't happen if graceful-fs is used. - if (er.code === "EMFILE" && timeout < options.emfileWait) { - return setTimeout(() => rimraf_(p, options, CB), timeout ++) - } - - // already gone - if (er.code === "ENOENT") er = null - } - - timeout = 0 - next(er) - } - rimraf_(p, options, CB) - }) - } - - if (options.disableGlob || !glob.hasMagic(p)) - return afterGlob(null, [p]) - - options.lstat(p, (er, stat) => { - if (!er) - return afterGlob(null, [p]) - - glob(p, options.glob, afterGlob) - }) - -} - -// 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') - - // 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) - - // Windows can EPERM on stat. Life is suffering. - if (er && er.code === "EPERM" && isWindows) - fixWinEPERM(p, options, er, cb) - - if (st && st.isDirectory()) - return rmdir(p, options, er, cb) - - 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) - - try { - options.chmodSync(p, 0o666) - } catch (er2) { - if (er2.code === "ENOENT") - return - else - throw er - } - - let stats - try { - stats = options.statSync(p) - } catch (er3) { - if (er3.code === "ENOENT") - return - else - throw er - } - - 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') - - // 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 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) - } - } - - if (!results.length) - return - - for (let i = 0; i < results.length; i++) { - const p = results[i] - - let st - try { - st = options.lstatSync(p) - } catch (er) { - if (er.code === "ENOENT") - return - - // Windows can EPERM on stat. Life is suffering. - if (er.code === "EPERM" && isWindows) - fixWinEPERMSync(p, options, er) - } - - 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) - } - } -} - -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 rmkidsSync = (p, options) => { - assert(p) - assert(options) - options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options)) - - // 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) -} - -module.exports = rimraf -rimraf.sync = rimrafSync - - -/***/ }), -/* 672 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const AggregateError = __webpack_require__(673); - -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'); - } - - if (!(typeof concurrency === 'number' && concurrency >= 1)) { - throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); - } - - const ret = []; - const errors = []; - const iterator = iterable[Symbol.iterator](); - let isRejected = false; - let isIterableDone = false; - let resolvingCount = 0; - let currentIndex = 0; - - const next = () => { - if (isRejected) { - return; - } - - const nextItem = iterator.next(); - const i = currentIndex; - currentIndex++; - - if (nextItem.done) { - isIterableDone = true; - - if (resolvingCount === 0) { - if (!stopOnError && errors.length !== 0) { - reject(new AggregateError(errors)); - } else { - resolve(ret); - } - } - - return; - } - - resolvingCount++; - - (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(); - } - } - })(); - }; - - for (let i = 0; i < concurrency; i++) { - next(); - - if (isIterableDone) { - break; - } - } - }); -}; - - -/***/ }), -/* 673 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const indentString = __webpack_require__(674); -const cleanStack = __webpack_require__(675); - -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); - }); - - 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); - - this.name = 'AggregateError'; - - Object.defineProperty(this, '_errors', {value: errors}); - } - - * [Symbol.iterator]() { - for (const error of this._errors) { - yield error; - } - } -} - -module.exports = AggregateError; - - -/***/ }), -/* 674 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -module.exports = (string, count = 1, options) => { - options = { - indent: ' ', - includeEmptyLines: false, - ...options - }; - - if (typeof string !== 'string') { - throw new TypeError( - `Expected \`input\` to be a \`string\`, got \`${typeof string}\`` - ); - } - - if (typeof count !== 'number') { - throw new TypeError( - `Expected \`count\` to be a \`number\`, got \`${typeof count}\`` - ); - } - - if (typeof options.indent !== 'string') { - throw new TypeError( - `Expected \`options.indent\` to be a \`string\`, got \`${typeof options.indent}\`` - ); - } - - if (count === 0) { - return string; - } - - const regex = options.includeEmptyLines ? /^/gm : /^(?!\s*$)/gm; - - return string.replace(regex, options.indent.repeat(count)); -}; - - -/***/ }), -/* 675 */ -/***/ (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 = 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 line; - }) - .join('\n'); -}; - - -/***/ }), -/* 676 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -const chalk = __webpack_require__(677); -const cliCursor = __webpack_require__(681); -const cliSpinners = __webpack_require__(685); -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); - - 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; - } - - // Legacy argument - // TODO: Deprecate sometime in the future - if (typeof options === 'string') { - options = { - symbol: options - }; - } - - options = options || {}; - - this.stop(); - this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); + fs.chownSync = chownFixSync(fs.chownSync) + fs.fchownSync = chownFixSync(fs.fchownSync) + fs.lchownSync = chownFixSync(fs.lchownSync) - return this; - } -} + fs.chmodSync = chmodFixSync(fs.chmodSync) + fs.fchmodSync = chmodFixSync(fs.fchmodSync) + fs.lchmodSync = chmodFixSync(fs.lchmodSync) -module.exports = function (opts) { - return new Ora(opts); -}; + fs.stat = statFix(fs.stat) + fs.fstat = statFix(fs.fstat) + fs.lstat = statFix(fs.lstat) -module.exports.promise = (action, options) => { - if (typeof action.then !== 'function') { - throw new TypeError('Parameter `action` must be a Promise'); - } + fs.statSync = statFixSync(fs.statSync) + fs.fstatSync = statFixSync(fs.fstatSync) + fs.lstatSync = statFixSync(fs.lstatSync) - const spinner = new Ora(options); - spinner.start(); + // 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 () {} + } - action.then( - () => { - spinner.succeed(); - }, - () => { - spinner.fail(); - } - ); + // 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. - return spinner; -}; + // 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) + } + // 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) + } -/***/ }), -/* 677 */ -/***/ (function(module, exports, __webpack_require__) { + // This ensures `util.promisify` works as it does for native `fs.read`. + read.__proto__ = fs$read + return read + })(fs.read) -"use strict"; + 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) -const escapeStringRegexp = __webpack_require__(3); -const ansiStyles = __webpack_require__(678); -const stdoutColor = __webpack_require__(679).stdout; + 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) + }) + }) + }) + } -const template = __webpack_require__(680); + fs.lchmodSync = function (path, mode) { + var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) -const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); + // 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 + } + } -// `supportsColor.level` → `ansiStyles.color[name]` mapping -const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; + 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) + }) + }) + }) + } -// `color-convert` models to exclude from the Chalk API due to conflicts and such -const skipModels = new Set(['gray']); + 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 + } -const styles = Object.create(null); + } else { + fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) } + fs.lutimesSync = function () {} + } + } -function applyOptions(obj, options) { - options = options || {}; + 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) + }) + } + } - // 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 chmodFixSync (orig) { + if (!orig) return orig + return function (target, mode) { + try { + return orig.call(fs, target, mode) + } catch (er) { + if (!chownErOk(er)) throw er + } + } + } -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)); - }; + 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) + }) + } + } - Object.setPrototypeOf(chalk, Chalk.prototype); - Object.setPrototypeOf(chalk.template, chalk); + 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 + } + } + } - chalk.template.constructor = Chalk; + 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) + } + } - return chalk.template; - } + 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; + } + } - applyOptions(this, options); -} + // 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 -// Use bright blue on Windows as the normal blue color is illegible -if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001B[94m'; -} + if (er.code === "ENOSYS") + return true -for (const key of Object.keys(ansiStyles)) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); + var nonroot = !process.getuid || process.getuid() !== 0 + if (nonroot) { + if (er.code === "EINVAL" || er.code === "EPERM") + return true + } - styles[key] = { - get() { - const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); - } - }; + return false + } } -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; - } +/***/ }), +/* 666 */ +/***/ (function(module, exports, __webpack_require__) { - 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); - }; - } - }; -} +var Stream = __webpack_require__(27).Stream -ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); -for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.has(model)) { - continue; - } +module.exports = legacy - 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 legacy (fs) { + return { + ReadStream: ReadStream, + WriteStream: WriteStream + } -const proto = Object.defineProperties(() => {}, styles); + function ReadStream (path, options) { + if (!(this instanceof ReadStream)) return new ReadStream(path, options); -function build(_styles, _empty, key) { - const builder = function () { - return applyStyle.apply(builder, arguments); - }; + Stream.call(this); - builder._styles = _styles; - builder._empty = _empty; + var self = this; - const self = this; + this.path = path; + this.fd = null; + this.readable = true; + this.paused = false; - Object.defineProperty(builder, 'level', { - enumerable: true, - get() { - return self.level; - }, - set(level) { - self.level = level; - } - }); + this.flags = 'r'; + this.mode = 438; /*=0666*/ + this.bufferSize = 64 * 1024; - Object.defineProperty(builder, 'enabled', { - enumerable: true, - get() { - return self.enabled; - }, - set(enabled) { - self.enabled = enabled; - } - }); + options = options || {}; - // See below for fix regarding invisible grey/dim combination on Windows - builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; + // 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]; + } - // `__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 (this.encoding) this.setEncoding(this.encoding); - return builder; -} + 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'); + } -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]); + if (this.start > this.end) { + throw new Error('start must be <= end'); + } - if (argsLen === 0) { - return ''; - } + this.pos = this.start; + } - if (argsLen > 1) { - // Don't slice `arguments`, it prevents V8 optimizations - for (let a = 1; a < argsLen; a++) { - str += ' ' + args[a]; - } - } + if (this.fd !== null) { + process.nextTick(function() { + self._read(); + }); + return; + } - if (!this.enabled || this.level <= 0 || !str) { - return this._empty ? '' : str; - } + fs.open(this.path, this.flags, this.mode, function (err, fd) { + if (err) { + self.emit('error', err); + self.readable = false; + return; + } - // 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 = ''; - } + self.fd = fd; + self.emit('open', fd); + self._read(); + }) + } - 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; + function WriteStream (path, options) { + if (!(this instanceof WriteStream)) return new WriteStream(path, options); - // 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}`); - } + Stream.call(this); - // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue - ansiStyles.dim.open = originalDim; + this.path = path; + this.fd = null; + this.writable = true; - return str; -} + this.flags = 'w'; + this.encoding = 'binary'; + this.mode = 438; /*=0666*/ + this.bytesWritten = 0; -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(' '); - } + options = options || {}; - const args = [].slice.call(arguments, 2); - const parts = [strings.raw[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]; + } - for (let i = 1; i < strings.length; i++) { - parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(strings.raw[i])); - } + 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'); + } - return template(chalk, parts.join('')); -} + this.pos = this.start; + } -Object.defineProperties(Chalk.prototype, styles); + this.busy = false; + this._queue = []; -module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = stdoutColor; -module.exports.default = module.exports; // For TypeScript + if (this.fd === null) { + this._open = fs.open; + this._queue.push([this._open, this.path, this.flags, this.mode, undefined]); + this.flush(); + } + } +} /***/ }), -/* 678 */ +/* 667 */ /***/ (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 wrapAnsi256 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};5;${code}m`; -}; -const wrapAnsi16m = (fn, offset) => function () { - const rgb = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; -}; +module.exports = clone -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], +function clone (obj) { + if (obj === null || typeof obj !== 'object') + return obj - // 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], + if (obj instanceof Object) + var copy = { __proto__: obj.__proto__ } + else + var copy = Object.create(null) - // 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] - } - }; + Object.getOwnPropertyNames(obj).forEach(function (key) { + Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key)) + }) - // Fix humans - styles.color.grey = styles.color.gray; + return copy +} - for (const groupName of Object.keys(styles)) { - const group = styles[groupName]; - for (const styleName of Object.keys(group)) { - const style = group[styleName]; +/***/ }), +/* 668 */ +/***/ (function(module, exports, __webpack_require__) { - styles[styleName] = { - open: `\u001B[${style[0]}m`, - close: `\u001B[${style[1]}m` - }; +"use strict"; - group[styleName] = styles[styleName]; +const path = __webpack_require__(16); - codes.set(style[0], style[1]); - } +module.exports = path_ => { + let cwd = process.cwd(); - Object.defineProperty(styles, groupName, { - value: group, - enumerable: false - }); + path_ = path.resolve(path_); - Object.defineProperty(styles, 'codes', { - value: codes, - enumerable: false - }); + if (process.platform === 'win32') { + cwd = cwd.toLowerCase(); + path_ = path_.toLowerCase(); } - const ansi2ansi = n => n; - const rgb2rgb = (r, g, b) => [r, g, b]; - - 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) - }; + return path_ === cwd; +}; - styles.bgColor.ansi = { - ansi: wrapAnsi16(ansi2ansi, 10) - }; - styles.bgColor.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 10) - }; - styles.bgColor.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 10) - }; - for (let key of Object.keys(colorConvert)) { - if (typeof colorConvert[key] !== 'object') { - continue; - } +/***/ }), +/* 669 */ +/***/ (function(module, exports, __webpack_require__) { - const suite = colorConvert[key]; +"use strict"; - if (key === 'ansi16') { - key = 'ansi'; - } +const path = __webpack_require__(16); - if ('ansi16' in suite) { - styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); - styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); - } +module.exports = (childPath, parentPath) => { + childPath = path.resolve(childPath); + parentPath = path.resolve(parentPath); - if ('ansi256' in suite) { - styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); - styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); - } + if (process.platform === 'win32') { + childPath = childPath.toLowerCase(); + parentPath = parentPath.toLowerCase(); + } - if ('rgb' in suite) { - styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); - styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); - } + if (childPath === parentPath) { + return false; } - return styles; -} + childPath += path.sep; + parentPath += path.sep; -// Make the export immutable -Object.defineProperty(module, 'exports', { - enumerable: true, - get: assembleStyles -}); + return childPath.startsWith(parentPath); +}; -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 679 */ +/* 670 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - -const os = __webpack_require__(11); -const hasFlag = __webpack_require__(12); - -const env = process.env; - -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; +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. } -function translateLevel(level) { - if (level === 0) { - return false; - } - - return { - level, - hasBasic: true, - has256: level >= 2, - has16m: level >= 3 - }; +const defaultGlobOpts = { + nosort: true, + silent: true } -function supportsColor(stream) { - if (forceColor === false) { - return 0; - } +// for EMFILE handling +let timeout = 0 - if (hasFlag('color=16m') || - hasFlag('color=full') || - hasFlag('color=truecolor')) { - return 3; - } +const isWindows = (process.platform === "win32") - if (hasFlag('color=256')) { - return 2; - } +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] + }) - if (stream && !stream.isTTY && forceColor !== true) { - // VS code debugger doesn't have isTTY set - if (env.VSCODE_PID) { - return 1; - } - return 0; - } + 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 min = forceColor ? 1 : 0; +const rimraf = (p, options, cb) => { + if (typeof options === 'function') { + cb = options + options = {} + } - 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; - } + 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') - return 1; - } + defaults(options) - if ('CI' in env) { - if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') { - return 1; - } + let busyTries = 0 + let errState = null + let n = 0 - return min; - } + const next = (er) => { + errState = errState || er + if (--n === 0) + cb(errState) + } - if ('TEAMCITY_VERSION' in env) { - return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; - } + const afterGlob = (er, results) => { + if (er) + return cb(er) - if (env.COLORTERM === 'truecolor') { - return 3; - } + n = results.length + if (n === 0) + return cb() - if ('TERM_PROGRAM' in env) { - const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); + 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) + } - switch (env.TERM_PROGRAM) { - case 'iTerm.app': - return version >= 3 ? 3 : 2; - case 'Apple_Terminal': - return 2; - // No default - } - } + // this one won't happen if graceful-fs is used. + if (er.code === "EMFILE" && timeout < options.emfileWait) { + return setTimeout(() => rimraf_(p, options, CB), timeout ++) + } - if (/-256(color)?$/i.test(env.TERM)) { - return 2; - } + // already gone + if (er.code === "ENOENT") er = null + } - if (/^screen|^xterm|^vt100|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { - return 1; - } + timeout = 0 + next(er) + } + rimraf_(p, options, CB) + }) + } - if ('COLORTERM' in env) { - return 1; - } + if (options.disableGlob || !glob.hasMagic(p)) + return afterGlob(null, [p]) - if (env.TERM === 'dumb') { - return min; - } + options.lstat(p, (er, stat) => { + if (!er) + return afterGlob(null, [p]) - return min; -} + glob(p, options.glob, afterGlob) + }) -function getSupportLevel(stream) { - const level = supportsColor(stream); - return translateLevel(level); } -module.exports = { - supportsColor: getSupportLevel, - stdout: getSupportLevel(process.stdout), - stderr: getSupportLevel(process.stderr) -}; +// 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') + // 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) -/***/ }), -/* 680 */ -/***/ (function(module, exports, __webpack_require__) { + // Windows can EPERM on stat. Life is suffering. + if (er && er.code === "EPERM" && isWindows) + fixWinEPERM(p, options, er, cb) -"use strict"; + if (st && st.isDirectory()) + return rmdir(p, options, er, cb) -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; + 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 ESCAPES = new Map([ - ['n', '\n'], - ['r', '\r'], - ['t', '\t'], - ['b', '\b'], - ['f', '\f'], - ['v', '\v'], - ['0', '\0'], - ['\\', '\\'], - ['e', '\u001B'], - ['a', '\u0007'] -]); +const fixWinEPERM = (p, options, er, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') + if (er) + assert(er instanceof Error) -function unescape(c) { - if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { - return String.fromCharCode(parseInt(c.slice(1), 16)); - } + 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) + }) + }) +} - return ESCAPES.get(c) || c; +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 + } + + let stats + try { + stats = options.statSync(p) + } catch (er3) { + if (er3.code === "ENOENT") + return + else + throw er + } + + if (stats.isDirectory()) + rmdirSync(p, options, er) + else + options.unlinkSync(p) } -function parseArguments(name, args) { - const results = []; - const chunks = args.trim().split(/\s*,\s*/g); - let matches; +const rmdir = (p, options, originalEr, cb) => { + assert(p) + assert(options) + if (originalEr) + assert(originalEr instanceof Error) + assert(typeof cb === 'function') - 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}')`); - } - } + // 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) + }) +} - return results; +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) + }) + }) + }) } -function parseStyle(style) { - STYLE_REGEX.lastIndex = 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 results = []; - let matches; + 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') - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; + let results - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); - } - } + if (options.disableGlob || !glob.hasMagic(p)) { + results = [p] + } else { + try { + options.lstatSync(p) + results = [p] + } catch (er) { + results = glob.sync(p, options.glob) + } + } - return results; -} + if (!results.length) + return -function buildStyle(chalk, styles) { - const enabled = {}; + for (let i = 0; i < results.length; i++) { + const p = results[i] - for (const layer of styles) { - for (const style of layer.styles) { - enabled[style[0]] = layer.inverse ? null : style.slice(1); - } - } + let st + try { + st = options.lstatSync(p) + } catch (er) { + if (er.code === "ENOENT") + return - 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}`); - } + // Windows can EPERM on stat. Life is suffering. + if (er.code === "EPERM" && isWindows) + fixWinEPERMSync(p, options, er) + } - if (enabled[styleName].length > 0) { - current = current[styleName].apply(current, enabled[styleName]); - } else { - current = current[styleName]; - } - } - } + 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 - return current; + rmdirSync(p, options, er) + } + } } -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'); - } +const rmdirSync = (p, options, originalEr) => { + assert(p) + assert(options) + if (originalEr) + assert(originalEr instanceof Error) - chunks.push(buildStyle(chalk, styles)(chunk.join(''))); - chunk = []; - styles.pop(); - } else { - chunk.push(chr); - } - }); + 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) + } +} - chunks.push(chunk.join('')); +const rmkidsSync = (p, options) => { + assert(p) + assert(options) + options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options)) - if (styles.length > 0) { - const errMsg = `Chalk template literal is missing ${styles.length} closing bracket${styles.length === 1 ? '' : 's'} (\`}\`)`; - throw new Error(errMsg); - } + // 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) +} - return chunks.join(''); -}; +module.exports = rimraf +rimraf.sync = rimrafSync /***/ }), -/* 681 */ +/* 671 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +"use strict"; + +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'); + } + + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } -const restoreCursor = __webpack_require__(682); + const ret = []; + const errors = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let isIterableDone = false; + let resolvingCount = 0; + let currentIndex = 0; -let hidden = false; + const next = () => { + if (isRejected) { + return; + } -exports.show = stream => { - const s = stream || process.stderr; + const nextItem = iterator.next(); + const i = currentIndex; + currentIndex++; - if (!s.isTTY) { - return; - } + if (nextItem.done) { + isIterableDone = true; - hidden = false; - s.write('\u001b[?25h'); -}; + if (resolvingCount === 0) { + if (!stopOnError && errors.length !== 0) { + reject(new AggregateError(errors)); + } else { + resolve(ret); + } + } -exports.hide = stream => { - const s = stream || process.stderr; + return; + } - if (!s.isTTY) { - return; - } + resolvingCount++; - restoreCursor(); - hidden = true; - s.write('\u001b[?25l'); -}; + (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(); + } + } + })(); + }; -exports.toggle = (force, stream) => { - if (force !== undefined) { - hidden = force; - } + for (let i = 0; i < concurrency; i++) { + next(); - if (hidden) { - exports.show(stream); - } else { - exports.hide(stream); - } + if (isIterableDone) { + break; + } + } + }); }; /***/ }), -/* 682 */ +/* 672 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const onetime = __webpack_require__(683); -const signalExit = __webpack_require__(377); - -module.exports = onetime(() => { - signalExit(() => { - process.stderr.write('\u001b[?25h'); - }, {alwaysLast: true}); -}); - +const indentString = __webpack_require__(673); +const cleanStack = __webpack_require__(674); -/***/ }), -/* 683 */ -/***/ (function(module, exports, __webpack_require__) { +const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); -"use strict"; +class AggregateError extends Error { + constructor(errors) { + if (!Array.isArray(errors)) { + throw new TypeError(`Expected input to be an Array, got ${typeof errors}`); + } -const mimicFn = __webpack_require__(684); + errors = [...errors].map(error => { + if (error instanceof Error) { + return error; + } -module.exports = (fn, opts) => { - // TODO: Remove this in v3 - if (opts === true) { - throw new TypeError('The second argument is now an options object'); - } + 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 (typeof fn !== 'function') { - throw new TypeError('Expected a function'); - } + return new Error(error); + }); - opts = opts || {}; + 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); - let ret; - let called = false; - const fnName = fn.displayName || fn.name || ''; + this.name = 'AggregateError'; - const onetime = function () { - if (called) { - if (opts.throw === true) { - throw new Error(`Function \`${fnName}\` can only be called once`); - } + Object.defineProperty(this, '_errors', {value: errors}); + } - return ret; + * [Symbol.iterator]() { + for (const error of this._errors) { + yield error; } + } +} - called = true; - ret = fn.apply(this, arguments); - fn = null; - - return ret; - }; - - mimicFn(onetime, fn); - - return onetime; -}; +module.exports = AggregateError; /***/ }), -/* 684 */ +/* 673 */ /***/ (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; -}; - +module.exports = (str, count, opts) => { + // Support older versions: use the third parameter as options.indent + // TODO: Remove the workaround in the next major version + const options = typeof opts === 'object' ? Object.assign({indent: ' '}, opts) : {indent: opts || ' '}; + count = count === undefined ? 1 : count; -/***/ }), -/* 685 */ -/***/ (function(module, exports, __webpack_require__) { + if (typeof str !== 'string') { + throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof str}\``); + } -"use strict"; + if (typeof count !== 'number') { + throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof count}\``); + } -module.exports = __webpack_require__(686); + if (typeof options.indent !== 'string') { + throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof options.indent}\``); + } + if (count === 0) { + return str; + } -/***/ }), -/* 686 */ -/***/ (function(module) { + const regex = options.includeEmptyLines ? /^/mg : /^(?!\s*$)/mg; + return str.replace(regex, options.indent.repeat(count)); +} +; -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\":[\"🌲\",\"🎄\"]}}"); /***/ }), -/* 687 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 674 */ +/***/ (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 _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. - */ +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); -const RunCommand = { - description: 'Run script defined in package.json in each package that contains that script.', - name: 'run', + return stack.replace(/\\/g, '/') + .split('\n') + .filter(line => { + const pathMatches = line.match(extractPathRegex); + if (pathMatches === null || !pathMatches[1]) { + return true; + } - async run(projects, projectGraph, { - extraArgs - }) { - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projects, projectGraph); + const match = pathMatches[1]; - 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); - } + // Electron + if ( + match.includes('.app/Contents/Resources/electron.asar') || + match.includes('.app/Contents/Resources/default_app.asar') + ) { + return false; + } - 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); - } - }); - } + 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'); }; + /***/ }), -/* 688 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 675 */ +/***/ (function(module, 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__(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 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); -/** - * 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. - */ + 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 -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. - */ + if (this.spinner.frames === undefined) { + throw new Error('Spinner must define `frames`'); + } -const WatchCommand = { - description: 'Runs `kbn:watch` script for every project.', - name: 'watch', + 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]; - async run(projects, projectGraph) { - const projectsToWatch = new Map(); + if (this.color) { + frame = chalk[this.color](frame); + } - 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); - } - } + this.frameIndex = ++this.frameIndex % frames.length; - 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; - } + return frame + ' ' + this.text; + } + clear() { + if (!this.enabled) { + return this; + } - 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. + this.stream.clearLine(); + this.stream.cursorTo(0); - const shouldWatchKibanaProject = projectsToWatch.delete(kibanaProjectName); - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projectsToWatch, projectGraph); + return this; + } + render() { + this.clear(); + this.stream.write(this.frame()); - if (shouldWatchKibanaProject) { - batchedProjects.push([projects.get(kibanaProjectName)]); - } + return this; + } + start(text) { + if (text) { + this.text = text; + } - 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}).`)); - }); - } + if (!this.enabled || this.id) { + return this; + } -}; + cliCursor.hide(this.stream); + this.render(); + this.id = setInterval(this.render.bind(this), this.interval); -/***/ }), -/* 689 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + return this; + } + stop() { + if (!this.enabled) { + return this; + } -"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. - */ + clearInterval(this.id); + this.id = null; + this.frameIndex = 0; + this.clear(); + cliCursor.show(this.stream); + 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; + } -/** - * Number of milliseconds we wait before we fall back to the default watch handler. - */ + // Legacy argument + // TODO: Deprecate sometime in the future + if (typeof options === 'string') { + options = { + symbol: options + }; + } -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. - */ + options = options || {}; -const defaultHandlerReadinessTimeout = 2000; -/** - * Describes configurable watch options. - */ + this.stop(); + this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); -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]; + return this; + } } -function waitUntilWatchIsReady(stream, opts = {}) { - const buildOutput$ = new rxjs__WEBPACK_IMPORTED_MODULE_0__["Subject"](); +module.exports = function (opts) { + return new Ora(opts); +}; - const onDataListener = data => buildOutput$.next(data.toString('utf-8')); +module.exports.promise = (action, options) => { + if (typeof action.then !== 'function') { + throw new TypeError('Parameter `action` must be a Promise'); + } + + const spinner = new Ora(options); + spinner.start(); - const onEndListener = () => buildOutput$.complete(); + action.then( + () => { + spinner.succeed(); + }, + () => { + spinner.fail(); + } + ); - const onErrorListener = e => buildOutput$.error(e); + return spinner; +}; - 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(); -} /***/ }), -/* 690 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +/* 676 */ +/***/ (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__(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; } - -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; } - -/* - * 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 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; +} -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) - }); +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 (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); - } + chalk.template = function () { + const args = [].slice.call(arguments); + return chalkTag.apply(null, [chalk.template].concat(args)); + }; - 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.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); - 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); + chalk.template.constructor = Chalk; - 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); - } + return chalk.template; + } - process.exit(1); - } + applyOptions(this, options); } -function toArray(value) { - if (value == null) { - return []; - } - - return Array.isArray(value) ? value : [value]; +// Use bright blue on Windows as the normal blue color is illegible +if (isSimpleWindowsTerm) { + ansiStyles.blue.open = '\u001B[94m'; } -/***/ }), -/* 691 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +for (const key of Object.keys(ansiStyles)) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); -module.exports = (str, count, opts) => { - // Support older versions: use the third parameter as options.indent - // TODO: Remove the workaround in the next major version - const options = typeof opts === 'object' ? Object.assign({indent: ' '}, opts) : {indent: opts || ' '}; - count = count === undefined ? 1 : count; + styles[key] = { + get() { + const codes = ansiStyles[key]; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + } + }; +} - if (typeof str !== 'string') { - throw new TypeError(`Expected \`input\` to be a \`string\`, got \`${typeof str}\``); +styles.visible = { + get() { + return build.call(this, this._styles || [], true, 'visible'); } +}; - if (typeof count !== 'number') { - throw new TypeError(`Expected \`count\` to be a \`number\`, got \`${typeof count}\``); +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); +for (const model of Object.keys(ansiStyles.color.ansi)) { + if (skipModels.has(model)) { + continue; } - if (typeof options.indent !== 'string') { - throw new TypeError(`Expected \`options.indent\` to be a \`string\`, got \`${typeof options.indent}\``); - } + 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 (count === 0) { - return str; +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); +for (const model of Object.keys(ansiStyles.bgColor.ansi)) { + if (skipModels.has(model)) { + continue; } - const regex = options.includeEmptyLines ? /^/mg : /^(?!\s*$)/mg; - return str.replace(regex, options.indent.repeat(count)); + 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); + }; + } + }; } -; - - -/***/ }), -/* 692 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; - -const stringWidth = __webpack_require__(693); -const stripAnsi = __webpack_require__(697); +const proto = Object.defineProperties(() => {}, styles); -const ESCAPES = new Set([ - '\u001B', - '\u009B' -]); +function build(_styles, _empty, key) { + const builder = function () { + return applyStyle.apply(builder, arguments); + }; -const END_CODE = 39; + builder._styles = _styles; + builder._empty = _empty; -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] -]); + const self = this; -const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`; + Object.defineProperty(builder, 'level', { + enumerable: true, + get() { + return self.level; + }, + set(level) { + self.level = level; + } + }); -// 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)); + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get() { + return self.enabled; + }, + set(enabled) { + self.enabled = enabled; + } + }); -// 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); + // See below for fix regarding invisible grey/dim combination on Windows + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; - let insideEscape = false; - let visible = stringWidth(stripAnsi(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 - for (const item of arr.entries()) { - const i = item[0]; - const char = item[1]; - const charLength = stringWidth(char); + return builder; +} - if (visible + charLength <= cols) { - rows[rows.length - 1] += char; - } else { - rows.push(char); - visible = 0; - } +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]); - if (ESCAPES.has(char)) { - insideEscape = true; - } else if (insideEscape && char === 'm') { - insideEscape = false; - continue; - } + if (argsLen === 0) { + return ''; + } - if (insideEscape) { - continue; + if (argsLen > 1) { + // Don't slice `arguments`, it prevents V8 optimizations + for (let a = 1; a < argsLen; a++) { + str += ' ' + args[a]; } + } - visible += charLength; - - if (visible === cols && i < arr.length - 1) { - rows.push(''); - visible = 0; - } + if (!this.enabled || this.level <= 0 || !str) { + return this._empty ? '' : str; } - // 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(); + // 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 = ''; } -}; -// 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 || {}; + 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; - if (str.trim() === '') { - return options.trim === false ? str : str.trim(); + // 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}`); } - let pre = ''; - let ret = ''; - let escapeCode; + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue + ansiStyles.dim.open = originalDim; - const lengths = wordLengths(str); - const words = str.split(' '); - const rows = ['']; + return str; +} - for (const item of Array.from(words).entries()) { - const i = item[0]; - const word = item[1]; +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(' '); + } - rows[rows.length - 1] = options.trim === false ? rows[rows.length - 1] : rows[rows.length - 1].trim(); - let rowLength = stringWidth(rows[rows.length - 1]); + const args = [].slice.call(arguments, 2); + const parts = [strings.raw[0]]; - 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; - } + for (let i = 1; i < strings.length; i++) { + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); + parts.push(String(strings.raw[i])); + } - rows[rows.length - 1] += ' '; - rowLength++; - } + return template(chalk, parts.join('')); +} - // 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; - } +Object.defineProperties(Chalk.prototype, styles); - if (rowLength + lengths[i] > cols && rowLength > 0) { - if (options.wordWrap === false && rowLength < cols) { - wrapWord(rows, word, cols); - continue; - } +module.exports = Chalk(); // eslint-disable-line new-cap +module.exports.supportsColor = stdoutColor; +module.exports.default = module.exports; // For TypeScript - rows.push(''); - } - if (rowLength + lengths[i] > cols && options.wordWrap === false) { - wrapWord(rows, word, cols); - continue; - } +/***/ }), +/* 677 */ +/***/ (function(module, exports, __webpack_require__) { - rows[rows.length - 1] += word; - } +"use strict"; +/* WEBPACK VAR INJECTION */(function(module) { +const colorConvert = __webpack_require__(6); - pre = rows.map(r => options.trim === false ? r : r.trim()).join('\n'); +const wrapAnsi16 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${code + offset}m`; +}; - for (const item of Array.from(pre).entries()) { - const i = item[0]; - const char = item[1]; +const wrapAnsi256 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};5;${code}m`; +}; - ret += char; +const wrapAnsi16m = (fn, offset) => function () { + const rgb = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; +}; - if (ESCAPES.has(char)) { - const code = parseFloat(/\d[^m]*/.exec(pre.slice(i, i + 4))); - escapeCode = code === END_CODE ? null : code; - } +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], - const code = ESCAPE_CODES.get(Number(escapeCode)); + // 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], - if (escapeCode && code) { - if (pre[i + 1] === '\n') { - ret += wrapAnsi(code); - } else if (char === '\n') { - ret += wrapAnsi(escapeCode); - } + // 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] } - } + }; - return ret; -}; + // Fix humans + styles.color.grey = styles.color.gray; -// 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'); -}; + for (const groupName of Object.keys(styles)) { + const group = styles[groupName]; + for (const styleName of Object.keys(group)) { + const style = group[styleName]; -/***/ }), -/* 693 */ -/***/ (function(module, exports, __webpack_require__) { + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m` + }; -"use strict"; + group[styleName] = styles[styleName]; -const stripAnsi = __webpack_require__(694); -const isFullwidthCodePoint = __webpack_require__(696); + codes.set(style[0], style[1]); + } -module.exports = str => { - if (typeof str !== 'string' || str.length === 0) { - return 0; + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false + }); + + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false + }); } - str = stripAnsi(str); + const ansi2ansi = n => n; + const rgb2rgb = (r, g, b) => [r, g, b]; - let width = 0; + styles.color.close = '\u001B[39m'; + styles.bgColor.close = '\u001B[49m'; - for (let i = 0; i < str.length; i++) { - const code = str.codePointAt(i); + styles.color.ansi = { + ansi: wrapAnsi16(ansi2ansi, 0) + }; + styles.color.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 0) + }; + styles.color.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 0) + }; - // Ignore control characters - if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) { - continue; - } + styles.bgColor.ansi = { + ansi: wrapAnsi16(ansi2ansi, 10) + }; + styles.bgColor.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 10) + }; + styles.bgColor.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 10) + }; - // Ignore combining characters - if (code >= 0x300 && code <= 0x36F) { + for (let key of Object.keys(colorConvert)) { + if (typeof colorConvert[key] !== 'object') { continue; } - // Surrogates - if (code > 0xFFFF) { - i++; - } - - width += isFullwidthCodePoint(code) ? 2 : 1; - } + const suite = colorConvert[key]; - return width; -}; + if (key === 'ansi16') { + key = 'ansi'; + } + if ('ansi16' in suite) { + styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); + styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); + } -/***/ }), -/* 694 */ -/***/ (function(module, exports, __webpack_require__) { + if ('ansi256' in suite) { + styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); + styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); + } -"use strict"; + if ('rgb' in suite) { + styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); + styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); + } + } -const ansiRegex = __webpack_require__(695); + return styles; +} -module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; +// Make the export immutable +Object.defineProperty(module, 'exports', { + enumerable: true, + get: assembleStyles +}); +/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 695 */ +/* 678 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +const os = __webpack_require__(11); +const hasFlag = __webpack_require__(12); -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('|'); - - return new RegExp(pattern, 'g'); -}; - - -/***/ }), -/* 696 */ -/***/ (function(module, exports, __webpack_require__) { +const env = process.env; -"use strict"; +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; +} -/* eslint-disable yoda */ -module.exports = x => { - if (Number.isNaN(x)) { +function translateLevel(level) { + if (level === 0) { return false; } - // 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; - } + return { + level, + hasBasic: true, + has256: level >= 2, + has16m: level >= 3 + }; +} - return false; -}; +function supportsColor(stream) { + if (forceColor === false) { + return 0; + } + if (hasFlag('color=16m') || + hasFlag('color=full') || + hasFlag('color=truecolor')) { + return 3; + } -/***/ }), -/* 697 */ -/***/ (function(module, exports, __webpack_require__) { + if (hasFlag('color=256')) { + return 2; + } -"use strict"; + if (stream && !stream.isTTY && forceColor !== true) { + // VS code debugger doesn't have isTTY set + if (env.VSCODE_PID) { + return 1; + } + return 0; + } -const ansiRegex = __webpack_require__(698); + const min = forceColor ? 1 : 0; -module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; + 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; + } + return 1; + } -/***/ }), -/* 698 */ -/***/ (function(module, exports, __webpack_require__) { + if ('CI' in env) { + if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') { + return 1; + } -"use strict"; + return min; + } + if ('TEAMCITY_VERSION' in env) { + return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; + } -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 (env.COLORTERM === 'truecolor') { + return 3; + } - return new RegExp(pattern, 'g'); -}; + if ('TERM_PROGRAM' in env) { + const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); + switch (env.TERM_PROGRAM) { + case 'iTerm.app': + return version >= 3 ? 3 : 2; + case 'Apple_Terminal': + return 2; + // No default + } + } -/***/ }), -/* 699 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (/-256(color)?$/i.test(env.TERM)) { + return 2; + } -"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 (/^screen|^xterm|^vt100|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { + return 1; + } + if ('COLORTERM' in env) { + return 1; + } -const projectKey = Symbol('__project'); -function renderProjectsTree(rootPath, projects) { - const projectsTree = buildProjectsTree(rootPath, projects); - return treeToString(createTreeStructure(projectsTree)); -} + if (env.TERM === 'dumb') { + return min; + } -function treeToString(tree) { - return [tree.name].concat(childrenToStrings(tree.children, '')).join('\n'); + return min; } -function childrenToStrings(tree, treePrefix) { - if (tree === undefined) { - return []; - } - - 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; +function getSupportLevel(stream) { + const level = supportsColor(stream); + return translateLevel(level); } -function createTreeStructure(tree) { - let name; - const children = []; - - 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 (project.size === 1 && project.has(projectKey)) { - const projectName = project.get(projectKey); - children.push({ - children: [], - name: dirOrProjectName(dir, projectName) - }); - continue; - } - - const subtree = createTreeStructure(project); // If the name is specified, we know there's a package at the "root" of the - // subtree itself. - - 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. - +module.exports = { + supportsColor: getSupportLevel, + stdout: getSupportLevel(process.stdout), + stderr: getSupportLevel(process.stderr) +}; - 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; - } - children.push({ - children: subtree.children, - name: chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(dir.toString()) - }); - } +/***/ }), +/* 679 */ +/***/ (function(module, exports, __webpack_require__) { - return { - name, - children - }; -} +"use strict"; -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}})}`; -} +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; -function buildProjectsTree(rootPath, projects) { - const tree = new Map(); +const ESCAPES = new Map([ + ['n', '\n'], + ['r', '\r'], + ['t', '\t'], + ['b', '\b'], + ['f', '\f'], + ['v', '\v'], + ['0', '\0'], + ['\\', '\\'], + ['e', '\u001B'], + ['a', '\u0007'] +]); - 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); - } - } +function unescape(c) { + if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { + return String.fromCharCode(parseInt(c.slice(1), 16)); + } - return tree; + return ESCAPES.get(c) || c; } -function addProjectToTree(tree, pathParts, project) { - if (pathParts.length === 0) { - tree.set(projectKey, project.name); - } else { - const [currentDir, ...rest] = pathParts; +function parseArguments(name, args) { + const results = []; + const chunks = args.trim().split(/\s*,\s*/g); + let matches; - if (!tree.has(currentDir)) { - tree.set(currentDir, new Map()); - } + 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}')`); + } + } - const subtree = tree.get(currentDir); - addProjectToTree(subtree, rest, project); - } + return results; } -/***/ }), -/* 700 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +function parseStyle(style) { + STYLE_REGEX.lastIndex = 0; -"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; } + const results = []; + let matches; -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; } + while ((matches = STYLE_REGEX.exec(style)) !== null) { + const name = matches[1]; -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; } + if (matches[2]) { + const args = parseArguments(name, matches[2]); + results.push([name].concat(args)); + } else { + results.push([name]); + } + } -/* - * 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. - */ + return results; +} +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}`); + } -/** - * 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. - */ + if (enabled[styleName].length > 0) { + current = current[styleName].apply(current, enabled[styleName]); + } else { + current = current[styleName]; + } + } + } -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 - })))); - } + return current; +} - constructor(allWorkspaceProjects) { - this.allWorkspaceProjects = allWorkspaceProjects; +module.exports = (chalk, tmp) => { + const styles = []; + const chunks = []; + let chunk = []; - _defineProperty(this, "kibanaProject", void 0); + // 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'); + } - const kibanaProject = allWorkspaceProjects.get('kibana'); + chunks.push(buildStyle(chalk, styles)(chunk.join(''))); + chunk = []; + styles.pop(); + } else { + chunk.push(chr); + } + }); - if (!kibanaProject) { - throw new TypeError('Unable to create Kibana object without all projects, including the Kibana project.'); - } + chunks.push(chunk.join('')); - this.kibanaProject = kibanaProject; - } - /** make an absolute path by resolving subPath relative to the kibana repo */ + 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(''); +}; - 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__) { - 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 */ +"use strict"; +const restoreCursor = __webpack_require__(681); - getAllProjects() { - return new Map(this.allWorkspaceProjects); - } - /** determine if a project with the given name exists */ +let hidden = false; +exports.show = stream => { + const s = stream || process.stderr; - hasProject(name) { - return this.allWorkspaceProjects.has(name); - } - /** get a specific project, throws if the name is not known (use hasProject() first) */ + if (!s.isTTY) { + return; + } + hidden = false; + s.write('\u001b[?25h'); +}; - getProject(name) { - const project = this.allWorkspaceProjects.get(name); +exports.hide = stream => { + const s = stream || process.stderr; - if (!project) { - throw new Error(`No package with name "${name}" in the workspace`); - } + if (!s.isTTY) { + return; + } - return project; - } - /** get a project and all of the projects it depends on in a ProjectMap */ + restoreCursor(); + hidden = true; + s.write('\u001b[?25l'); +}; +exports.toggle = (force, stream) => { + if (force !== undefined) { + hidden = force; + } - 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 */ + if (hidden) { + exports.show(stream); + } else { + exports.hide(stream); + } +}; - 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); +/***/ }), +/* 681 */ +/***/ (function(module, exports, __webpack_require__) { - 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); +"use strict"; - if (pathMatches && notExcluded && isIncluded) { - filteredProjects.set(project.name, project); - } - } +const onetime = __webpack_require__(682); +const signalExit = __webpack_require__(377); - return filteredProjects; - } +module.exports = onetime(() => { + signalExit(() => { + process.stderr.write('\u001b[?25h'); + }, {alwaysLast: true}); +}); -} /***/ }), -/* 701 */ +/* 682 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const minimatch = __webpack_require__(505); -const arrayUnion = __webpack_require__(702); -const arrayDiffer = __webpack_require__(703); -const arrify = __webpack_require__(704); +const mimicFn = __webpack_require__(683); -module.exports = (list, patterns, options = {}) => { - list = arrify(list); - patterns = arrify(patterns); +module.exports = (fn, opts) => { + // TODO: Remove this in v3 + if (opts === true) { + throw new TypeError('The second argument is now an options object'); + } - if (list.length === 0 || patterns.length === 0) { - return []; + if (typeof fn !== 'function') { + throw new TypeError('Expected a function'); } - return patterns.reduce((result, pattern) => { - let process = arrayUnion; + opts = opts || {}; - if (pattern[0] === '!') { - pattern = pattern.slice(1); - process = arrayDiffer; - } + let ret; + let called = false; + const fnName = fn.displayName || fn.name || ''; - return process(result, minimatch.match(list, pattern, options)); - }, []); -}; + const onetime = function () { + if (called) { + if (opts.throw === true) { + throw new Error(`Function \`${fnName}\` can only be called once`); + } + return ret; + } -/***/ }), -/* 702 */ -/***/ (function(module, exports, __webpack_require__) { + called = true; + ret = fn.apply(this, arguments); + fn = null; -"use strict"; + return ret; + }; + mimicFn(onetime, fn); -module.exports = (...arguments_) => { - return [...new Set([].concat(...arguments_))]; + return onetime; }; /***/ }), -/* 703 */ +/* 683 */ /***/ (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)); + } -const arrayDiffer = (array, ...values) => { - const rest = new Set([].concat(...values)); - return array.filter(element => !rest.has(element)); + return to; }; -module.exports = arrayDiffer; - /***/ }), -/* 704 */ +/* 684 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +module.exports = __webpack_require__(685); -const arrify = value => { - if (value === null || value === undefined) { - return []; - } - - 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; +/***/ }), +/* 685 */ +/***/ (function(module) { +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\":[\"🌲\",\"🎄\"]}}"); /***/ }), -/* 705 */ +/* 686 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); -/* 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"]; }); - +/* 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 @@ -80688,24 +78830,46 @@ __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); + } + }); + } + +}; + /***/ }), -/* 706 */ +/* 687 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "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__(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); +/* 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); /* * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with @@ -80730,2066 +78894,1657 @@ __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); - } - } -} /** - * 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. + * 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. */ -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'); - } -} +const kibanaProjectName = 'kibana'; /** - * 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 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. * - * 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. + * 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. */ +const WatchCommand = { + description: 'Runs `kbn:watch` script for every project.', + name: 'watch', -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`. - - 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); -} - -/***/ }), -/* 707 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -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); - -const preprocessSrcPath = (srcPath, options) => options.cwd ? path.resolve(options.cwd, srcPath) : srcPath; - -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; -}; + async run(projects, projectGraph) { + const projectsToWatch = new Map(); -module.exports = cpy; -// TODO: Remove this for the next major release -module.exports.default = cpy; + 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); + } + } + 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; + } -/***/ }), -/* 708 */ -/***/ (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); -module.exports = function (val) { - if (val === null || val === undefined) { - return []; - } + if (shouldWatchKibanaProject) { + batchedProjects.push([projects.get(kibanaProjectName)]); + } - return Array.isArray(val) ? val : [val]; -}; + 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}).`)); + }); + } +}; /***/ }), -/* 709 */ -/***/ (function(module, exports, __webpack_require__) { +/* 688 */ +/***/ (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 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 DEFAULT_FILTER = () => false; - -const isNegative = pattern => pattern[0] === '!'; - -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'); - } -}; +/** + * Number of milliseconds we wait before we fall back to the default watch handler. + */ -const generateGlobTasks = (patterns, taskOptions) => { - patterns = arrayUnion([].concat(patterns)); - assertPatternsInput(patterns); - checkCwdOption(taskOptions); +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 globTasks = []; +const defaultHandlerReadinessTimeout = 2000; +/** + * Describes configurable watch options. + */ - taskOptions = Object.assign({ - ignore: [], - expandDirectories: true - }, taskOptions); +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]; +} - patterns.forEach((pattern, i) => { - if (isNegative(pattern)) { - return; - } +function waitUntilWatchIsReady(stream, opts = {}) { + const buildOutput$ = new rxjs__WEBPACK_IMPORTED_MODULE_0__["Subject"](); - const ignore = patterns - .slice(i) - .filter(isNegative) - .map(pattern => pattern.slice(1)); + const onDataListener = data => buildOutput$.next(data.toString('utf-8')); - const options = Object.assign({}, taskOptions, { - ignore: taskOptions.ignore.concat(ignore) - }); + const onEndListener = () => buildOutput$.complete(); - globTasks.push({pattern, options}); - }); + const onErrorListener = e => buildOutput$.error(e); - return globTasks; -}; + 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(); +} -const globDirs = (task, fn) => { - let options = {}; - if (task.options.cwd) { - options.cwd = task.options.cwd; - } +/***/ }), +/* 689 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - 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); - } +"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; } - return fn(task.pattern, options); -}; +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; } -const getPattern = (task, fn) => task.options.expandDirectories ? globDirs(task, fn) : [task.pattern]; +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; } -const globToTask = task => glob => { - const {options} = task; - if (options.ignore && Array.isArray(options.ignore) && options.expandDirectories) { - options.ignore = dirGlob.sync(options.ignore); - } +/* + * 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. + */ - 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); +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) + }); - const getFilter = () => { - return options && options.gitignore ? - gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : - DEFAULT_FILTER; - }; + 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); + } - const tasks = globTasks.reduce((tasks, task) => { - const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); - return tasks.concat(newTask); - }, []); + 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`)); - const filter = getFilter(); - return tasks.reduce( - (matches, task) => arrayUnion(matches, fastGlob.sync(task.pattern, task.options)), - [] - ).filter(p => !filter(p)); -}; + 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); -module.exports.generateGlobTasks = generateGlobTasks; + 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); + } -module.exports.hasMagic = (patterns, options) => [] - .concat(patterns) - .some(pattern => glob.hasMagic(pattern, options)); + process.exit(1); + } +} -module.exports.gitignore = gitignore; +function toArray(value) { + if (value == null) { + return []; + } + return Array.isArray(value) ? value : [value]; +} /***/ }), -/* 710 */ +/* 690 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var arrayUniq = __webpack_require__(711); +const stringWidth = __webpack_require__(691); +const stripAnsi = __webpack_require__(695); -module.exports = function () { - return arrayUniq([].concat.apply([], arguments)); -}; +const ESCAPES = new Set([ + '\u001B', + '\u009B' +]); +const END_CODE = 39; -/***/ }), -/* 711 */ -/***/ (function(module, exports, __webpack_require__) { +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] +]); -"use strict"; +const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`; +// 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)); -// there's 3 implementations written in increasing order of efficiency +// 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); -// 1 - no Set type is defined -function uniqNoSet(arr) { - var ret = []; + let insideEscape = false; + let visible = stringWidth(stripAnsi(rows[rows.length - 1])); - for (var i = 0; i < arr.length; i++) { - if (ret.indexOf(arr[i]) === -1) { - ret.push(arr[i]); + for (const item of arr.entries()) { + const i = item[0]; + const char = item[1]; + const charLength = stringWidth(char); + + if (visible + charLength <= cols) { + rows[rows.length - 1] += char; + } else { + rows.push(char); + visible = 0; } - } - return ret; -} + if (ESCAPES.has(char)) { + insideEscape = true; + } else if (insideEscape && char === 'm') { + insideEscape = false; + continue; + } -// 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 (insideEscape) { + continue; } - return false; - }); -} + visible += charLength; -// 3 - a standard Set type is defined and it has a forEach method -function uniqSetWithForEach(arr) { - var ret = []; + if (visible === cols && i < arr.length - 1) { + rows.push(''); + visible = 0; + } + } - (new Set(arr)).forEach(function (el) { - ret.push(el); - }); + // 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(); + } +}; - return ret; -} +// 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 || {}; -// V8 currently has a broken implementation -// https://github.com/joyent/node/issues/8449 -function doesForEachActuallyWork() { - var ret = false; + if (str.trim() === '') { + return options.trim === false ? str : str.trim(); + } - (new Set([true])).forEach(function (el) { - ret = el; - }); + let pre = ''; + let ret = ''; + let escapeCode; - return ret === true; -} + const lengths = wordLengths(str); + const words = str.split(' '); + const rows = ['']; -if ('Set' in global) { - if (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) { - module.exports = uniqSetWithForEach; - } else { - module.exports = uniqSet; - } -} else { - module.exports = uniqNoSet; -} + for (const item of Array.from(words).entries()) { + const i = item[0]; + const word = item[1]; + rows[rows.length - 1] = options.trim === false ? rows[rows.length - 1] : rows[rows.length - 1].trim(); + let rowLength = stringWidth(rows[rows.length - 1]); -/***/ }), -/* 712 */ -/***/ (function(module, exports, __webpack_require__) { + 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; + } -// 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. + rows[rows.length - 1] += ' '; + rowLength++; + } -module.exports = glob + // 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 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 + if (rowLength + lengths[i] > cols && rowLength > 0) { + if (options.wordWrap === false && rowLength < cols) { + wrapWord(rows, word, cols); + continue; + } -var once = __webpack_require__(385) + rows.push(''); + } -function glob (pattern, options, cb) { - if (typeof options === 'function') cb = options, options = {} - if (!options) options = {} + if (rowLength + lengths[i] > cols && options.wordWrap === false) { + wrapWord(rows, word, cols); + continue; + } - if (options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return globSync(pattern, options) - } + rows[rows.length - 1] += word; + } - return new Glob(pattern, options, cb) -} + pre = rows.map(r => options.trim === false ? r : r.trim()).join('\n'); -glob.sync = globSync -var GlobSync = glob.GlobSync = globSync.GlobSync + for (const item of Array.from(pre).entries()) { + const i = item[0]; + const char = item[1]; -// old api surface -glob.glob = glob + ret += char; -function extend (origin, add) { - if (add === null || typeof add !== 'object') { - return origin - } + if (ESCAPES.has(char)) { + const code = parseFloat(/\d[^m]*/.exec(pre.slice(i, i + 4))); + escapeCode = code === END_CODE ? null : code; + } - var keys = Object.keys(add) - var i = keys.length - while (i--) { - origin[keys[i]] = add[keys[i]] - } - return origin -} + const code = ESCAPE_CODES.get(Number(escapeCode)); -glob.hasMagic = function (pattern, options_) { - var options = extend({}, options_) - options.noprocess = true + if (escapeCode && code) { + if (pre[i + 1] === '\n') { + ret += wrapAnsi(code); + } else if (char === '\n') { + ret += wrapAnsi(escapeCode); + } + } + } - var g = new Glob(pattern, options) - var set = g.minimatch.set + return ret; +}; - if (!pattern) - return false +// 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'); +}; - if (set.length > 1) - return true - for (var j = 0; j < set[0].length; j++) { - if (typeof set[0][j] !== 'string') - return true - } +/***/ }), +/* 691 */ +/***/ (function(module, exports, __webpack_require__) { - return false -} +"use strict"; -glob.Glob = Glob -inherits(Glob, EE) -function Glob (pattern, options, cb) { - if (typeof options === 'function') { - cb = options - options = null - } +const stripAnsi = __webpack_require__(692); +const isFullwidthCodePoint = __webpack_require__(694); - if (options && options.sync) { - if (cb) - throw new TypeError('callback provided to sync glob') - return new GlobSync(pattern, options) - } +module.exports = str => { + if (typeof str !== 'string' || str.length === 0) { + return 0; + } - if (!(this instanceof Glob)) - return new Glob(pattern, options, cb) + str = stripAnsi(str); - setopts(this, pattern, options) - this._didRealPath = false + let width = 0; - // process each pattern in the minimatch set - var n = this.minimatch.set.length + for (let i = 0; i < str.length; i++) { + const code = str.codePointAt(i); - // 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) + // Ignore control characters + if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) { + continue; + } - if (typeof cb === 'function') { - cb = once(cb) - this.on('error', cb) - this.on('end', function (matches) { - cb(null, matches) - }) - } + // Ignore combining characters + if (code >= 0x300 && code <= 0x36F) { + continue; + } - var self = this - this._processing = 0 + // Surrogates + if (code > 0xFFFF) { + i++; + } - this._emitQueue = [] - this._processQueue = [] - this.paused = false + width += isFullwidthCodePoint(code) ? 2 : 1; + } - if (this.noprocess) - return this + return width; +}; - if (n === 0) - return done() - var sync = true - for (var i = 0; i < n; i ++) { - this._process(this.minimatch.set[i], i, false, done) - } - sync = false +/***/ }), +/* 692 */ +/***/ (function(module, exports, __webpack_require__) { - function done () { - --self._processing - if (self._processing <= 0) { - if (sync) { - process.nextTick(function () { - self._finish() - }) - } else { - self._finish() - } - } - } -} +"use strict"; -Glob.prototype._finish = function () { - assert(this instanceof Glob) - if (this.aborted) - return +const ansiRegex = __webpack_require__(693); - if (this.realpath && !this._didRealpath) - return this._realpath() +module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; - common.finish(this) - this.emit('end', this.found) -} -Glob.prototype._realpath = function () { - if (this._didRealpath) - return +/***/ }), +/* 693 */ +/***/ (function(module, exports, __webpack_require__) { - this._didRealpath = true +"use strict"; - var n = this.matches.length - if (n === 0) - return this._finish() - var self = this - for (var i = 0; i < this.matches.length; i++) - this._realpathSet(i, next) +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('|'); - function next () { - if (--n === 0) - self._finish() - } -} + return new RegExp(pattern, 'g'); +}; -Glob.prototype._realpathSet = function (index, cb) { - var matchset = this.matches[index] - if (!matchset) - return cb() - var found = Object.keys(matchset) - var self = this - var n = found.length +/***/ }), +/* 694 */ +/***/ (function(module, exports, __webpack_require__) { - if (n === 0) - return cb() +"use strict"; - 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 +/* eslint-disable yoda */ +module.exports = x => { + if (Number.isNaN(x)) { + return false; + } - if (--n === 0) { - self.matches[index] = set - cb() - } - }) - }) -} + // 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; + } -Glob.prototype._mark = function (p) { - return common.mark(this, p) -} + return false; +}; -Glob.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} -Glob.prototype.abort = function () { - this.aborted = true - this.emit('abort') -} +/***/ }), +/* 695 */ +/***/ (function(module, exports, __webpack_require__) { -Glob.prototype.pause = function () { - if (!this.paused) { - this.paused = true - this.emit('pause') - } -} +"use strict"; -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]) - } - } - } -} +const ansiRegex = __webpack_require__(696); -Glob.prototype._process = function (pattern, index, inGlobStar, cb) { - assert(this instanceof Glob) - assert(typeof cb === 'function') +module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; - if (this.aborted) - return - this._processing++ - if (this.paused) { - this._processQueue.push([pattern, index, inGlobStar, cb]) - return - } +/***/ }), +/* 696 */ +/***/ (function(module, exports, __webpack_require__) { - //console.error('PROCESS %d', this._processing, pattern) +"use strict"; - // 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, cb) - 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('|'); - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break + return new RegExp(pattern, 'g'); +}; - 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 - } - var remain = pattern.slice(n) +/***/ }), +/* 697 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - // 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 +"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. + */ - var abs = this._makeAbs(read) - //if ignored, skip _processing - if (childrenIgnored(this, read)) - return cb() +const projectKey = Symbol('__project'); +function renderProjectsTree(rootPath, projects) { + const projectsTree = buildProjectsTree(rootPath, projects); + return treeToString(createTreeStructure(projectsTree)); +} - 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) +function treeToString(tree) { + return [tree.name].concat(childrenToStrings(tree.children, '')).join('\n'); } -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) - }) +function childrenToStrings(tree, treePrefix) { + if (tree === undefined) { + return []; + } + + 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; } -Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { +function createTreeStructure(tree) { + let name; + const children = []; - // if the abs isn't a dir, then nothing can match! - if (!entries) - return cb() + 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`. - // 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) + if (project.size === 1 && project.has(projectKey)) { + const projectName = project.get(projectKey); + children.push({ + children: [], + name: dirOrProjectName(dir, projectName) + }); + continue; } - } - //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) + const subtree = createTreeStructure(project); // If the name is specified, we know there's a package at the "root" of the + // subtree itself. - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return cb() + 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 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) + 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; + } + + children.push({ + children: subtree.children, + name: chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(dir.toString()) + }); + } + + return { + name, + children + }; +} + +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}})}`; +} - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix !== '/') - e = prefix + '/' + e - else - e = prefix + e - } +function buildProjectsTree(rootPath, projects) { + const tree = new Map(); - if (e.charAt(0) === '/' && !this.nomount) { - e = path.join(this.root, e) - } - this._emitMatch(index, e) + 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); } - // 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() + return tree; } -Glob.prototype._emitMatch = function (index, e) { - if (this.aborted) - return +function addProjectToTree(tree, pathParts, project) { + if (pathParts.length === 0) { + tree.set(projectKey, project.name); + } else { + const [currentDir, ...rest] = pathParts; - if (isIgnored(this, e)) - return + if (!tree.has(currentDir)) { + tree.set(currentDir, new Map()); + } - if (this.paused) { - this._emitQueue.push([index, e]) - return + const subtree = tree.get(currentDir); + addProjectToTree(subtree, rest, project); } +} - var abs = isAbsolute(e) ? e : this._makeAbs(e) +/***/ }), +/* 698 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - if (this.mark) - e = this._mark(e) +"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; } - if (this.absolute) - e = abs +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 (this.matches[index][e]) - return +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; } - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } +/* + * 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. + */ - this.matches[index][e] = true - var st = this.statCache[abs] - if (st) - this.emit('stat', e, st) - this.emit('match', e) -} -Glob.prototype._readdirInGlobStar = function (abs, cb) { - if (this.aborted) - return +/** + * 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. + */ - // follow all symlinked directories forever - // just proceed as if this is a non-globstar situation - if (this.follow) - return this._readdir(abs, false, 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 lstatkey = 'lstat\0' + abs - var self = this - var lstatcb = inflight(lstatkey, lstatcb_) + constructor(allWorkspaceProjects) { + this.allWorkspaceProjects = allWorkspaceProjects; - if (lstatcb) - fs.lstat(abs, lstatcb) + _defineProperty(this, "kibanaProject", void 0); - function lstatcb_ (er, lstat) { - if (er && er.code === 'ENOENT') - return cb() + const kibanaProject = allWorkspaceProjects.get('kibana'); - var isSym = lstat && lstat.isSymbolicLink() - self.symlinks[abs] = isSym + if (!kibanaProject) { + throw new TypeError('Unable to create Kibana object without all projects, including the Kibana project.'); + } - // 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) + this.kibanaProject = kibanaProject; } -} + /** make an absolute path by resolving subPath relative to the kibana repo */ -Glob.prototype._readdir = function (abs, inGlobStar, cb) { - if (this.aborted) - return - cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) - if (!cb) - return + 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 */ - //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() + 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 */ - if (Array.isArray(c)) - return cb(null, c) + + getAllProjects() { + return new Map(this.allWorkspaceProjects); } + /** determine if a project with the given name exists */ - 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) + hasProject(name) { + return this.allWorkspaceProjects.has(name); } -} + /** get a specific project, throws if the name is not known (use hasProject() first) */ -Glob.prototype._readdirEntries = function (abs, entries, cb) { - if (this.aborted) - return - // 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 + getProject(name) { + const project = this.allWorkspaceProjects.get(name); + + if (!project) { + throw new Error(`No package with name "${name}" in the workspace`); } + + return project; } + /** get a project and all of the projects it depends on in a ProjectMap */ - this.cache[abs] = entries - return cb(null, entries) -} -Glob.prototype._readdirError = function (f, er, cb) { - if (this.aborted) - return + 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 */ - // 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 - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break + 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); - 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() + 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); + + if (pathMatches && notExcluded && isIncluded) { + filteredProjects.set(project.name, project); } - if (!this.silent) - console.error('glob error', er) - break + } + + return filteredProjects; } - return cb() } -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) - }) -} +/***/ }), +/* 699 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; -Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - //console.error('pgs2', prefix, remain[0], entries) +const minimatch = __webpack_require__(505); +const arrayUnion = __webpack_require__(700); +const arrayDiffer = __webpack_require__(701); +const arrify = __webpack_require__(702); - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return cb() +module.exports = (list, patterns, options = {}) => { + list = arrify(list); + patterns = arrify(patterns); - // 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 (list.length === 0 || patterns.length === 0) { + return []; + } - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false, cb) + return patterns.reduce((result, pattern) => { + let process = arrayUnion; - var isSym = this.symlinks[abs] - var len = entries.length + if (pattern[0] === '!') { + pattern = pattern.slice(1); + process = arrayDiffer; + } - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return cb() + return process(result, minimatch.match(list, pattern, 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) +/***/ }), +/* 700 */ +/***/ (function(module, exports, __webpack_require__) { - var below = gspref.concat(entries[i], remain) - this._process(below, index, true, cb) - } +"use strict"; - cb() -} -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) { +module.exports = (...arguments_) => { + return [...new Set([].concat(...arguments_))]; +}; - //console.error('ps2', prefix, exists) - if (!this.matches[index]) - this.matches[index] = Object.create(null) +/***/ }), +/* 701 */ +/***/ (function(module, exports, __webpack_require__) { - // If it doesn't exist, then just mark the lack of results - if (!exists) - return cb() +"use strict"; - 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 += '/' - } - } - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') +const arrayDiffer = (array, ...values) => { + const rest = new Set([].concat(...values)); + return array.filter(element => !rest.has(element)); +}; - // Mark this as a match - this._emitMatch(index, prefix) - cb() -} +module.exports = arrayDiffer; -// 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() +/***/ }), +/* 702 */ +/***/ (function(module, exports, __webpack_require__) { - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] +"use strict"; - if (Array.isArray(c)) - c = 'DIR' - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return cb(null, c) +const arrify = value => { + if (value === null || value === undefined) { + return []; + } - if (needDir && c === 'FILE') - return cb() + if (Array.isArray(value)) { + return value; + } - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } + if (typeof value === 'string') { + return [value]; + } - 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) - } - } + if (typeof value[Symbol.iterator] === 'function') { + return [...value]; + } - var self = this - var statcb = inflight('stat\0' + abs, lstatcb_) - if (statcb) - fs.lstat(abs, statcb) + return [value]; +}; - 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) - } - } -} +module.exports = arrify; -Glob.prototype._stat2 = function (f, abs, er, stat, cb) { - if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { - this.statCache[abs] = false - return cb() - } - var needDir = f.slice(-1) === '/' - this.statCache[abs] = stat +/***/ }), +/* 703 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - if (abs.slice(-1) === '/' && stat && !stat.isDirectory()) - return cb(null, false, stat) +"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"]; }); + +/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(920); +/* 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 + * 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. + */ + + + +/***/ }), +/* 704 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"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. + */ - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' - this.cache[abs] = this.cache[abs] || c - if (needDir && c === 'FILE') - return cb() - return cb(null, c, stat) -} -/***/ }), -/* 713 */ -/***/ (function(module, exports, __webpack_require__) { -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); -} -/***/ }), -/* 714 */ -/***/ (function(module, 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(', ')}]`); -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 + for (const batch of batchedProjects) { + for (const project of batch) { + await deleteTarget(project); + await buildProject(project); + await copyToBuild(project, kibanaRoot, buildRoot); } } } +/** + * 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')]; -/***/ }), -/* 715 */ -/***/ (function(module, exports, __webpack_require__) { + if (projects.has('x-pack')) { + projectsSubset.push(projects.get('x-pack')); + } -module.exports = globSync -globSync.GlobSync = GlobSync + const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])(projectsSubset, projects, { + onlyProductionDependencies: true + }); // We remove Kibana, as we're already building Kibana -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 + productionProjects.delete('kibana'); -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') + if (onlyOSS) { + productionProjects.forEach(project => { + if (project.getBuildConfig().oss === false) { + productionProjects.delete(project.json.name); + } + }); + } - return new GlobSync(pattern, options).found + return productionProjects; } -function GlobSync (pattern, options) { - if (!pattern) - throw new Error('must provide pattern') - - 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') - - if (!(this instanceof GlobSync)) - return new GlobSync(pattern, options) - - setopts(this, pattern, options) - - if (this.noprocess) - return this +async function deleteTarget(project) { + const targetDir = project.targetLocation; - 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) + if (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isDirectory"])(targetDir)) { + await del__WEBPACK_IMPORTED_MODULE_1___default()(targetDir, { + force: true + }); } - this._finish() } -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 - } - } - }) +async function buildProject(project) { + if (project.hasScript('build')) { + await project.runScript('build'); } - common.finish(this) } +/** + * 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. + */ -GlobSync.prototype._process = function (pattern, index, inGlobStar) { - assert(this instanceof GlobSync) +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`. - // 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. + 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); +} - // 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 +/***/ }), +/* 705 */ +/***/ (function(module, 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"; - 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 EventEmitter = __webpack_require__(379); +const path = __webpack_require__(16); +const os = __webpack_require__(11); +const pAll = __webpack_require__(706); +const arrify = __webpack_require__(708); +const globby = __webpack_require__(709); +const isGlob = __webpack_require__(601); +const cpFile = __webpack_require__(907); +const junk = __webpack_require__(917); +const CpyError = __webpack_require__(918); - var remain = pattern.slice(n) +const defaultOptions = { + ignoreJunk: true +}; - // 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 preprocessSourcePath = (source, options) => options.cwd ? path.resolve(options.cwd, source) : source; - var abs = this._makeAbs(read) +const preprocessDestinationPath = (source, destination, options) => { + let basename = path.basename(source); + const dirname = path.dirname(source); - //if ignored, skip processing - if (childrenIgnored(this, read)) - return + if (typeof options.rename === 'string') { + basename = options.rename; + } else if (typeof options.rename === 'function') { + basename = options.rename(basename); + } - 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) -} + if (options.cwd) { + destination = path.resolve(options.cwd, destination); + } + if (options.parents) { + return path.join(destination, dirname, basename); + } -GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { - var entries = this._readdir(abs, inGlobStar) + return path.join(destination, basename); +}; - // if the abs isn't a dir, then nothing can match! - if (!entries) - return +module.exports = (source, destination, { + concurrency = (os.cpus().length || 1) * 2, + ...options +} = {}) => { + const progressEmitter = new EventEmitter(); - // 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) === '.' + options = { + ...defaultOptions, + ...options + }; - 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) - } - } + const promise = (async () => { + source = arrify(source); - var len = matchedEntries.length - // If there are no matched entries, then nothing matches. - if (len === 0) - return + if (source.length === 0 || !destination) { + throw new CpyError('`source` and `destination` required'); + } - // 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. + const copyStatus = new Map(); + let completedFiles = 0; + let completedSize = 0; - if (remain.length === 1 && !this.mark && !this.stat) { - if (!this.matches[index]) - this.matches[index] = Object.create(null) + let files; + try { + files = await globby(source, options); - for (var i = 0; i < len; i ++) { - var e = matchedEntries[i] - if (prefix) { - if (prefix.slice(-1) !== '/') - e = prefix + '/' + e - else - e = prefix + e - } + if (options.ignoreJunk) { + files = files.filter(file => junk.not(path.basename(file))); + } + } catch (error) { + throw new CpyError(`Cannot glob \`${source}\`: ${error.message}`, error); + } - 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 - } + const sourcePaths = source.filter(value => !isGlob(value)); - // 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) - } -} + if (files.length === 0 || (sourcePaths.length > 0 && !sourcePaths.every(value => files.includes(value)))) { + throw new CpyError(`Cannot copy \`${source}\`: the file doesn't exist`); + } + const fileProgressHandler = event => { + const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; -GlobSync.prototype._emitMatch = function (index, e) { - if (isIgnored(this, e)) - return + if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { + completedSize -= fileStatus.written; + completedSize += event.written; - var abs = this._makeAbs(e) + if (event.percent === 1 && fileStatus.percent !== 1) { + completedFiles++; + } - if (this.mark) - e = this._mark(e) + copyStatus.set(event.src, { + written: event.written, + percent: event.percent + }); - if (this.absolute) { - e = abs - } + progressEmitter.emit('progress', { + totalFiles: files.length, + percent: completedFiles / files.length, + completedFiles, + completedSize + }); + } + }; - if (this.matches[index][e]) - return + return pAll(files.map(sourcePath => { + return async () => { + const from = preprocessSourcePath(sourcePath, options); + const to = preprocessDestinationPath(sourcePath, destination, options); - if (this.nodir) { - var c = this.cache[abs] - if (c === 'DIR' || Array.isArray(c)) - return - } + try { + await cpFile(from, to, options).on('progress', fileProgressHandler); + } catch (error) { + throw new CpyError(`Cannot copy from \`${from}\` to \`${to}\`: ${error.message}`, error); + } - this.matches[index][e] = true + return to; + }; + }), {concurrency}); + })(); - if (this.stat) - this._stat(e) -} + promise.on = (...arguments_) => { + progressEmitter.on(...arguments_); + return promise; + }; + return promise; +}; -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) - var entries - var lstat - var stat - try { - lstat = fs.lstatSync(abs) - } catch (er) { - if (er.code === 'ENOENT') { - // lstat failed, doesn't exist - return null - } - } +/***/ }), +/* 706 */ +/***/ (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 pMap = __webpack_require__(707); - return entries -} +module.exports = (iterable, options) => pMap(iterable, element => element(), options); +// TODO: Remove this for the next major release +module.exports.default = module.exports; -GlobSync.prototype._readdir = function (abs, inGlobStar) { - var entries - if (inGlobStar && !ownProp(this.symlinks, abs)) - return this._readdirInGlobStar(abs) +/***/ }), +/* 707 */ +/***/ (function(module, exports, __webpack_require__) { - if (ownProp(this.cache, abs)) { - var c = this.cache[abs] - if (!c || c === 'FILE') - return null +"use strict"; - if (Array.isArray(c)) - return c - } - try { - return this._readdirEntries(abs, fs.readdirSync(abs)) - } catch (er) { - this._readdirError(abs, er) - return null - } -} +const pMap = (iterable, mapper, options) => new Promise((resolve, reject) => { + options = Object.assign({ + concurrency: Infinity + }, options); -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 - } - } + if (typeof mapper !== 'function') { + throw new TypeError('Mapper function is required'); + } - this.cache[abs] = entries + const {concurrency} = options; - // mark and cache dir-ness - return entries -} + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } -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 ret = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let isIterableDone = false; + let resolvingCount = 0; + let currentIndex = 0; - case 'ENOENT': // not terribly unusual - case 'ELOOP': - case 'ENAMETOOLONG': - case 'UNKNOWN': - this.cache[this._makeAbs(f)] = false - break + const next = () => { + if (isRejected) { + return; + } - 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 nextItem = iterator.next(); + const i = currentIndex; + currentIndex++; -GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { + if (nextItem.done) { + isIterableDone = true; - var entries = this._readdir(abs, inGlobStar) + if (resolvingCount === 0) { + resolve(ret); + } - // no entries means not a dir, so it can never have matches - // foo.txt/** doesn't match foo.txt - if (!entries) - return + return; + } - // 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) + resolvingCount++; - // the noGlobStar pattern exits the inGlobStar state - this._process(noGlobStar, index, false) + Promise.resolve(nextItem.value) + .then(element => mapper(element, i)) + .then( + value => { + ret[i] = value; + resolvingCount--; + next(); + }, + error => { + isRejected = true; + reject(error); + } + ); + }; + + for (let i = 0; i < concurrency; i++) { + next(); + + if (isIterableDone) { + break; + } + } +}); - var len = entries.length - var isSym = this.symlinks[abs] +module.exports = pMap; +// TODO: Remove this for the next major release +module.exports.default = pMap; - // If it's a symlink, and we're in a globstar, then stop - if (isSym && inGlobStar) - return - for (var i = 0; i < len; i++) { - var e = entries[i] - if (e.charAt(0) === '.' && !this.dot) - continue +/***/ }), +/* 708 */ +/***/ (function(module, exports, __webpack_require__) { - // these two cases enter the inGlobStar state - var instead = gspref.concat(entries[i], remainWithoutGlobStar) - this._process(instead, index, true) +"use strict"; - 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) +const arrify = value => { + if (value === null || value === undefined) { + return []; + } - if (!this.matches[index]) - this.matches[index] = Object.create(null) + if (Array.isArray(value)) { + return value; + } - // If it doesn't exist, then just mark the lack of results - if (!exists) - return + if (typeof value === 'string') { + return [value]; + } - 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 += '/' - } - } + if (typeof value[Symbol.iterator] === 'function') { + return [...value]; + } - if (process.platform === 'win32') - prefix = prefix.replace(/\\/g, '/') + return [value]; +}; - // Mark this as a match - this._emitMatch(index, prefix) -} +module.exports = arrify; -// Returns either 'DIR', 'FILE', or false -GlobSync.prototype._stat = function (f) { - var abs = this._makeAbs(f) - var needDir = f.slice(-1) === '/' - if (f.length > this.maxLength) - return false +/***/ }), +/* 709 */ +/***/ (function(module, exports, __webpack_require__) { - if (!this.stat && ownProp(this.cache, abs)) { - var c = this.cache[abs] +"use strict"; - if (Array.isArray(c)) - c = 'DIR' +const fs = __webpack_require__(23); +const arrayUnion = __webpack_require__(710); +const glob = __webpack_require__(502); +const fastGlob = __webpack_require__(712); +const dirGlob = __webpack_require__(900); +const gitignore = __webpack_require__(903); - // It exists, but maybe not how we need it - if (!needDir || c === 'DIR') - return c +const DEFAULT_FILTER = () => false; - if (needDir && c === 'FILE') - return false +const isNegative = pattern => pattern[0] === '!'; - // otherwise we have to stat, because maybe c=true - // if we know it exists, but not what it is. - } +const assertPatternsInput = patterns => { + if (!patterns.every(x => typeof x === 'string')) { + throw new TypeError('Patterns must be a string or an array of strings'); + } +}; - 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 checkCwdOption = options => { + if (options && options.cwd && !fs.statSync(options.cwd).isDirectory()) { + throw new Error('The `cwd` option must be a path to a directory'); + } +}; - if (lstat && lstat.isSymbolicLink()) { - try { - stat = fs.statSync(abs) - } catch (er) { - stat = lstat - } - } else { - stat = lstat - } - } +const generateGlobTasks = (patterns, taskOptions) => { + patterns = arrayUnion([].concat(patterns)); + assertPatternsInput(patterns); + checkCwdOption(taskOptions); - this.statCache[abs] = stat + const globTasks = []; - var c = true - if (stat) - c = stat.isDirectory() ? 'DIR' : 'FILE' + taskOptions = Object.assign({ + ignore: [], + expandDirectories: true + }, taskOptions); - this.cache[abs] = this.cache[abs] || c + patterns.forEach((pattern, i) => { + if (isNegative(pattern)) { + return; + } - if (needDir && c === 'FILE') - return false + const ignore = patterns + .slice(i) + .filter(isNegative) + .map(pattern => pattern.slice(1)); - return c -} + const options = Object.assign({}, taskOptions, { + ignore: taskOptions.ignore.concat(ignore) + }); -GlobSync.prototype._mark = function (p) { - return common.mark(this, p) -} + globTasks.push({pattern, options}); + }); -GlobSync.prototype._makeAbs = function (f) { - return common.makeAbs(this, f) -} + return globTasks; +}; +const globDirs = (task, fn) => { + let options = {}; + if (task.options.cwd) { + options.cwd = task.options.cwd; + } -/***/ }), -/* 716 */ -/***/ (function(module, exports, __webpack_require__) { + 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); + } -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 fn(task.pattern, options); +}; -function ownProp (obj, field) { - return Object.prototype.hasOwnProperty.call(obj, field) -} +const getPattern = (task, fn) => task.options.expandDirectories ? globDirs(task, fn) : [task.pattern]; -var path = __webpack_require__(16) -var minimatch = __webpack_require__(505) -var isAbsolute = __webpack_require__(511) -var Minimatch = minimatch.Minimatch +const globToTask = task => glob => { + const {options} = task; + if (options.ignore && Array.isArray(options.ignore) && options.expandDirectories) { + options.ignore = dirGlob.sync(options.ignore); + } -function alphasorti (a, b) { - return a.toLowerCase().localeCompare(b.toLowerCase()) -} + return { + pattern: glob, + options + }; +}; -function alphasort (a, b) { - return a.localeCompare(b) -} +const globby = (patterns, options) => { + let globTasks; -function setupIgnores (self, options) { - self.ignore = options.ignore || [] + try { + globTasks = generateGlobTasks(patterns, options); + } catch (error) { + return Promise.reject(error); + } - if (!Array.isArray(self.ignore)) - self.ignore = [self.ignore] + const getTasks = Promise.all(globTasks.map(task => Promise.resolve(getPattern(task, dirGlob)) + .then(globs => Promise.all(globs.map(globToTask(task)))) + )) + .then(tasks => arrayUnion(...tasks)); - if (self.ignore.length) { - self.ignore = self.ignore.map(ignoreMap) - } -} + const getFilter = () => { + return Promise.resolve( + options && options.gitignore ? + gitignore({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER + ); + }; -// 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 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))); + }); +}; - return { - matcher: new Minimatch(pattern, { dot: true }), - gmatcher: gmatcher - } -} +module.exports = globby; +// TODO: Remove this for the next major release +module.exports.default = globby; -function setopts (self, pattern, options) { - if (!options) - options = {} +module.exports.sync = (patterns, options) => { + const globTasks = generateGlobTasks(patterns, options); - // 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 getFilter = () => { + return options && options.gitignore ? + gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER; + }; - 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 + const tasks = globTasks.reduce((tasks, task) => { + const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); + return tasks.concat(newTask); + }, []); - 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 filter = getFilter(); + return tasks.reduce( + (matches, task) => arrayUnion(matches, fastGlob.sync(task.pattern, task.options)), + [] + ).filter(p => !filter(p)); +}; - setupIgnores(self, options) +module.exports.generateGlobTasks = generateGlobTasks; - 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 - } +module.exports.hasMagic = (patterns, options) => [] + .concat(patterns) + .some(pattern => glob.hasMagic(pattern, options)); - self.root = options.root || path.resolve(self.cwd, "/") - self.root = path.resolve(self.root) - if (process.platform === "win32") - self.root = self.root.replace(/\\/g, "/") +module.exports.gitignore = gitignore; - // 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 - // disable comments and negation in Minimatch. - // Note that they are not supported in Glob itself anyway. - options.nonegate = true - options.nocomment = true +/***/ }), +/* 710 */ +/***/ (function(module, exports, __webpack_require__) { - self.minimatch = new Minimatch(pattern, options) - self.options = self.minimatch.options -} +"use strict"; -function finish (self) { - var nou = self.nounique - var all = nou ? [] : Object.create(null) +var arrayUniq = __webpack_require__(711); - 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 - }) - } - } +module.exports = function () { + return arrayUniq([].concat.apply([], arguments)); +}; - if (!nou) - all = Object.keys(all) - if (!self.nosort) - all = all.sort(self.nocase ? alphasorti : alphasort) +/***/ }), +/* 711 */ +/***/ (function(module, exports, __webpack_require__) { - // 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 - }) - } - } +"use strict"; - if (self.ignore.length) - all = all.filter(function(m) { - return !isIgnored(self, m) - }) - self.found = all -} +// there's 3 implementations written in increasing order of efficiency -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) === '/' +// 1 - no Set type is defined +function uniqNoSet(arr) { + var ret = []; - if (isDir && !slash) - m += '/' - else if (!isDir && slash) - m = m.slice(0, -1) + for (var i = 0; i < arr.length; i++) { + if (ret.indexOf(arr[i]) === -1) { + ret.push(arr[i]); + } + } - if (m !== p) { - var mabs = makeAbs(self, m) - self.statCache[mabs] = self.statCache[abs] - self.cache[mabs] = self.cache[abs] - } - } + return ret; +} - return m +// 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; + } + + return false; + }); } -// 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) - } +// 3 - a standard Set type is defined and it has a forEach method +function uniqSetWithForEach(arr) { + var ret = []; - if (process.platform === 'win32') - abs = abs.replace(/\\/g, '/') + (new Set(arr)).forEach(function (el) { + ret.push(el); + }); - return abs + return ret; } +// V8 currently has a broken implementation +// https://github.com/joyent/node/issues/8449 +function doesForEachActuallyWork() { + var ret = false; -// 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 + (new Set([true])).forEach(function (el) { + ret = el; + }); - return self.ignore.some(function(item) { - return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) - }) + return ret === true; } -function childrenIgnored (self, path) { - if (!self.ignore.length) - return false - - return self.ignore.some(function(item) { - return !!(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; } /***/ }), -/* 717 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(718); +const pkg = __webpack_require__(713); module.exports = pkg.async; module.exports.default = pkg.async; @@ -82802,19 +80557,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 718 */ +/* 713 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -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); +var optionsManager = __webpack_require__(714); +var taskManager = __webpack_require__(715); +var reader_async_1 = __webpack_require__(871); +var reader_stream_1 = __webpack_require__(895); +var reader_sync_1 = __webpack_require__(896); +var arrayUtils = __webpack_require__(898); +var streamUtils = __webpack_require__(899); /** * Synchronous API. */ @@ -82880,7 +80635,7 @@ function isString(source) { /***/ }), -/* 719 */ +/* 714 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82918,13 +80673,13 @@ exports.prepare = prepare; /***/ }), -/* 720 */ +/* 715 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(721); +var patternUtils = __webpack_require__(716); /** * Generate tasks based on parent directory of each pattern. */ @@ -83015,16 +80770,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 721 */ +/* 716 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var globParent = __webpack_require__(722); -var isGlob = __webpack_require__(725); -var micromatch = __webpack_require__(726); +var globParent = __webpack_require__(717); +var isGlob = __webpack_require__(720); +var micromatch = __webpack_require__(721); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -83170,15 +80925,15 @@ exports.matchAny = matchAny; /***/ }), -/* 722 */ +/* 717 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(16); -var isglob = __webpack_require__(723); -var pathDirname = __webpack_require__(724); +var isglob = __webpack_require__(718); +var pathDirname = __webpack_require__(719); var isWin32 = __webpack_require__(11).platform() === 'win32'; module.exports = function globParent(str) { @@ -83201,7 +80956,7 @@ module.exports = function globParent(str) { /***/ }), -/* 723 */ +/* 718 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -83211,7 +80966,7 @@ module.exports = function globParent(str) { * Licensed under the MIT License. */ -var isExtglob = __webpack_require__(607); +var isExtglob = __webpack_require__(602); module.exports = function isGlob(str) { if (typeof str !== 'string' || str === '') { @@ -83232,7 +80987,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 724 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83382,7 +81137,7 @@ module.exports.win32 = win32; /***/ }), -/* 725 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -83392,7 +81147,7 @@ module.exports.win32 = win32; * Released under the MIT License. */ -var isExtglob = __webpack_require__(607); +var isExtglob = __webpack_require__(602); var chars = { '{': '}', '(': ')', '[': ']'}; module.exports = function isGlob(str, options) { @@ -83434,7 +81189,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 726 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83445,18 +81200,18 @@ module.exports = function isGlob(str, options) { */ var util = __webpack_require__(29); -var braces = __webpack_require__(727); -var toRegex = __webpack_require__(829); -var extend = __webpack_require__(837); +var braces = __webpack_require__(722); +var toRegex = __webpack_require__(824); +var extend = __webpack_require__(832); /** * Local dependencies */ -var compilers = __webpack_require__(840); -var parsers = __webpack_require__(872); -var cache = __webpack_require__(873); -var utils = __webpack_require__(874); +var compilers = __webpack_require__(835); +var parsers = __webpack_require__(867); +var cache = __webpack_require__(868); +var utils = __webpack_require__(869); var MAX_LENGTH = 1024 * 64; /** @@ -84318,7 +82073,7 @@ module.exports = micromatch; /***/ }), -/* 727 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84328,18 +82083,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(728); -var unique = __webpack_require__(740); -var extend = __webpack_require__(737); +var toRegex = __webpack_require__(723); +var unique = __webpack_require__(735); +var extend = __webpack_require__(732); /** * Local dependencies */ -var compilers = __webpack_require__(741); -var parsers = __webpack_require__(756); -var Braces = __webpack_require__(766); -var utils = __webpack_require__(742); +var compilers = __webpack_require__(736); +var parsers = __webpack_require__(751); +var Braces = __webpack_require__(761); +var utils = __webpack_require__(737); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -84643,15 +82398,15 @@ module.exports = braces; /***/ }), -/* 728 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(729); -var extend = __webpack_require__(737); -var not = __webpack_require__(739); +var define = __webpack_require__(724); +var extend = __webpack_require__(732); +var not = __webpack_require__(734); var MAX_LENGTH = 1024 * 64; /** @@ -84798,7 +82553,7 @@ module.exports.makeRe = makeRe; /***/ }), -/* 729 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84811,7 +82566,7 @@ module.exports.makeRe = makeRe; -var isDescriptor = __webpack_require__(730); +var isDescriptor = __webpack_require__(725); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -84836,7 +82591,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 730 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84849,25 +82604,466 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(731); -var isAccessor = __webpack_require__(732); -var isData = __webpack_require__(735); +var typeOf = __webpack_require__(726); +var isAccessor = __webpack_require__(727); +var isData = __webpack_require__(730); + +module.exports = function isDescriptor(obj, key) { + if (typeOf(obj) !== 'object') { + return false; + } + if ('get' in obj) { + return isAccessor(obj, key); + } + return isData(obj, key); +}; + + +/***/ }), +/* 726 */ +/***/ (function(module, exports) { + +var toString = Object.prototype.toString; + +/** + * Get the native `typeof` a value. + * + * @param {*} `val` + * @return {*} Native javascript type + */ + +module.exports = function kindOf(val) { + var type = typeof val; + + // primitivies + if (type === 'undefined') { + return 'undefined'; + } + if (val === null) { + return 'null'; + } + if (val === true || val === false || val instanceof Boolean) { + return 'boolean'; + } + if (type === 'string' || val instanceof String) { + return 'string'; + } + if (type === 'number' || val instanceof Number) { + return 'number'; + } + + // functions + if (type === 'function' || val instanceof Function) { + if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { + return 'generatorfunction'; + } + return 'function'; + } + + // array + if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { + return 'array'; + } + + // check for instances of RegExp and Date before calling `toString` + if (val instanceof RegExp) { + return 'regexp'; + } + if (val instanceof Date) { + return 'date'; + } + + // other objects + type = toString.call(val); + + if (type === '[object RegExp]') { + return 'regexp'; + } + if (type === '[object Date]') { + return 'date'; + } + if (type === '[object Arguments]') { + return 'arguments'; + } + if (type === '[object Error]') { + return 'error'; + } + if (type === '[object Promise]') { + return 'promise'; + } + + // buffer + if (isBuffer(val)) { + return 'buffer'; + } + + // es6: Map, WeakMap, Set, WeakSet + if (type === '[object Set]') { + return 'set'; + } + if (type === '[object WeakSet]') { + return 'weakset'; + } + if (type === '[object Map]') { + return 'map'; + } + if (type === '[object WeakMap]') { + return 'weakmap'; + } + if (type === '[object Symbol]') { + return 'symbol'; + } + + if (type === '[object Map Iterator]') { + return 'mapiterator'; + } + if (type === '[object Set Iterator]') { + return 'setiterator'; + } + if (type === '[object String Iterator]') { + return 'stringiterator'; + } + if (type === '[object Array Iterator]') { + return 'arrayiterator'; + } + + // typed arrays + if (type === '[object Int8Array]') { + return 'int8array'; + } + if (type === '[object Uint8Array]') { + return 'uint8array'; + } + if (type === '[object Uint8ClampedArray]') { + return 'uint8clampedarray'; + } + if (type === '[object Int16Array]') { + return 'int16array'; + } + if (type === '[object Uint16Array]') { + return 'uint16array'; + } + if (type === '[object Int32Array]') { + return 'int32array'; + } + if (type === '[object Uint32Array]') { + return 'uint32array'; + } + if (type === '[object Float32Array]') { + return 'float32array'; + } + if (type === '[object Float64Array]') { + return 'float64array'; + } + + // must be a plain object + return 'object'; +}; + +/** + * If you need to support Safari 5-7 (8-10 yr-old browser), + * take a look at https://github.com/feross/is-buffer + */ + +function isBuffer(val) { + return val.constructor + && typeof val.constructor.isBuffer === 'function' + && val.constructor.isBuffer(val); +} + + +/***/ }), +/* 727 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * is-accessor-descriptor + * + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. + */ + + + +var typeOf = __webpack_require__(728); + +// accessor descriptor properties +var accessor = { + get: 'function', + set: 'function', + configurable: 'boolean', + enumerable: 'boolean' +}; + +function isAccessorDescriptor(obj, prop) { + if (typeof prop === 'string') { + var val = Object.getOwnPropertyDescriptor(obj, prop); + return typeof val !== 'undefined'; + } + + if (typeOf(obj) !== 'object') { + return false; + } + + if (has(obj, 'value') || has(obj, 'writable')) { + return false; + } + + if (!has(obj, 'get') || typeof obj.get !== 'function') { + return false; + } + + // tldr: it's valid to have "set" be undefined + // "set" might be undefined if `Object.getOwnPropertyDescriptor` + // was used to get the value, and only `get` was defined by the user + if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { + return false; + } + + for (var key in obj) { + if (!accessor.hasOwnProperty(key)) { + continue; + } + + if (typeOf(obj[key]) === accessor[key]) { + continue; + } + + if (typeof obj[key] !== 'undefined') { + return false; + } + } + return true; +} + +function has(obj, key) { + return {}.hasOwnProperty.call(obj, key); +} + +/** + * Expose `isAccessorDescriptor` + */ + +module.exports = isAccessorDescriptor; + + +/***/ }), +/* 728 */ +/***/ (function(module, exports, __webpack_require__) { + +var isBuffer = __webpack_require__(729); +var toString = Object.prototype.toString; + +/** + * Get the native `typeof` a value. + * + * @param {*} `val` + * @return {*} Native javascript type + */ + +module.exports = function kindOf(val) { + // primitivies + if (typeof val === 'undefined') { + return 'undefined'; + } + if (val === null) { + return 'null'; + } + if (val === true || val === false || val instanceof Boolean) { + return 'boolean'; + } + if (typeof val === 'string' || val instanceof String) { + return 'string'; + } + if (typeof val === 'number' || val instanceof Number) { + return 'number'; + } + + // functions + if (typeof val === 'function' || val instanceof Function) { + return 'function'; + } + + // array + if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { + return 'array'; + } + + // check for instances of RegExp and Date before calling `toString` + if (val instanceof RegExp) { + return 'regexp'; + } + if (val instanceof Date) { + return 'date'; + } + + // other objects + var type = toString.call(val); + + if (type === '[object RegExp]') { + return 'regexp'; + } + if (type === '[object Date]') { + return 'date'; + } + if (type === '[object Arguments]') { + return 'arguments'; + } + if (type === '[object Error]') { + return 'error'; + } + + // buffer + if (isBuffer(val)) { + return 'buffer'; + } + + // es6: Map, WeakMap, Set, WeakSet + if (type === '[object Set]') { + return 'set'; + } + if (type === '[object WeakSet]') { + return 'weakset'; + } + if (type === '[object Map]') { + return 'map'; + } + if (type === '[object WeakMap]') { + return 'weakmap'; + } + if (type === '[object Symbol]') { + return 'symbol'; + } + + // typed arrays + if (type === '[object Int8Array]') { + return 'int8array'; + } + if (type === '[object Uint8Array]') { + return 'uint8array'; + } + if (type === '[object Uint8ClampedArray]') { + return 'uint8clampedarray'; + } + if (type === '[object Int16Array]') { + return 'int16array'; + } + if (type === '[object Uint16Array]') { + return 'uint16array'; + } + if (type === '[object Int32Array]') { + return 'int32array'; + } + if (type === '[object Uint32Array]') { + return 'uint32array'; + } + if (type === '[object Float32Array]') { + return 'float32array'; + } + if (type === '[object Float64Array]') { + return 'float64array'; + } + + // must be a plain object + return 'object'; +}; + + +/***/ }), +/* 729 */ +/***/ (function(module, exports) { + +/*! + * Determine if an object is a Buffer + * + * @author Feross Aboukhadijeh + * @license MIT + */ + +// The _isBuffer check is for Safari 5-7 support, because it's missing +// Object.prototype.constructor. Remove this eventually +module.exports = function (obj) { + return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) +} + +function isBuffer (obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) +} + +// For Node v0.10 support. Remove this eventually. +function isSlowBuffer (obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) +} + + +/***/ }), +/* 730 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * is-data-descriptor + * + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. + */ + + + +var typeOf = __webpack_require__(731); + +// data descriptor properties +var data = { + configurable: 'boolean', + enumerable: 'boolean', + writable: 'boolean' +}; + +function isDataDescriptor(obj, prop) { + if (typeOf(obj) !== 'object') { + return false; + } + + if (typeof prop === 'string') { + var val = Object.getOwnPropertyDescriptor(obj, prop); + return typeof val !== 'undefined'; + } + + if (!('value' in obj) && !('writable' in obj)) { + return false; + } + + for (var key in obj) { + if (key === 'value') continue; + + if (!data.hasOwnProperty(key)) { + continue; + } + + if (typeOf(obj[key]) === data[key]) { + continue; + } + + if (typeof obj[key] !== 'undefined') { + return false; + } + } + return true; +} + +/** + * Expose `isDataDescriptor` + */ -module.exports = function isDescriptor(obj, key) { - if (typeOf(obj) !== 'object') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); - } - return isData(obj, key); -}; +module.exports = isDataDescriptor; /***/ }), /* 731 */ -/***/ (function(module, exports) { +/***/ (function(module, exports, __webpack_require__) { +var isBuffer = __webpack_require__(729); var toString = Object.prototype.toString; /** @@ -84878,10 +83074,8 @@ var toString = Object.prototype.toString; */ module.exports = function kindOf(val) { - var type = typeof val; - // primitivies - if (type === 'undefined') { + if (typeof val === 'undefined') { return 'undefined'; } if (val === null) { @@ -84890,18 +83084,15 @@ module.exports = function kindOf(val) { if (val === true || val === false || val instanceof Boolean) { return 'boolean'; } - if (type === 'string' || val instanceof String) { + if (typeof val === 'string' || val instanceof String) { return 'string'; } - if (type === 'number' || val instanceof Number) { + if (typeof val === 'number' || val instanceof Number) { return 'number'; } // functions - if (type === 'function' || val instanceof Function) { - if (typeof val.constructor.name !== 'undefined' && val.constructor.name.slice(0, 9) === 'Generator') { - return 'generatorfunction'; - } + if (typeof val === 'function' || val instanceof Function) { return 'function'; } @@ -84919,7 +83110,7 @@ module.exports = function kindOf(val) { } // other objects - type = toString.call(val); + var type = toString.call(val); if (type === '[object RegExp]') { return 'regexp'; @@ -84933,9 +83124,6 @@ module.exports = function kindOf(val) { if (type === '[object Error]') { return 'error'; } - if (type === '[object Promise]') { - return 'promise'; - } // buffer if (isBuffer(val)) { @@ -84958,20 +83146,7 @@ module.exports = function kindOf(val) { if (type === '[object Symbol]') { return 'symbol'; } - - if (type === '[object Map Iterator]') { - return 'mapiterator'; - } - if (type === '[object Set Iterator]') { - return 'setiterator'; - } - if (type === '[object String Iterator]') { - return 'stringiterator'; - } - if (type === '[object Array Iterator]') { - return 'arrayiterator'; - } - + // typed arrays if (type === '[object Int8Array]') { return 'int8array'; @@ -85005,448 +83180,1035 @@ module.exports = function kindOf(val) { return 'object'; }; + +/***/ }), +/* 732 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var isObject = __webpack_require__(733); + +module.exports = function extend(o/*, objects*/) { + if (!isObject(o)) { o = {}; } + + var len = arguments.length; + for (var i = 1; i < len; i++) { + var obj = arguments[i]; + + if (isObject(obj)) { + assign(o, obj); + } + } + return o; +}; + +function assign(a, b) { + for (var key in b) { + if (hasOwn(b, key)) { + a[key] = b[key]; + } + } +} + +/** + * Returns true if the given `key` is an own property of `obj`. + */ + +function hasOwn(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); +} + + +/***/ }), +/* 733 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * is-extendable + * + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. + */ + + + +module.exports = function isExtendable(val) { + return typeof val !== 'undefined' && val !== null + && (typeof val === 'object' || typeof val === 'function'); +}; + + +/***/ }), +/* 734 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var extend = __webpack_require__(732); + +/** + * The main export is a function that takes a `pattern` string and an `options` object. + * + * ```js + & var not = require('regex-not'); + & console.log(not('foo')); + & //=> /^(?:(?!^(?:foo)$).)*$/ + * ``` + * + * @param {String} `pattern` + * @param {Object} `options` + * @return {RegExp} Converts the given `pattern` to a regex using the specified `options`. + * @api public + */ + +function toRegex(pattern, options) { + return new RegExp(toRegex.create(pattern, options)); +} + +/** + * Create a regex-compatible string from the given `pattern` and `options`. + * + * ```js + & var not = require('regex-not'); + & console.log(not.create('foo')); + & //=> '^(?:(?!^(?:foo)$).)*$' + * ``` + * @param {String} `pattern` + * @param {Object} `options` + * @return {String} + * @api public + */ + +toRegex.create = function(pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected a string'); + } + + var opts = extend({}, options); + if (opts && opts.contains === true) { + opts.strictNegate = false; + } + + var open = opts.strictOpen !== false ? '^' : ''; + var close = opts.strictClose !== false ? '$' : ''; + var endChar = opts.endChar ? opts.endChar : '+'; + var str = pattern; + + if (opts && opts.strictNegate === false) { + str = '(?:(?!(?:' + pattern + ')).)' + endChar; + } else { + str = '(?:(?!^(?:' + pattern + ')$).)' + endChar; + } + + return open + str + close; +}; + +/** + * Expose `toRegex` + */ + +module.exports = toRegex; + + +/***/ }), +/* 735 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * array-unique + * + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. + */ + + + +module.exports = function unique(arr) { + if (!Array.isArray(arr)) { + throw new TypeError('array-unique expects an array.'); + } + + var len = arr.length; + var i = -1; + + while (i++ < len) { + var j = i + 1; + + for (; j < arr.length; ++j) { + if (arr[i] === arr[j]) { + arr.splice(j--, 1); + } + } + } + return arr; +}; + +module.exports.immutable = function uniqueImmutable(arr) { + if (!Array.isArray(arr)) { + throw new TypeError('array-unique expects an array.'); + } + + var arrLen = arr.length; + var newArr = new Array(arrLen); + + for (var i = 0; i < arrLen; i++) { + newArr[i] = arr[i]; + } + + return module.exports(newArr); +}; + + +/***/ }), +/* 736 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var utils = __webpack_require__(737); + +module.exports = function(braces, options) { + braces.compiler + + /** + * bos + */ + + .set('bos', function() { + if (this.output) return; + this.ast.queue = isEscaped(this.ast) ? [this.ast.val] : []; + this.ast.count = 1; + }) + + /** + * Square brackets + */ + + .set('bracket', function(node) { + var close = node.close; + var open = !node.escaped ? '[' : '\\['; + var negated = node.negated; + var inner = node.inner; + + inner = inner.replace(/\\(?=[\\\w]|$)/g, '\\\\'); + if (inner === ']-') { + inner = '\\]\\-'; + } + + if (negated && inner.indexOf('.') === -1) { + inner += '.'; + } + if (negated && inner.indexOf('/') === -1) { + inner += '/'; + } + + var val = open + negated + inner + close; + var queue = node.parent.queue; + var last = utils.arrayify(queue.pop()); + + queue.push(utils.join(last, val)); + queue.push.apply(queue, []); + }) + + /** + * Brace + */ + + .set('brace', function(node) { + node.queue = isEscaped(node) ? [node.val] : []; + node.count = 1; + return this.mapVisit(node.nodes); + }) + + /** + * Open + */ + + .set('brace.open', function(node) { + node.parent.open = node.val; + }) + + /** + * Inner + */ + + .set('text', function(node) { + var queue = node.parent.queue; + var escaped = node.escaped; + var segs = [node.val]; + + if (node.optimize === false) { + options = utils.extend({}, options, {optimize: false}); + } + + if (node.multiplier > 1) { + node.parent.count *= node.multiplier; + } + + if (options.quantifiers === true && utils.isQuantifier(node.val)) { + escaped = true; + + } else if (node.val.length > 1) { + if (isType(node.parent, 'brace') && !isEscaped(node)) { + var expanded = utils.expand(node.val, options); + segs = expanded.segs; + + if (expanded.isOptimized) { + node.parent.isOptimized = true; + } + + // if nothing was expanded, we probably have a literal brace + if (!segs.length) { + var val = (expanded.val || node.val); + if (options.unescape !== false) { + // unescape unexpanded brace sequence/set separators + val = val.replace(/\\([,.])/g, '$1'); + // strip quotes + val = val.replace(/["'`]/g, ''); + } + + segs = [val]; + escaped = true; + } + } + + } else if (node.val === ',') { + if (options.expand) { + node.parent.queue.push(['']); + segs = ['']; + } else { + segs = ['|']; + } + } else { + escaped = true; + } + + if (escaped && isType(node.parent, 'brace')) { + if (node.parent.nodes.length <= 4 && node.parent.count === 1) { + node.parent.escaped = true; + } else if (node.parent.length <= 3) { + node.parent.escaped = true; + } + } + + if (!hasQueue(node.parent)) { + node.parent.queue = segs; + return; + } + + var last = utils.arrayify(queue.pop()); + if (node.parent.count > 1 && options.expand) { + last = multiply(last, node.parent.count); + node.parent.count = 1; + } + + queue.push(utils.join(utils.flatten(last), segs.shift())); + queue.push.apply(queue, segs); + }) + + /** + * Close + */ + + .set('brace.close', function(node) { + var queue = node.parent.queue; + var prev = node.parent.parent; + var last = prev.queue.pop(); + var open = node.parent.open; + var close = node.val; + + if (open && close && isOptimized(node, options)) { + open = '('; + close = ')'; + } + + // if a close brace exists, and the previous segment is one character + // don't wrap the result in braces or parens + var ele = utils.last(queue); + if (node.parent.count > 1 && options.expand) { + ele = multiply(queue.pop(), node.parent.count); + node.parent.count = 1; + queue.push(ele); + } + + if (close && typeof ele === 'string' && ele.length === 1) { + open = ''; + close = ''; + } + + if ((isLiteralBrace(node, options) || noInner(node)) && !node.parent.hasEmpty) { + queue.push(utils.join(open, queue.pop() || '')); + queue = utils.flatten(utils.join(queue, close)); + } + + if (typeof last === 'undefined') { + prev.queue = [queue]; + } else { + prev.queue.push(utils.flatten(utils.join(last, queue))); + } + }) + + /** + * eos + */ + + .set('eos', function(node) { + if (this.input) return; + + if (options.optimize !== false) { + this.output = utils.last(utils.flatten(this.ast.queue)); + } else if (Array.isArray(utils.last(this.ast.queue))) { + this.output = utils.flatten(this.ast.queue.pop()); + } else { + this.output = utils.flatten(this.ast.queue); + } + + if (node.parent.count > 1 && options.expand) { + this.output = multiply(this.output, node.parent.count); + } + + this.output = utils.arrayify(this.output); + this.ast.queue = []; + }); + +}; + +/** + * Multiply the segments in the current brace level + */ + +function multiply(queue, n, options) { + return utils.flatten(utils.repeat(utils.arrayify(queue), n)); +} + +/** + * Return true if `node` is escaped + */ + +function isEscaped(node) { + return node.escaped === true; +} + +/** + * Returns true if regex parens should be used for sets. If the parent `type` + * is not `brace`, then we're on a root node, which means we should never + * expand segments and open/close braces should be `{}` (since this indicates + * a brace is missing from the set) + */ + +function isOptimized(node, options) { + if (node.parent.isOptimized) return true; + return isType(node.parent, 'brace') + && !isEscaped(node.parent) + && options.expand !== true; +} + +/** + * Returns true if the value in `node` should be wrapped in a literal brace. + * @return {Boolean} + */ + +function isLiteralBrace(node, options) { + return isEscaped(node.parent) || options.optimize !== false; +} + +/** + * Returns true if the given `node` does not have an inner value. + * @return {Boolean} + */ + +function noInner(node, type) { + if (node.parent.queue.length === 1) { + return true; + } + var nodes = node.parent.nodes; + return nodes.length === 3 + && isType(nodes[0], 'brace.open') + && !isType(nodes[1], 'text') + && isType(nodes[2], 'brace.close'); +} + +/** + * Returns true if the given `node` is the given `type` + * @return {Boolean} + */ + +function isType(node, type) { + return typeof node !== 'undefined' && node.type === type; +} + /** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer + * Returns true if the given `node` has a non-empty queue. + * @return {Boolean} */ -function isBuffer(val) { - return val.constructor - && typeof val.constructor.isBuffer === 'function' - && val.constructor.isBuffer(val); +function hasQueue(node) { + return Array.isArray(node.queue) && node.queue.length; } /***/ }), -/* 732 */ +/* 737 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * is-accessor-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + + +var splitString = __webpack_require__(738); +var utils = module.exports; + +/** + * Module dependencies */ +utils.extend = __webpack_require__(732); +utils.flatten = __webpack_require__(744); +utils.isObject = __webpack_require__(742); +utils.fillRange = __webpack_require__(745); +utils.repeat = __webpack_require__(750); +utils.unique = __webpack_require__(735); +utils.define = function(obj, key, val) { + Object.defineProperty(obj, key, { + writable: true, + configurable: true, + enumerable: false, + value: val + }); +}; -var typeOf = __webpack_require__(733); +/** + * Returns true if the given string contains only empty brace sets. + */ -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' +utils.isEmptySets = function(str) { + return /^(?:\{,\})+$/.test(str); }; -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } +/** + * Returns true if the given string contains only empty brace sets. + */ - if (typeOf(obj) !== 'object') { - return false; +utils.isQuotedString = function(str) { + var open = str.charAt(0); + if (open === '\'' || open === '"' || open === '`') { + return str.slice(-1) === open; } + return false; +}; - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } +/** + * Create the key to use for memoization. The unique key is generated + * by iterating over the options and concatenating key-value pairs + * to the pattern string. + */ - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; +utils.createKey = function(pattern, options) { + var id = pattern; + if (typeof options === 'undefined') { + return id; } + var keys = Object.keys(options); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + id += ';' + key + '=' + String(options[key]); + } + return id; +}; - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; +/** + * Normalize options + */ + +utils.createOptions = function(options) { + var opts = utils.extend.apply(null, arguments); + if (typeof opts.expand === 'boolean') { + opts.optimize = !opts.expand; + } + if (typeof opts.optimize === 'boolean') { + opts.expand = !opts.optimize; + } + if (opts.optimize === true) { + opts.makeRe = true; } + return opts; +}; - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; - } +/** + * Join patterns in `a` to patterns in `b` + */ - if (typeOf(obj[key]) === accessor[key]) { +utils.join = function(a, b, options) { + options = options || {}; + a = utils.arrayify(a); + b = utils.arrayify(b); + + if (!a.length) return b; + if (!b.length) return a; + + var len = a.length; + var idx = -1; + var arr = []; + + while (++idx < len) { + var val = a[idx]; + if (Array.isArray(val)) { + for (var i = 0; i < val.length; i++) { + val[i] = utils.join(val[i], b, options); + } + arr.push(val); continue; } - if (typeof obj[key] !== 'undefined') { - return false; + for (var j = 0; j < b.length; j++) { + var bval = b[j]; + + if (Array.isArray(bval)) { + arr.push(utils.join(val, bval, options)); + } else { + arr.push(val + bval); + } } } - return true; -} - -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} + return arr; +}; /** - * Expose `isAccessorDescriptor` + * Split the given string on `,` if not escaped. */ -module.exports = isAccessorDescriptor; - - -/***/ }), -/* 733 */ -/***/ (function(module, exports, __webpack_require__) { - -var isBuffer = __webpack_require__(734); -var toString = Object.prototype.toString; +utils.split = function(str, options) { + var opts = utils.extend({sep: ','}, options); + if (typeof opts.keepQuotes !== 'boolean') { + opts.keepQuotes = true; + } + if (opts.unescape === false) { + opts.keepEscaping = true; + } + return splitString(str, opts, utils.escapeBrackets(opts)); +}; /** - * Get the native `typeof` a value. + * Expand ranges or sets in the given `pattern`. * - * @param {*} `val` - * @return {*} Native javascript type + * @param {String} `str` + * @param {Object} `options` + * @return {Object} */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } +utils.expand = function(str, options) { + var opts = utils.extend({rangeLimit: 10000}, options); + var segs = utils.split(str, opts); + var tok = { segs: segs }; - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; + if (utils.isQuotedString(str)) { + return tok; } - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; + if (opts.rangeLimit === true) { + opts.rangeLimit = 10000; } - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } + if (segs.length > 1) { + if (opts.optimize === false) { + tok.val = segs[0]; + return tok; + } - // other objects - var type = toString.call(val); + tok.segs = utils.stringifyArray(tok.segs); + } else if (segs.length === 1) { + var arr = str.split('..'); - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } + if (arr.length === 1) { + tok.val = tok.segs[tok.segs.length - 1] || tok.val || str; + tok.segs = []; + return tok; + } - // buffer - if (isBuffer(val)) { - return 'buffer'; - } + if (arr.length === 2 && arr[0] === arr[1]) { + tok.escaped = true; + tok.val = arr[0]; + tok.segs = []; + return tok; + } - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } + if (arr.length > 1) { + if (opts.optimize !== false) { + opts.optimize = true; + delete opts.expand; + } - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; + if (opts.optimize !== true) { + var min = Math.min(arr[0], arr[1]); + var max = Math.max(arr[0], arr[1]); + var step = arr[2] || 1; + + if (opts.rangeLimit !== false && ((max - min) / step >= opts.rangeLimit)) { + throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); + } + } + + arr.push(opts); + tok.segs = utils.fillRange.apply(null, arr); + + if (!tok.segs.length) { + tok.escaped = true; + tok.val = str; + return tok; + } + + if (opts.optimize === true) { + tok.segs = utils.stringifyArray(tok.segs); + } + + if (tok.segs === '') { + tok.val = str; + } else { + tok.val = tok.segs[0]; + } + return tok; + } + } else { + tok.val = str; } + return tok; +}; - // must be a plain object - return 'object'; +/** + * Ensure commas inside brackets and parens are not split. + * @param {Object} `tok` Token from the `split-string` module + * @return {undefined} + */ + +utils.escapeBrackets = function(options) { + return function(tok) { + if (tok.escaped && tok.val === 'b') { + tok.val = '\\b'; + return; + } + + if (tok.val !== '(' && tok.val !== '[') return; + var opts = utils.extend({}, options); + var brackets = []; + var parens = []; + var stack = []; + var val = tok.val; + var str = tok.str; + var i = tok.idx - 1; + + while (++i < str.length) { + var ch = str[i]; + + if (ch === '\\') { + val += (opts.keepEscaping === false ? '' : ch) + str[++i]; + continue; + } + + if (ch === '(') { + parens.push(ch); + stack.push(ch); + } + + if (ch === '[') { + brackets.push(ch); + stack.push(ch); + } + + if (ch === ')') { + parens.pop(); + stack.pop(); + if (!stack.length) { + val += ch; + break; + } + } + + if (ch === ']') { + brackets.pop(); + stack.pop(); + if (!stack.length) { + val += ch; + break; + } + } + val += ch; + } + + tok.split = false; + tok.val = val.slice(1); + tok.idx = i; + }; }; +/** + * Returns true if the given string looks like a regex quantifier + * @return {Boolean} + */ -/***/ }), -/* 734 */ -/***/ (function(module, exports) { +utils.isQuantifier = function(str) { + return /^(?:[0-9]?,[0-9]|[0-9],)$/.test(str); +}; -/*! - * Determine if an object is a Buffer - * - * @author Feross Aboukhadijeh - * @license MIT +/** + * Cast `val` to an array. + * @param {*} `val` */ -// The _isBuffer check is for Safari 5-7 support, because it's missing -// Object.prototype.constructor. Remove this eventually -module.exports = function (obj) { - return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) -} +utils.stringifyArray = function(arr) { + return [utils.arrayify(arr).join('|')]; +}; -function isBuffer (obj) { - return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) -} +/** + * Cast `val` to an array. + * @param {*} `val` + */ -// For Node v0.10 support. Remove this eventually. -function isSlowBuffer (obj) { - return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) -} +utils.arrayify = function(arr) { + if (typeof arr === 'undefined') { + return []; + } + if (typeof arr === 'string') { + return [arr]; + } + return arr; +}; + +/** + * Returns true if the given `str` is a non-empty string + * @return {Boolean} + */ + +utils.isString = function(str) { + return str != null && typeof str === 'string'; +}; + +/** + * Get the last element from `array` + * @param {Array} `array` + * @return {*} + */ + +utils.last = function(arr, n) { + return arr[arr.length - (n || 1)]; +}; + +utils.escapeRegex = function(str) { + return str.replace(/\\?([!^*?()[\]{}+?/])/g, '\\$1'); +}; /***/ }), -/* 735 */ +/* 738 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-data-descriptor + * split-string * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. */ -var typeOf = __webpack_require__(736); +var extend = __webpack_require__(739); -// data descriptor properties -var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' -}; +module.exports = function(str, options, fn) { + if (typeof str !== 'string') { + throw new TypeError('expected a string'); + } -function isDataDescriptor(obj, prop) { - if (typeOf(obj) !== 'object') { - return false; + if (typeof options === 'function') { + fn = options; + options = null; } - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; + // allow separator to be defined as a string + if (typeof options === 'string') { + options = { sep: options }; + } + + var opts = extend({sep: '.'}, options); + var quotes = opts.quotes || ['"', "'", '`']; + var brackets; + + if (opts.brackets === true) { + brackets = { + '<': '>', + '(': ')', + '[': ']', + '{': '}' + }; + } else if (opts.brackets) { + brackets = opts.brackets; } - if (!('value' in obj) && !('writable' in obj)) { - return false; + var tokens = []; + var stack = []; + var arr = ['']; + var sep = opts.sep; + var len = str.length; + var idx = -1; + var closeIdx; + + function expected() { + if (brackets && stack.length) { + return brackets[stack[stack.length - 1]]; + } } - for (var key in obj) { - if (key === 'value') continue; + while (++idx < len) { + var ch = str[idx]; + var next = str[idx + 1]; + var tok = { val: ch, idx: idx, arr: arr, str: str }; + tokens.push(tok); - if (!data.hasOwnProperty(key)) { + if (ch === '\\') { + tok.val = keepEscaping(opts, str, idx) === true ? (ch + next) : next; + tok.escaped = true; + if (typeof fn === 'function') { + fn(tok); + } + arr[arr.length - 1] += tok.val; + idx++; continue; } - if (typeOf(obj[key]) === data[key]) { - continue; - } + if (brackets && brackets[ch]) { + stack.push(ch); + var e = expected(); + var i = idx + 1; - if (typeof obj[key] !== 'undefined') { - return false; - } - } - return true; -} + if (str.indexOf(e, i + 1) !== -1) { + while (stack.length && i < len) { + var s = str[++i]; + if (s === '\\') { + s++; + continue; + } -/** - * Expose `isDataDescriptor` - */ + if (quotes.indexOf(s) !== -1) { + i = getClosingQuote(str, s, i + 1); + continue; + } -module.exports = isDataDescriptor; + e = expected(); + if (stack.length && str.indexOf(e, i + 1) === -1) { + break; + } + if (brackets[s]) { + stack.push(s); + continue; + } -/***/ }), -/* 736 */ -/***/ (function(module, exports, __webpack_require__) { + if (e === s) { + stack.pop(); + } + } + } -var isBuffer = __webpack_require__(734); -var toString = Object.prototype.toString; + closeIdx = i; + if (closeIdx === -1) { + arr[arr.length - 1] += ch; + continue; + } -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ + ch = str.slice(idx, closeIdx + 1); + tok.val = ch; + tok.idx = idx = closeIdx; + } -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } + if (quotes.indexOf(ch) !== -1) { + closeIdx = getClosingQuote(str, ch, idx + 1); + if (closeIdx === -1) { + arr[arr.length - 1] += ch; + continue; + } - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } + if (keepQuotes(ch, opts) === true) { + ch = str.slice(idx, closeIdx + 1); + } else { + ch = str.slice(idx + 1, closeIdx); + } - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } + tok.val = ch; + tok.idx = idx = closeIdx; + } - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } + if (typeof fn === 'function') { + fn(tok, tokens); + ch = tok.val; + idx = tok.idx; + } - // other objects - var type = toString.call(val); + if (tok.val === sep && tok.split !== false) { + arr.push(''); + continue; + } - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; + arr[arr.length - 1] += tok.val; } - // buffer - if (isBuffer(val)) { - return 'buffer'; - } + return arr; +}; - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; +function getClosingQuote(str, ch, i, brackets) { + var idx = str.indexOf(ch, i); + if (str.charAt(idx - 1) === '\\') { + return getClosingQuote(str, ch, idx + 1); } + return idx; +} - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; - } +function keepQuotes(ch, opts) { + if (opts.keepDoubleQuotes === true && ch === '"') return true; + if (opts.keepSingleQuotes === true && ch === "'") return true; + return opts.keepQuotes; +} - // must be a plain object - return 'object'; -}; +function keepEscaping(opts, str, idx) { + if (typeof opts.keepEscaping === 'function') { + return opts.keepEscaping(str, idx); + } + return opts.keepEscaping === true || str[idx + 1] === '\\'; +} /***/ }), -/* 737 */ +/* 739 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(738); - -module.exports = function extend(o/*, objects*/) { - if (!isObject(o)) { o = {}; } - - var len = arguments.length; - for (var i = 1; i < len; i++) { - var obj = arguments[i]; +var isExtendable = __webpack_require__(740); +var assignSymbols = __webpack_require__(743); - if (isObject(obj)) { - assign(o, obj); +module.exports = Object.assign || function(obj/*, objects*/) { + if (obj === null || typeof obj === 'undefined') { + throw new TypeError('Cannot convert undefined or null to object'); + } + if (!isObject(obj)) { + obj = {}; + } + for (var i = 1; i < arguments.length; i++) { + var val = arguments[i]; + if (isString(val)) { + val = toObject(val); + } + if (isObject(val)) { + assign(obj, val); + assignSymbols(obj, val); } } - return o; + return obj; }; function assign(a, b) { @@ -85457,6 +84219,22 @@ function assign(a, b) { } } +function isString(val) { + return (val && typeof val === 'string'); +} + +function toObject(str) { + var obj = {}; + for (var i in str) { + obj[i] = str[i]; + } + return obj; +} + +function isObject(val) { + return (val && typeof val === 'object') || isExtendable(val); +} + /** * Returns true if the given `key` is an own property of `obj`. */ @@ -85465,8951 +84243,10107 @@ function hasOwn(obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); } +function isEnum(obj, key) { + return Object.prototype.propertyIsEnumerable.call(obj, key); +} + /***/ }), -/* 738 */ +/* 740 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! * is-extendable * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. */ +var isPlainObject = __webpack_require__(741); + module.exports = function isExtendable(val) { - return typeof val !== 'undefined' && val !== null - && (typeof val === 'object' || typeof val === 'function'); + return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); }; /***/ }), -/* 739 */ +/* 741 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * is-plain-object + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ -var extend = __webpack_require__(737); -/** - * The main export is a function that takes a `pattern` string and an `options` object. - * - * ```js - & var not = require('regex-not'); - & console.log(not('foo')); - & //=> /^(?:(?!^(?:foo)$).)*$/ - * ``` - * - * @param {String} `pattern` - * @param {Object} `options` - * @return {RegExp} Converts the given `pattern` to a regex using the specified `options`. - * @api public - */ +var isObject = __webpack_require__(742); -function toRegex(pattern, options) { - return new RegExp(toRegex.create(pattern, options)); +function isObjectObject(o) { + return isObject(o) === true + && Object.prototype.toString.call(o) === '[object Object]'; } -/** - * Create a regex-compatible string from the given `pattern` and `options`. - * - * ```js - & var not = require('regex-not'); - & console.log(not.create('foo')); - & //=> '^(?:(?!^(?:foo)$).)*$' - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {String} - * @api public - */ +module.exports = function isPlainObject(o) { + var ctor,prot; -toRegex.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } + if (isObjectObject(o) === false) return false; - var opts = extend({}, options); - if (opts && opts.contains === true) { - opts.strictNegate = false; - } + // If has modified constructor + ctor = o.constructor; + if (typeof ctor !== 'function') return false; - var open = opts.strictOpen !== false ? '^' : ''; - var close = opts.strictClose !== false ? '$' : ''; - var endChar = opts.endChar ? opts.endChar : '+'; - var str = pattern; + // If has modified prototype + prot = ctor.prototype; + if (isObjectObject(prot) === false) return false; - if (opts && opts.strictNegate === false) { - str = '(?:(?!(?:' + pattern + ')).)' + endChar; - } else { - str = '(?:(?!^(?:' + pattern + ')$).)' + endChar; + // If constructor does not have an Object-specific method + if (prot.hasOwnProperty('isPrototypeOf') === false) { + return false; } - return open + str + close; + // Most likely a plain Object + return true; }; -/** - * Expose `toRegex` - */ - -module.exports = toRegex; - /***/ }), -/* 740 */ +/* 742 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * array-unique + * isobject * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. */ -module.exports = function unique(arr) { - if (!Array.isArray(arr)) { - throw new TypeError('array-unique expects an array.'); - } - - var len = arr.length; - var i = -1; - - while (i++ < len) { - var j = i + 1; - - for (; j < arr.length; ++j) { - if (arr[i] === arr[j]) { - arr.splice(j--, 1); - } - } - } - return arr; -}; - -module.exports.immutable = function uniqueImmutable(arr) { - if (!Array.isArray(arr)) { - throw new TypeError('array-unique expects an array.'); - } - - var arrLen = arr.length; - var newArr = new Array(arrLen); - - for (var i = 0; i < arrLen; i++) { - newArr[i] = arr[i]; - } - - return module.exports(newArr); +module.exports = function isObject(val) { + return val != null && typeof val === 'object' && Array.isArray(val) === false; }; /***/ }), -/* 741 */ +/* 743 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * assign-symbols + * + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. + */ -var utils = __webpack_require__(742); -module.exports = function(braces, options) { - braces.compiler +module.exports = function(receiver, objects) { + if (receiver === null || typeof receiver === 'undefined') { + throw new TypeError('expected first argument to be an object.'); + } - /** - * bos - */ + if (typeof objects === 'undefined' || typeof Symbol === 'undefined') { + return receiver; + } - .set('bos', function() { - if (this.output) return; - this.ast.queue = isEscaped(this.ast) ? [this.ast.val] : []; - this.ast.count = 1; - }) + if (typeof Object.getOwnPropertySymbols !== 'function') { + return receiver; + } - /** - * Square brackets - */ + var isEnumerable = Object.prototype.propertyIsEnumerable; + var target = Object(receiver); + var len = arguments.length, i = 0; - .set('bracket', function(node) { - var close = node.close; - var open = !node.escaped ? '[' : '\\['; - var negated = node.negated; - var inner = node.inner; + while (++i < len) { + var provider = Object(arguments[i]); + var names = Object.getOwnPropertySymbols(provider); - inner = inner.replace(/\\(?=[\\\w]|$)/g, '\\\\'); - if (inner === ']-') { - inner = '\\]\\-'; - } + for (var j = 0; j < names.length; j++) { + var key = names[j]; - if (negated && inner.indexOf('.') === -1) { - inner += '.'; - } - if (negated && inner.indexOf('/') === -1) { - inner += '/'; + if (isEnumerable.call(provider, key)) { + target[key] = provider[key]; } + } + } + return target; +}; - var val = open + negated + inner + close; - var queue = node.parent.queue; - var last = utils.arrayify(queue.pop()); - - queue.push(utils.join(last, val)); - queue.push.apply(queue, []); - }) - - /** - * Brace - */ - - .set('brace', function(node) { - node.queue = isEscaped(node) ? [node.val] : []; - node.count = 1; - return this.mapVisit(node.nodes); - }) - - /** - * Open - */ - .set('brace.open', function(node) { - node.parent.open = node.val; - }) +/***/ }), +/* 744 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * Inner - */ +"use strict"; +/*! + * arr-flatten + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ - .set('text', function(node) { - var queue = node.parent.queue; - var escaped = node.escaped; - var segs = [node.val]; - if (node.optimize === false) { - options = utils.extend({}, options, {optimize: false}); - } - if (node.multiplier > 1) { - node.parent.count *= node.multiplier; - } +module.exports = function (arr) { + return flat(arr, []); +}; - if (options.quantifiers === true && utils.isQuantifier(node.val)) { - escaped = true; +function flat(arr, res) { + var i = 0, cur; + var len = arr.length; + for (; i < len; i++) { + cur = arr[i]; + Array.isArray(cur) ? flat(cur, res) : res.push(cur); + } + return res; +} - } else if (node.val.length > 1) { - if (isType(node.parent, 'brace') && !isEscaped(node)) { - var expanded = utils.expand(node.val, options); - segs = expanded.segs; - if (expanded.isOptimized) { - node.parent.isOptimized = true; - } +/***/ }), +/* 745 */ +/***/ (function(module, exports, __webpack_require__) { - // if nothing was expanded, we probably have a literal brace - if (!segs.length) { - var val = (expanded.val || node.val); - if (options.unescape !== false) { - // unescape unexpanded brace sequence/set separators - val = val.replace(/\\([,.])/g, '$1'); - // strip quotes - val = val.replace(/["'`]/g, ''); - } +"use strict"; +/*! + * fill-range + * + * Copyright (c) 2014-2015, 2017, Jon Schlinkert. + * Released under the MIT License. + */ - segs = [val]; - escaped = true; - } - } - } else if (node.val === ',') { - if (options.expand) { - node.parent.queue.push(['']); - segs = ['']; - } else { - segs = ['|']; - } - } else { - escaped = true; - } - if (escaped && isType(node.parent, 'brace')) { - if (node.parent.nodes.length <= 4 && node.parent.count === 1) { - node.parent.escaped = true; - } else if (node.parent.length <= 3) { - node.parent.escaped = true; - } - } +var util = __webpack_require__(29); +var isNumber = __webpack_require__(746); +var extend = __webpack_require__(732); +var repeat = __webpack_require__(748); +var toRegex = __webpack_require__(749); - if (!hasQueue(node.parent)) { - node.parent.queue = segs; - return; - } +/** + * Return a range of numbers or letters. + * + * @param {String} `start` Start of the range + * @param {String} `stop` End of the range + * @param {String} `step` Increment or decrement to use. + * @param {Function} `fn` Custom function to modify each element in the range. + * @return {Array} + */ - var last = utils.arrayify(queue.pop()); - if (node.parent.count > 1 && options.expand) { - last = multiply(last, node.parent.count); - node.parent.count = 1; - } +function fillRange(start, stop, step, options) { + if (typeof start === 'undefined') { + return []; + } - queue.push(utils.join(utils.flatten(last), segs.shift())); - queue.push.apply(queue, segs); - }) + if (typeof stop === 'undefined' || start === stop) { + // special case, for handling negative zero + var isString = typeof start === 'string'; + if (isNumber(start) && !toNumber(start)) { + return [isString ? '0' : 0]; + } + return [start]; + } - /** - * Close - */ + if (typeof step !== 'number' && typeof step !== 'string') { + options = step; + step = undefined; + } - .set('brace.close', function(node) { - var queue = node.parent.queue; - var prev = node.parent.parent; - var last = prev.queue.pop(); - var open = node.parent.open; - var close = node.val; + if (typeof options === 'function') { + options = { transform: options }; + } - if (open && close && isOptimized(node, options)) { - open = '('; - close = ')'; - } + var opts = extend({step: step}, options); + if (opts.step && !isValidNumber(opts.step)) { + if (opts.strictRanges === true) { + throw new TypeError('expected options.step to be a number'); + } + return []; + } - // if a close brace exists, and the previous segment is one character - // don't wrap the result in braces or parens - var ele = utils.last(queue); - if (node.parent.count > 1 && options.expand) { - ele = multiply(queue.pop(), node.parent.count); - node.parent.count = 1; - queue.push(ele); - } + opts.isNumber = isValidNumber(start) && isValidNumber(stop); + if (!opts.isNumber && !isValid(start, stop)) { + if (opts.strictRanges === true) { + throw new RangeError('invalid range arguments: ' + util.inspect([start, stop])); + } + return []; + } - if (close && typeof ele === 'string' && ele.length === 1) { - open = ''; - close = ''; - } + opts.isPadded = isPadded(start) || isPadded(stop); + opts.toString = opts.stringify + || typeof opts.step === 'string' + || typeof start === 'string' + || typeof stop === 'string' + || !opts.isNumber; - if ((isLiteralBrace(node, options) || noInner(node)) && !node.parent.hasEmpty) { - queue.push(utils.join(open, queue.pop() || '')); - queue = utils.flatten(utils.join(queue, close)); - } + if (opts.isPadded) { + opts.maxLength = Math.max(String(start).length, String(stop).length); + } - if (typeof last === 'undefined') { - prev.queue = [queue]; - } else { - prev.queue.push(utils.flatten(utils.join(last, queue))); - } - }) + // support legacy minimatch/fill-range options + if (typeof opts.optimize === 'boolean') opts.toRegex = opts.optimize; + if (typeof opts.makeRe === 'boolean') opts.toRegex = opts.makeRe; + return expand(start, stop, opts); +} - /** - * eos - */ +function expand(start, stop, options) { + var a = options.isNumber ? toNumber(start) : start.charCodeAt(0); + var b = options.isNumber ? toNumber(stop) : stop.charCodeAt(0); - .set('eos', function(node) { - if (this.input) return; + var step = Math.abs(toNumber(options.step)) || 1; + if (options.toRegex && step === 1) { + return toRange(a, b, start, stop, options); + } - if (options.optimize !== false) { - this.output = utils.last(utils.flatten(this.ast.queue)); - } else if (Array.isArray(utils.last(this.ast.queue))) { - this.output = utils.flatten(this.ast.queue.pop()); - } else { - this.output = utils.flatten(this.ast.queue); - } + var zero = {greater: [], lesser: []}; + var asc = a < b; + var arr = new Array(Math.round((asc ? b - a : a - b) / step)); + var idx = 0; - if (node.parent.count > 1 && options.expand) { - this.output = multiply(this.output, node.parent.count); - } + while (asc ? a <= b : a >= b) { + var val = options.isNumber ? a : String.fromCharCode(a); + if (options.toRegex && (val >= 0 || !options.isNumber)) { + zero.greater.push(val); + } else { + zero.lesser.push(Math.abs(val)); + } - this.output = utils.arrayify(this.output); - this.ast.queue = []; - }); + if (options.isPadded) { + val = zeros(val, options); + } -}; + if (options.toString) { + val = String(val); + } -/** - * Multiply the segments in the current brace level - */ + if (typeof options.transform === 'function') { + arr[idx++] = options.transform(val, a, b, step, idx, arr, options); + } else { + arr[idx++] = val; + } -function multiply(queue, n, options) { - return utils.flatten(utils.repeat(utils.arrayify(queue), n)); + if (asc) { + a += step; + } else { + a -= step; + } + } + + if (options.toRegex === true) { + return toSequence(arr, zero, options); + } + return arr; } -/** - * Return true if `node` is escaped - */ +function toRange(a, b, start, stop, options) { + if (options.isPadded) { + return toRegex(start, stop, options); + } -function isEscaped(node) { - return node.escaped === true; + if (options.isNumber) { + return toRegex(Math.min(a, b), Math.max(a, b), options); + } + + var start = String.fromCharCode(Math.min(a, b)); + var stop = String.fromCharCode(Math.max(a, b)); + return '[' + start + '-' + stop + ']'; } -/** - * Returns true if regex parens should be used for sets. If the parent `type` - * is not `brace`, then we're on a root node, which means we should never - * expand segments and open/close braces should be `{}` (since this indicates - * a brace is missing from the set) - */ +function toSequence(arr, zeros, options) { + var greater = '', lesser = ''; + if (zeros.greater.length) { + greater = zeros.greater.join('|'); + } + if (zeros.lesser.length) { + lesser = '-(' + zeros.lesser.join('|') + ')'; + } + var res = greater && lesser + ? greater + '|' + lesser + : greater || lesser; -function isOptimized(node, options) { - if (node.parent.isOptimized) return true; - return isType(node.parent, 'brace') - && !isEscaped(node.parent) - && options.expand !== true; + if (options.capture) { + return '(' + res + ')'; + } + return res; } -/** - * Returns true if the value in `node` should be wrapped in a literal brace. - * @return {Boolean} - */ +function zeros(val, options) { + if (options.isPadded) { + var str = String(val); + var len = str.length; + var dash = ''; + if (str.charAt(0) === '-') { + dash = '-'; + str = str.slice(1); + } + var diff = options.maxLength - len; + var pad = repeat('0', diff); + val = (dash + pad + str); + } + if (options.stringify) { + return String(val); + } + return val; +} -function isLiteralBrace(node, options) { - return isEscaped(node.parent) || options.optimize !== false; +function toNumber(val) { + return Number(val) || 0; } -/** - * Returns true if the given `node` does not have an inner value. - * @return {Boolean} - */ +function isPadded(str) { + return /^-?0\d/.test(str); +} -function noInner(node, type) { - if (node.parent.queue.length === 1) { - return true; - } - var nodes = node.parent.nodes; - return nodes.length === 3 - && isType(nodes[0], 'brace.open') - && !isType(nodes[1], 'text') - && isType(nodes[2], 'brace.close'); +function isValid(min, max) { + return (isValidNumber(min) || isValidLetter(min)) + && (isValidNumber(max) || isValidLetter(max)); } -/** - * Returns true if the given `node` is the given `type` - * @return {Boolean} - */ +function isValidLetter(ch) { + return typeof ch === 'string' && ch.length === 1 && /^\w+$/.test(ch); +} -function isType(node, type) { - return typeof node !== 'undefined' && node.type === type; +function isValidNumber(n) { + return isNumber(n) && !/\./.test(n); } /** - * Returns true if the given `node` has a non-empty queue. - * @return {Boolean} + * Expose `fillRange` + * @type {Function} */ -function hasQueue(node) { - return Array.isArray(node.queue) && node.queue.length; -} +module.exports = fillRange; /***/ }), -/* 742 */ +/* 746 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * is-number + * + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. + */ -var splitString = __webpack_require__(743); -var utils = module.exports; -/** - * Module dependencies - */ +var typeOf = __webpack_require__(747); -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); +module.exports = function isNumber(num) { + var type = typeOf(num); -utils.define = function(obj, key, val) { - Object.defineProperty(obj, key, { - writable: true, - configurable: true, - enumerable: false, - value: val - }); + if (type === 'string') { + if (!num.trim()) return false; + } else if (type !== 'number') { + return false; + } + + return (num - num + 1) >= 0; }; -/** - * Returns true if the given string contains only empty brace sets. - */ -utils.isEmptySets = function(str) { - return /^(?:\{,\})+$/.test(str); -}; +/***/ }), +/* 747 */ +/***/ (function(module, exports, __webpack_require__) { + +var isBuffer = __webpack_require__(729); +var toString = Object.prototype.toString; /** - * Returns true if the given string contains only empty brace sets. + * Get the native `typeof` a value. + * + * @param {*} `val` + * @return {*} Native javascript type */ -utils.isQuotedString = function(str) { - var open = str.charAt(0); - if (open === '\'' || open === '"' || open === '`') { - return str.slice(-1) === open; +module.exports = function kindOf(val) { + // primitivies + if (typeof val === 'undefined') { + return 'undefined'; + } + if (val === null) { + return 'null'; + } + if (val === true || val === false || val instanceof Boolean) { + return 'boolean'; + } + if (typeof val === 'string' || val instanceof String) { + return 'string'; + } + if (typeof val === 'number' || val instanceof Number) { + return 'number'; } - return false; -}; -/** - * Create the key to use for memoization. The unique key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ + // functions + if (typeof val === 'function' || val instanceof Function) { + return 'function'; + } -utils.createKey = function(pattern, options) { - var id = pattern; - if (typeof options === 'undefined') { - return id; + // array + if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { + return 'array'; } - var keys = Object.keys(options); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - id += ';' + key + '=' + String(options[key]); + + // check for instances of RegExp and Date before calling `toString` + if (val instanceof RegExp) { + return 'regexp'; + } + if (val instanceof Date) { + return 'date'; } - return id; -}; -/** - * Normalize options - */ + // other objects + var type = toString.call(val); -utils.createOptions = function(options) { - var opts = utils.extend.apply(null, arguments); - if (typeof opts.expand === 'boolean') { - opts.optimize = !opts.expand; + if (type === '[object RegExp]') { + return 'regexp'; } - if (typeof opts.optimize === 'boolean') { - opts.expand = !opts.optimize; + if (type === '[object Date]') { + return 'date'; } - if (opts.optimize === true) { - opts.makeRe = true; + if (type === '[object Arguments]') { + return 'arguments'; } - return opts; + if (type === '[object Error]') { + return 'error'; + } + + // buffer + if (isBuffer(val)) { + return 'buffer'; + } + + // es6: Map, WeakMap, Set, WeakSet + if (type === '[object Set]') { + return 'set'; + } + if (type === '[object WeakSet]') { + return 'weakset'; + } + if (type === '[object Map]') { + return 'map'; + } + if (type === '[object WeakMap]') { + return 'weakmap'; + } + if (type === '[object Symbol]') { + return 'symbol'; + } + + // typed arrays + if (type === '[object Int8Array]') { + return 'int8array'; + } + if (type === '[object Uint8Array]') { + return 'uint8array'; + } + if (type === '[object Uint8ClampedArray]') { + return 'uint8clampedarray'; + } + if (type === '[object Int16Array]') { + return 'int16array'; + } + if (type === '[object Uint16Array]') { + return 'uint16array'; + } + if (type === '[object Int32Array]') { + return 'int32array'; + } + if (type === '[object Uint32Array]') { + return 'uint32array'; + } + if (type === '[object Float32Array]') { + return 'float32array'; + } + if (type === '[object Float64Array]') { + return 'float64array'; + } + + // must be a plain object + return 'object'; }; -/** - * Join patterns in `a` to patterns in `b` - */ -utils.join = function(a, b, options) { - options = options || {}; - a = utils.arrayify(a); - b = utils.arrayify(b); +/***/ }), +/* 748 */ +/***/ (function(module, exports, __webpack_require__) { - if (!a.length) return b; - if (!b.length) return a; +"use strict"; +/*! + * repeat-string + * + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. + */ - var len = a.length; - var idx = -1; - var arr = []; - while (++idx < len) { - var val = a[idx]; - if (Array.isArray(val)) { - for (var i = 0; i < val.length; i++) { - val[i] = utils.join(val[i], b, options); - } - arr.push(val); - continue; - } - for (var j = 0; j < b.length; j++) { - var bval = b[j]; +/** + * Results cache + */ - if (Array.isArray(bval)) { - arr.push(utils.join(val, bval, options)); - } else { - arr.push(val + bval); - } - } - } - return arr; -}; +var res = ''; +var cache; /** - * Split the given string on `,` if not escaped. + * Expose `repeat` */ -utils.split = function(str, options) { - var opts = utils.extend({sep: ','}, options); - if (typeof opts.keepQuotes !== 'boolean') { - opts.keepQuotes = true; - } - if (opts.unescape === false) { - opts.keepEscaping = true; - } - return splitString(str, opts, utils.escapeBrackets(opts)); -}; +module.exports = repeat; /** - * Expand ranges or sets in the given `pattern`. + * Repeat the given `string` the specified `number` + * of times. * - * @param {String} `str` - * @param {Object} `options` - * @return {Object} + * **Example:** + * + * ```js + * var repeat = require('repeat-string'); + * repeat('A', 5); + * //=> AAAAA + * ``` + * + * @param {String} `string` The string to repeat + * @param {Number} `number` The number of times to repeat the string + * @return {String} Repeated string + * @api public */ -utils.expand = function(str, options) { - var opts = utils.extend({rangeLimit: 10000}, options); - var segs = utils.split(str, opts); - var tok = { segs: segs }; - - if (utils.isQuotedString(str)) { - return tok; +function repeat(str, num) { + if (typeof str !== 'string') { + throw new TypeError('expected a string'); } - if (opts.rangeLimit === true) { - opts.rangeLimit = 10000; + // cover common, quick use cases + if (num === 1) return str; + if (num === 2) return str + str; + + var max = str.length * num; + if (cache !== str || typeof cache === 'undefined') { + cache = str; + res = ''; + } else if (res.length >= max) { + return res.substr(0, max); } - if (segs.length > 1) { - if (opts.optimize === false) { - tok.val = segs[0]; - return tok; + while (max > res.length && num > 1) { + if (num & 1) { + res += str; } - tok.segs = utils.stringifyArray(tok.segs); - } else if (segs.length === 1) { - var arr = str.split('..'); - - if (arr.length === 1) { - tok.val = tok.segs[tok.segs.length - 1] || tok.val || str; - tok.segs = []; - return tok; - } + num >>= 1; + str += str; + } - if (arr.length === 2 && arr[0] === arr[1]) { - tok.escaped = true; - tok.val = arr[0]; - tok.segs = []; - return tok; - } + res += str; + res = res.substr(0, max); + return res; +} - if (arr.length > 1) { - if (opts.optimize !== false) { - opts.optimize = true; - delete opts.expand; - } - if (opts.optimize !== true) { - var min = Math.min(arr[0], arr[1]); - var max = Math.max(arr[0], arr[1]); - var step = arr[2] || 1; +/***/ }), +/* 749 */ +/***/ (function(module, exports, __webpack_require__) { - if (opts.rangeLimit !== false && ((max - min) / step >= opts.rangeLimit)) { - throw new RangeError('expanded array length exceeds range limit. Use options.rangeLimit to increase or disable the limit.'); - } - } +"use strict"; +/*! + * to-regex-range + * + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. + */ - arr.push(opts); - tok.segs = utils.fillRange.apply(null, arr); - if (!tok.segs.length) { - tok.escaped = true; - tok.val = str; - return tok; - } - if (opts.optimize === true) { - tok.segs = utils.stringifyArray(tok.segs); - } +var repeat = __webpack_require__(748); +var isNumber = __webpack_require__(746); +var cache = {}; - if (tok.segs === '') { - tok.val = str; - } else { - tok.val = tok.segs[0]; - } - return tok; - } - } else { - tok.val = str; +function toRegexRange(min, max, options) { + if (isNumber(min) === false) { + throw new RangeError('toRegexRange: first argument is invalid.'); } - return tok; -}; -/** - * Ensure commas inside brackets and parens are not split. - * @param {Object} `tok` Token from the `split-string` module - * @return {undefined} - */ + if (typeof max === 'undefined' || min === max) { + return String(min); + } -utils.escapeBrackets = function(options) { - return function(tok) { - if (tok.escaped && tok.val === 'b') { - tok.val = '\\b'; - return; - } + if (isNumber(max) === false) { + throw new RangeError('toRegexRange: second argument is invalid.'); + } - if (tok.val !== '(' && tok.val !== '[') return; - var opts = utils.extend({}, options); - var brackets = []; - var parens = []; - var stack = []; - var val = tok.val; - var str = tok.str; - var i = tok.idx - 1; + options = options || {}; + var relax = String(options.relaxZeros); + var shorthand = String(options.shorthand); + var capture = String(options.capture); + var key = min + ':' + max + '=' + relax + shorthand + capture; + if (cache.hasOwnProperty(key)) { + return cache[key].result; + } - while (++i < str.length) { - var ch = str[i]; + var a = Math.min(min, max); + var b = Math.max(min, max); - if (ch === '\\') { - val += (opts.keepEscaping === false ? '' : ch) + str[++i]; - continue; - } + if (Math.abs(a - b) === 1) { + var result = min + '|' + max; + if (options.capture) { + return '(' + result + ')'; + } + return result; + } - if (ch === '(') { - parens.push(ch); - stack.push(ch); - } + var isPadded = padding(min) || padding(max); + var positives = []; + var negatives = []; - if (ch === '[') { - brackets.push(ch); - stack.push(ch); - } + var tok = {min: min, max: max, a: a, b: b}; + if (isPadded) { + tok.isPadded = isPadded; + tok.maxLen = String(tok.max).length; + } - if (ch === ')') { - parens.pop(); - stack.pop(); - if (!stack.length) { - val += ch; - break; - } - } + if (a < 0) { + var newMin = b < 0 ? Math.abs(b) : 1; + var newMax = Math.abs(a); + negatives = splitToPatterns(newMin, newMax, tok, options); + a = tok.a = 0; + } - if (ch === ']') { - brackets.pop(); - stack.pop(); - if (!stack.length) { - val += ch; - break; - } - } - val += ch; - } + if (b >= 0) { + positives = splitToPatterns(a, b, tok, options); + } - tok.split = false; - tok.val = val.slice(1); - tok.idx = i; - }; -}; + tok.negatives = negatives; + tok.positives = positives; + tok.result = siftPatterns(negatives, positives, options); -/** - * Returns true if the given string looks like a regex quantifier - * @return {Boolean} - */ + if (options.capture && (positives.length + negatives.length) > 1) { + tok.result = '(' + tok.result + ')'; + } -utils.isQuantifier = function(str) { - return /^(?:[0-9]?,[0-9]|[0-9],)$/.test(str); -}; + cache[key] = tok; + return tok.result; +} -/** - * Cast `val` to an array. - * @param {*} `val` - */ +function siftPatterns(neg, pos, options) { + var onlyNegative = filterPatterns(neg, pos, '-', false, options) || []; + var onlyPositive = filterPatterns(pos, neg, '', false, options) || []; + var intersected = filterPatterns(neg, pos, '-?', true, options) || []; + var subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); + return subpatterns.join('|'); +} -utils.stringifyArray = function(arr) { - return [utils.arrayify(arr).join('|')]; -}; +function splitToRanges(min, max) { + min = Number(min); + max = Number(max); -/** - * Cast `val` to an array. - * @param {*} `val` - */ + var nines = 1; + var stops = [max]; + var stop = +countNines(min, nines); -utils.arrayify = function(arr) { - if (typeof arr === 'undefined') { - return []; - } - if (typeof arr === 'string') { - return [arr]; + while (min <= stop && stop <= max) { + stops = push(stops, stop); + nines += 1; + stop = +countNines(min, nines); } - return arr; -}; -/** - * Returns true if the given `str` is a non-empty string - * @return {Boolean} - */ + var zeros = 1; + stop = countZeros(max + 1, zeros) - 1; -utils.isString = function(str) { - return str != null && typeof str === 'string'; -}; + while (min < stop && stop <= max) { + stops = push(stops, stop); + zeros += 1; + stop = countZeros(max + 1, zeros) - 1; + } + + stops.sort(compare); + return stops; +} /** - * Get the last element from `array` - * @param {Array} `array` - * @return {*} + * Convert a range to a regex pattern + * @param {Number} `start` + * @param {Number} `stop` + * @return {String} */ -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - -utils.escapeRegex = function(str) { - return str.replace(/\\?([!^*?()[\]{}+?/])/g, '\\$1'); -}; - - -/***/ }), -/* 743 */ -/***/ (function(module, exports, __webpack_require__) { +function rangeToPattern(start, stop, options) { + if (start === stop) { + return {pattern: String(start), digits: []}; + } -"use strict"; -/*! - * split-string - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ + var zipped = zip(String(start), String(stop)); + var len = zipped.length, i = -1; + var pattern = ''; + var digits = 0; + while (++i < len) { + var numbers = zipped[i]; + var startDigit = numbers[0]; + var stopDigit = numbers[1]; -var extend = __webpack_require__(744); + if (startDigit === stopDigit) { + pattern += startDigit; -module.exports = function(str, options, fn) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } + } else if (startDigit !== '0' || stopDigit !== '9') { + pattern += toCharacterClass(startDigit, stopDigit); - if (typeof options === 'function') { - fn = options; - options = null; + } else { + digits += 1; + } } - // allow separator to be defined as a string - if (typeof options === 'string') { - options = { sep: options }; + if (digits) { + pattern += options.shorthand ? '\\d' : '[0-9]'; } - var opts = extend({sep: '.'}, options); - var quotes = opts.quotes || ['"', "'", '`']; - var brackets; - - if (opts.brackets === true) { - brackets = { - '<': '>', - '(': ')', - '[': ']', - '{': '}' - }; - } else if (opts.brackets) { - brackets = opts.brackets; - } + return { pattern: pattern, digits: [digits] }; +} - var tokens = []; - var stack = []; - var arr = ['']; - var sep = opts.sep; - var len = str.length; +function splitToPatterns(min, max, tok, options) { + var ranges = splitToRanges(min, max); + var len = ranges.length; var idx = -1; - var closeIdx; - function expected() { - if (brackets && stack.length) { - return brackets[stack[stack.length - 1]]; - } - } + var tokens = []; + var start = min; + var prev; while (++idx < len) { - var ch = str[idx]; - var next = str[idx + 1]; - var tok = { val: ch, idx: idx, arr: arr, str: str }; - tokens.push(tok); + var range = ranges[idx]; + var obj = rangeToPattern(start, range, options); + var zeros = ''; - if (ch === '\\') { - tok.val = keepEscaping(opts, str, idx) === true ? (ch + next) : next; - tok.escaped = true; - if (typeof fn === 'function') { - fn(tok); + if (!tok.isPadded && prev && prev.pattern === obj.pattern) { + if (prev.digits.length > 1) { + prev.digits.pop(); } - arr[arr.length - 1] += tok.val; - idx++; + prev.digits.push(obj.digits[0]); + prev.string = prev.pattern + toQuantifier(prev.digits); + start = range + 1; continue; } - if (brackets && brackets[ch]) { - stack.push(ch); - var e = expected(); - var i = idx + 1; - - if (str.indexOf(e, i + 1) !== -1) { - while (stack.length && i < len) { - var s = str[++i]; - if (s === '\\') { - s++; - continue; - } - - if (quotes.indexOf(s) !== -1) { - i = getClosingQuote(str, s, i + 1); - continue; - } - - e = expected(); - if (stack.length && str.indexOf(e, i + 1) === -1) { - break; - } - - if (brackets[s]) { - stack.push(s); - continue; - } - - if (e === s) { - stack.pop(); - } - } - } + if (tok.isPadded) { + zeros = padZeros(range, tok); + } - closeIdx = i; - if (closeIdx === -1) { - arr[arr.length - 1] += ch; - continue; - } + obj.string = zeros + obj.pattern + toQuantifier(obj.digits); + tokens.push(obj); + start = range + 1; + prev = obj; + } - ch = str.slice(idx, closeIdx + 1); - tok.val = ch; - tok.idx = idx = closeIdx; - } + return tokens; +} - if (quotes.indexOf(ch) !== -1) { - closeIdx = getClosingQuote(str, ch, idx + 1); - if (closeIdx === -1) { - arr[arr.length - 1] += ch; - continue; - } +function filterPatterns(arr, comparison, prefix, intersection, options) { + var res = []; - if (keepQuotes(ch, opts) === true) { - ch = str.slice(idx, closeIdx + 1); - } else { - ch = str.slice(idx + 1, closeIdx); - } + for (var i = 0; i < arr.length; i++) { + var tok = arr[i]; + var ele = tok.string; - tok.val = ch; - tok.idx = idx = closeIdx; + if (options.relaxZeros !== false) { + if (prefix === '-' && ele.charAt(0) === '0') { + if (ele.charAt(1) === '{') { + ele = '0*' + ele.replace(/^0\{\d+\}/, ''); + } else { + ele = '0*' + ele.slice(1); + } + } } - if (typeof fn === 'function') { - fn(tok, tokens); - ch = tok.val; - idx = tok.idx; + if (!intersection && !contains(comparison, 'string', ele)) { + res.push(prefix + ele); } - if (tok.val === sep && tok.split !== false) { - arr.push(''); - continue; + if (intersection && contains(comparison, 'string', ele)) { + res.push(prefix + ele); } - - arr[arr.length - 1] += tok.val; } + return res; +} + +/** + * Zip strings (`for in` can be used on string characters) + */ +function zip(a, b) { + var arr = []; + for (var ch in a) arr.push([a[ch], b[ch]]); return arr; -}; +} -function getClosingQuote(str, ch, i, brackets) { - var idx = str.indexOf(ch, i); - if (str.charAt(idx - 1) === '\\') { - return getClosingQuote(str, ch, idx + 1); - } - return idx; +function compare(a, b) { + return a > b ? 1 : b > a ? -1 : 0; } -function keepQuotes(ch, opts) { - if (opts.keepDoubleQuotes === true && ch === '"') return true; - if (opts.keepSingleQuotes === true && ch === "'") return true; - return opts.keepQuotes; +function push(arr, ele) { + if (arr.indexOf(ele) === -1) arr.push(ele); + return arr; } -function keepEscaping(opts, str, idx) { - if (typeof opts.keepEscaping === 'function') { - return opts.keepEscaping(str, idx); +function contains(arr, key, val) { + for (var i = 0; i < arr.length; i++) { + if (arr[i][key] === val) { + return true; + } } - return opts.keepEscaping === true || str[idx + 1] === '\\'; + return false; } +function countNines(min, len) { + return String(min).slice(0, -len) + repeat('9', len); +} -/***/ }), -/* 744 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var isExtendable = __webpack_require__(745); -var assignSymbols = __webpack_require__(748); - -module.exports = Object.assign || function(obj/*, objects*/) { - if (obj === null || typeof obj === 'undefined') { - throw new TypeError('Cannot convert undefined or null to object'); - } - if (!isObject(obj)) { - obj = {}; - } - for (var i = 1; i < arguments.length; i++) { - var val = arguments[i]; - if (isString(val)) { - val = toObject(val); - } - if (isObject(val)) { - assign(obj, val); - assignSymbols(obj, val); - } - } - return obj; -}; +function countZeros(integer, zeros) { + return integer - (integer % Math.pow(10, zeros)); +} -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } +function toQuantifier(digits) { + var start = digits[0]; + var stop = digits[1] ? (',' + digits[1]) : ''; + if (!stop && (!start || start === 1)) { + return ''; } + return '{' + start + stop + '}'; } -function isString(val) { - return (val && typeof val === 'string'); +function toCharacterClass(a, b) { + return '[' + a + ((b - a === 1) ? '' : '-') + b + ']'; } -function toObject(str) { - var obj = {}; - for (var i in str) { - obj[i] = str[i]; - } - return obj; +function padding(str) { + return /^-?(0+)\d/.exec(str); } -function isObject(val) { - return (val && typeof val === 'object') || isExtendable(val); +function padZeros(val, tok) { + if (tok.isPadded) { + var diff = Math.abs(tok.maxLen - String(val).length); + switch (diff) { + case 0: + return ''; + case 1: + return '0'; + default: { + return '0{' + diff + '}'; + } + } + } + return val; } /** - * Returns true if the given `key` is an own property of `obj`. + * Expose `toRegexRange` */ -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} - -function isEnum(obj, key) { - return Object.prototype.propertyIsEnumerable.call(obj, key); -} +module.exports = toRegexRange; /***/ }), -/* 745 */ +/* 750 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-extendable + * repeat-element * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * Copyright (c) 2015 Jon Schlinkert. + * Licensed under the MIT license. */ -var isPlainObject = __webpack_require__(746); +module.exports = function repeat(ele, num) { + var arr = new Array(num); + + for (var i = 0; i < num; i++) { + arr[i] = ele; + } -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); + return arr; }; /***/ }), -/* 746 */ +/* 751 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * is-plain-object - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ - -var isObject = __webpack_require__(747); +var Node = __webpack_require__(752); +var utils = __webpack_require__(737); -function isObjectObject(o) { - return isObject(o) === true - && Object.prototype.toString.call(o) === '[object Object]'; -} - -module.exports = function isPlainObject(o) { - var ctor,prot; +/** + * Braces parsers + */ - if (isObjectObject(o) === false) return false; +module.exports = function(braces, options) { + braces.parser + .set('bos', function() { + if (!this.parsed) { + this.ast = this.nodes[0] = new Node(this.ast); + } + }) - // If has modified constructor - ctor = o.constructor; - if (typeof ctor !== 'function') return false; + /** + * Character parsers + */ - // If has modified prototype - prot = ctor.prototype; - if (isObjectObject(prot) === false) return false; + .set('escape', function() { + var pos = this.position(); + var m = this.match(/^(?:\\(.)|\$\{)/); + if (!m) return; - // If constructor does not have an Object-specific method - if (prot.hasOwnProperty('isPrototypeOf') === false) { - return false; - } + var prev = this.prev(); + var last = utils.last(prev.nodes); - // Most likely a plain Object - return true; -}; + var node = pos(new Node({ + type: 'text', + multiplier: 1, + val: m[0] + })); + if (node.val === '\\\\') { + return node; + } -/***/ }), -/* 747 */ -/***/ (function(module, exports, __webpack_require__) { + if (node.val === '${') { + var str = this.input; + var idx = -1; + var ch; -"use strict"; -/*! - * isobject - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ + while ((ch = str[++idx])) { + this.consume(1); + node.val += ch; + if (ch === '\\') { + node.val += str[++idx]; + continue; + } + if (ch === '}') { + break; + } + } + } + if (this.options.unescape !== false) { + node.val = node.val.replace(/\\([{}])/g, '$1'); + } + if (last.val === '"' && this.input.charAt(0) === '"') { + last.val = node.val; + this.consume(1); + return; + } -module.exports = function isObject(val) { - return val != null && typeof val === 'object' && Array.isArray(val) === false; -}; + return concatNodes.call(this, pos, node, prev, options); + }) + /** + * Brackets: "[...]" (basic, this is overridden by + * other parsers in more advanced implementations) + */ -/***/ }), -/* 748 */ -/***/ (function(module, exports, __webpack_require__) { + .set('bracket', function() { + var isInside = this.isInside('brace'); + var pos = this.position(); + var m = this.match(/^(?:\[([!^]?)([^\]]{2,}|\]-)(\]|[^*+?]+)|\[)/); + if (!m) return; -"use strict"; -/*! - * assign-symbols - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ + var prev = this.prev(); + var val = m[0]; + var negated = m[1] ? '^' : ''; + var inner = m[2] || ''; + var close = m[3] || ''; + if (isInside && prev.type === 'brace') { + prev.text = prev.text || ''; + prev.text += val; + } + var esc = this.input.slice(0, 2); + if (inner === '' && esc === '\\]') { + inner += esc; + this.consume(2); -module.exports = function(receiver, objects) { - if (receiver === null || typeof receiver === 'undefined') { - throw new TypeError('expected first argument to be an object.'); - } + var str = this.input; + var idx = -1; + var ch; - if (typeof objects === 'undefined' || typeof Symbol === 'undefined') { - return receiver; - } + while ((ch = str[++idx])) { + this.consume(1); + if (ch === ']') { + close = ch; + break; + } + inner += ch; + } + } - if (typeof Object.getOwnPropertySymbols !== 'function') { - return receiver; - } + return pos(new Node({ + type: 'bracket', + val: val, + escaped: close !== ']', + negated: negated, + inner: inner, + close: close + })); + }) - var isEnumerable = Object.prototype.propertyIsEnumerable; - var target = Object(receiver); - var len = arguments.length, i = 0; + /** + * Empty braces (we capture these early to + * speed up processing in the compiler) + */ - while (++i < len) { - var provider = Object(arguments[i]); - var names = Object.getOwnPropertySymbols(provider); + .set('multiplier', function() { + var isInside = this.isInside('brace'); + var pos = this.position(); + var m = this.match(/^\{((?:,|\{,+\})+)\}/); + if (!m) return; - for (var j = 0; j < names.length; j++) { - var key = names[j]; + this.multiplier = true; + var prev = this.prev(); + var val = m[0]; - if (isEnumerable.call(provider, key)) { - target[key] = provider[key]; + if (isInside && prev.type === 'brace') { + prev.text = prev.text || ''; + prev.text += val; } - } - } - return target; -}; - - -/***/ }), -/* 749 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; -/*! - * arr-flatten - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ + var node = pos(new Node({ + type: 'text', + multiplier: 1, + match: m, + val: val + })); + return concatNodes.call(this, pos, node, prev, options); + }) + /** + * Open + */ -module.exports = function (arr) { - return flat(arr, []); -}; + .set('brace.open', function() { + var pos = this.position(); + var m = this.match(/^\{(?!(?:[^\\}]?|,+)\})/); + if (!m) return; -function flat(arr, res) { - var i = 0, cur; - var len = arr.length; - for (; i < len; i++) { - cur = arr[i]; - Array.isArray(cur) ? flat(cur, res) : res.push(cur); - } - return res; -} + var prev = this.prev(); + var last = utils.last(prev.nodes); + // if the last parsed character was an extglob character + // we need to _not optimize_ the brace pattern because + // it might be mistaken for an extglob by a downstream parser + if (last && last.val && isExtglobChar(last.val.slice(-1))) { + last.optimize = false; + } -/***/ }), -/* 750 */ -/***/ (function(module, exports, __webpack_require__) { + var open = pos(new Node({ + type: 'brace.open', + val: m[0] + })); -"use strict"; -/*! - * fill-range - * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ + var node = pos(new Node({ + type: 'brace', + nodes: [] + })); + node.push(open); + prev.push(node); + this.push('brace', node); + }) + /** + * Close + */ -var util = __webpack_require__(29); -var isNumber = __webpack_require__(751); -var extend = __webpack_require__(737); -var repeat = __webpack_require__(753); -var toRegex = __webpack_require__(754); + .set('brace.close', function() { + var pos = this.position(); + var m = this.match(/^\}/); + if (!m || !m[0]) return; -/** - * Return a range of numbers or letters. - * - * @param {String} `start` Start of the range - * @param {String} `stop` End of the range - * @param {String} `step` Increment or decrement to use. - * @param {Function} `fn` Custom function to modify each element in the range. - * @return {Array} - */ + var brace = this.pop('brace'); + var node = pos(new Node({ + type: 'brace.close', + val: m[0] + })); -function fillRange(start, stop, step, options) { - if (typeof start === 'undefined') { - return []; - } + if (!this.isType(brace, 'brace')) { + if (this.options.strict) { + throw new Error('missing opening "{"'); + } + node.type = 'text'; + node.multiplier = 0; + node.escaped = true; + return node; + } - if (typeof stop === 'undefined' || start === stop) { - // special case, for handling negative zero - var isString = typeof start === 'string'; - if (isNumber(start) && !toNumber(start)) { - return [isString ? '0' : 0]; - } - return [start]; - } + var prev = this.prev(); + var last = utils.last(prev.nodes); + if (last.text) { + var lastNode = utils.last(last.nodes); + if (lastNode.val === ')' && /[!@*?+]\(/.test(last.text)) { + var open = last.nodes[0]; + var text = last.nodes[1]; + if (open.type === 'brace.open' && text && text.type === 'text') { + text.optimize = false; + } + } + } - if (typeof step !== 'number' && typeof step !== 'string') { - options = step; - step = undefined; - } + if (brace.nodes.length > 2) { + var first = brace.nodes[1]; + if (first.type === 'text' && first.val === ',') { + brace.nodes.splice(1, 1); + brace.nodes.push(first); + } + } - if (typeof options === 'function') { - options = { transform: options }; - } + brace.push(node); + }) - var opts = extend({step: step}, options); - if (opts.step && !isValidNumber(opts.step)) { - if (opts.strictRanges === true) { - throw new TypeError('expected options.step to be a number'); - } - return []; - } + /** + * Capture boundary characters + */ - opts.isNumber = isValidNumber(start) && isValidNumber(stop); - if (!opts.isNumber && !isValid(start, stop)) { - if (opts.strictRanges === true) { - throw new RangeError('invalid range arguments: ' + util.inspect([start, stop])); - } - return []; - } + .set('boundary', function() { + var pos = this.position(); + var m = this.match(/^[$^](?!\{)/); + if (!m) return; + return pos(new Node({ + type: 'text', + val: m[0] + })); + }) - opts.isPadded = isPadded(start) || isPadded(stop); - opts.toString = opts.stringify - || typeof opts.step === 'string' - || typeof start === 'string' - || typeof stop === 'string' - || !opts.isNumber; + /** + * One or zero, non-comma characters wrapped in braces + */ - if (opts.isPadded) { - opts.maxLength = Math.max(String(start).length, String(stop).length); - } + .set('nobrace', function() { + var isInside = this.isInside('brace'); + var pos = this.position(); + var m = this.match(/^\{[^,]?\}/); + if (!m) return; - // support legacy minimatch/fill-range options - if (typeof opts.optimize === 'boolean') opts.toRegex = opts.optimize; - if (typeof opts.makeRe === 'boolean') opts.toRegex = opts.makeRe; - return expand(start, stop, opts); -} + var prev = this.prev(); + var val = m[0]; -function expand(start, stop, options) { - var a = options.isNumber ? toNumber(start) : start.charCodeAt(0); - var b = options.isNumber ? toNumber(stop) : stop.charCodeAt(0); + if (isInside && prev.type === 'brace') { + prev.text = prev.text || ''; + prev.text += val; + } - var step = Math.abs(toNumber(options.step)) || 1; - if (options.toRegex && step === 1) { - return toRange(a, b, start, stop, options); - } + return pos(new Node({ + type: 'text', + multiplier: 0, + val: val + })); + }) - var zero = {greater: [], lesser: []}; - var asc = a < b; - var arr = new Array(Math.round((asc ? b - a : a - b) / step)); - var idx = 0; + /** + * Text + */ - while (asc ? a <= b : a >= b) { - var val = options.isNumber ? a : String.fromCharCode(a); - if (options.toRegex && (val >= 0 || !options.isNumber)) { - zero.greater.push(val); - } else { - zero.lesser.push(Math.abs(val)); - } + .set('text', function() { + var isInside = this.isInside('brace'); + var pos = this.position(); + var m = this.match(/^((?!\\)[^${}[\]])+/); + if (!m) return; - if (options.isPadded) { - val = zeros(val, options); - } + var prev = this.prev(); + var val = m[0]; - if (options.toString) { - val = String(val); - } + if (isInside && prev.type === 'brace') { + prev.text = prev.text || ''; + prev.text += val; + } - if (typeof options.transform === 'function') { - arr[idx++] = options.transform(val, a, b, step, idx, arr, options); - } else { - arr[idx++] = val; - } + var node = pos(new Node({ + type: 'text', + multiplier: 1, + val: val + })); - if (asc) { - a += step; - } else { - a -= step; - } - } + return concatNodes.call(this, pos, node, prev, options); + }); +}; - if (options.toRegex === true) { - return toSequence(arr, zero, options); - } - return arr; +/** + * Returns true if the character is an extglob character. + */ + +function isExtglobChar(ch) { + return ch === '!' || ch === '@' || ch === '*' || ch === '?' || ch === '+'; } -function toRange(a, b, start, stop, options) { - if (options.isPadded) { - return toRegex(start, stop, options); - } +/** + * Combine text nodes, and calculate empty sets (`{,,}`) + * @param {Function} `pos` Function to calculate node position + * @param {Object} `node` AST node + * @return {Object} + */ - if (options.isNumber) { - return toRegex(Math.min(a, b), Math.max(a, b), options); - } +function concatNodes(pos, node, parent, options) { + node.orig = node.val; + var prev = this.prev(); + var last = utils.last(prev.nodes); + var isEscaped = false; - var start = String.fromCharCode(Math.min(a, b)); - var stop = String.fromCharCode(Math.max(a, b)); - return '[' + start + '-' + stop + ']'; -} + if (node.val.length > 1) { + var a = node.val.charAt(0); + var b = node.val.slice(-1); -function toSequence(arr, zeros, options) { - var greater = '', lesser = ''; - if (zeros.greater.length) { - greater = zeros.greater.join('|'); - } - if (zeros.lesser.length) { - lesser = '-(' + zeros.lesser.join('|') + ')'; + isEscaped = (a === '"' && b === '"') + || (a === "'" && b === "'") + || (a === '`' && b === '`'); } - var res = greater && lesser - ? greater + '|' + lesser - : greater || lesser; - if (options.capture) { - return '(' + res + ')'; + if (isEscaped && options.unescape !== false) { + node.val = node.val.slice(1, node.val.length - 1); + node.escaped = true; } - return res; -} -function zeros(val, options) { - if (options.isPadded) { - var str = String(val); - var len = str.length; - var dash = ''; - if (str.charAt(0) === '-') { - dash = '-'; - str = str.slice(1); + if (node.match) { + var match = node.match[1]; + if (!match || match.indexOf('}') === -1) { + match = node.match[0]; } - var diff = options.maxLength - len; - var pad = repeat('0', diff); - val = (dash + pad + str); + + // replace each set with a single "," + var val = match.replace(/\{/g, ',').replace(/\}/g, ''); + node.multiplier *= val.length; + node.val = ''; } - if (options.stringify) { - return String(val); + + var simpleText = last.type === 'text' + && last.multiplier === 1 + && node.multiplier === 1 + && node.val; + + if (simpleText) { + last.val += node.val; + return; } - return val; -} -function toNumber(val) { - return Number(val) || 0; + prev.push(node); } -function isPadded(str) { - return /^-?0\d/.test(str); -} -function isValid(min, max) { - return (isValidNumber(min) || isValidLetter(min)) - && (isValidNumber(max) || isValidLetter(max)); -} +/***/ }), +/* 752 */ +/***/ (function(module, exports, __webpack_require__) { -function isValidLetter(ch) { - return typeof ch === 'string' && ch.length === 1 && /^\w+$/.test(ch); -} +"use strict"; -function isValidNumber(n) { - return isNumber(n) && !/\./.test(n); -} + +var isObject = __webpack_require__(742); +var define = __webpack_require__(753); +var utils = __webpack_require__(760); +var ownNames; /** - * Expose `fillRange` - * @type {Function} + * Create a new AST `Node` with the given `val` and `type`. + * + * ```js + * var node = new Node('*', 'Star'); + * var node = new Node({type: 'star', val: '*'}); + * ``` + * @name Node + * @param {String|Object} `val` Pass a matched substring, or an object to merge onto the node. + * @param {String} `type` The node type to use when `val` is a string. + * @return {Object} node instance + * @api public */ -module.exports = fillRange; +function Node(val, type, parent) { + if (typeof type !== 'string') { + parent = type; + type = null; + } + define(this, 'parent', parent); + define(this, 'isNode', true); + define(this, 'expect', null); -/***/ }), -/* 751 */ -/***/ (function(module, exports, __webpack_require__) { + if (typeof type !== 'string' && isObject(val)) { + lazyKeys(); + var keys = Object.keys(val); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (ownNames.indexOf(key) === -1) { + this[key] = val[key]; + } + } + } else { + this.type = type; + this.val = val; + } +} -"use strict"; -/*! - * is-number +/** + * Returns true if the given value is a node. * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. + * ```js + * var Node = require('snapdragon-node'); + * var node = new Node({type: 'foo'}); + * console.log(Node.isNode(node)); //=> true + * console.log(Node.isNode({})); //=> false + * ``` + * @param {Object} `node` + * @returns {Boolean} + * @api public */ +Node.isNode = function(node) { + return utils.isNode(node); +}; +/** + * Define a non-enumberable property on the node instance. + * Useful for adding properties that shouldn't be extended + * or visible during debugging. + * + * ```js + * var node = new Node(); + * node.define('foo', 'something non-enumerable'); + * ``` + * @param {String} `name` + * @param {any} `val` + * @return {Object} returns the node instance + * @api public + */ -var typeOf = __webpack_require__(752); - -module.exports = function isNumber(num) { - var type = typeOf(num); +Node.prototype.define = function(name, val) { + define(this, name, val); + return this; +}; - if (type === 'string') { - if (!num.trim()) return false; - } else if (type !== 'number') { - return false; - } +/** + * Returns true if `node.val` is an empty string, or `node.nodes` does + * not contain any non-empty text nodes. + * + * ```js + * var node = new Node({type: 'text'}); + * node.isEmpty(); //=> true + * node.val = 'foo'; + * node.isEmpty(); //=> false + * ``` + * @param {Function} `fn` (optional) Filter function that is called on `node` and/or child nodes. `isEmpty` will return false immediately when the filter function returns false on any nodes. + * @return {Boolean} + * @api public + */ - return (num - num + 1) >= 0; +Node.prototype.isEmpty = function(fn) { + return utils.isEmpty(this, fn); }; +/** + * Given node `foo` and node `bar`, push node `bar` onto `foo.nodes`, and + * set `foo` as `bar.parent`. + * + * ```js + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * foo.push(bar); + * ``` + * @param {Object} `node` + * @return {Number} Returns the length of `node.nodes` + * @api public + */ -/***/ }), -/* 752 */ -/***/ (function(module, exports, __webpack_require__) { +Node.prototype.push = function(node) { + assert(Node.isNode(node), 'expected node to be an instance of Node'); + define(node, 'parent', this); -var isBuffer = __webpack_require__(734); -var toString = Object.prototype.toString; + this.nodes = this.nodes || []; + return this.nodes.push(node); +}; /** - * Get the native `typeof` a value. + * Given node `foo` and node `bar`, unshift node `bar` onto `foo.nodes`, and + * set `foo` as `bar.parent`. * - * @param {*} `val` - * @return {*} Native javascript type + * ```js + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * foo.unshift(bar); + * ``` + * @param {Object} `node` + * @return {Number} Returns the length of `node.nodes` + * @api public */ -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; - } - - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; - } +Node.prototype.unshift = function(node) { + assert(Node.isNode(node), 'expected node to be an instance of Node'); + define(node, 'parent', this); - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } + this.nodes = this.nodes || []; + return this.nodes.unshift(node); +}; - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } +/** + * Pop a node from `node.nodes`. + * + * ```js + * var node = new Node({type: 'foo'}); + * node.push(new Node({type: 'a'})); + * node.push(new Node({type: 'b'})); + * node.push(new Node({type: 'c'})); + * node.push(new Node({type: 'd'})); + * console.log(node.nodes.length); + * //=> 4 + * node.pop(); + * console.log(node.nodes.length); + * //=> 3 + * ``` + * @return {Number} Returns the popped `node` + * @api public + */ - // other objects - var type = toString.call(val); +Node.prototype.pop = function() { + return this.nodes && this.nodes.pop(); +}; - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } +/** + * Shift a node from `node.nodes`. + * + * ```js + * var node = new Node({type: 'foo'}); + * node.push(new Node({type: 'a'})); + * node.push(new Node({type: 'b'})); + * node.push(new Node({type: 'c'})); + * node.push(new Node({type: 'd'})); + * console.log(node.nodes.length); + * //=> 4 + * node.shift(); + * console.log(node.nodes.length); + * //=> 3 + * ``` + * @return {Object} Returns the shifted `node` + * @api public + */ - // buffer - if (isBuffer(val)) { - return 'buffer'; - } +Node.prototype.shift = function() { + return this.nodes && this.nodes.shift(); +}; - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } +/** + * Remove `node` from `node.nodes`. + * + * ```js + * node.remove(childNode); + * ``` + * @param {Object} `node` + * @return {Object} Returns the removed node. + * @api public + */ - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; - } - if (type === '[object Float64Array]') { - return 'float64array'; +Node.prototype.remove = function(node) { + assert(Node.isNode(node), 'expected node to be an instance of Node'); + this.nodes = this.nodes || []; + var idx = node.index; + if (idx !== -1) { + node.index = -1; + return this.nodes.splice(idx, 1); } - - // must be a plain object - return 'object'; + return null; }; - -/***/ }), -/* 753 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * repeat-string +/** + * Get the first child node from `node.nodes` that matches the given `type`. + * If `type` is a number, the child node at that index is returned. * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. + * ```js + * var child = node.find(1); //<= index of the node to get + * var child = node.find('foo'); //<= node.type of a child node + * var child = node.find(/^(foo|bar)$/); //<= regex to match node.type + * var child = node.find(['foo', 'bar']); //<= array of node.type(s) + * ``` + * @param {String} `type` + * @return {Object} Returns a child node or undefined. + * @api public */ - +Node.prototype.find = function(type) { + return utils.findNode(this.nodes, type); +}; /** - * Results cache + * Return true if the node is the given `type`. + * + * ```js + * var node = new Node({type: 'bar'}); + * cosole.log(node.isType('foo')); // false + * cosole.log(node.isType(/^(foo|bar)$/)); // true + * cosole.log(node.isType(['foo', 'bar'])); // true + * ``` + * @param {String} `type` + * @return {Boolean} + * @api public */ -var res = ''; -var cache; +Node.prototype.isType = function(type) { + return utils.isType(this, type); +}; /** - * Expose `repeat` + * Return true if the `node.nodes` has the given `type`. + * + * ```js + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * foo.push(bar); + * + * cosole.log(foo.hasType('qux')); // false + * cosole.log(foo.hasType(/^(qux|bar)$/)); // true + * cosole.log(foo.hasType(['qux', 'bar'])); // true + * ``` + * @param {String} `type` + * @return {Boolean} + * @api public */ -module.exports = repeat; +Node.prototype.hasType = function(type) { + return utils.hasType(this, type); +}; /** - * Repeat the given `string` the specified `number` - * of times. - * - * **Example:** + * Get the siblings array, or `null` if it doesn't exist. * * ```js - * var repeat = require('repeat-string'); - * repeat('A', 5); - * //=> AAAAA - * ``` + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * var baz = new Node({type: 'baz'}); + * foo.push(bar); + * foo.push(baz); * - * @param {String} `string` The string to repeat - * @param {Number} `number` The number of times to repeat the string - * @return {String} Repeated string + * console.log(bar.siblings.length) // 2 + * console.log(baz.siblings.length) // 2 + * ``` + * @return {Array} * @api public */ -function repeat(str, num) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); +Object.defineProperty(Node.prototype, 'siblings', { + set: function() { + throw new Error('node.siblings is a getter and cannot be defined'); + }, + get: function() { + return this.parent ? this.parent.nodes : null; } +}); - // cover common, quick use cases - if (num === 1) return str; - if (num === 2) return str + str; - - var max = str.length * num; - if (cache !== str || typeof cache === 'undefined') { - cache = str; - res = ''; - } else if (res.length >= max) { - return res.substr(0, max); - } +/** + * Get the node's current index from `node.parent.nodes`. + * This should always be correct, even when the parent adds nodes. + * + * ```js + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * var baz = new Node({type: 'baz'}); + * var qux = new Node({type: 'qux'}); + * foo.push(bar); + * foo.push(baz); + * foo.unshift(qux); + * + * console.log(bar.index) // 1 + * console.log(baz.index) // 2 + * console.log(qux.index) // 0 + * ``` + * @return {Number} + * @api public + */ - while (max > res.length && num > 1) { - if (num & 1) { - res += str; +Object.defineProperty(Node.prototype, 'index', { + set: function(index) { + define(this, 'idx', index); + }, + get: function() { + if (!Array.isArray(this.siblings)) { + return -1; } - - num >>= 1; - str += str; + var tok = this.idx !== -1 ? this.siblings[this.idx] : null; + if (tok !== this) { + this.idx = this.siblings.indexOf(this); + } + return this.idx; } +}); - res += str; - res = res.substr(0, max); - return res; -} - - -/***/ }), -/* 754 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * to-regex-range +/** + * Get the previous node from the siblings array or `null`. * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. + * ```js + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * var baz = new Node({type: 'baz'}); + * foo.push(bar); + * foo.push(baz); + * + * console.log(baz.prev.type) // 'bar' + * ``` + * @return {Object} + * @api public */ - - -var repeat = __webpack_require__(753); -var isNumber = __webpack_require__(751); -var cache = {}; - -function toRegexRange(min, max, options) { - if (isNumber(min) === false) { - throw new RangeError('toRegexRange: first argument is invalid.'); - } - - if (typeof max === 'undefined' || min === max) { - return String(min); - } - - if (isNumber(max) === false) { - throw new RangeError('toRegexRange: second argument is invalid.'); - } - - options = options || {}; - var relax = String(options.relaxZeros); - var shorthand = String(options.shorthand); - var capture = String(options.capture); - var key = min + ':' + max + '=' + relax + shorthand + capture; - if (cache.hasOwnProperty(key)) { - return cache[key].result; - } - - var a = Math.min(min, max); - var b = Math.max(min, max); - - if (Math.abs(a - b) === 1) { - var result = min + '|' + max; - if (options.capture) { - return '(' + result + ')'; +Object.defineProperty(Node.prototype, 'prev', { + set: function() { + throw new Error('node.prev is a getter and cannot be defined'); + }, + get: function() { + if (Array.isArray(this.siblings)) { + return this.siblings[this.index - 1] || this.parent.prev; } - return result; - } - - var isPadded = padding(min) || padding(max); - var positives = []; - var negatives = []; - - var tok = {min: min, max: max, a: a, b: b}; - if (isPadded) { - tok.isPadded = isPadded; - tok.maxLen = String(tok.max).length; - } - - if (a < 0) { - var newMin = b < 0 ? Math.abs(b) : 1; - var newMax = Math.abs(a); - negatives = splitToPatterns(newMin, newMax, tok, options); - a = tok.a = 0; - } - - if (b >= 0) { - positives = splitToPatterns(a, b, tok, options); - } - - tok.negatives = negatives; - tok.positives = positives; - tok.result = siftPatterns(negatives, positives, options); - - if (options.capture && (positives.length + negatives.length) > 1) { - tok.result = '(' + tok.result + ')'; - } - - cache[key] = tok; - return tok.result; -} - -function siftPatterns(neg, pos, options) { - var onlyNegative = filterPatterns(neg, pos, '-', false, options) || []; - var onlyPositive = filterPatterns(pos, neg, '', false, options) || []; - var intersected = filterPatterns(neg, pos, '-?', true, options) || []; - var subpatterns = onlyNegative.concat(intersected).concat(onlyPositive); - return subpatterns.join('|'); -} - -function splitToRanges(min, max) { - min = Number(min); - max = Number(max); - - var nines = 1; - var stops = [max]; - var stop = +countNines(min, nines); - - while (min <= stop && stop <= max) { - stops = push(stops, stop); - nines += 1; - stop = +countNines(min, nines); - } - - var zeros = 1; - stop = countZeros(max + 1, zeros) - 1; - - while (min < stop && stop <= max) { - stops = push(stops, stop); - zeros += 1; - stop = countZeros(max + 1, zeros) - 1; + return null; } - - stops.sort(compare); - return stops; -} +}); /** - * Convert a range to a regex pattern - * @param {Number} `start` - * @param {Number} `stop` - * @return {String} + * Get the siblings array, or `null` if it doesn't exist. + * + * ```js + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * var baz = new Node({type: 'baz'}); + * foo.push(bar); + * foo.push(baz); + * + * console.log(bar.siblings.length) // 2 + * console.log(baz.siblings.length) // 2 + * ``` + * @return {Object} + * @api public */ -function rangeToPattern(start, stop, options) { - if (start === stop) { - return {pattern: String(start), digits: []}; - } - - var zipped = zip(String(start), String(stop)); - var len = zipped.length, i = -1; - - var pattern = ''; - var digits = 0; - - while (++i < len) { - var numbers = zipped[i]; - var startDigit = numbers[0]; - var stopDigit = numbers[1]; - - if (startDigit === stopDigit) { - pattern += startDigit; - - } else if (startDigit !== '0' || stopDigit !== '9') { - pattern += toCharacterClass(startDigit, stopDigit); - - } else { - digits += 1; +Object.defineProperty(Node.prototype, 'next', { + set: function() { + throw new Error('node.next is a getter and cannot be defined'); + }, + get: function() { + if (Array.isArray(this.siblings)) { + return this.siblings[this.index + 1] || this.parent.next; } + return null; } +}); - if (digits) { - pattern += options.shorthand ? '\\d' : '[0-9]'; - } - - return { pattern: pattern, digits: [digits] }; -} - -function splitToPatterns(min, max, tok, options) { - var ranges = splitToRanges(min, max); - var len = ranges.length; - var idx = -1; - - var tokens = []; - var start = min; - var prev; - - while (++idx < len) { - var range = ranges[idx]; - var obj = rangeToPattern(start, range, options); - var zeros = ''; - - if (!tok.isPadded && prev && prev.pattern === obj.pattern) { - if (prev.digits.length > 1) { - prev.digits.pop(); - } - prev.digits.push(obj.digits[0]); - prev.string = prev.pattern + toQuantifier(prev.digits); - start = range + 1; - continue; - } - - if (tok.isPadded) { - zeros = padZeros(range, tok); - } +/** + * Get the first node from `node.nodes`. + * + * ```js + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * var baz = new Node({type: 'baz'}); + * var qux = new Node({type: 'qux'}); + * foo.push(bar); + * foo.push(baz); + * foo.push(qux); + * + * console.log(foo.first.type) // 'bar' + * ``` + * @return {Object} The first node, or undefiend + * @api public + */ - obj.string = zeros + obj.pattern + toQuantifier(obj.digits); - tokens.push(obj); - start = range + 1; - prev = obj; +Object.defineProperty(Node.prototype, 'first', { + get: function() { + return this.nodes ? this.nodes[0] : null; } +}); - return tokens; -} - -function filterPatterns(arr, comparison, prefix, intersection, options) { - var res = []; - - for (var i = 0; i < arr.length; i++) { - var tok = arr[i]; - var ele = tok.string; - - if (options.relaxZeros !== false) { - if (prefix === '-' && ele.charAt(0) === '0') { - if (ele.charAt(1) === '{') { - ele = '0*' + ele.replace(/^0\{\d+\}/, ''); - } else { - ele = '0*' + ele.slice(1); - } - } - } - - if (!intersection && !contains(comparison, 'string', ele)) { - res.push(prefix + ele); - } +/** + * Get the last node from `node.nodes`. + * + * ```js + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * var baz = new Node({type: 'baz'}); + * var qux = new Node({type: 'qux'}); + * foo.push(bar); + * foo.push(baz); + * foo.push(qux); + * + * console.log(foo.last.type) // 'qux' + * ``` + * @return {Object} The last node, or undefiend + * @api public + */ - if (intersection && contains(comparison, 'string', ele)) { - res.push(prefix + ele); - } +Object.defineProperty(Node.prototype, 'last', { + get: function() { + return this.nodes ? utils.last(this.nodes) : null; } - return res; -} +}); /** - * Zip strings (`for in` can be used on string characters) + * Get the last node from `node.nodes`. + * + * ```js + * var foo = new Node({type: 'foo'}); + * var bar = new Node({type: 'bar'}); + * var baz = new Node({type: 'baz'}); + * var qux = new Node({type: 'qux'}); + * foo.push(bar); + * foo.push(baz); + * foo.push(qux); + * + * console.log(foo.last.type) // 'qux' + * ``` + * @return {Object} The last node, or undefiend + * @api public */ -function zip(a, b) { - var arr = []; - for (var ch in a) arr.push([a[ch], b[ch]]); - return arr; -} - -function compare(a, b) { - return a > b ? 1 : b > a ? -1 : 0; -} - -function push(arr, ele) { - if (arr.indexOf(ele) === -1) arr.push(ele); - return arr; -} - -function contains(arr, key, val) { - for (var i = 0; i < arr.length; i++) { - if (arr[i][key] === val) { - return true; +Object.defineProperty(Node.prototype, 'scope', { + get: function() { + if (this.isScope !== true) { + return this.parent ? this.parent.scope : this; } + return this; } - return false; -} - -function countNines(min, len) { - return String(min).slice(0, -len) + repeat('9', len); -} - -function countZeros(integer, zeros) { - return integer - (integer % Math.pow(10, zeros)); -} - -function toQuantifier(digits) { - var start = digits[0]; - var stop = digits[1] ? (',' + digits[1]) : ''; - if (!stop && (!start || start === 1)) { - return ''; - } - return '{' + start + stop + '}'; -} - -function toCharacterClass(a, b) { - return '[' + a + ((b - a === 1) ? '' : '-') + b + ']'; -} - -function padding(str) { - return /^-?(0+)\d/.exec(str); -} - -function padZeros(val, tok) { - if (tok.isPadded) { - var diff = Math.abs(tok.maxLen - String(val).length); - switch (diff) { - case 0: - return ''; - case 1: - return '0'; - default: { - return '0{' + diff + '}'; - } - } +}); + +/** + * Get own property names from Node prototype, but only the + * first time `Node` is instantiated + */ + +function lazyKeys() { + if (!ownNames) { + ownNames = Object.getOwnPropertyNames(Node.prototype); } - return val; } /** - * Expose `toRegexRange` + * Simplified assertion. Throws an error is `val` is falsey. */ -module.exports = toRegexRange; +function assert(val, message) { + if (!val) throw new Error(message); +} + +/** + * Expose `Node` + */ + +exports = module.exports = Node; /***/ }), -/* 755 */ +/* 753 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * repeat-element + * define-property * - * Copyright (c) 2015 Jon Schlinkert. - * Licensed under the MIT license. + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -module.exports = function repeat(ele, num) { - var arr = new Array(num); +var isDescriptor = __webpack_require__(754); - for (var i = 0; i < num; i++) { - arr[i] = ele; +module.exports = function defineProperty(obj, prop, val) { + if (typeof obj !== 'object' && typeof obj !== 'function') { + throw new TypeError('expected an object or function.'); } - return arr; + if (typeof prop !== 'string') { + throw new TypeError('expected `prop` to be a string.'); + } + + if (isDescriptor(val) && ('set' in val || 'get' in val)) { + return Object.defineProperty(obj, prop, val); + } + + return Object.defineProperty(obj, prop, { + configurable: true, + enumerable: false, + writable: true, + value: val + }); }; /***/ }), -/* 756 */ +/* 754 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * is-descriptor + * + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. + */ -var Node = __webpack_require__(757); -var utils = __webpack_require__(742); -/** - * Braces parsers - */ +var typeOf = __webpack_require__(755); +var isAccessor = __webpack_require__(756); +var isData = __webpack_require__(758); -module.exports = function(braces, options) { - braces.parser - .set('bos', function() { - if (!this.parsed) { - this.ast = this.nodes[0] = new Node(this.ast); - } - }) +module.exports = function isDescriptor(obj, key) { + if (typeOf(obj) !== 'object') { + return false; + } + if ('get' in obj) { + return isAccessor(obj, key); + } + return isData(obj, key); +}; - /** - * Character parsers - */ - .set('escape', function() { - var pos = this.position(); - var m = this.match(/^(?:\\(.)|\$\{)/); - if (!m) return; +/***/ }), +/* 755 */ +/***/ (function(module, exports) { - var prev = this.prev(); - var last = utils.last(prev.nodes); +var toString = Object.prototype.toString; - var node = pos(new Node({ - type: 'text', - multiplier: 1, - val: m[0] - })); +module.exports = function kindOf(val) { + if (val === void 0) return 'undefined'; + if (val === null) return 'null'; - if (node.val === '\\\\') { - return node; - } + var type = typeof val; + if (type === 'boolean') return 'boolean'; + if (type === 'string') return 'string'; + if (type === 'number') return 'number'; + if (type === 'symbol') return 'symbol'; + if (type === 'function') { + return isGeneratorFn(val) ? 'generatorfunction' : 'function'; + } - if (node.val === '${') { - var str = this.input; - var idx = -1; - var ch; + if (isArray(val)) return 'array'; + if (isBuffer(val)) return 'buffer'; + if (isArguments(val)) return 'arguments'; + if (isDate(val)) return 'date'; + if (isError(val)) return 'error'; + if (isRegexp(val)) return 'regexp'; - while ((ch = str[++idx])) { - this.consume(1); - node.val += ch; - if (ch === '\\') { - node.val += str[++idx]; - continue; - } - if (ch === '}') { - break; - } - } - } + switch (ctorName(val)) { + case 'Symbol': return 'symbol'; + case 'Promise': return 'promise'; - if (this.options.unescape !== false) { - node.val = node.val.replace(/\\([{}])/g, '$1'); - } + // Set, Map, WeakSet, WeakMap + case 'WeakMap': return 'weakmap'; + case 'WeakSet': return 'weakset'; + case 'Map': return 'map'; + case 'Set': return 'set'; - if (last.val === '"' && this.input.charAt(0) === '"') { - last.val = node.val; - this.consume(1); - return; - } + // 8-bit typed arrays + case 'Int8Array': return 'int8array'; + case 'Uint8Array': return 'uint8array'; + case 'Uint8ClampedArray': return 'uint8clampedarray'; - return concatNodes.call(this, pos, node, prev, options); - }) + // 16-bit typed arrays + case 'Int16Array': return 'int16array'; + case 'Uint16Array': return 'uint16array'; - /** - * Brackets: "[...]" (basic, this is overridden by - * other parsers in more advanced implementations) - */ + // 32-bit typed arrays + case 'Int32Array': return 'int32array'; + case 'Uint32Array': return 'uint32array'; + case 'Float32Array': return 'float32array'; + case 'Float64Array': return 'float64array'; + } - .set('bracket', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^(?:\[([!^]?)([^\]]{2,}|\]-)(\]|[^*+?]+)|\[)/); - if (!m) return; + if (isGeneratorObj(val)) { + return 'generator'; + } - var prev = this.prev(); - var val = m[0]; - var negated = m[1] ? '^' : ''; - var inner = m[2] || ''; - var close = m[3] || ''; + // Non-plain objects + type = toString.call(val); + switch (type) { + case '[object Object]': return 'object'; + // iterators + case '[object Map Iterator]': return 'mapiterator'; + case '[object Set Iterator]': return 'setiterator'; + case '[object String Iterator]': return 'stringiterator'; + case '[object Array Iterator]': return 'arrayiterator'; + } - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } + // other + return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); +}; - var esc = this.input.slice(0, 2); - if (inner === '' && esc === '\\]') { - inner += esc; - this.consume(2); +function ctorName(val) { + return val.constructor ? val.constructor.name : null; +} - var str = this.input; - var idx = -1; - var ch; +function isArray(val) { + if (Array.isArray) return Array.isArray(val); + return val instanceof Array; +} - while ((ch = str[++idx])) { - this.consume(1); - if (ch === ']') { - close = ch; - break; - } - inner += ch; - } - } +function isError(val) { + return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); +} - return pos(new Node({ - type: 'bracket', - val: val, - escaped: close !== ']', - negated: negated, - inner: inner, - close: close - })); - }) +function isDate(val) { + if (val instanceof Date) return true; + return typeof val.toDateString === 'function' + && typeof val.getDate === 'function' + && typeof val.setDate === 'function'; +} - /** - * Empty braces (we capture these early to - * speed up processing in the compiler) - */ +function isRegexp(val) { + if (val instanceof RegExp) return true; + return typeof val.flags === 'string' + && typeof val.ignoreCase === 'boolean' + && typeof val.multiline === 'boolean' + && typeof val.global === 'boolean'; +} - .set('multiplier', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^\{((?:,|\{,+\})+)\}/); - if (!m) return; +function isGeneratorFn(name, val) { + return ctorName(name) === 'GeneratorFunction'; +} - this.multiplier = true; - var prev = this.prev(); - var val = m[0]; +function isGeneratorObj(val) { + return typeof val.throw === 'function' + && typeof val.return === 'function' + && typeof val.next === 'function'; +} - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } +function isArguments(val) { + try { + if (typeof val.length === 'number' && typeof val.callee === 'function') { + return true; + } + } catch (err) { + if (err.message.indexOf('callee') !== -1) { + return true; + } + } + return false; +} - var node = pos(new Node({ - type: 'text', - multiplier: 1, - match: m, - val: val - })); +/** + * If you need to support Safari 5-7 (8-10 yr-old browser), + * take a look at https://github.com/feross/is-buffer + */ - return concatNodes.call(this, pos, node, prev, options); - }) +function isBuffer(val) { + if (val.constructor && typeof val.constructor.isBuffer === 'function') { + return val.constructor.isBuffer(val); + } + return false; +} - /** - * Open - */ - .set('brace.open', function() { - var pos = this.position(); - var m = this.match(/^\{(?!(?:[^\\}]?|,+)\})/); - if (!m) return; +/***/ }), +/* 756 */ +/***/ (function(module, exports, __webpack_require__) { - var prev = this.prev(); - var last = utils.last(prev.nodes); +"use strict"; +/*! + * is-accessor-descriptor + * + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. + */ - // if the last parsed character was an extglob character - // we need to _not optimize_ the brace pattern because - // it might be mistaken for an extglob by a downstream parser - if (last && last.val && isExtglobChar(last.val.slice(-1))) { - last.optimize = false; - } - var open = pos(new Node({ - type: 'brace.open', - val: m[0] - })); - var node = pos(new Node({ - type: 'brace', - nodes: [] - })); +var typeOf = __webpack_require__(757); - node.push(open); - prev.push(node); - this.push('brace', node); - }) +// accessor descriptor properties +var accessor = { + get: 'function', + set: 'function', + configurable: 'boolean', + enumerable: 'boolean' +}; - /** - * Close - */ +function isAccessorDescriptor(obj, prop) { + if (typeof prop === 'string') { + var val = Object.getOwnPropertyDescriptor(obj, prop); + return typeof val !== 'undefined'; + } - .set('brace.close', function() { - var pos = this.position(); - var m = this.match(/^\}/); - if (!m || !m[0]) return; + if (typeOf(obj) !== 'object') { + return false; + } - var brace = this.pop('brace'); - var node = pos(new Node({ - type: 'brace.close', - val: m[0] - })); + if (has(obj, 'value') || has(obj, 'writable')) { + return false; + } - if (!this.isType(brace, 'brace')) { - if (this.options.strict) { - throw new Error('missing opening "{"'); - } - node.type = 'text'; - node.multiplier = 0; - node.escaped = true; - return node; - } + if (!has(obj, 'get') || typeof obj.get !== 'function') { + return false; + } - var prev = this.prev(); - var last = utils.last(prev.nodes); - if (last.text) { - var lastNode = utils.last(last.nodes); - if (lastNode.val === ')' && /[!@*?+]\(/.test(last.text)) { - var open = last.nodes[0]; - var text = last.nodes[1]; - if (open.type === 'brace.open' && text && text.type === 'text') { - text.optimize = false; - } - } - } + // tldr: it's valid to have "set" be undefined + // "set" might be undefined if `Object.getOwnPropertyDescriptor` + // was used to get the value, and only `get` was defined by the user + if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { + return false; + } - if (brace.nodes.length > 2) { - var first = brace.nodes[1]; - if (first.type === 'text' && first.val === ',') { - brace.nodes.splice(1, 1); - brace.nodes.push(first); - } - } + for (var key in obj) { + if (!accessor.hasOwnProperty(key)) { + continue; + } - brace.push(node); - }) + if (typeOf(obj[key]) === accessor[key]) { + continue; + } - /** - * Capture boundary characters - */ + if (typeof obj[key] !== 'undefined') { + return false; + } + } + return true; +} - .set('boundary', function() { - var pos = this.position(); - var m = this.match(/^[$^](?!\{)/); - if (!m) return; - return pos(new Node({ - type: 'text', - val: m[0] - })); - }) +function has(obj, key) { + return {}.hasOwnProperty.call(obj, key); +} - /** - * One or zero, non-comma characters wrapped in braces - */ +/** + * Expose `isAccessorDescriptor` + */ - .set('nobrace', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^\{[^,]?\}/); - if (!m) return; +module.exports = isAccessorDescriptor; - var prev = this.prev(); - var val = m[0]; - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } +/***/ }), +/* 757 */ +/***/ (function(module, exports) { - return pos(new Node({ - type: 'text', - multiplier: 0, - val: val - })); - }) +var toString = Object.prototype.toString; - /** - * Text - */ +module.exports = function kindOf(val) { + if (val === void 0) return 'undefined'; + if (val === null) return 'null'; - .set('text', function() { - var isInside = this.isInside('brace'); - var pos = this.position(); - var m = this.match(/^((?!\\)[^${}[\]])+/); - if (!m) return; + var type = typeof val; + if (type === 'boolean') return 'boolean'; + if (type === 'string') return 'string'; + if (type === 'number') return 'number'; + if (type === 'symbol') return 'symbol'; + if (type === 'function') { + return isGeneratorFn(val) ? 'generatorfunction' : 'function'; + } - var prev = this.prev(); - var val = m[0]; + if (isArray(val)) return 'array'; + if (isBuffer(val)) return 'buffer'; + if (isArguments(val)) return 'arguments'; + if (isDate(val)) return 'date'; + if (isError(val)) return 'error'; + if (isRegexp(val)) return 'regexp'; + + switch (ctorName(val)) { + case 'Symbol': return 'symbol'; + case 'Promise': return 'promise'; + + // Set, Map, WeakSet, WeakMap + case 'WeakMap': return 'weakmap'; + case 'WeakSet': return 'weakset'; + case 'Map': return 'map'; + case 'Set': return 'set'; + + // 8-bit typed arrays + case 'Int8Array': return 'int8array'; + case 'Uint8Array': return 'uint8array'; + case 'Uint8ClampedArray': return 'uint8clampedarray'; + + // 16-bit typed arrays + case 'Int16Array': return 'int16array'; + case 'Uint16Array': return 'uint16array'; + + // 32-bit typed arrays + case 'Int32Array': return 'int32array'; + case 'Uint32Array': return 'uint32array'; + case 'Float32Array': return 'float32array'; + case 'Float64Array': return 'float64array'; + } - if (isInside && prev.type === 'brace') { - prev.text = prev.text || ''; - prev.text += val; - } + if (isGeneratorObj(val)) { + return 'generator'; + } - var node = pos(new Node({ - type: 'text', - multiplier: 1, - val: val - })); + // Non-plain objects + type = toString.call(val); + switch (type) { + case '[object Object]': return 'object'; + // iterators + case '[object Map Iterator]': return 'mapiterator'; + case '[object Set Iterator]': return 'setiterator'; + case '[object String Iterator]': return 'stringiterator'; + case '[object Array Iterator]': return 'arrayiterator'; + } - return concatNodes.call(this, pos, node, prev, options); - }); + // other + return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); }; -/** - * Returns true if the character is an extglob character. - */ +function ctorName(val) { + return val.constructor ? val.constructor.name : null; +} -function isExtglobChar(ch) { - return ch === '!' || ch === '@' || ch === '*' || ch === '?' || ch === '+'; +function isArray(val) { + if (Array.isArray) return Array.isArray(val); + return val instanceof Array; } -/** - * Combine text nodes, and calculate empty sets (`{,,}`) - * @param {Function} `pos` Function to calculate node position - * @param {Object} `node` AST node - * @return {Object} - */ +function isError(val) { + return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); +} -function concatNodes(pos, node, parent, options) { - node.orig = node.val; - var prev = this.prev(); - var last = utils.last(prev.nodes); - var isEscaped = false; +function isDate(val) { + if (val instanceof Date) return true; + return typeof val.toDateString === 'function' + && typeof val.getDate === 'function' + && typeof val.setDate === 'function'; +} - if (node.val.length > 1) { - var a = node.val.charAt(0); - var b = node.val.slice(-1); +function isRegexp(val) { + if (val instanceof RegExp) return true; + return typeof val.flags === 'string' + && typeof val.ignoreCase === 'boolean' + && typeof val.multiline === 'boolean' + && typeof val.global === 'boolean'; +} - isEscaped = (a === '"' && b === '"') - || (a === "'" && b === "'") - || (a === '`' && b === '`'); - } +function isGeneratorFn(name, val) { + return ctorName(name) === 'GeneratorFunction'; +} - if (isEscaped && options.unescape !== false) { - node.val = node.val.slice(1, node.val.length - 1); - node.escaped = true; - } +function isGeneratorObj(val) { + return typeof val.throw === 'function' + && typeof val.return === 'function' + && typeof val.next === 'function'; +} - if (node.match) { - var match = node.match[1]; - if (!match || match.indexOf('}') === -1) { - match = node.match[0]; +function isArguments(val) { + try { + if (typeof val.length === 'number' && typeof val.callee === 'function') { + return true; + } + } catch (err) { + if (err.message.indexOf('callee') !== -1) { + return true; } - - // replace each set with a single "," - var val = match.replace(/\{/g, ',').replace(/\}/g, ''); - node.multiplier *= val.length; - node.val = ''; } + return false; +} - var simpleText = last.type === 'text' - && last.multiplier === 1 - && node.multiplier === 1 - && node.val; +/** + * If you need to support Safari 5-7 (8-10 yr-old browser), + * take a look at https://github.com/feross/is-buffer + */ - if (simpleText) { - last.val += node.val; - return; +function isBuffer(val) { + if (val.constructor && typeof val.constructor.isBuffer === 'function') { + return val.constructor.isBuffer(val); } - - prev.push(node); + return false; } /***/ }), -/* 757 */ +/* 758 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * is-data-descriptor + * + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. + */ -var isObject = __webpack_require__(747); -var define = __webpack_require__(758); -var utils = __webpack_require__(765); -var ownNames; -/** - * Create a new AST `Node` with the given `val` and `type`. - * - * ```js - * var node = new Node('*', 'Star'); - * var node = new Node({type: 'star', val: '*'}); - * ``` - * @name Node - * @param {String|Object} `val` Pass a matched substring, or an object to merge onto the node. - * @param {String} `type` The node type to use when `val` is a string. - * @return {Object} node instance - * @api public - */ +var typeOf = __webpack_require__(759); -function Node(val, type, parent) { - if (typeof type !== 'string') { - parent = type; - type = null; +module.exports = function isDataDescriptor(obj, prop) { + // data descriptor properties + var data = { + configurable: 'boolean', + enumerable: 'boolean', + writable: 'boolean' + }; + + if (typeOf(obj) !== 'object') { + return false; } - define(this, 'parent', parent); - define(this, 'isNode', true); - define(this, 'expect', null); + if (typeof prop === 'string') { + var val = Object.getOwnPropertyDescriptor(obj, prop); + return typeof val !== 'undefined'; + } - if (typeof type !== 'string' && isObject(val)) { - lazyKeys(); - var keys = Object.keys(val); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (ownNames.indexOf(key) === -1) { - this[key] = val[key]; - } - } - } else { - this.type = type; - this.val = val; + if (!('value' in obj) && !('writable' in obj)) { + return false; } -} -/** - * Returns true if the given value is a node. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(Node.isNode(node)); //=> true - * console.log(Node.isNode({})); //=> false - * ``` - * @param {Object} `node` - * @returns {Boolean} - * @api public - */ + for (var key in obj) { + if (key === 'value') continue; -Node.isNode = function(node) { - return utils.isNode(node); -}; + if (!data.hasOwnProperty(key)) { + continue; + } -/** - * Define a non-enumberable property on the node instance. - * Useful for adding properties that shouldn't be extended - * or visible during debugging. - * - * ```js - * var node = new Node(); - * node.define('foo', 'something non-enumerable'); - * ``` - * @param {String} `name` - * @param {any} `val` - * @return {Object} returns the node instance - * @api public - */ + if (typeOf(obj[key]) === data[key]) { + continue; + } -Node.prototype.define = function(name, val) { - define(this, name, val); - return this; + if (typeof obj[key] !== 'undefined') { + return false; + } + } + return true; }; -/** - * Returns true if `node.val` is an empty string, or `node.nodes` does - * not contain any non-empty text nodes. - * - * ```js - * var node = new Node({type: 'text'}); - * node.isEmpty(); //=> true - * node.val = 'foo'; - * node.isEmpty(); //=> false - * ``` - * @param {Function} `fn` (optional) Filter function that is called on `node` and/or child nodes. `isEmpty` will return false immediately when the filter function returns false on any nodes. - * @return {Boolean} - * @api public - */ -Node.prototype.isEmpty = function(fn) { - return utils.isEmpty(this, fn); -}; +/***/ }), +/* 759 */ +/***/ (function(module, exports) { -/** - * Given node `foo` and node `bar`, push node `bar` onto `foo.nodes`, and - * set `foo` as `bar.parent`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * foo.push(bar); - * ``` - * @param {Object} `node` - * @return {Number} Returns the length of `node.nodes` - * @api public - */ +var toString = Object.prototype.toString; -Node.prototype.push = function(node) { - assert(Node.isNode(node), 'expected node to be an instance of Node'); - define(node, 'parent', this); +module.exports = function kindOf(val) { + if (val === void 0) return 'undefined'; + if (val === null) return 'null'; - this.nodes = this.nodes || []; - return this.nodes.push(node); -}; + var type = typeof val; + if (type === 'boolean') return 'boolean'; + if (type === 'string') return 'string'; + if (type === 'number') return 'number'; + if (type === 'symbol') return 'symbol'; + if (type === 'function') { + return isGeneratorFn(val) ? 'generatorfunction' : 'function'; + } -/** - * Given node `foo` and node `bar`, unshift node `bar` onto `foo.nodes`, and - * set `foo` as `bar.parent`. - * - * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * foo.unshift(bar); - * ``` - * @param {Object} `node` - * @return {Number} Returns the length of `node.nodes` - * @api public - */ + if (isArray(val)) return 'array'; + if (isBuffer(val)) return 'buffer'; + if (isArguments(val)) return 'arguments'; + if (isDate(val)) return 'date'; + if (isError(val)) return 'error'; + if (isRegexp(val)) return 'regexp'; -Node.prototype.unshift = function(node) { - assert(Node.isNode(node), 'expected node to be an instance of Node'); - define(node, 'parent', this); + switch (ctorName(val)) { + case 'Symbol': return 'symbol'; + case 'Promise': return 'promise'; - this.nodes = this.nodes || []; - return this.nodes.unshift(node); -}; + // Set, Map, WeakSet, WeakMap + case 'WeakMap': return 'weakmap'; + case 'WeakSet': return 'weakset'; + case 'Map': return 'map'; + case 'Set': return 'set'; -/** - * Pop a node from `node.nodes`. - * - * ```js - * var node = new Node({type: 'foo'}); - * node.push(new Node({type: 'a'})); - * node.push(new Node({type: 'b'})); - * node.push(new Node({type: 'c'})); - * node.push(new Node({type: 'd'})); - * console.log(node.nodes.length); - * //=> 4 - * node.pop(); - * console.log(node.nodes.length); - * //=> 3 - * ``` - * @return {Number} Returns the popped `node` - * @api public - */ + // 8-bit typed arrays + case 'Int8Array': return 'int8array'; + case 'Uint8Array': return 'uint8array'; + case 'Uint8ClampedArray': return 'uint8clampedarray'; -Node.prototype.pop = function() { - return this.nodes && this.nodes.pop(); -}; + // 16-bit typed arrays + case 'Int16Array': return 'int16array'; + case 'Uint16Array': return 'uint16array'; -/** - * Shift a node from `node.nodes`. - * - * ```js - * var node = new Node({type: 'foo'}); - * node.push(new Node({type: 'a'})); - * node.push(new Node({type: 'b'})); - * node.push(new Node({type: 'c'})); - * node.push(new Node({type: 'd'})); - * console.log(node.nodes.length); - * //=> 4 - * node.shift(); - * console.log(node.nodes.length); - * //=> 3 - * ``` - * @return {Object} Returns the shifted `node` - * @api public - */ + // 32-bit typed arrays + case 'Int32Array': return 'int32array'; + case 'Uint32Array': return 'uint32array'; + case 'Float32Array': return 'float32array'; + case 'Float64Array': return 'float64array'; + } -Node.prototype.shift = function() { - return this.nodes && this.nodes.shift(); + if (isGeneratorObj(val)) { + return 'generator'; + } + + // Non-plain objects + type = toString.call(val); + switch (type) { + case '[object Object]': return 'object'; + // iterators + case '[object Map Iterator]': return 'mapiterator'; + case '[object Set Iterator]': return 'setiterator'; + case '[object String Iterator]': return 'stringiterator'; + case '[object Array Iterator]': return 'arrayiterator'; + } + + // other + return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); }; -/** - * Remove `node` from `node.nodes`. - * - * ```js - * node.remove(childNode); - * ``` - * @param {Object} `node` - * @return {Object} Returns the removed node. - * @api public - */ +function ctorName(val) { + return val.constructor ? val.constructor.name : null; +} -Node.prototype.remove = function(node) { - assert(Node.isNode(node), 'expected node to be an instance of Node'); - this.nodes = this.nodes || []; - var idx = node.index; - if (idx !== -1) { - node.index = -1; - return this.nodes.splice(idx, 1); +function isArray(val) { + if (Array.isArray) return Array.isArray(val); + return val instanceof Array; +} + +function isError(val) { + return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); +} + +function isDate(val) { + if (val instanceof Date) return true; + return typeof val.toDateString === 'function' + && typeof val.getDate === 'function' + && typeof val.setDate === 'function'; +} + +function isRegexp(val) { + if (val instanceof RegExp) return true; + return typeof val.flags === 'string' + && typeof val.ignoreCase === 'boolean' + && typeof val.multiline === 'boolean' + && typeof val.global === 'boolean'; +} + +function isGeneratorFn(name, val) { + return ctorName(name) === 'GeneratorFunction'; +} + +function isGeneratorObj(val) { + return typeof val.throw === 'function' + && typeof val.return === 'function' + && typeof val.next === 'function'; +} + +function isArguments(val) { + try { + if (typeof val.length === 'number' && typeof val.callee === 'function') { + return true; + } + } catch (err) { + if (err.message.indexOf('callee') !== -1) { + return true; + } } - return null; -}; + return false; +} /** - * Get the first child node from `node.nodes` that matches the given `type`. - * If `type` is a number, the child node at that index is returned. - * - * ```js - * var child = node.find(1); //<= index of the node to get - * var child = node.find('foo'); //<= node.type of a child node - * var child = node.find(/^(foo|bar)$/); //<= regex to match node.type - * var child = node.find(['foo', 'bar']); //<= array of node.type(s) - * ``` - * @param {String} `type` - * @return {Object} Returns a child node or undefined. - * @api public + * If you need to support Safari 5-7 (8-10 yr-old browser), + * take a look at https://github.com/feross/is-buffer */ -Node.prototype.find = function(type) { - return utils.findNode(this.nodes, type); -}; +function isBuffer(val) { + if (val.constructor && typeof val.constructor.isBuffer === 'function') { + return val.constructor.isBuffer(val); + } + return false; +} + + +/***/ }), +/* 760 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var typeOf = __webpack_require__(747); +var utils = module.exports; /** - * Return true if the node is the given `type`. + * Returns true if the given value is a node. * * ```js - * var node = new Node({type: 'bar'}); - * cosole.log(node.isType('foo')); // false - * cosole.log(node.isType(/^(foo|bar)$/)); // true - * cosole.log(node.isType(['foo', 'bar'])); // true + * var Node = require('snapdragon-node'); + * var node = new Node({type: 'foo'}); + * console.log(utils.isNode(node)); //=> true + * console.log(utils.isNode({})); //=> false * ``` - * @param {String} `type` - * @return {Boolean} + * @param {Object} `node` Instance of [snapdragon-node][] + * @returns {Boolean} * @api public */ -Node.prototype.isType = function(type) { - return utils.isType(this, type); +utils.isNode = function(node) { + return typeOf(node) === 'object' && node.isNode === true; }; /** - * Return true if the `node.nodes` has the given `type`. + * Emit an empty string for the given `node`. * * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * foo.push(bar); - * - * cosole.log(foo.hasType('qux')); // false - * cosole.log(foo.hasType(/^(qux|bar)$/)); // true - * cosole.log(foo.hasType(['qux', 'bar'])); // true + * // do nothing for beginning-of-string + * snapdragon.compiler.set('bos', utils.noop); * ``` - * @param {String} `type` - * @return {Boolean} + * @param {Object} `node` Instance of [snapdragon-node][] + * @returns {undefined} * @api public */ -Node.prototype.hasType = function(type) { - return utils.hasType(this, type); +utils.noop = function(node) { + append(this, '', node); }; /** - * Get the siblings array, or `null` if it doesn't exist. + * Appdend `node.val` to `compiler.output`, exactly as it was created + * by the parser. * * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * foo.push(bar); - * foo.push(baz); - * - * console.log(bar.siblings.length) // 2 - * console.log(baz.siblings.length) // 2 + * snapdragon.compiler.set('text', utils.identity); * ``` - * @return {Array} + * @param {Object} `node` Instance of [snapdragon-node][] + * @returns {undefined} * @api public */ -Object.defineProperty(Node.prototype, 'siblings', { - set: function() { - throw new Error('node.siblings is a getter and cannot be defined'); - }, - get: function() { - return this.parent ? this.parent.nodes : null; - } -}); +utils.identity = function(node) { + append(this, node.val, node); +}; /** - * Get the node's current index from `node.parent.nodes`. - * This should always be correct, even when the parent adds nodes. + * Previously named `.emit`, this method appends the given `val` + * to `compiler.output` for the given node. Useful when you know + * what value should be appended advance, regardless of the actual + * value of `node.val`. * * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.unshift(qux); - * - * console.log(bar.index) // 1 - * console.log(baz.index) // 2 - * console.log(qux.index) // 0 + * snapdragon.compiler + * .set('i', function(node) { + * this.mapVisit(node); + * }) + * .set('i.open', utils.append('')) + * .set('i.close', utils.append('')) * ``` - * @return {Number} + * @param {Object} `node` Instance of [snapdragon-node][] + * @returns {Function} Returns a compiler middleware function. * @api public */ -Object.defineProperty(Node.prototype, 'index', { - set: function(index) { - define(this, 'idx', index); - }, - get: function() { - if (!Array.isArray(this.siblings)) { - return -1; - } - var tok = this.idx !== -1 ? this.siblings[this.idx] : null; - if (tok !== this) { - this.idx = this.siblings.indexOf(this); - } - return this.idx; - } -}); +utils.append = function(val) { + return function(node) { + append(this, val, node); + }; +}; /** - * Get the previous node from the siblings array or `null`. + * Used in compiler middleware, this onverts an AST node into + * an empty `text` node and deletes `node.nodes` if it exists. + * The advantage of this method is that, as opposed to completely + * removing the node, indices will not need to be re-calculated + * in sibling nodes, and nothing is appended to the output. * * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * foo.push(bar); - * foo.push(baz); - * - * console.log(baz.prev.type) // 'bar' + * utils.toNoop(node); + * // convert `node.nodes` to the given value instead of deleting it + * utils.toNoop(node, []); * ``` - * @return {Object} + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Array} `nodes` Optionally pass a new `nodes` value, to replace the existing `node.nodes` array. * @api public */ -Object.defineProperty(Node.prototype, 'prev', { - set: function() { - throw new Error('node.prev is a getter and cannot be defined'); - }, - get: function() { - if (Array.isArray(this.siblings)) { - return this.siblings[this.index - 1] || this.parent.prev; - } - return null; +utils.toNoop = function(node, nodes) { + if (nodes) { + node.nodes = nodes; + } else { + delete node.nodes; + node.type = 'text'; + node.val = ''; } -}); +}; /** - * Get the siblings array, or `null` if it doesn't exist. + * Visit `node` with the given `fn`. The built-in `.visit` method in snapdragon + * automatically calls registered compilers, this allows you to pass a visitor + * function. * * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * foo.push(bar); - * foo.push(baz); - * - * console.log(bar.siblings.length) // 2 - * console.log(baz.siblings.length) // 2 + * snapdragon.compiler.set('i', function(node) { + * utils.visit(node, function(childNode) { + * // do stuff with "childNode" + * return childNode; + * }); + * }); * ``` - * @return {Object} + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `fn` + * @return {Object} returns the node after recursively visiting all child nodes. * @api public */ -Object.defineProperty(Node.prototype, 'next', { - set: function() { - throw new Error('node.next is a getter and cannot be defined'); - }, - get: function() { - if (Array.isArray(this.siblings)) { - return this.siblings[this.index + 1] || this.parent.next; - } - return null; - } -}); +utils.visit = function(node, fn) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isFunction(fn), 'expected a visitor function'); + fn(node); + return node.nodes ? utils.mapVisit(node, fn) : node; +}; /** - * Get the first node from `node.nodes`. + * Map [visit](#visit) the given `fn` over `node.nodes`. This is called by + * [visit](#visit), use this method if you do not want `fn` to be called on + * the first node. * * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.push(qux); - * - * console.log(foo.first.type) // 'bar' + * snapdragon.compiler.set('i', function(node) { + * utils.mapVisit(node, function(childNode) { + * // do stuff with "childNode" + * return childNode; + * }); + * }); * ``` - * @return {Object} The first node, or undefiend + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Object} `options` + * @param {Function} `fn` + * @return {Object} returns the node * @api public */ -Object.defineProperty(Node.prototype, 'first', { - get: function() { - return this.nodes ? this.nodes[0] : null; +utils.mapVisit = function(node, fn) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isArray(node.nodes), 'expected node.nodes to be an array'); + assert(isFunction(fn), 'expected a visitor function'); + + for (var i = 0; i < node.nodes.length; i++) { + utils.visit(node.nodes[i], fn); } -}); + return node; +}; /** - * Get the last node from `node.nodes`. + * Unshift an `*.open` node onto `node.nodes`. * * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.push(qux); + * var Node = require('snapdragon-node'); + * snapdragon.parser.set('brace', function(node) { + * var match = this.match(/^{/); + * if (match) { + * var parent = new Node({type: 'brace'}); + * utils.addOpen(parent, Node); + * console.log(parent.nodes[0]): + * // { type: 'brace.open', val: '' }; * - * console.log(foo.last.type) // 'qux' + * // push the parent "brace" node onto the stack + * this.push(parent); + * + * // return the parent node, so it's also added to the AST + * return brace; + * } + * }); * ``` - * @return {Object} The last node, or undefiend + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. + * @param {Function} `filter` Optionaly specify a filter function to exclude the node. + * @return {Object} Returns the created opening node. * @api public */ -Object.defineProperty(Node.prototype, 'last', { - get: function() { - return this.nodes ? utils.last(this.nodes) : null; +utils.addOpen = function(node, Node, val, filter) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isFunction(Node), 'expected Node to be a constructor function'); + + if (typeof val === 'function') { + filter = val; + val = ''; } -}); + + if (typeof filter === 'function' && !filter(node)) return; + var open = new Node({ type: node.type + '.open', val: val}); + var unshift = node.unshift || node.unshiftNode; + if (typeof unshift === 'function') { + unshift.call(node, open); + } else { + utils.unshiftNode(node, open); + } + return open; +}; /** - * Get the last node from `node.nodes`. + * Push a `*.close` node onto `node.nodes`. * * ```js - * var foo = new Node({type: 'foo'}); - * var bar = new Node({type: 'bar'}); - * var baz = new Node({type: 'baz'}); - * var qux = new Node({type: 'qux'}); - * foo.push(bar); - * foo.push(baz); - * foo.push(qux); + * var Node = require('snapdragon-node'); + * snapdragon.parser.set('brace', function(node) { + * var match = this.match(/^}/); + * if (match) { + * var parent = this.parent(); + * if (parent.type !== 'brace') { + * throw new Error('missing opening: ' + '}'); + * } * - * console.log(foo.last.type) // 'qux' + * utils.addClose(parent, Node); + * console.log(parent.nodes[parent.nodes.length - 1]): + * // { type: 'brace.close', val: '' }; + * + * // no need to return a node, since the parent + * // was already added to the AST + * return; + * } + * }); * ``` - * @return {Object} The last node, or undefiend + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. + * @param {Function} `filter` Optionaly specify a filter function to exclude the node. + * @return {Object} Returns the created closing node. * @api public */ -Object.defineProperty(Node.prototype, 'scope', { - get: function() { - if (this.isScope !== true) { - return this.parent ? this.parent.scope : this; - } - return this; - } -}); +utils.addClose = function(node, Node, val, filter) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isFunction(Node), 'expected Node to be a constructor function'); -/** - * Get own property names from Node prototype, but only the - * first time `Node` is instantiated - */ + if (typeof val === 'function') { + filter = val; + val = ''; + } -function lazyKeys() { - if (!ownNames) { - ownNames = Object.getOwnPropertyNames(Node.prototype); + if (typeof filter === 'function' && !filter(node)) return; + var close = new Node({ type: node.type + '.close', val: val}); + var push = node.push || node.pushNode; + if (typeof push === 'function') { + push.call(node, close); + } else { + utils.pushNode(node, close); } -} + return close; +}; /** - * Simplified assertion. Throws an error is `val` is falsey. + * Wraps the given `node` with `*.open` and `*.close` nodes. + * + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. + * @param {Function} `filter` Optionaly specify a filter function to exclude the node. + * @return {Object} Returns the node + * @api public */ -function assert(val, message) { - if (!val) throw new Error(message); -} +utils.wrapNodes = function(node, Node, filter) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isFunction(Node), 'expected Node to be a constructor function'); + + utils.addOpen(node, Node, filter); + utils.addClose(node, Node, filter); + return node; +}; /** - * Expose `Node` + * Push the given `node` onto `parent.nodes`, and set `parent` as `node.parent. + * + * ```js + * var parent = new Node({type: 'foo'}); + * var node = new Node({type: 'bar'}); + * utils.pushNode(parent, node); + * console.log(parent.nodes[0].type) // 'bar' + * console.log(node.parent.type) // 'foo' + * ``` + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Object} Returns the child node + * @api public */ -exports = module.exports = Node; - +utils.pushNode = function(parent, node) { + assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); + assert(utils.isNode(node), 'expected node to be an instance of Node'); -/***/ }), -/* 758 */ -/***/ (function(module, exports, __webpack_require__) { + node.define('parent', parent); + parent.nodes = parent.nodes || []; + parent.nodes.push(node); + return node; +}; -"use strict"; -/*! - * define-property +/** + * Unshift `node` onto `parent.nodes`, and set `parent` as `node.parent. * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. + * ```js + * var parent = new Node({type: 'foo'}); + * var node = new Node({type: 'bar'}); + * utils.unshiftNode(parent, node); + * console.log(parent.nodes[0].type) // 'bar' + * console.log(node.parent.type) // 'foo' + * ``` + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {undefined} + * @api public */ +utils.unshiftNode = function(parent, node) { + assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); + assert(utils.isNode(node), 'expected node to be an instance of Node'); - -var isDescriptor = __webpack_require__(759); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } - - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); + node.define('parent', parent); + parent.nodes = parent.nodes || []; + parent.nodes.unshift(node); }; - -/***/ }), -/* 759 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-descriptor +/** + * Pop the last `node` off of `parent.nodes`. The advantage of + * using this method is that it checks for `node.nodes` and works + * with any version of `snapdragon-node`. * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * ```js + * var parent = new Node({type: 'foo'}); + * utils.pushNode(parent, new Node({type: 'foo'})); + * utils.pushNode(parent, new Node({type: 'bar'})); + * utils.pushNode(parent, new Node({type: 'baz'})); + * console.log(parent.nodes.length); //=> 3 + * utils.popNode(parent); + * console.log(parent.nodes.length); //=> 2 + * ``` + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. + * @api public */ - - -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') { - return false; - } - if ('get' in obj) { - return isAccessor(obj, key); +utils.popNode = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + if (typeof node.pop === 'function') { + return node.pop(); } - return isData(obj, key); + return node.nodes && node.nodes.pop(); }; +/** + * Shift the first `node` off of `parent.nodes`. The advantage of + * using this method is that it checks for `node.nodes` and works + * with any version of `snapdragon-node`. + * + * ```js + * var parent = new Node({type: 'foo'}); + * utils.pushNode(parent, new Node({type: 'foo'})); + * utils.pushNode(parent, new Node({type: 'bar'})); + * utils.pushNode(parent, new Node({type: 'baz'})); + * console.log(parent.nodes.length); //=> 3 + * utils.shiftNode(parent); + * console.log(parent.nodes.length); //=> 2 + * ``` + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. + * @api public + */ -/***/ }), -/* 760 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; +utils.shiftNode = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + if (typeof node.shift === 'function') { + return node.shift(); } + return node.nodes && node.nodes.shift(); +}; - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; - - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; +/** + * Remove the specified `node` from `parent.nodes`. + * + * ```js + * var parent = new Node({type: 'abc'}); + * var foo = new Node({type: 'foo'}); + * utils.pushNode(parent, foo); + * utils.pushNode(parent, new Node({type: 'bar'})); + * utils.pushNode(parent, new Node({type: 'baz'})); + * console.log(parent.nodes.length); //=> 3 + * utils.removeNode(parent, foo); + * console.log(parent.nodes.length); //=> 2 + * ``` + * @param {Object} `parent` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Object|undefined} Returns the removed node, if successful, or undefined if it does not exist on `parent.nodes`. + * @api public + */ - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; +utils.removeNode = function(parent, node) { + assert(utils.isNode(parent), 'expected parent.node to be an instance of Node'); + assert(utils.isNode(node), 'expected node to be an instance of Node'); - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; + if (!parent.nodes) { + return null; } - if (isGeneratorObj(val)) { - return 'generator'; + if (typeof parent.remove === 'function') { + return parent.remove(node); } - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; + var idx = parent.nodes.indexOf(node); + if (idx !== -1) { + return parent.nodes.splice(idx, 1); } - - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); }; -function ctorName(val) { - return val.constructor ? val.constructor.name : null; -} - -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} - -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} - -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} - -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} +/** + * Returns true if `node.type` matches the given `type`. Throws a + * `TypeError` if `node` is not an instance of `Node`. + * + * ```js + * var Node = require('snapdragon-node'); + * var node = new Node({type: 'foo'}); + * console.log(utils.isType(node, 'foo')); // false + * console.log(utils.isType(node, 'bar')); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {String} `type` + * @return {Boolean} + * @api public + */ -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} +utils.isType = function(node, type) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + switch (typeOf(type)) { + case 'array': + var types = type.slice(); + for (var i = 0; i < types.length; i++) { + if (utils.isType(node, types[i])) { + return true; + } + } + return false; + case 'string': + return node.type === type; + case 'regexp': + return type.test(node.type); + default: { + throw new TypeError('expected "type" to be an array, string or regexp'); + } + } +}; -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} +/** + * Returns true if the given `node` has the given `type` in `node.nodes`. + * Throws a `TypeError` if `node` is not an instance of `Node`. + * + * ```js + * var Node = require('snapdragon-node'); + * var node = new Node({ + * type: 'foo', + * nodes: [ + * new Node({type: 'bar'}), + * new Node({type: 'baz'}) + * ] + * }); + * console.log(utils.hasType(node, 'xyz')); // false + * console.log(utils.hasType(node, 'baz')); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {String} `type` + * @return {Boolean} + * @api public + */ -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { +utils.hasType = function(node, type) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + if (!Array.isArray(node.nodes)) return false; + for (var i = 0; i < node.nodes.length; i++) { + if (utils.isType(node.nodes[i], type)) { return true; } } return false; -} +}; /** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer + * Returns the first node from `node.nodes` of the given `type` + * + * ```js + * var node = new Node({ + * type: 'foo', + * nodes: [ + * new Node({type: 'text', val: 'abc'}), + * new Node({type: 'text', val: 'xyz'}) + * ] + * }); + * + * var textNode = utils.firstOfType(node.nodes, 'text'); + * console.log(textNode.val); + * //=> 'abc' + * ``` + * @param {Array} `nodes` + * @param {String} `type` + * @return {Object|undefined} Returns the first matching node or undefined. + * @api public */ -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); +utils.firstOfType = function(nodes, type) { + for (var i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (utils.isType(node, type)) { + return node; + } } - return false; -} - - -/***/ }), -/* 761 */ -/***/ (function(module, exports, __webpack_require__) { +}; -"use strict"; -/*! - * is-accessor-descriptor +/** + * Returns the node at the specified index, or the first node of the + * given `type` from `node.nodes`. * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * ```js + * var node = new Node({ + * type: 'foo', + * nodes: [ + * new Node({type: 'text', val: 'abc'}), + * new Node({type: 'text', val: 'xyz'}) + * ] + * }); + * + * var nodeOne = utils.findNode(node.nodes, 'text'); + * console.log(nodeOne.val); + * //=> 'abc' + * + * var nodeTwo = utils.findNode(node.nodes, 1); + * console.log(nodeTwo.val); + * //=> 'xyz' + * ``` + * + * @param {Array} `nodes` + * @param {String|Number} `type` Node type or index. + * @return {Object} Returns a node or undefined. + * @api public */ - - -var typeOf = __webpack_require__(762); - -// accessor descriptor properties -var accessor = { - get: 'function', - set: 'function', - configurable: 'boolean', - enumerable: 'boolean' -}; - -function isAccessorDescriptor(obj, prop) { - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; +utils.findNode = function(nodes, type) { + if (!Array.isArray(nodes)) { + return null; } - - if (typeOf(obj) !== 'object') { - return false; + if (typeof type === 'number') { + return nodes[type]; } + return utils.firstOfType(nodes, type); +}; - if (has(obj, 'value') || has(obj, 'writable')) { - return false; - } +/** + * Returns true if the given node is an "*.open" node. + * + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({type: 'brace'}); + * var open = new Node({type: 'brace.open'}); + * var close = new Node({type: 'brace.close'}); + * + * console.log(utils.isOpen(brace)); // false + * console.log(utils.isOpen(open)); // true + * console.log(utils.isOpen(close)); // false + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public + */ - if (!has(obj, 'get') || typeof obj.get !== 'function') { - return false; - } +utils.isOpen = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + return node.type.slice(-5) === '.open'; +}; - // tldr: it's valid to have "set" be undefined - // "set" might be undefined if `Object.getOwnPropertyDescriptor` - // was used to get the value, and only `get` was defined by the user - if (has(obj, 'set') && typeof obj[key] !== 'function' && typeof obj[key] !== 'undefined') { - return false; - } +/** + * Returns true if the given node is a "*.close" node. + * + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({type: 'brace'}); + * var open = new Node({type: 'brace.open'}); + * var close = new Node({type: 'brace.close'}); + * + * console.log(utils.isClose(brace)); // false + * console.log(utils.isClose(open)); // false + * console.log(utils.isClose(close)); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public + */ - for (var key in obj) { - if (!accessor.hasOwnProperty(key)) { - continue; - } +utils.isClose = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + return node.type.slice(-6) === '.close'; +}; - if (typeOf(obj[key]) === accessor[key]) { - continue; - } +/** + * Returns true if `node.nodes` **has** an `.open` node + * + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({ + * type: 'brace', + * nodes: [] + * }); + * + * var open = new Node({type: 'brace.open'}); + * console.log(utils.hasOpen(brace)); // false + * + * brace.pushNode(open); + * console.log(utils.hasOpen(brace)); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public + */ - if (typeof obj[key] !== 'undefined') { - return false; - } +utils.hasOpen = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + var first = node.first || node.nodes ? node.nodes[0] : null; + if (utils.isNode(first)) { + return first.type === node.type + '.open'; } - return true; -} - -function has(obj, key) { - return {}.hasOwnProperty.call(obj, key); -} + return false; +}; /** - * Expose `isAccessorDescriptor` + * Returns true if `node.nodes` **has** a `.close` node + * + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({ + * type: 'brace', + * nodes: [] + * }); + * + * var close = new Node({type: 'brace.close'}); + * console.log(utils.hasClose(brace)); // false + * + * brace.pushNode(close); + * console.log(utils.hasClose(brace)); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public */ -module.exports = isAccessorDescriptor; - - -/***/ }), -/* 762 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; +utils.hasClose = function(node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + var last = node.last || node.nodes ? node.nodes[node.nodes.length - 1] : null; + if (utils.isNode(last)) { + return last.type === node.type + '.close'; } + return false; +}; - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; +/** + * Returns true if `node.nodes` has both `.open` and `.close` nodes + * + * ```js + * var Node = require('snapdragon-node'); + * var brace = new Node({ + * type: 'brace', + * nodes: [] + * }); + * + * var open = new Node({type: 'brace.open'}); + * var close = new Node({type: 'brace.close'}); + * console.log(utils.hasOpen(brace)); // false + * console.log(utils.hasClose(brace)); // false + * + * brace.pushNode(open); + * brace.pushNode(close); + * console.log(utils.hasOpen(brace)); // true + * console.log(utils.hasClose(brace)); // true + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Boolean} + * @api public + */ - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; +utils.hasOpenAndClose = function(node) { + return utils.hasOpen(node) && utils.hasClose(node); +}; - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; +/** + * Push the given `node` onto the `state.inside` array for the + * given type. This array is used as a specialized "stack" for + * only the given `node.type`. + * + * ```js + * var state = { inside: {}}; + * var node = new Node({type: 'brace'}); + * utils.addType(state, node); + * console.log(state.inside); + * //=> { brace: [{type: 'brace'}] } + * ``` + * @param {Object} `state` The `compiler.state` object or custom state object. + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Array} Returns the `state.inside` stack for the given type. + * @api public + */ - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; +utils.addType = function(state, node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isObject(state), 'expected state to be an object'); - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } + var type = node.parent + ? node.parent.type + : node.type.replace(/\.open$/, ''); - if (isGeneratorObj(val)) { - return 'generator'; + if (!state.hasOwnProperty('inside')) { + state.inside = {}; } - - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; + if (!state.inside.hasOwnProperty(type)) { + state.inside[type] = []; } - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); + var arr = state.inside[type]; + arr.push(node); + return arr; }; -function ctorName(val) { - return val.constructor ? val.constructor.name : null; -} - -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} - -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} +/** + * Remove the given `node` from the `state.inside` array for the + * given type. This array is used as a specialized "stack" for + * only the given `node.type`. + * + * ```js + * var state = { inside: {}}; + * var node = new Node({type: 'brace'}); + * utils.addType(state, node); + * console.log(state.inside); + * //=> { brace: [{type: 'brace'}] } + * utils.removeType(state, node); + * //=> { brace: [] } + * ``` + * @param {Object} `state` The `compiler.state` object or custom state object. + * @param {Object} `node` Instance of [snapdragon-node][] + * @return {Array} Returns the `state.inside` stack for the given type. + * @api public + */ -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} +utils.removeType = function(state, node) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isObject(state), 'expected state to be an object'); -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} + var type = node.parent + ? node.parent.type + : node.type.replace(/\.close$/, ''); -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} + if (state.inside.hasOwnProperty(type)) { + return state.inside[type].pop(); + } +}; -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} +/** + * Returns true if `node.val` is an empty string, or `node.nodes` does + * not contain any non-empty text nodes. + * + * ```js + * var node = new Node({type: 'text'}); + * utils.isEmpty(node); //=> true + * node.val = 'foo'; + * utils.isEmpty(node); //=> false + * ``` + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {Function} `fn` + * @return {Boolean} + * @api public + */ -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { +utils.isEmpty = function(node, fn) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + + if (!Array.isArray(node.nodes)) { + if (node.type !== 'text') { return true; } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; + if (typeof fn === 'function') { + return fn(node, node.parent); } + return !utils.trim(node.val); } - return false; -} - -/** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer - */ -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); + for (var i = 0; i < node.nodes.length; i++) { + var child = node.nodes[i]; + if (utils.isOpen(child) || utils.isClose(child)) { + continue; + } + if (!utils.isEmpty(child, fn)) { + return false; + } } - return false; -} + return true; +}; -/***/ }), -/* 763 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-data-descriptor +/** + * Returns true if the `state.inside` stack for the given type exists + * and has one or more nodes on it. * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * ```js + * var state = { inside: {}}; + * var node = new Node({type: 'brace'}); + * console.log(utils.isInsideType(state, 'brace')); //=> false + * utils.addType(state, node); + * console.log(utils.isInsideType(state, 'brace')); //=> true + * utils.removeType(state, node); + * console.log(utils.isInsideType(state, 'brace')); //=> false + * ``` + * @param {Object} `state` + * @param {String} `type` + * @return {Boolean} + * @api public */ +utils.isInsideType = function(state, type) { + assert(isObject(state), 'expected state to be an object'); + assert(isString(type), 'expected type to be a string'); - -var typeOf = __webpack_require__(764); - -module.exports = function isDataDescriptor(obj, prop) { - // data descriptor properties - var data = { - configurable: 'boolean', - enumerable: 'boolean', - writable: 'boolean' - }; - - if (typeOf(obj) !== 'object') { + if (!state.hasOwnProperty('inside')) { return false; } - if (typeof prop === 'string') { - var val = Object.getOwnPropertyDescriptor(obj, prop); - return typeof val !== 'undefined'; - } - - if (!('value' in obj) && !('writable' in obj)) { + if (!state.inside.hasOwnProperty(type)) { return false; } - for (var key in obj) { - if (key === 'value') continue; + return state.inside[type].length > 0; +}; - if (!data.hasOwnProperty(key)) { - continue; - } +/** + * Returns true if `node` is either a child or grand-child of the given `type`, + * or `state.inside[type]` is a non-empty array. + * + * ```js + * var state = { inside: {}}; + * var node = new Node({type: 'brace'}); + * var open = new Node({type: 'brace.open'}); + * console.log(utils.isInside(state, open, 'brace')); //=> false + * utils.pushNode(node, open); + * console.log(utils.isInside(state, open, 'brace')); //=> true + * ``` + * @param {Object} `state` Either the `compiler.state` object, if it exists, or a user-supplied state object. + * @param {Object} `node` Instance of [snapdragon-node][] + * @param {String} `type` The `node.type` to check for. + * @return {Boolean} + * @api public + */ - if (typeOf(obj[key]) === data[key]) { - continue; - } +utils.isInside = function(state, node, type) { + assert(utils.isNode(node), 'expected node to be an instance of Node'); + assert(isObject(state), 'expected state to be an object'); - if (typeof obj[key] !== 'undefined') { - return false; + if (Array.isArray(type)) { + for (var i = 0; i < type.length; i++) { + if (utils.isInside(state, node, type[i])) { + return true; + } } + return false; } - return true; -}; + var parent = node.parent; + if (typeof type === 'string') { + return (parent && parent.type === type) || utils.isInsideType(state, type); + } -/***/ }), -/* 764 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; + if (typeOf(type) === 'regexp') { + if (parent && parent.type && type.test(parent.type)) { + return true; + } -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; + var keys = Object.keys(state.inside); + var len = keys.length; + var idx = -1; + while (++idx < len) { + var key = keys[idx]; + var val = state.inside[key]; - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; + if (Array.isArray(val) && val.length !== 0 && type.test(key)) { + return true; + } + } } + return false; +}; - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; +/** + * Get the last `n` element from the given `array`. Used for getting + * a node from `node.nodes.` + * + * @param {Array} `array` + * @param {Number} `n` + * @return {undefined} + * @api public + */ - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; +utils.last = function(arr, n) { + return arr[arr.length - (n || 1)]; +}; - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; +/** + * Cast the given `val` to an array. + * + * ```js + * console.log(utils.arrayify('')); + * //=> [] + * console.log(utils.arrayify('foo')); + * //=> ['foo'] + * console.log(utils.arrayify(['foo'])); + * //=> ['foo'] + * ``` + * @param {any} `val` + * @return {Array} + * @api public + */ - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; +utils.arrayify = function(val) { + if (typeof val === 'string' && val !== '') { + return [val]; } - - if (isGeneratorObj(val)) { - return 'generator'; + if (!Array.isArray(val)) { + return []; } + return val; +}; - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } +/** + * Convert the given `val` to a string by joining with `,`. Useful + * for creating a cheerio/CSS/DOM-style selector from a list of strings. + * + * @param {any} `val` + * @return {Array} + * @api public + */ - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); +utils.stringify = function(val) { + return utils.arrayify(val).join(','); }; -function ctorName(val) { - return val.constructor ? val.constructor.name : null; -} +/** + * Ensure that the given value is a string and call `.trim()` on it, + * or return an empty string. + * + * @param {String} `str` + * @return {String} + * @api public + */ -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} +utils.trim = function(str) { + return typeof str === 'string' ? str.trim() : ''; +}; -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} +/** + * Return true if val is an object + */ -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; +function isObject(val) { + return typeOf(val) === 'object'; } -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; +/** + * Return true if val is a string + */ + +function isString(val) { + return typeof val === 'string'; } -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; +/** + * Return true if val is a function + */ + +function isFunction(val) { + return typeof val === 'function'; } -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; +/** + * Return true if val is an array + */ + +function isArray(val) { + return Array.isArray(val); } -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } +/** + * Shim to ensure the `.append` methods work with any version of snapdragon + */ + +function append(compiler, val, node) { + if (typeof compiler.append !== 'function') { + return compiler.emit(val, node); } - return false; + return compiler.append(val, node); } /** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer + * Simplified assertion. Throws an error is `val` is falsey. */ -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; +function assert(val, message) { + if (!val) throw new Error(message); } /***/ }), -/* 765 */ +/* 761 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(752); -var utils = module.exports; +var extend = __webpack_require__(732); +var Snapdragon = __webpack_require__(762); +var compilers = __webpack_require__(736); +var parsers = __webpack_require__(751); +var utils = __webpack_require__(737); /** - * Returns true if the given value is a node. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(utils.isNode(node)); //=> true - * console.log(utils.isNode({})); //=> false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {Boolean} - * @api public + * Customize Snapdragon parser and renderer */ -utils.isNode = function(node) { - return typeOf(node) === 'object' && node.isNode === true; +function Braces(options) { + this.options = extend({}, options); +} + +/** + * Initialize braces + */ + +Braces.prototype.init = function(options) { + if (this.isInitialized) return; + this.isInitialized = true; + var opts = utils.createOptions({}, this.options, options); + this.snapdragon = this.options.snapdragon || new Snapdragon(opts); + this.compiler = this.snapdragon.compiler; + this.parser = this.snapdragon.parser; + + compilers(this.snapdragon, opts); + parsers(this.snapdragon, opts); + + /** + * Call Snapdragon `.parse` method. When AST is returned, we check to + * see if any unclosed braces are left on the stack and, if so, we iterate + * over the stack and correct the AST so that compilers are called in the correct + * order and unbalance braces are properly escaped. + */ + + utils.define(this.snapdragon, 'parse', function(pattern, options) { + var parsed = Snapdragon.prototype.parse.apply(this, arguments); + this.parser.ast.input = pattern; + + var stack = this.parser.stack; + while (stack.length) { + addParent({type: 'brace.close', val: ''}, stack.pop()); + } + + function addParent(node, parent) { + utils.define(node, 'parent', parent); + parent.nodes.push(node); + } + + // add non-enumerable parser reference + utils.define(parsed, 'parser', this.parser); + return parsed; + }); }; /** - * Emit an empty string for the given `node`. - * - * ```js - * // do nothing for beginning-of-string - * snapdragon.compiler.set('bos', utils.noop); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {undefined} - * @api public + * Decorate `.parse` method */ -utils.noop = function(node) { - append(this, '', node); +Braces.prototype.parse = function(ast, options) { + if (ast && typeof ast === 'object' && ast.nodes) return ast; + this.init(options); + return this.snapdragon.parse(ast, options); }; /** - * Appdend `node.val` to `compiler.output`, exactly as it was created - * by the parser. - * - * ```js - * snapdragon.compiler.set('text', utils.identity); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {undefined} - * @api public + * Decorate `.compile` method */ -utils.identity = function(node) { - append(this, node.val, node); +Braces.prototype.compile = function(ast, options) { + if (typeof ast === 'string') { + ast = this.parse(ast, options); + } else { + this.init(options); + } + return this.snapdragon.compile(ast, options); +}; + +/** + * Expand + */ + +Braces.prototype.expand = function(pattern) { + var ast = this.parse(pattern, {expand: true}); + return this.compile(ast, {expand: true}); +}; + +/** + * Optimize + */ + +Braces.prototype.optimize = function(pattern) { + var ast = this.parse(pattern, {optimize: true}); + return this.compile(ast, {optimize: true}); }; /** - * Previously named `.emit`, this method appends the given `val` - * to `compiler.output` for the given node. Useful when you know - * what value should be appended advance, regardless of the actual - * value of `node.val`. + * Expose `Braces` + */ + +module.exports = Braces; + + +/***/ }), +/* 762 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var Base = __webpack_require__(763); +var define = __webpack_require__(724); +var Compiler = __webpack_require__(792); +var Parser = __webpack_require__(821); +var utils = __webpack_require__(801); +var regexCache = {}; +var cache = {}; + +/** + * Create a new instance of `Snapdragon` with the given `options`. * * ```js - * snapdragon.compiler - * .set('i', function(node) { - * this.mapVisit(node); - * }) - * .set('i.open', utils.append('')) - * .set('i.close', utils.append('')) + * var snapdragon = new Snapdragon(); * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @returns {Function} Returns a compiler middleware function. + * + * @param {Object} `options` * @api public */ -utils.append = function(val) { - return function(node) { - append(this, val, node); - }; -}; +function Snapdragon(options) { + Base.call(this, null, options); + this.options = utils.extend({source: 'string'}, this.options); + this.compiler = new Compiler(this.options); + this.parser = new Parser(this.options); + + Object.defineProperty(this, 'compilers', { + get: function() { + return this.compiler.compilers; + } + }); + + Object.defineProperty(this, 'parsers', { + get: function() { + return this.parser.parsers; + } + }); + + Object.defineProperty(this, 'regex', { + get: function() { + return this.parser.regex; + } + }); +} /** - * Used in compiler middleware, this onverts an AST node into - * an empty `text` node and deletes `node.nodes` if it exists. - * The advantage of this method is that, as opposed to completely - * removing the node, indices will not need to be re-calculated - * in sibling nodes, and nothing is appended to the output. - * - * ```js - * utils.toNoop(node); - * // convert `node.nodes` to the given value instead of deleting it - * utils.toNoop(node, []); - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Array} `nodes` Optionally pass a new `nodes` value, to replace the existing `node.nodes` array. - * @api public + * Inherit Base */ -utils.toNoop = function(node, nodes) { - if (nodes) { - node.nodes = nodes; - } else { - delete node.nodes; - node.type = 'text'; - node.val = ''; - } -}; +Base.extend(Snapdragon); /** - * Visit `node` with the given `fn`. The built-in `.visit` method in snapdragon - * automatically calls registered compilers, this allows you to pass a visitor - * function. + * Add a parser to `snapdragon.parsers` for capturing the given `type` using + * the specified regex or parser function. A function is useful if you need + * to customize how the token is created and/or have access to the parser + * instance to check options, etc. * * ```js - * snapdragon.compiler.set('i', function(node) { - * utils.visit(node, function(childNode) { - * // do stuff with "childNode" - * return childNode; + * snapdragon + * .capture('slash', /^\//) + * .capture('dot', function() { + * var pos = this.position(); + * var m = this.match(/^\./); + * if (!m) return; + * return pos({ + * type: 'dot', + * val: m[0] + * }); * }); - * }); * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `fn` - * @return {Object} returns the node after recursively visiting all child nodes. + * @param {String} `type` + * @param {RegExp|Function} `regex` + * @return {Object} Returns the parser instance for chaining * @api public */ -utils.visit = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(fn), 'expected a visitor function'); - fn(node); - return node.nodes ? utils.mapVisit(node, fn) : node; +Snapdragon.prototype.capture = function() { + return this.parser.capture.apply(this.parser, arguments); }; /** - * Map [visit](#visit) the given `fn` over `node.nodes`. This is called by - * [visit](#visit), use this method if you do not want `fn` to be called on - * the first node. + * Register a plugin `fn`. * * ```js - * snapdragon.compiler.set('i', function(node) { - * utils.mapVisit(node, function(childNode) { - * // do stuff with "childNode" - * return childNode; - * }); + * var snapdragon = new Snapdgragon([options]); + * snapdragon.use(function() { + * console.log(this); //<= snapdragon instance + * console.log(this.parser); //<= parser instance + * console.log(this.compiler); //<= compiler instance * }); * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Object} `options` - * @param {Function} `fn` - * @return {Object} returns the node + * @param {Object} `fn` * @api public */ -utils.mapVisit = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isArray(node.nodes), 'expected node.nodes to be an array'); - assert(isFunction(fn), 'expected a visitor function'); - - for (var i = 0; i < node.nodes.length; i++) { - utils.visit(node.nodes[i], fn); - } - return node; +Snapdragon.prototype.use = function(fn) { + fn.call(this, this); + return this; }; /** - * Unshift an `*.open` node onto `node.nodes`. + * Parse the given `str`. * * ```js - * var Node = require('snapdragon-node'); - * snapdragon.parser.set('brace', function(node) { - * var match = this.match(/^{/); - * if (match) { - * var parent = new Node({type: 'brace'}); - * utils.addOpen(parent, Node); - * console.log(parent.nodes[0]): - * // { type: 'brace.open', val: '' }; - * - * // push the parent "brace" node onto the stack - * this.push(parent); + * var snapdragon = new Snapdgragon([options]); + * // register parsers + * snapdragon.parser.use(function() {}); * - * // return the parent node, so it's also added to the AST - * return brace; - * } - * }); + * // parse + * var ast = snapdragon.parse('foo/bar'); + * console.log(ast); * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the created opening node. + * @param {String} `str` + * @param {Object} `options` Set `options.sourcemap` to true to enable source maps. + * @return {Object} Returns an AST. * @api public */ -utils.addOpen = function(node, Node, val, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); - - if (typeof val === 'function') { - filter = val; - val = ''; - } +Snapdragon.prototype.parse = function(str, options) { + this.options = utils.extend({}, this.options, options); + var parsed = this.parser.parse(str, this.options); - if (typeof filter === 'function' && !filter(node)) return; - var open = new Node({ type: node.type + '.open', val: val}); - var unshift = node.unshift || node.unshiftNode; - if (typeof unshift === 'function') { - unshift.call(node, open); - } else { - utils.unshiftNode(node, open); - } - return open; + // add non-enumerable parser reference + define(parsed, 'parser', this.parser); + return parsed; }; /** - * Push a `*.close` node onto `node.nodes`. + * Compile the given `AST`. * * ```js - * var Node = require('snapdragon-node'); - * snapdragon.parser.set('brace', function(node) { - * var match = this.match(/^}/); - * if (match) { - * var parent = this.parent(); - * if (parent.type !== 'brace') { - * throw new Error('missing opening: ' + '}'); - * } + * var snapdragon = new Snapdgragon([options]); + * // register plugins + * snapdragon.use(function() {}); + * // register parser plugins + * snapdragon.parser.use(function() {}); + * // register compiler plugins + * snapdragon.compiler.use(function() {}); * - * utils.addClose(parent, Node); - * console.log(parent.nodes[parent.nodes.length - 1]): - * // { type: 'brace.close', val: '' }; + * // parse + * var ast = snapdragon.parse('foo/bar'); * - * // no need to return a node, since the parent - * // was already added to the AST - * return; - * } - * }); + * // compile + * var res = snapdragon.compile(ast); + * console.log(res.output); * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the created closing node. + * @param {Object} `ast` + * @param {Object} `options` + * @return {Object} Returns an object with an `output` property with the rendered string. * @api public */ -utils.addClose = function(node, Node, val, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); - - if (typeof val === 'function') { - filter = val; - val = ''; - } +Snapdragon.prototype.compile = function(ast, options) { + this.options = utils.extend({}, this.options, options); + var compiled = this.compiler.compile(ast, this.options); - if (typeof filter === 'function' && !filter(node)) return; - var close = new Node({ type: node.type + '.close', val: val}); - var push = node.push || node.pushNode; - if (typeof push === 'function') { - push.call(node, close); - } else { - utils.pushNode(node, close); - } - return close; + // add non-enumerable compiler reference + define(compiled, 'compiler', this.compiler); + return compiled; }; /** - * Wraps the given `node` with `*.open` and `*.close` nodes. - * - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `Node` (required) Node constructor function from [snapdragon-node][]. - * @param {Function} `filter` Optionaly specify a filter function to exclude the node. - * @return {Object} Returns the node - * @api public + * Expose `Snapdragon` */ -utils.wrapNodes = function(node, Node, filter) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isFunction(Node), 'expected Node to be a constructor function'); - - utils.addOpen(node, Node, filter); - utils.addClose(node, Node, filter); - return node; -}; +module.exports = Snapdragon; /** - * Push the given `node` onto `parent.nodes`, and set `parent` as `node.parent. - * - * ```js - * var parent = new Node({type: 'foo'}); - * var node = new Node({type: 'bar'}); - * utils.pushNode(parent, node); - * console.log(parent.nodes[0].type) // 'bar' - * console.log(node.parent.type) // 'foo' - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Object} Returns the child node - * @api public + * Expose `Parser` and `Compiler` */ -utils.pushNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); +module.exports.Compiler = Compiler; +module.exports.Parser = Parser; - node.define('parent', parent); - parent.nodes = parent.nodes || []; - parent.nodes.push(node); - return node; -}; -/** - * Unshift `node` onto `parent.nodes`, and set `parent` as `node.parent. - * - * ```js - * var parent = new Node({type: 'foo'}); - * var node = new Node({type: 'bar'}); - * utils.unshiftNode(parent, node); - * console.log(parent.nodes[0].type) // 'bar' - * console.log(node.parent.type) // 'foo' - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {undefined} - * @api public - */ +/***/ }), +/* 763 */ +/***/ (function(module, exports, __webpack_require__) { -utils.unshiftNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); +"use strict"; - node.define('parent', parent); - parent.nodes = parent.nodes || []; - parent.nodes.unshift(node); -}; + +var util = __webpack_require__(29); +var define = __webpack_require__(764); +var CacheBase = __webpack_require__(765); +var Emitter = __webpack_require__(766); +var isObject = __webpack_require__(742); +var merge = __webpack_require__(783); +var pascal = __webpack_require__(786); +var cu = __webpack_require__(787); /** - * Pop the last `node` off of `parent.nodes`. The advantage of - * using this method is that it checks for `node.nodes` and works - * with any version of `snapdragon-node`. - * - * ```js - * var parent = new Node({type: 'foo'}); - * utils.pushNode(parent, new Node({type: 'foo'})); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.popNode(parent); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. - * @api public + * Optionally define a custom `cache` namespace to use. */ -utils.popNode = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (typeof node.pop === 'function') { - return node.pop(); +function namespace(name) { + var Cache = name ? CacheBase.namespace(name) : CacheBase; + var fns = []; + + /** + * Create an instance of `Base` with the given `config` and `options`. + * + * ```js + * // initialize with `config` and `options` + * var app = new Base({isApp: true}, {abc: true}); + * app.set('foo', 'bar'); + * + * // values defined with the given `config` object will be on the root of the instance + * console.log(app.baz); //=> undefined + * console.log(app.foo); //=> 'bar' + * // or use `.get` + * console.log(app.get('isApp')); //=> true + * console.log(app.get('foo')); //=> 'bar' + * + * // values defined with the given `options` object will be on `app.options + * console.log(app.options.abc); //=> true + * ``` + * + * @param {Object} `config` If supplied, this object is passed to [cache-base][] to merge onto the the instance upon instantiation. + * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object. + * @api public + */ + + function Base(config, options) { + if (!(this instanceof Base)) { + return new Base(config, options); + } + Cache.call(this, config); + this.is('base'); + this.initBase(config, options); } - return node.nodes && node.nodes.pop(); -}; -/** - * Shift the first `node` off of `parent.nodes`. The advantage of - * using this method is that it checks for `node.nodes` and works - * with any version of `snapdragon-node`. - * - * ```js - * var parent = new Node({type: 'foo'}); - * utils.pushNode(parent, new Node({type: 'foo'})); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.shiftNode(parent); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Number|Undefined} Returns the length of `node.nodes` or undefined. - * @api public - */ + /** + * Inherit cache-base + */ + + util.inherits(Base, Cache); + + /** + * Add static emitter methods + */ + + Emitter(Base); + + /** + * Initialize `Base` defaults with the given `config` object + */ + + Base.prototype.initBase = function(config, options) { + this.options = merge({}, this.options, options); + this.cache = this.cache || {}; + this.define('registered', {}); + if (name) this[name] = {}; + + // make `app._callbacks` non-enumerable + this.define('_callbacks', this._callbacks); + if (isObject(config)) { + this.visit('set', config); + } + Base.run(this, 'use', fns); + }; + + /** + * Set the given `name` on `app._name` and `app.is*` properties. Used for doing + * lookups in plugins. + * + * ```js + * app.is('foo'); + * console.log(app._name); + * //=> 'foo' + * console.log(app.isFoo); + * //=> true + * app.is('bar'); + * console.log(app.isFoo); + * //=> true + * console.log(app.isBar); + * //=> true + * console.log(app._name); + * //=> 'bar' + * ``` + * @name .is + * @param {String} `name` + * @return {Boolean} + * @api public + */ + + Base.prototype.is = function(name) { + if (typeof name !== 'string') { + throw new TypeError('expected name to be a string'); + } + this.define('is' + pascal(name), true); + this.define('_name', name); + this.define('_appname', name); + return this; + }; + + /** + * Returns true if a plugin has already been registered on an instance. + * + * Plugin implementors are encouraged to use this first thing in a plugin + * to prevent the plugin from being called more than once on the same + * instance. + * + * ```js + * var base = new Base(); + * base.use(function(app) { + * if (app.isRegistered('myPlugin')) return; + * // do stuff to `app` + * }); + * + * // to also record the plugin as being registered + * base.use(function(app) { + * if (app.isRegistered('myPlugin', true)) return; + * // do stuff to `app` + * }); + * ``` + * @name .isRegistered + * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once. + * @param {String} `name` The plugin name. + * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument. + * @return {Boolean} Returns true if a plugin is already registered. + * @api public + */ + + Base.prototype.isRegistered = function(name, register) { + if (this.registered.hasOwnProperty(name)) { + return true; + } + if (register !== false) { + this.registered[name] = true; + this.emit('plugin', name); + } + return false; + }; + + /** + * Define a plugin function to be called immediately upon init. Plugins are chainable + * and expose the following arguments to the plugin function: + * + * - `app`: the current instance of `Base` + * - `base`: the [first ancestor instance](#base) of `Base` + * + * ```js + * var app = new Base() + * .use(foo) + * .use(bar) + * .use(baz) + * ``` + * @name .use + * @param {Function} `fn` plugin function to call + * @return {Object} Returns the item instance for chaining. + * @api public + */ -utils.shiftNode = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (typeof node.shift === 'function') { - return node.shift(); - } - return node.nodes && node.nodes.shift(); -}; + Base.prototype.use = function(fn) { + fn.call(this, this); + return this; + }; -/** - * Remove the specified `node` from `parent.nodes`. - * - * ```js - * var parent = new Node({type: 'abc'}); - * var foo = new Node({type: 'foo'}); - * utils.pushNode(parent, foo); - * utils.pushNode(parent, new Node({type: 'bar'})); - * utils.pushNode(parent, new Node({type: 'baz'})); - * console.log(parent.nodes.length); //=> 3 - * utils.removeNode(parent, foo); - * console.log(parent.nodes.length); //=> 2 - * ``` - * @param {Object} `parent` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Object|undefined} Returns the removed node, if successful, or undefined if it does not exist on `parent.nodes`. - * @api public - */ + /** + * The `.define` method is used for adding non-enumerable property on the instance. + * Dot-notation is **not supported** with `define`. + * + * ```js + * // arbitrary `render` function using lodash `template` + * app.define('render', function(str, locals) { + * return _.template(str)(locals); + * }); + * ``` + * @name .define + * @param {String} `key` The name of the property to define. + * @param {any} `value` + * @return {Object} Returns the instance for chaining. + * @api public + */ -utils.removeNode = function(parent, node) { - assert(utils.isNode(parent), 'expected parent.node to be an instance of Node'); - assert(utils.isNode(node), 'expected node to be an instance of Node'); + Base.prototype.define = function(key, val) { + if (isObject(key)) { + return this.visit('define', key); + } + define(this, key, val); + return this; + }; - if (!parent.nodes) { - return null; - } + /** + * Mix property `key` onto the Base prototype. If base is inherited using + * `Base.extend` this method will be overridden by a new `mixin` method that will + * only add properties to the prototype of the inheriting application. + * + * ```js + * app.mixin('foo', function() { + * // do stuff + * }); + * ``` + * @name .mixin + * @param {String} `key` + * @param {Object|Array} `val` + * @return {Object} Returns the `base` instance for chaining. + * @api public + */ - if (typeof parent.remove === 'function') { - return parent.remove(node); - } + Base.prototype.mixin = function(key, val) { + Base.prototype[key] = val; + return this; + }; - var idx = parent.nodes.indexOf(node); - if (idx !== -1) { - return parent.nodes.splice(idx, 1); - } -}; + /** + * Non-enumberable mixin array, used by the static [Base.mixin]() method. + */ -/** - * Returns true if `node.type` matches the given `type`. Throws a - * `TypeError` if `node` is not an instance of `Node`. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({type: 'foo'}); - * console.log(utils.isType(node, 'foo')); // false - * console.log(utils.isType(node, 'bar')); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` - * @return {Boolean} - * @api public - */ + Base.prototype.mixins = Base.prototype.mixins || []; -utils.isType = function(node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - switch (typeOf(type)) { - case 'array': - var types = type.slice(); - for (var i = 0; i < types.length; i++) { - if (utils.isType(node, types[i])) { - return true; - } - } - return false; - case 'string': - return node.type === type; - case 'regexp': - return type.test(node.type); - default: { - throw new TypeError('expected "type" to be an array, string or regexp'); + /** + * Getter/setter used when creating nested instances of `Base`, for storing a reference + * to the first ancestor instance. This works by setting an instance of `Base` on the `parent` + * property of a "child" instance. The `base` property defaults to the current instance if + * no `parent` property is defined. + * + * ```js + * // create an instance of `Base`, this is our first ("base") instance + * var first = new Base(); + * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later + * + * // create another instance + * var second = new Base(); + * // create a reference to the first instance (`first`) + * second.parent = first; + * + * // create another instance + * var third = new Base(); + * // create a reference to the previous instance (`second`) + * // repeat this pattern every time a "child" instance is created + * third.parent = second; + * + * // we can always access the first instance using the `base` property + * console.log(first.base.foo); + * //=> 'bar' + * console.log(second.base.foo); + * //=> 'bar' + * console.log(third.base.foo); + * //=> 'bar' + * // and now you know how to get to third base ;) + * ``` + * @name .base + * @api public + */ + + Object.defineProperty(Base.prototype, 'base', { + configurable: true, + get: function() { + return this.parent ? this.parent.base : this; } - } -}; + }); -/** - * Returns true if the given `node` has the given `type` in `node.nodes`. - * Throws a `TypeError` if `node` is not an instance of `Node`. - * - * ```js - * var Node = require('snapdragon-node'); - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'bar'}), - * new Node({type: 'baz'}) - * ] - * }); - * console.log(utils.hasType(node, 'xyz')); // false - * console.log(utils.hasType(node, 'baz')); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` - * @return {Boolean} - * @api public - */ + /** + * Static method for adding global plugin functions that will + * be added to an instance when created. + * + * ```js + * Base.use(function(app) { + * app.foo = 'bar'; + * }); + * var app = new Base(); + * console.log(app.foo); + * //=> 'bar' + * ``` + * @name #use + * @param {Function} `fn` Plugin function to use on each instance. + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ -utils.hasType = function(node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - if (!Array.isArray(node.nodes)) return false; - for (var i = 0; i < node.nodes.length; i++) { - if (utils.isType(node.nodes[i], type)) { - return true; - } - } - return false; -}; + define(Base, 'use', function(fn) { + fns.push(fn); + return Base; + }); -/** - * Returns the first node from `node.nodes` of the given `type` - * - * ```js - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'text', val: 'abc'}), - * new Node({type: 'text', val: 'xyz'}) - * ] - * }); - * - * var textNode = utils.firstOfType(node.nodes, 'text'); - * console.log(textNode.val); - * //=> 'abc' - * ``` - * @param {Array} `nodes` - * @param {String} `type` - * @return {Object|undefined} Returns the first matching node or undefined. - * @api public - */ + /** + * Run an array of functions by passing each function + * to a method on the given object specified by the given property. + * + * @param {Object} `obj` Object containing method to use. + * @param {String} `prop` Name of the method on the object to use. + * @param {Array} `arr` Array of functions to pass to the method. + */ -utils.firstOfType = function(nodes, type) { - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - if (utils.isType(node, type)) { - return node; + define(Base, 'run', function(obj, prop, arr) { + var len = arr.length, i = 0; + while (len--) { + obj[prop](arr[i++]); } - } -}; - -/** - * Returns the node at the specified index, or the first node of the - * given `type` from `node.nodes`. - * - * ```js - * var node = new Node({ - * type: 'foo', - * nodes: [ - * new Node({type: 'text', val: 'abc'}), - * new Node({type: 'text', val: 'xyz'}) - * ] - * }); - * - * var nodeOne = utils.findNode(node.nodes, 'text'); - * console.log(nodeOne.val); - * //=> 'abc' - * - * var nodeTwo = utils.findNode(node.nodes, 1); - * console.log(nodeTwo.val); - * //=> 'xyz' - * ``` - * - * @param {Array} `nodes` - * @param {String|Number} `type` Node type or index. - * @return {Object} Returns a node or undefined. - * @api public - */ + return Base; + }); -utils.findNode = function(nodes, type) { - if (!Array.isArray(nodes)) { - return null; - } - if (typeof type === 'number') { - return nodes[type]; - } - return utils.firstOfType(nodes, type); -}; + /** + * Static method for inheriting the prototype and static methods of the `Base` class. + * This method greatly simplifies the process of creating inheritance-based applications. + * See [static-extend][] for more details. + * + * ```js + * var extend = cu.extend(Parent); + * Parent.extend(Child); + * + * // optional methods + * Parent.extend(Child, { + * foo: function() {}, + * bar: function() {} + * }); + * ``` + * @name #extend + * @param {Function} `Ctor` constructor to extend + * @param {Object} `methods` Optional prototype properties to mix in. + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ -/** - * Returns true if the given node is an "*.open" node. - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * - * console.log(utils.isOpen(brace)); // false - * console.log(utils.isOpen(open)); // true - * console.log(utils.isOpen(close)); // false - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ + define(Base, 'extend', cu.extend(Base, function(Ctor, Parent) { + Ctor.prototype.mixins = Ctor.prototype.mixins || []; -utils.isOpen = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - return node.type.slice(-5) === '.open'; -}; + define(Ctor, 'mixin', function(fn) { + var mixin = fn(Ctor.prototype, Ctor); + if (typeof mixin === 'function') { + Ctor.prototype.mixins.push(mixin); + } + return Ctor; + }); -/** - * Returns true if the given node is a "*.close" node. - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * - * console.log(utils.isClose(brace)); // false - * console.log(utils.isClose(open)); // false - * console.log(utils.isClose(close)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ + define(Ctor, 'mixins', function(Child) { + Base.run(Child, 'mixin', Ctor.prototype.mixins); + return Ctor; + }); -utils.isClose = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - return node.type.slice(-6) === '.close'; -}; + Ctor.prototype.mixin = function(key, value) { + Ctor.prototype[key] = value; + return this; + }; + return Base; + })); -/** - * Returns true if `node.nodes` **has** an `.open` node - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var open = new Node({type: 'brace.open'}); - * console.log(utils.hasOpen(brace)); // false - * - * brace.pushNode(open); - * console.log(utils.hasOpen(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ + /** + * Used for adding methods to the `Base` prototype, and/or to the prototype of child instances. + * When a mixin function returns a function, the returned function is pushed onto the `.mixins` + * array, making it available to be used on inheriting classes whenever `Base.mixins()` is + * called (e.g. `Base.mixins(Child)`). + * + * ```js + * Base.mixin(function(proto) { + * proto.foo = function(msg) { + * return 'foo ' + msg; + * }; + * }); + * ``` + * @name #mixin + * @param {Function} `fn` Function to call + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ -utils.hasOpen = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - var first = node.first || node.nodes ? node.nodes[0] : null; - if (utils.isNode(first)) { - return first.type === node.type + '.open'; - } - return false; -}; + define(Base, 'mixin', function(fn) { + var mixin = fn(Base.prototype, Base); + if (typeof mixin === 'function') { + Base.prototype.mixins.push(mixin); + } + return Base; + }); -/** - * Returns true if `node.nodes` **has** a `.close` node - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var close = new Node({type: 'brace.close'}); - * console.log(utils.hasClose(brace)); // false - * - * brace.pushNode(close); - * console.log(utils.hasClose(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public - */ + /** + * Static method for running global mixin functions against a child constructor. + * Mixins must be registered before calling this method. + * + * ```js + * Base.extend(Child); + * Base.mixins(Child); + * ``` + * @name #mixins + * @param {Function} `Child` Constructor function of a child class + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ -utils.hasClose = function(node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - var last = node.last || node.nodes ? node.nodes[node.nodes.length - 1] : null; - if (utils.isNode(last)) { - return last.type === node.type + '.close'; - } - return false; -}; + define(Base, 'mixins', function(Child) { + Base.run(Child, 'mixin', Base.prototype.mixins); + return Base; + }); -/** - * Returns true if `node.nodes` has both `.open` and `.close` nodes - * - * ```js - * var Node = require('snapdragon-node'); - * var brace = new Node({ - * type: 'brace', - * nodes: [] - * }); - * - * var open = new Node({type: 'brace.open'}); - * var close = new Node({type: 'brace.close'}); - * console.log(utils.hasOpen(brace)); // false - * console.log(utils.hasClose(brace)); // false - * - * brace.pushNode(open); - * brace.pushNode(close); - * console.log(utils.hasOpen(brace)); // true - * console.log(utils.hasClose(brace)); // true - * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Boolean} - * @api public + /** + * Similar to `util.inherit`, but copies all static properties, prototype properties, and + * getters/setters from `Provider` to `Receiver`. See [class-utils][]{#inherit} for more details. + * + * ```js + * Base.inherit(Foo, Bar); + * ``` + * @name #inherit + * @param {Function} `Receiver` Receiving (child) constructor + * @param {Function} `Provider` Providing (parent) constructor + * @return {Object} Returns the `Base` constructor for chaining + * @api public + */ + + define(Base, 'inherit', cu.inherit); + define(Base, 'bubble', cu.bubble); + return Base; +} + +/** + * Expose `Base` with default settings */ -utils.hasOpenAndClose = function(node) { - return utils.hasOpen(node) && utils.hasClose(node); -}; +module.exports = namespace(); /** - * Push the given `node` onto the `state.inside` array for the - * given type. This array is used as a specialized "stack" for - * only the given `node.type`. + * Allow users to define a namespace + */ + +module.exports.namespace = namespace; + + +/***/ }), +/* 764 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * define-property * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * utils.addType(state, node); - * console.log(state.inside); - * //=> { brace: [{type: 'brace'}] } - * ``` - * @param {Object} `state` The `compiler.state` object or custom state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Array} Returns the `state.inside` stack for the given type. - * @api public + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -utils.addType = function(state, node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); - var type = node.parent - ? node.parent.type - : node.type.replace(/\.open$/, ''); - if (!state.hasOwnProperty('inside')) { - state.inside = {}; +var isDescriptor = __webpack_require__(754); + +module.exports = function defineProperty(obj, prop, val) { + if (typeof obj !== 'object' && typeof obj !== 'function') { + throw new TypeError('expected an object or function.'); } - if (!state.inside.hasOwnProperty(type)) { - state.inside[type] = []; + + if (typeof prop !== 'string') { + throw new TypeError('expected `prop` to be a string.'); } - var arr = state.inside[type]; - arr.push(node); - return arr; + if (isDescriptor(val) && ('set' in val || 'get' in val)) { + return Object.defineProperty(obj, prop, val); + } + + return Object.defineProperty(obj, prop, { + configurable: true, + enumerable: false, + writable: true, + value: val + }); }; -/** - * Remove the given `node` from the `state.inside` array for the - * given type. This array is used as a specialized "stack" for - * only the given `node.type`. - * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * utils.addType(state, node); - * console.log(state.inside); - * //=> { brace: [{type: 'brace'}] } - * utils.removeType(state, node); - * //=> { brace: [] } - * ``` - * @param {Object} `state` The `compiler.state` object or custom state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @return {Array} Returns the `state.inside` stack for the given type. - * @api public - */ -utils.removeType = function(state, node) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); +/***/ }), +/* 765 */ +/***/ (function(module, exports, __webpack_require__) { - var type = node.parent - ? node.parent.type - : node.type.replace(/\.close$/, ''); +"use strict"; - if (state.inside.hasOwnProperty(type)) { - return state.inside[type].pop(); - } -}; + +var isObject = __webpack_require__(742); +var Emitter = __webpack_require__(766); +var visit = __webpack_require__(767); +var toPath = __webpack_require__(770); +var union = __webpack_require__(771); +var del = __webpack_require__(775); +var get = __webpack_require__(773); +var has = __webpack_require__(780); +var set = __webpack_require__(774); /** - * Returns true if `node.val` is an empty string, or `node.nodes` does - * not contain any non-empty text nodes. + * Create a `Cache` constructor that when instantiated will + * store values on the given `prop`. * * ```js - * var node = new Node({type: 'text'}); - * utils.isEmpty(node); //=> true - * node.val = 'foo'; - * utils.isEmpty(node); //=> false + * var Cache = require('cache-base').namespace('data'); + * var cache = new Cache(); + * + * cache.set('foo', 'bar'); + * //=> {data: {foo: 'bar'}} * ``` - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {Function} `fn` - * @return {Boolean} + * @param {String} `prop` The property name to use for storing values. + * @return {Function} Returns a custom `Cache` constructor * @api public */ -utils.isEmpty = function(node, fn) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); +function namespace(prop) { - if (!Array.isArray(node.nodes)) { - if (node.type !== 'text') { - return true; + /** + * Create a new `Cache`. Internally the `Cache` constructor is created using + * the `namespace` function, with `cache` defined as the storage object. + * + * ```js + * var app = new Cache(); + * ``` + * @param {Object} `cache` Optionally pass an object to initialize with. + * @constructor + * @api public + */ + + function Cache(cache) { + if (prop) { + this[prop] = {}; } - if (typeof fn === 'function') { - return fn(node, node.parent); + if (cache) { + this.set(cache); } - return !utils.trim(node.val); } - for (var i = 0; i < node.nodes.length; i++) { - var child = node.nodes[i]; - if (utils.isOpen(child) || utils.isClose(child)) { - continue; - } - if (!utils.isEmpty(child, fn)) { - return false; - } - } + /** + * Inherit Emitter + */ + + Emitter(Cache.prototype); + + /** + * Assign `value` to `key`. Also emits `set` with + * the key and value. + * + * ```js + * app.on('set', function(key, val) { + * // do something when `set` is emitted + * }); + * + * app.set(key, value); + * + * // also takes an object or array + * app.set({name: 'Halle'}); + * app.set([{foo: 'bar'}, {baz: 'quux'}]); + * console.log(app); + * //=> {name: 'Halle', foo: 'bar', baz: 'quux'} + * ``` + * + * @name .set + * @emits `set` with `key` and `value` as arguments. + * @param {String} `key` + * @param {any} `value` + * @return {Object} Returns the instance for chaining. + * @api public + */ + + Cache.prototype.set = function(key, val) { + if (Array.isArray(key) && arguments.length === 2) { + key = toPath(key); + } + if (isObject(key) || Array.isArray(key)) { + this.visit('set', key); + } else { + set(prop ? this[prop] : this, key, val); + this.emit('set', key, val); + } + return this; + }; + + /** + * Union `array` to `key`. Also emits `set` with + * the key and value. + * + * ```js + * app.union('a.b', ['foo']); + * app.union('a.b', ['bar']); + * console.log(app.get('a')); + * //=> {b: ['foo', 'bar']} + * ``` + * @name .union + * @param {String} `key` + * @param {any} `value` + * @return {Object} Returns the instance for chaining. + * @api public + */ + + Cache.prototype.union = function(key, val) { + if (Array.isArray(key) && arguments.length === 2) { + key = toPath(key); + } + var ctx = prop ? this[prop] : this; + union(ctx, key, arrayify(val)); + this.emit('union', val); + return this; + }; + + /** + * Return the value of `key`. Dot notation may be used + * to get [nested property values][get-value]. + * + * ```js + * app.set('a.b.c', 'd'); + * app.get('a.b'); + * //=> {c: 'd'} + * + * app.get(['a', 'b']); + * //=> {c: 'd'} + * ``` + * + * @name .get + * @emits `get` with `key` and `value` as arguments. + * @param {String} `key` The name of the property to get. Dot-notation may be used. + * @return {any} Returns the value of `key` + * @api public + */ + + Cache.prototype.get = function(key) { + key = toPath(arguments); + + var ctx = prop ? this[prop] : this; + var val = get(ctx, key); + + this.emit('get', key, val); + return val; + }; + + /** + * Return true if app has a stored value for `key`, + * false only if value is `undefined`. + * + * ```js + * app.set('foo', 'bar'); + * app.has('foo'); + * //=> true + * ``` + * + * @name .has + * @emits `has` with `key` and true or false as arguments. + * @param {String} `key` + * @return {Boolean} + * @api public + */ + + Cache.prototype.has = function(key) { + key = toPath(arguments); + + var ctx = prop ? this[prop] : this; + var val = get(ctx, key); + + var has = typeof val !== 'undefined'; + this.emit('has', key, has); + return has; + }; + + /** + * Delete one or more properties from the instance. + * + * ```js + * app.del(); // delete all + * // or + * app.del('foo'); + * // or + * app.del(['foo', 'bar']); + * ``` + * @name .del + * @emits `del` with the `key` as the only argument. + * @param {String|Array} `key` Property name or array of property names. + * @return {Object} Returns the instance for chaining. + * @api public + */ + + Cache.prototype.del = function(key) { + if (Array.isArray(key)) { + this.visit('del', key); + } else { + del(prop ? this[prop] : this, key); + this.emit('del', key); + } + return this; + }; + + /** + * Reset the entire cache to an empty object. + * + * ```js + * app.clear(); + * ``` + * @api public + */ + + Cache.prototype.clear = function() { + if (prop) { + this[prop] = {}; + } + }; + + /** + * Visit `method` over the properties in the given object, or map + * visit over the object-elements in an array. + * + * @name .visit + * @param {String} `method` The name of the `base` method to call. + * @param {Object|Array} `val` The object or array to iterate over. + * @return {Object} Returns the instance for chaining. + * @api public + */ + + Cache.prototype.visit = function(method, val) { + visit(this, method, val); + return this; + }; + + return Cache; +} + +/** + * Cast val to an array + */ + +function arrayify(val) { + return val ? (Array.isArray(val) ? val : [val]) : []; +} + +/** + * Expose `Cache` + */ + +module.exports = namespace(); + +/** + * Expose `Cache.namespace` + */ + +module.exports.namespace = namespace; + + +/***/ }), +/* 766 */ +/***/ (function(module, exports, __webpack_require__) { + + +/** + * Expose `Emitter`. + */ + +if (true) { + module.exports = Emitter; +} + +/** + * Initialize a new `Emitter`. + * + * @api public + */ + +function Emitter(obj) { + if (obj) return mixin(obj); +}; + +/** + * Mixin the emitter properties. + * + * @param {Object} obj + * @return {Object} + * @api private + */ + +function mixin(obj) { + for (var key in Emitter.prototype) { + obj[key] = Emitter.prototype[key]; + } + return obj; +} + +/** + * Listen on the given `event` with `fn`. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.on = +Emitter.prototype.addEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + (this._callbacks['$' + event] = this._callbacks['$' + event] || []) + .push(fn); + return this; +}; + +/** + * Adds an `event` listener that will be invoked a single + * time then automatically removed. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.once = function(event, fn){ + function on() { + this.off(event, on); + fn.apply(this, arguments); + } + + on.fn = fn; + this.on(event, on); + return this; +}; + +/** + * Remove the given callback for `event` or all + * registered callbacks. + * + * @param {String} event + * @param {Function} fn + * @return {Emitter} + * @api public + */ + +Emitter.prototype.off = +Emitter.prototype.removeListener = +Emitter.prototype.removeAllListeners = +Emitter.prototype.removeEventListener = function(event, fn){ + this._callbacks = this._callbacks || {}; + + // all + if (0 == arguments.length) { + this._callbacks = {}; + return this; + } + + // specific event + var callbacks = this._callbacks['$' + event]; + if (!callbacks) return this; + + // remove all handlers + if (1 == arguments.length) { + delete this._callbacks['$' + event]; + return this; + } + + // remove specific handler + var cb; + for (var i = 0; i < callbacks.length; i++) { + cb = callbacks[i]; + if (cb === fn || cb.fn === fn) { + callbacks.splice(i, 1); + break; + } + } + return this; +}; + +/** + * Emit `event` with the given args. + * + * @param {String} event + * @param {Mixed} ... + * @return {Emitter} + */ + +Emitter.prototype.emit = function(event){ + this._callbacks = this._callbacks || {}; + var args = [].slice.call(arguments, 1) + , callbacks = this._callbacks['$' + event]; + + if (callbacks) { + callbacks = callbacks.slice(0); + for (var i = 0, len = callbacks.length; i < len; ++i) { + callbacks[i].apply(this, args); + } + } + + return this; +}; + +/** + * Return array of callbacks for `event`. + * + * @param {String} event + * @return {Array} + * @api public + */ + +Emitter.prototype.listeners = function(event){ + this._callbacks = this._callbacks || {}; + return this._callbacks['$' + event] || []; +}; + +/** + * Check if this emitter has `event` handlers. + * + * @param {String} event + * @return {Boolean} + * @api public + */ + +Emitter.prototype.hasListeners = function(event){ + return !! this.listeners(event).length; +}; + - return true; -}; +/***/ }), +/* 767 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Returns true if the `state.inside` stack for the given type exists - * and has one or more nodes on it. +"use strict"; +/*! + * collection-visit * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * console.log(utils.isInsideType(state, 'brace')); //=> false - * utils.addType(state, node); - * console.log(utils.isInsideType(state, 'brace')); //=> true - * utils.removeType(state, node); - * console.log(utils.isInsideType(state, 'brace')); //=> false - * ``` - * @param {Object} `state` - * @param {String} `type` - * @return {Boolean} - * @api public + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -utils.isInsideType = function(state, type) { - assert(isObject(state), 'expected state to be an object'); - assert(isString(type), 'expected type to be a string'); - if (!state.hasOwnProperty('inside')) { - return false; + +var visit = __webpack_require__(768); +var mapVisit = __webpack_require__(769); + +module.exports = function(collection, method, val) { + var result; + + if (typeof val === 'string' && (method in collection)) { + var args = [].slice.call(arguments, 2); + result = collection[method].apply(collection, args); + } else if (Array.isArray(val)) { + result = mapVisit.apply(null, arguments); + } else { + result = visit.apply(null, arguments); } - if (!state.inside.hasOwnProperty(type)) { - return false; + if (typeof result !== 'undefined') { + return result; } - return state.inside[type].length > 0; + return collection; }; -/** - * Returns true if `node` is either a child or grand-child of the given `type`, - * or `state.inside[type]` is a non-empty array. + +/***/ }), +/* 768 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * object-visit * - * ```js - * var state = { inside: {}}; - * var node = new Node({type: 'brace'}); - * var open = new Node({type: 'brace.open'}); - * console.log(utils.isInside(state, open, 'brace')); //=> false - * utils.pushNode(node, open); - * console.log(utils.isInside(state, open, 'brace')); //=> true - * ``` - * @param {Object} `state` Either the `compiler.state` object, if it exists, or a user-supplied state object. - * @param {Object} `node` Instance of [snapdragon-node][] - * @param {String} `type` The `node.type` to check for. - * @return {Boolean} - * @api public + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -utils.isInside = function(state, node, type) { - assert(utils.isNode(node), 'expected node to be an instance of Node'); - assert(isObject(state), 'expected state to be an object'); - if (Array.isArray(type)) { - for (var i = 0; i < type.length; i++) { - if (utils.isInside(state, node, type[i])) { - return true; - } - } - return false; + +var isObject = __webpack_require__(742); + +module.exports = function visit(thisArg, method, target, val) { + if (!isObject(thisArg) && typeof thisArg !== 'function') { + throw new Error('object-visit expects `thisArg` to be an object.'); } - var parent = node.parent; - if (typeof type === 'string') { - return (parent && parent.type === type) || utils.isInsideType(state, type); + if (typeof method !== 'string') { + throw new Error('object-visit expects `method` name to be a string'); } - if (typeOf(type) === 'regexp') { - if (parent && parent.type && type.test(parent.type)) { - return true; - } + if (typeof thisArg[method] !== 'function') { + return thisArg; + } - var keys = Object.keys(state.inside); - var len = keys.length; - var idx = -1; - while (++idx < len) { - var key = keys[idx]; - var val = state.inside[key]; + var args = [].slice.call(arguments, 3); + target = target || {}; - if (Array.isArray(val) && val.length !== 0 && type.test(key)) { - return true; - } - } + for (var key in target) { + var arr = [key, target[key]].concat(args); + thisArg[method].apply(thisArg, arr); } - return false; + return thisArg; }; -/** - * Get the last `n` element from the given `array`. Used for getting - * a node from `node.nodes.` - * - * @param {Array} `array` - * @param {Number} `n` - * @return {undefined} - * @api public - */ -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; +/***/ }), +/* 769 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var util = __webpack_require__(29); +var visit = __webpack_require__(768); /** - * Cast the given `val` to an array. + * Map `visit` over an array of objects. * - * ```js - * console.log(utils.arrayify('')); - * //=> [] - * console.log(utils.arrayify('foo')); - * //=> ['foo'] - * console.log(utils.arrayify(['foo'])); - * //=> ['foo'] - * ``` - * @param {any} `val` - * @return {Array} - * @api public + * @param {Object} `collection` The context in which to invoke `method` + * @param {String} `method` Name of the method to call on `collection` + * @param {Object} `arr` Array of objects. */ -utils.arrayify = function(val) { - if (typeof val === 'string' && val !== '') { - return [val]; +module.exports = function mapVisit(collection, method, val) { + if (isObject(val)) { + return visit.apply(null, arguments); } + if (!Array.isArray(val)) { - return []; + throw new TypeError('expected an array: ' + util.inspect(val)); } - return val; -}; - -/** - * Convert the given `val` to a string by joining with `,`. Useful - * for creating a cheerio/CSS/DOM-style selector from a list of strings. - * - * @param {any} `val` - * @return {Array} - * @api public - */ - -utils.stringify = function(val) { - return utils.arrayify(val).join(','); -}; -/** - * Ensure that the given value is a string and call `.trim()` on it, - * or return an empty string. - * - * @param {String} `str` - * @return {String} - * @api public - */ + var args = [].slice.call(arguments, 3); -utils.trim = function(str) { - return typeof str === 'string' ? str.trim() : ''; + for (var i = 0; i < val.length; i++) { + var ele = val[i]; + if (isObject(ele)) { + visit.apply(null, [collection, method, ele].concat(args)); + } else { + collection[method].apply(collection, [ele].concat(args)); + } + } }; -/** - * Return true if val is an object - */ - function isObject(val) { - return typeOf(val) === 'object'; + return val && (typeof val === 'function' || (!Array.isArray(val) && typeof val === 'object')); } -/** - * Return true if val is a string - */ -function isString(val) { - return typeof val === 'string'; -} +/***/ }), +/* 770 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Return true if val is a function +"use strict"; +/*! + * to-object-path + * + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. */ -function isFunction(val) { - return typeof val === 'function'; -} - -/** - * Return true if val is an array - */ -function isArray(val) { - return Array.isArray(val); -} -/** - * Shim to ensure the `.append` methods work with any version of snapdragon - */ +var typeOf = __webpack_require__(747); -function append(compiler, val, node) { - if (typeof compiler.append !== 'function') { - return compiler.emit(val, node); +module.exports = function toPath(args) { + if (typeOf(args) !== 'arguments') { + args = arguments; } - return compiler.append(val, node); -} + return filter(args).join('.'); +}; -/** - * Simplified assertion. Throws an error is `val` is falsey. - */ +function filter(arr) { + var len = arr.length; + var idx = -1; + var res = []; -function assert(val, message) { - if (!val) throw new Error(message); + while (++idx < len) { + var ele = arr[idx]; + if (typeOf(ele) === 'arguments' || Array.isArray(ele)) { + res.push.apply(res, filter(ele)); + } else if (typeof ele === 'string') { + res.push(ele); + } + } + return res; } /***/ }), -/* 766 */ +/* 771 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -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); +var isObject = __webpack_require__(733); +var union = __webpack_require__(772); +var get = __webpack_require__(773); +var set = __webpack_require__(774); -/** - * Customize Snapdragon parser and renderer - */ +module.exports = function unionValue(obj, prop, value) { + if (!isObject(obj)) { + throw new TypeError('union-value expects the first argument to be an object.'); + } -function Braces(options) { - this.options = extend({}, options); + if (typeof prop !== 'string') { + throw new TypeError('union-value expects `prop` to be a string.'); + } + + var arr = arrayify(get(obj, prop)); + set(obj, prop, union(arr, arrayify(value))); + return obj; +}; + +function arrayify(val) { + if (val === null || typeof val === 'undefined') { + return []; + } + if (Array.isArray(val)) { + return val; + } + return [val]; } -/** - * Initialize braces - */ -Braces.prototype.init = function(options) { - if (this.isInitialized) return; - this.isInitialized = true; - var opts = utils.createOptions({}, this.options, options); - this.snapdragon = this.options.snapdragon || new Snapdragon(opts); - this.compiler = this.snapdragon.compiler; - this.parser = this.snapdragon.parser; +/***/ }), +/* 772 */ +/***/ (function(module, exports, __webpack_require__) { - compilers(this.snapdragon, opts); - parsers(this.snapdragon, opts); +"use strict"; - /** - * Call Snapdragon `.parse` method. When AST is returned, we check to - * see if any unclosed braces are left on the stack and, if so, we iterate - * over the stack and correct the AST so that compilers are called in the correct - * order and unbalance braces are properly escaped. - */ - utils.define(this.snapdragon, 'parse', function(pattern, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - this.parser.ast.input = pattern; +module.exports = function union(init) { + if (!Array.isArray(init)) { + throw new TypeError('arr-union expects the first argument to be an array.'); + } - var stack = this.parser.stack; - while (stack.length) { - addParent({type: 'brace.close', val: ''}, stack.pop()); - } + var len = arguments.length; + var i = 0; - function addParent(node, parent) { - utils.define(node, 'parent', parent); - parent.nodes.push(node); + while (++i < len) { + var arg = arguments[i]; + if (!arg) continue; + + if (!Array.isArray(arg)) { + arg = [arg]; } - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); + for (var j = 0; j < arg.length; j++) { + var ele = arg[j]; + + if (init.indexOf(ele) >= 0) { + continue; + } + init.push(ele); + } + } + return init; }; -/** - * Decorate `.parse` method - */ -Braces.prototype.parse = function(ast, options) { - if (ast && typeof ast === 'object' && ast.nodes) return ast; - this.init(options); - return this.snapdragon.parse(ast, options); -}; +/***/ }), +/* 773 */ +/***/ (function(module, exports) { -/** - * Decorate `.compile` method +/*! + * get-value + * + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. */ -Braces.prototype.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = this.parse(ast, options); - } else { - this.init(options); +module.exports = function(obj, prop, a, b, c) { + if (!isObject(obj) || !prop) { + return obj; } - return this.snapdragon.compile(ast, options); -}; -/** - * Expand - */ + prop = toString(prop); -Braces.prototype.expand = function(pattern) { - var ast = this.parse(pattern, {expand: true}); - return this.compile(ast, {expand: true}); -}; + // allowing for multiple properties to be passed as + // a string or array, but much faster (3-4x) than doing + // `[].slice.call(arguments)` + if (a) prop += '.' + toString(a); + if (b) prop += '.' + toString(b); + if (c) prop += '.' + toString(c); -/** - * Optimize - */ + if (prop in obj) { + return obj[prop]; + } -Braces.prototype.optimize = function(pattern) { - var ast = this.parse(pattern, {optimize: true}); - return this.compile(ast, {optimize: true}); + var segs = prop.split('.'); + var len = segs.length; + var i = -1; + + while (obj && (++i < len)) { + var key = segs[i]; + while (key[key.length - 1] === '\\') { + key = key.slice(0, -1) + '.' + segs[++i]; + } + obj = obj[key]; + } + return obj; }; -/** - * Expose `Braces` - */ +function isObject(val) { + return val !== null && (typeof val === 'object' || typeof val === 'function'); +} -module.exports = Braces; +function toString(val) { + if (!val) return ''; + if (Array.isArray(val)) { + return val.join('.'); + } + return val; +} /***/ }), -/* 767 */ +/* 774 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * set-value + * + * Copyright (c) 2014-2015, 2017, Jon Schlinkert. + * Released under the MIT License. + */ -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 = {}; -/** - * Create a new instance of `Snapdragon` with the given `options`. - * - * ```js - * var snapdragon = new Snapdragon(); - * ``` - * - * @param {Object} `options` - * @api public - */ +var split = __webpack_require__(738); +var extend = __webpack_require__(732); +var isPlainObject = __webpack_require__(741); +var isObject = __webpack_require__(733); -function Snapdragon(options) { - Base.call(this, null, options); - this.options = utils.extend({source: 'string'}, this.options); - this.compiler = new Compiler(this.options); - this.parser = new Parser(this.options); +module.exports = function(obj, prop, val) { + if (!isObject(obj)) { + return obj; + } - Object.defineProperty(this, 'compilers', { - get: function() { - return this.compiler.compilers; - } - }); + if (Array.isArray(prop)) { + prop = [].concat.apply([], prop).join('.'); + } - Object.defineProperty(this, 'parsers', { - get: function() { - return this.parser.parsers; + if (typeof prop !== 'string') { + return obj; + } + + var keys = split(prop, {sep: '.', brackets: true}).filter(isValidKey); + var len = keys.length; + var idx = -1; + var current = obj; + + while (++idx < len) { + var key = keys[idx]; + if (idx !== len - 1) { + if (!isObject(current[key])) { + current[key] = {}; + } + current = current[key]; + continue; } - }); - Object.defineProperty(this, 'regex', { - get: function() { - return this.parser.regex; + if (isPlainObject(current[key]) && isPlainObject(val)) { + current[key] = extend({}, current[key], val); + } else { + current[key] = val; } - }); + } + + return obj; +}; + +function isValidKey(key) { + return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; } -/** - * Inherit Base - */ -Base.extend(Snapdragon); +/***/ }), +/* 775 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Add a parser to `snapdragon.parsers` for capturing the given `type` using - * the specified regex or parser function. A function is useful if you need - * to customize how the token is created and/or have access to the parser - * instance to check options, etc. +"use strict"; +/*! + * unset-value * - * ```js - * snapdragon - * .capture('slash', /^\//) - * .capture('dot', function() { - * var pos = this.position(); - * var m = this.match(/^\./); - * if (!m) return; - * return pos({ - * type: 'dot', - * val: m[0] - * }); - * }); - * ``` - * @param {String} `type` - * @param {RegExp|Function} `regex` - * @return {Object} Returns the parser instance for chaining - * @api public + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. */ -Snapdragon.prototype.capture = function() { - return this.parser.capture.apply(this.parser, arguments); -}; -/** - * Register a plugin `fn`. - * - * ```js - * var snapdragon = new Snapdgragon([options]); - * snapdragon.use(function() { - * console.log(this); //<= snapdragon instance - * console.log(this.parser); //<= parser instance - * console.log(this.compiler); //<= compiler instance - * }); - * ``` - * @param {Object} `fn` - * @api public - */ -Snapdragon.prototype.use = function(fn) { - fn.call(this, this); - return this; +var isObject = __webpack_require__(742); +var has = __webpack_require__(776); + +module.exports = function unset(obj, prop) { + if (!isObject(obj)) { + throw new TypeError('expected an object.'); + } + if (obj.hasOwnProperty(prop)) { + delete obj[prop]; + return true; + } + + if (has(obj, prop)) { + var segs = prop.split('.'); + var last = segs.pop(); + while (segs.length && segs[segs.length - 1].slice(-1) === '\\') { + last = segs.pop().slice(0, -1) + '.' + last; + } + while (segs.length) obj = obj[prop = segs.shift()]; + return (delete obj[last]); + } + return true; }; -/** - * Parse the given `str`. - * - * ```js - * var snapdragon = new Snapdgragon([options]); - * // register parsers - * snapdragon.parser.use(function() {}); + +/***/ }), +/* 776 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * has-value * - * // parse - * var ast = snapdragon.parse('foo/bar'); - * console.log(ast); - * ``` - * @param {String} `str` - * @param {Object} `options` Set `options.sourcemap` to true to enable source maps. - * @return {Object} Returns an AST. - * @api public + * Copyright (c) 2014-2016, Jon Schlinkert. + * Licensed under the MIT License. */ -Snapdragon.prototype.parse = function(str, options) { - this.options = utils.extend({}, this.options, options); - var parsed = this.parser.parse(str, this.options); - // add non-enumerable parser reference - define(parsed, 'parser', this.parser); - return parsed; + +var isObject = __webpack_require__(777); +var hasValues = __webpack_require__(779); +var get = __webpack_require__(773); + +module.exports = function(obj, prop, noZero) { + if (isObject(obj)) { + return hasValues(get(obj, prop), noZero); + } + return hasValues(obj, prop); }; -/** - * Compile the given `AST`. - * - * ```js - * var snapdragon = new Snapdgragon([options]); - * // register plugins - * snapdragon.use(function() {}); - * // register parser plugins - * snapdragon.parser.use(function() {}); - * // register compiler plugins - * snapdragon.compiler.use(function() {}); - * - * // parse - * var ast = snapdragon.parse('foo/bar'); + +/***/ }), +/* 777 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * isobject * - * // compile - * var res = snapdragon.compile(ast); - * console.log(res.output); - * ``` - * @param {Object} `ast` - * @param {Object} `options` - * @return {Object} Returns an object with an `output` property with the rendered string. - * @api public + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. */ -Snapdragon.prototype.compile = function(ast, options) { - this.options = utils.extend({}, this.options, options); - var compiled = this.compiler.compile(ast, this.options); - // add non-enumerable compiler reference - define(compiled, 'compiler', this.compiler); - return compiled; + +var isArray = __webpack_require__(778); + +module.exports = function isObject(val) { + return val != null && typeof val === 'object' && isArray(val) === false; }; -/** - * Expose `Snapdragon` - */ -module.exports = Snapdragon; +/***/ }), +/* 778 */ +/***/ (function(module, exports) { -/** - * Expose `Parser` and `Compiler` - */ +var toString = {}.toString; -module.exports.Compiler = Compiler; -module.exports.Parser = Parser; +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; /***/ }), -/* 768 */ +/* 779 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * has-values + * + * Copyright (c) 2014-2015, Jon Schlinkert. + * Licensed under the MIT License. + */ -var util = __webpack_require__(29); -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. - */ +module.exports = function hasValue(o, noZero) { + if (o === null || o === undefined) { + return false; + } -function namespace(name) { - var Cache = name ? CacheBase.namespace(name) : CacheBase; - var fns = []; + if (typeof o === 'boolean') { + return true; + } - /** - * Create an instance of `Base` with the given `config` and `options`. - * - * ```js - * // initialize with `config` and `options` - * var app = new Base({isApp: true}, {abc: true}); - * app.set('foo', 'bar'); - * - * // values defined with the given `config` object will be on the root of the instance - * console.log(app.baz); //=> undefined - * console.log(app.foo); //=> 'bar' - * // or use `.get` - * console.log(app.get('isApp')); //=> true - * console.log(app.get('foo')); //=> 'bar' - * - * // values defined with the given `options` object will be on `app.options - * console.log(app.options.abc); //=> true - * ``` - * - * @param {Object} `config` If supplied, this object is passed to [cache-base][] to merge onto the the instance upon instantiation. - * @param {Object} `options` If supplied, this object is used to initialize the `base.options` object. - * @api public - */ + if (typeof o === 'number') { + if (o === 0 && noZero === true) { + return false; + } + return true; + } - function Base(config, options) { - if (!(this instanceof Base)) { - return new Base(config, options); + if (o.length !== undefined) { + return o.length !== 0; + } + + for (var key in o) { + if (o.hasOwnProperty(key)) { + return true; } - Cache.call(this, config); - this.is('base'); - this.initBase(config, options); } + return false; +}; - /** - * Inherit cache-base - */ - util.inherits(Base, Cache); +/***/ }), +/* 780 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * Add static emitter methods - */ +"use strict"; +/*! + * has-value + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Licensed under the MIT License. + */ - Emitter(Base); - /** - * Initialize `Base` defaults with the given `config` object - */ - Base.prototype.initBase = function(config, options) { - this.options = merge({}, this.options, options); - this.cache = this.cache || {}; - this.define('registered', {}); - if (name) this[name] = {}; +var isObject = __webpack_require__(742); +var hasValues = __webpack_require__(781); +var get = __webpack_require__(773); - // make `app._callbacks` non-enumerable - this.define('_callbacks', this._callbacks); - if (isObject(config)) { - this.visit('set', config); - } - Base.run(this, 'use', fns); - }; +module.exports = function(val, prop) { + return hasValues(isObject(val) && prop ? get(val, prop) : val); +}; - /** - * Set the given `name` on `app._name` and `app.is*` properties. Used for doing - * lookups in plugins. - * - * ```js - * app.is('foo'); - * console.log(app._name); - * //=> 'foo' - * console.log(app.isFoo); - * //=> true - * app.is('bar'); - * console.log(app.isFoo); - * //=> true - * console.log(app.isBar); - * //=> true - * console.log(app._name); - * //=> 'bar' - * ``` - * @name .is - * @param {String} `name` - * @return {Boolean} - * @api public - */ - Base.prototype.is = function(name) { - if (typeof name !== 'string') { - throw new TypeError('expected name to be a string'); - } - this.define('is' + pascal(name), true); - this.define('_name', name); - this.define('_appname', name); - return this; - }; +/***/ }), +/* 781 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * Returns true if a plugin has already been registered on an instance. - * - * Plugin implementors are encouraged to use this first thing in a plugin - * to prevent the plugin from being called more than once on the same - * instance. - * - * ```js - * var base = new Base(); - * base.use(function(app) { - * if (app.isRegistered('myPlugin')) return; - * // do stuff to `app` - * }); - * - * // to also record the plugin as being registered - * base.use(function(app) { - * if (app.isRegistered('myPlugin', true)) return; - * // do stuff to `app` - * }); - * ``` - * @name .isRegistered - * @emits `plugin` Emits the name of the plugin being registered. Useful for unit tests, to ensure plugins are only registered once. - * @param {String} `name` The plugin name. - * @param {Boolean} `register` If the plugin if not already registered, to record it as being registered pass `true` as the second argument. - * @return {Boolean} Returns true if a plugin is already registered. - * @api public - */ +"use strict"; +/*! + * has-values + * + * Copyright (c) 2014-2015, 2017, Jon Schlinkert. + * Released under the MIT License. + */ - Base.prototype.isRegistered = function(name, register) { - if (this.registered.hasOwnProperty(name)) { - return true; - } - if (register !== false) { - this.registered[name] = true; - this.emit('plugin', name); - } - return false; - }; - /** - * Define a plugin function to be called immediately upon init. Plugins are chainable - * and expose the following arguments to the plugin function: - * - * - `app`: the current instance of `Base` - * - `base`: the [first ancestor instance](#base) of `Base` - * - * ```js - * var app = new Base() - * .use(foo) - * .use(bar) - * .use(baz) - * ``` - * @name .use - * @param {Function} `fn` plugin function to call - * @return {Object} Returns the item instance for chaining. - * @api public - */ - Base.prototype.use = function(fn) { - fn.call(this, this); - return this; - }; +var typeOf = __webpack_require__(782); +var isNumber = __webpack_require__(746); - /** - * The `.define` method is used for adding non-enumerable property on the instance. - * Dot-notation is **not supported** with `define`. - * - * ```js - * // arbitrary `render` function using lodash `template` - * app.define('render', function(str, locals) { - * return _.template(str)(locals); - * }); - * ``` - * @name .define - * @param {String} `key` The name of the property to define. - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ +module.exports = function hasValue(val) { + // is-number checks for NaN and other edge cases + if (isNumber(val)) { + return true; + } - Base.prototype.define = function(key, val) { - if (isObject(key)) { - return this.visit('define', key); + switch (typeOf(val)) { + case 'null': + case 'boolean': + case 'function': + return true; + case 'string': + case 'arguments': + return val.length !== 0; + case 'error': + return val.message !== ''; + case 'array': + var len = val.length; + if (len === 0) { + return false; + } + for (var i = 0; i < len; i++) { + if (hasValue(val[i])) { + return true; + } + } + return false; + case 'file': + case 'map': + case 'set': + return val.size !== 0; + case 'object': + var keys = Object.keys(val); + if (keys.length === 0) { + return false; + } + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (hasValue(val[key])) { + return true; + } + } + return false; + default: { + return false; } - define(this, key, val); - return this; - }; + } +}; - /** - * Mix property `key` onto the Base prototype. If base is inherited using - * `Base.extend` this method will be overridden by a new `mixin` method that will - * only add properties to the prototype of the inheriting application. - * - * ```js - * app.mixin('foo', function() { - * // do stuff - * }); - * ``` - * @name .mixin - * @param {String} `key` - * @param {Object|Array} `val` - * @return {Object} Returns the `base` instance for chaining. - * @api public - */ - Base.prototype.mixin = function(key, val) { - Base.prototype[key] = val; - return this; - }; +/***/ }), +/* 782 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * Non-enumberable mixin array, used by the static [Base.mixin]() method. - */ +var isBuffer = __webpack_require__(729); +var toString = Object.prototype.toString; + +/** + * Get the native `typeof` a value. + * + * @param {*} `val` + * @return {*} Native javascript type + */ + +module.exports = function kindOf(val) { + // primitivies + if (typeof val === 'undefined') { + return 'undefined'; + } + if (val === null) { + return 'null'; + } + if (val === true || val === false || val instanceof Boolean) { + return 'boolean'; + } + if (typeof val === 'string' || val instanceof String) { + return 'string'; + } + if (typeof val === 'number' || val instanceof Number) { + return 'number'; + } + + // functions + if (typeof val === 'function' || val instanceof Function) { + return 'function'; + } - Base.prototype.mixins = Base.prototype.mixins || []; + // array + if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { + return 'array'; + } - /** - * Getter/setter used when creating nested instances of `Base`, for storing a reference - * to the first ancestor instance. This works by setting an instance of `Base` on the `parent` - * property of a "child" instance. The `base` property defaults to the current instance if - * no `parent` property is defined. - * - * ```js - * // create an instance of `Base`, this is our first ("base") instance - * var first = new Base(); - * first.foo = 'bar'; // arbitrary property, to make it easier to see what's happening later - * - * // create another instance - * var second = new Base(); - * // create a reference to the first instance (`first`) - * second.parent = first; - * - * // create another instance - * var third = new Base(); - * // create a reference to the previous instance (`second`) - * // repeat this pattern every time a "child" instance is created - * third.parent = second; - * - * // we can always access the first instance using the `base` property - * console.log(first.base.foo); - * //=> 'bar' - * console.log(second.base.foo); - * //=> 'bar' - * console.log(third.base.foo); - * //=> 'bar' - * // and now you know how to get to third base ;) - * ``` - * @name .base - * @api public - */ + // check for instances of RegExp and Date before calling `toString` + if (val instanceof RegExp) { + return 'regexp'; + } + if (val instanceof Date) { + return 'date'; + } - Object.defineProperty(Base.prototype, 'base', { - configurable: true, - get: function() { - return this.parent ? this.parent.base : this; - } - }); + // other objects + var type = toString.call(val); - /** - * Static method for adding global plugin functions that will - * be added to an instance when created. - * - * ```js - * Base.use(function(app) { - * app.foo = 'bar'; - * }); - * var app = new Base(); - * console.log(app.foo); - * //=> 'bar' - * ``` - * @name #use - * @param {Function} `fn` Plugin function to use on each instance. - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ + if (type === '[object RegExp]') { + return 'regexp'; + } + if (type === '[object Date]') { + return 'date'; + } + if (type === '[object Arguments]') { + return 'arguments'; + } + if (type === '[object Error]') { + return 'error'; + } + if (type === '[object Promise]') { + return 'promise'; + } - define(Base, 'use', function(fn) { - fns.push(fn); - return Base; - }); + // buffer + if (isBuffer(val)) { + return 'buffer'; + } - /** - * Run an array of functions by passing each function - * to a method on the given object specified by the given property. - * - * @param {Object} `obj` Object containing method to use. - * @param {String} `prop` Name of the method on the object to use. - * @param {Array} `arr` Array of functions to pass to the method. - */ + // es6: Map, WeakMap, Set, WeakSet + if (type === '[object Set]') { + return 'set'; + } + if (type === '[object WeakSet]') { + return 'weakset'; + } + if (type === '[object Map]') { + return 'map'; + } + if (type === '[object WeakMap]') { + return 'weakmap'; + } + if (type === '[object Symbol]') { + return 'symbol'; + } - define(Base, 'run', function(obj, prop, arr) { - var len = arr.length, i = 0; - while (len--) { - obj[prop](arr[i++]); - } - return Base; - }); + // typed arrays + if (type === '[object Int8Array]') { + return 'int8array'; + } + if (type === '[object Uint8Array]') { + return 'uint8array'; + } + if (type === '[object Uint8ClampedArray]') { + return 'uint8clampedarray'; + } + if (type === '[object Int16Array]') { + return 'int16array'; + } + if (type === '[object Uint16Array]') { + return 'uint16array'; + } + if (type === '[object Int32Array]') { + return 'int32array'; + } + if (type === '[object Uint32Array]') { + return 'uint32array'; + } + if (type === '[object Float32Array]') { + return 'float32array'; + } + if (type === '[object Float64Array]') { + return 'float64array'; + } - /** - * Static method for inheriting the prototype and static methods of the `Base` class. - * This method greatly simplifies the process of creating inheritance-based applications. - * See [static-extend][] for more details. - * - * ```js - * var extend = cu.extend(Parent); - * Parent.extend(Child); - * - * // optional methods - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @name #extend - * @param {Function} `Ctor` constructor to extend - * @param {Object} `methods` Optional prototype properties to mix in. - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ + // must be a plain object + return 'object'; +}; - define(Base, 'extend', cu.extend(Base, function(Ctor, Parent) { - Ctor.prototype.mixins = Ctor.prototype.mixins || []; - define(Ctor, 'mixin', function(fn) { - var mixin = fn(Ctor.prototype, Ctor); - if (typeof mixin === 'function') { - Ctor.prototype.mixins.push(mixin); - } - return Ctor; - }); +/***/ }), +/* 783 */ +/***/ (function(module, exports, __webpack_require__) { - define(Ctor, 'mixins', function(Child) { - Base.run(Child, 'mixin', Ctor.prototype.mixins); - return Ctor; - }); +"use strict"; - Ctor.prototype.mixin = function(key, value) { - Ctor.prototype[key] = value; - return this; - }; - return Base; - })); - /** - * Used for adding methods to the `Base` prototype, and/or to the prototype of child instances. - * When a mixin function returns a function, the returned function is pushed onto the `.mixins` - * array, making it available to be used on inheriting classes whenever `Base.mixins()` is - * called (e.g. `Base.mixins(Child)`). - * - * ```js - * Base.mixin(function(proto) { - * proto.foo = function(msg) { - * return 'foo ' + msg; - * }; - * }); - * ``` - * @name #mixin - * @param {Function} `fn` Function to call - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ +var isExtendable = __webpack_require__(784); +var forIn = __webpack_require__(785); - define(Base, 'mixin', function(fn) { - var mixin = fn(Base.prototype, Base); - if (typeof mixin === 'function') { - Base.prototype.mixins.push(mixin); +function mixinDeep(target, objects) { + var len = arguments.length, i = 0; + while (++i < len) { + var obj = arguments[i]; + if (isObject(obj)) { + forIn(obj, copy, target); } - return Base; - }); + } + return target; +} - /** - * Static method for running global mixin functions against a child constructor. - * Mixins must be registered before calling this method. - * - * ```js - * Base.extend(Child); - * Base.mixins(Child); - * ``` - * @name #mixins - * @param {Function} `Child` Constructor function of a child class - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ +/** + * Copy properties from the source object to the + * target object. + * + * @param {*} `val` + * @param {String} `key` + */ - define(Base, 'mixins', function(Child) { - Base.run(Child, 'mixin', Base.prototype.mixins); - return Base; - }); +function copy(val, key) { + if (!isValidKey(key)) { + return; + } - /** - * Similar to `util.inherit`, but copies all static properties, prototype properties, and - * getters/setters from `Provider` to `Receiver`. See [class-utils][]{#inherit} for more details. - * - * ```js - * Base.inherit(Foo, Bar); - * ``` - * @name #inherit - * @param {Function} `Receiver` Receiving (child) constructor - * @param {Function} `Provider` Providing (parent) constructor - * @return {Object} Returns the `Base` constructor for chaining - * @api public - */ + var obj = this[key]; + if (isObject(val) && isObject(obj)) { + mixinDeep(obj, val); + } else { + this[key] = val; + } +} - define(Base, 'inherit', cu.inherit); - define(Base, 'bubble', cu.bubble); - return Base; +/** + * Returns true if `val` is an object or function. + * + * @param {any} val + * @return {Boolean} + */ + +function isObject(val) { + return isExtendable(val) && !Array.isArray(val); } /** - * Expose `Base` with default settings + * Returns true if `key` is a valid key to use when extending objects. + * + * @param {String} `key` + * @return {Boolean} */ -module.exports = namespace(); +function isValidKey(key) { + return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; +}; /** - * Allow users to define a namespace + * Expose `mixinDeep` */ -module.exports.namespace = namespace; +module.exports = mixinDeep; /***/ }), -/* 769 */ +/* 784 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * define-property + * is-extendable * - * Copyright (c) 2015, 2017, Jon Schlinkert. + * Copyright (c) 2015-2017, Jon Schlinkert. * Released under the MIT License. */ -var isDescriptor = __webpack_require__(759); - -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } - - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); - } +var isPlainObject = __webpack_require__(741); - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); +module.exports = function isExtendable(val) { + return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); }; /***/ }), -/* 770 */ +/* 785 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * for-in + * + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. + */ -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 - * store values on the given `prop`. - * - * ```js - * var Cache = require('cache-base').namespace('data'); - * var cache = new Cache(); +module.exports = function forIn(obj, fn, thisArg) { + for (var key in obj) { + if (fn.call(thisArg, obj[key], key, obj) === false) { + break; + } + } +}; + + +/***/ }), +/* 786 */ +/***/ (function(module, exports) { + +/*! + * pascalcase * - * cache.set('foo', 'bar'); - * //=> {data: {foo: 'bar'}} - * ``` - * @param {String} `prop` The property name to use for storing values. - * @return {Function} Returns a custom `Cache` constructor - * @api public + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. */ -function namespace(prop) { +function pascalcase(str) { + if (typeof str !== 'string') { + throw new TypeError('expected a string.'); + } + str = str.replace(/([A-Z])/g, ' $1'); + if (str.length === 1) { return str.toUpperCase(); } + str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase(); + str = str.charAt(0).toUpperCase() + str.slice(1); + return str.replace(/[\W_]+(\w|$)/g, function (_, ch) { + return ch.toUpperCase(); + }); +} - /** - * Create a new `Cache`. Internally the `Cache` constructor is created using - * the `namespace` function, with `cache` defined as the storage object. - * - * ```js - * var app = new Cache(); - * ``` - * @param {Object} `cache` Optionally pass an object to initialize with. - * @constructor - * @api public - */ +module.exports = pascalcase; - function Cache(cache) { - if (prop) { - this[prop] = {}; - } - if (cache) { - this.set(cache); - } - } - /** - * Inherit Emitter - */ +/***/ }), +/* 787 */ +/***/ (function(module, exports, __webpack_require__) { - Emitter(Cache.prototype); +"use strict"; - /** - * Assign `value` to `key`. Also emits `set` with - * the key and value. - * - * ```js - * app.on('set', function(key, val) { - * // do something when `set` is emitted - * }); - * - * app.set(key, value); - * - * // also takes an object or array - * app.set({name: 'Halle'}); - * app.set([{foo: 'bar'}, {baz: 'quux'}]); - * console.log(app); - * //=> {name: 'Halle', foo: 'bar', baz: 'quux'} - * ``` - * - * @name .set - * @emits `set` with `key` and `value` as arguments. - * @param {String} `key` - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ - Cache.prototype.set = function(key, val) { - if (Array.isArray(key) && arguments.length === 2) { - key = toPath(key); - } - if (isObject(key) || Array.isArray(key)) { - this.visit('set', key); - } else { - set(prop ? this[prop] : this, key, val); - this.emit('set', key, val); - } - return this; - }; +var util = __webpack_require__(29); +var utils = __webpack_require__(788); - /** - * Union `array` to `key`. Also emits `set` with - * the key and value. - * - * ```js - * app.union('a.b', ['foo']); - * app.union('a.b', ['bar']); - * console.log(app.get('a')); - * //=> {b: ['foo', 'bar']} - * ``` - * @name .union - * @param {String} `key` - * @param {any} `value` - * @return {Object} Returns the instance for chaining. - * @api public - */ +/** + * Expose class utils + */ - Cache.prototype.union = function(key, val) { - if (Array.isArray(key) && arguments.length === 2) { - key = toPath(key); - } - var ctx = prop ? this[prop] : this; - union(ctx, key, arrayify(val)); - this.emit('union', val); - return this; - }; +var cu = module.exports; - /** - * Return the value of `key`. Dot notation may be used - * to get [nested property values][get-value]. - * - * ```js - * app.set('a.b.c', 'd'); - * app.get('a.b'); - * //=> {c: 'd'} - * - * app.get(['a', 'b']); - * //=> {c: 'd'} - * ``` - * - * @name .get - * @emits `get` with `key` and `value` as arguments. - * @param {String} `key` The name of the property to get. Dot-notation may be used. - * @return {any} Returns the value of `key` - * @api public - */ +/** + * Expose class utils: `cu` + */ + +cu.isObject = function isObject(val) { + return utils.isObj(val) || typeof val === 'function'; +}; + +/** + * Returns true if an array has any of the given elements, or an + * object has any of the give keys. + * + * ```js + * cu.has(['a', 'b', 'c'], 'c'); + * //=> true + * + * cu.has(['a', 'b', 'c'], ['c', 'z']); + * //=> true + * + * cu.has({a: 'b', c: 'd'}, ['c', 'z']); + * //=> true + * ``` + * @param {Object} `obj` + * @param {String|Array} `val` + * @return {Boolean} + * @api public + */ - Cache.prototype.get = function(key) { - key = toPath(arguments); +cu.has = function has(obj, val) { + val = cu.arrayify(val); + var len = val.length; - var ctx = prop ? this[prop] : this; - var val = get(ctx, key); + if (cu.isObject(obj)) { + for (var key in obj) { + if (val.indexOf(key) > -1) { + return true; + } + } - this.emit('get', key, val); - return val; - }; + var keys = cu.nativeKeys(obj); + return cu.has(keys, val); + } - /** - * Return true if app has a stored value for `key`, - * false only if value is `undefined`. - * - * ```js - * app.set('foo', 'bar'); - * app.has('foo'); - * //=> true - * ``` - * - * @name .has - * @emits `has` with `key` and true or false as arguments. - * @param {String} `key` - * @return {Boolean} - * @api public - */ + if (Array.isArray(obj)) { + var arr = obj; + while (len--) { + if (arr.indexOf(val[len]) > -1) { + return true; + } + } + return false; + } - Cache.prototype.has = function(key) { - key = toPath(arguments); + throw new TypeError('expected an array or object.'); +}; - var ctx = prop ? this[prop] : this; - var val = get(ctx, key); +/** + * Returns true if an array or object has all of the given values. + * + * ```js + * cu.hasAll(['a', 'b', 'c'], 'c'); + * //=> true + * + * cu.hasAll(['a', 'b', 'c'], ['c', 'z']); + * //=> false + * + * cu.hasAll({a: 'b', c: 'd'}, ['c', 'z']); + * //=> false + * ``` + * @param {Object|Array} `val` + * @param {String|Array} `values` + * @return {Boolean} + * @api public + */ - var has = typeof val !== 'undefined'; - this.emit('has', key, has); - return has; - }; +cu.hasAll = function hasAll(val, values) { + values = cu.arrayify(values); + var len = values.length; + while (len--) { + if (!cu.has(val, values[len])) { + return false; + } + } + return true; +}; - /** - * Delete one or more properties from the instance. - * - * ```js - * app.del(); // delete all - * // or - * app.del('foo'); - * // or - * app.del(['foo', 'bar']); - * ``` - * @name .del - * @emits `del` with the `key` as the only argument. - * @param {String|Array} `key` Property name or array of property names. - * @return {Object} Returns the instance for chaining. - * @api public - */ +/** + * Cast the given value to an array. + * + * ```js + * cu.arrayify('foo'); + * //=> ['foo'] + * + * cu.arrayify(['foo']); + * //=> ['foo'] + * ``` + * + * @param {String|Array} `val` + * @return {Array} + * @api public + */ - Cache.prototype.del = function(key) { - if (Array.isArray(key)) { - this.visit('del', key); - } else { - del(prop ? this[prop] : this, key); - this.emit('del', key); - } - return this; - }; +cu.arrayify = function arrayify(val) { + return val ? (Array.isArray(val) ? val : [val]) : []; +}; - /** - * Reset the entire cache to an empty object. - * - * ```js - * app.clear(); - * ``` - * @api public - */ +/** + * Noop + */ - Cache.prototype.clear = function() { - if (prop) { - this[prop] = {}; - } - }; +cu.noop = function noop() { + return; +}; - /** - * Visit `method` over the properties in the given object, or map - * visit over the object-elements in an array. - * - * @name .visit - * @param {String} `method` The name of the `base` method to call. - * @param {Object|Array} `val` The object or array to iterate over. - * @return {Object} Returns the instance for chaining. - * @api public - */ +/** + * Returns the first argument passed to the function. + */ - Cache.prototype.visit = function(method, val) { - visit(this, method, val); - return this; - }; +cu.identity = function identity(val) { + return val; +}; - return Cache; -} +/** + * Returns true if a value has a `contructor` + * + * ```js + * cu.hasConstructor({}); + * //=> true + * + * cu.hasConstructor(Object.create(null)); + * //=> false + * ``` + * @param {Object} `value` + * @return {Boolean} + * @api public + */ + +cu.hasConstructor = function hasConstructor(val) { + return cu.isObject(val) && typeof val.constructor !== 'undefined'; +}; /** - * Cast val to an array + * Get the native `ownPropertyNames` from the constructor of the + * given `object`. An empty array is returned if the object does + * not have a constructor. + * + * ```js + * cu.nativeKeys({a: 'b', b: 'c', c: 'd'}) + * //=> ['a', 'b', 'c'] + * + * cu.nativeKeys(function(){}) + * //=> ['length', 'caller'] + * ``` + * + * @param {Object} `obj` Object that has a `constructor`. + * @return {Array} Array of keys. + * @api public */ -function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -} +cu.nativeKeys = function nativeKeys(val) { + if (!cu.hasConstructor(val)) return []; + return Object.getOwnPropertyNames(val); +}; /** - * Expose `Cache` + * Returns property descriptor `key` if it's an "own" property + * of the given object. + * + * ```js + * function App() {} + * Object.defineProperty(App.prototype, 'count', { + * get: function() { + * return Object.keys(this).length; + * } + * }); + * cu.getDescriptor(App.prototype, 'count'); + * // returns: + * // { + * // get: [Function], + * // set: undefined, + * // enumerable: false, + * // configurable: false + * // } + * ``` + * + * @param {Object} `obj` + * @param {String} `key` + * @return {Object} Returns descriptor `key` + * @api public */ -module.exports = namespace(); +cu.getDescriptor = function getDescriptor(obj, key) { + if (!cu.isObject(obj)) { + throw new TypeError('expected an object.'); + } + if (typeof key !== 'string') { + throw new TypeError('expected key to be a string.'); + } + return Object.getOwnPropertyDescriptor(obj, key); +}; /** - * Expose `Cache.namespace` + * Copy a descriptor from one object to another. + * + * ```js + * function App() {} + * Object.defineProperty(App.prototype, 'count', { + * get: function() { + * return Object.keys(this).length; + * } + * }); + * var obj = {}; + * cu.copyDescriptor(obj, App.prototype, 'count'); + * ``` + * @param {Object} `receiver` + * @param {Object} `provider` + * @param {String} `name` + * @return {Object} + * @api public */ -module.exports.namespace = namespace; +cu.copyDescriptor = function copyDescriptor(receiver, provider, name) { + if (!cu.isObject(receiver)) { + throw new TypeError('expected receiving object to be an object.'); + } + if (!cu.isObject(provider)) { + throw new TypeError('expected providing object to be an object.'); + } + if (typeof name !== 'string') { + throw new TypeError('expected name to be a string.'); + } + var val = cu.getDescriptor(provider, name); + if (val) Object.defineProperty(receiver, name, val); +}; -/***/ }), -/* 771 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * Copy static properties, prototype properties, and descriptors + * from one object to another. + * + * @param {Object} `receiver` + * @param {Object} `provider` + * @param {String|Array} `omit` One or more properties to omit + * @return {Object} + * @api public + */ - -/** - * Expose `Emitter`. - */ - -if (true) { - module.exports = Emitter; -} - -/** - * Initialize a new `Emitter`. - * - * @api public - */ - -function Emitter(obj) { - if (obj) return mixin(obj); -}; - -/** - * Mixin the emitter properties. - * - * @param {Object} obj - * @return {Object} - * @api private - */ - -function mixin(obj) { - for (var key in Emitter.prototype) { - obj[key] = Emitter.prototype[key]; - } - return obj; -} - -/** - * Listen on the given `event` with `fn`. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.on = -Emitter.prototype.addEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - (this._callbacks['$' + event] = this._callbacks['$' + event] || []) - .push(fn); - return this; -}; - -/** - * Adds an `event` listener that will be invoked a single - * time then automatically removed. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.once = function(event, fn){ - function on() { - this.off(event, on); - fn.apply(this, arguments); - } - - on.fn = fn; - this.on(event, on); - return this; -}; - -/** - * Remove the given callback for `event` or all - * registered callbacks. - * - * @param {String} event - * @param {Function} fn - * @return {Emitter} - * @api public - */ - -Emitter.prototype.off = -Emitter.prototype.removeListener = -Emitter.prototype.removeAllListeners = -Emitter.prototype.removeEventListener = function(event, fn){ - this._callbacks = this._callbacks || {}; - - // all - if (0 == arguments.length) { - this._callbacks = {}; - return this; - } - - // specific event - var callbacks = this._callbacks['$' + event]; - if (!callbacks) return this; - - // remove all handlers - if (1 == arguments.length) { - delete this._callbacks['$' + event]; - return this; - } - - // remove specific handler - var cb; - for (var i = 0; i < callbacks.length; i++) { - cb = callbacks[i]; - if (cb === fn || cb.fn === fn) { - callbacks.splice(i, 1); - break; - } - } - return this; -}; - -/** - * Emit `event` with the given args. - * - * @param {String} event - * @param {Mixed} ... - * @return {Emitter} - */ - -Emitter.prototype.emit = function(event){ - this._callbacks = this._callbacks || {}; - var args = [].slice.call(arguments, 1) - , callbacks = this._callbacks['$' + event]; - - if (callbacks) { - callbacks = callbacks.slice(0); - for (var i = 0, len = callbacks.length; i < len; ++i) { - callbacks[i].apply(this, args); - } - } - - return this; -}; - -/** - * Return array of callbacks for `event`. - * - * @param {String} event - * @return {Array} - * @api public - */ - -Emitter.prototype.listeners = function(event){ - this._callbacks = this._callbacks || {}; - return this._callbacks['$' + event] || []; -}; - -/** - * Check if this emitter has `event` handlers. - * - * @param {String} event - * @return {Boolean} - * @api public - */ - -Emitter.prototype.hasListeners = function(event){ - return !! this.listeners(event).length; -}; +cu.copy = function copy(receiver, provider, omit) { + if (!cu.isObject(receiver)) { + throw new TypeError('expected receiving object to be an object.'); + } + if (!cu.isObject(provider)) { + throw new TypeError('expected providing object to be an object.'); + } + var props = Object.getOwnPropertyNames(provider); + var keys = Object.keys(provider); + var len = props.length, + key; + omit = cu.arrayify(omit); + while (len--) { + key = props[len]; -/***/ }), -/* 772 */ -/***/ (function(module, exports, __webpack_require__) { + if (cu.has(keys, key)) { + utils.define(receiver, key, provider[key]); + } else if (!(key in receiver) && !cu.has(omit, key)) { + cu.copyDescriptor(receiver, provider, key); + } + } +}; -"use strict"; -/*! - * collection-visit +/** + * Inherit the static properties, prototype properties, and descriptors + * from of an object. * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. + * @param {Object} `receiver` + * @param {Object} `provider` + * @param {String|Array} `omit` One or more properties to omit + * @return {Object} + * @api public */ +cu.inherit = function inherit(receiver, provider, omit) { + if (!cu.isObject(receiver)) { + throw new TypeError('expected receiving object to be an object.'); + } + if (!cu.isObject(provider)) { + throw new TypeError('expected providing object to be an object.'); + } + + var keys = []; + for (var key in provider) { + keys.push(key); + receiver[key] = provider[key]; + } + keys = keys.concat(cu.arrayify(omit)); -var visit = __webpack_require__(773); -var mapVisit = __webpack_require__(774); + var a = provider.prototype || provider; + var b = receiver.prototype || receiver; + cu.copy(b, a, keys); +}; -module.exports = function(collection, method, val) { - var result; +/** + * Returns a function for extending the static properties, + * prototype properties, and descriptors from the `Parent` + * constructor onto `Child` constructors. + * + * ```js + * var extend = cu.extend(Parent); + * Parent.extend(Child); + * + * // optional methods + * Parent.extend(Child, { + * foo: function() {}, + * bar: function() {} + * }); + * ``` + * @param {Function} `Parent` Parent ctor + * @param {Function} `extend` Optional extend function to handle custom extensions. Useful when updating methods that require a specific prototype. + * @param {Function} `Child` Child ctor + * @param {Object} `proto` Optionally pass additional prototype properties to inherit. + * @return {Object} + * @api public + */ - if (typeof val === 'string' && (method in collection)) { - var args = [].slice.call(arguments, 2); - result = collection[method].apply(collection, args); - } else if (Array.isArray(val)) { - result = mapVisit.apply(null, arguments); - } else { - result = visit.apply(null, arguments); - } +cu.extend = function() { + // keep it lazy, instead of assigning to `cu.extend` + return utils.staticExtend.apply(null, arguments); +}; - if (typeof result !== 'undefined') { - return result; - } +/** + * Bubble up events emitted from static methods on the Parent ctor. + * + * @param {Object} `Parent` + * @param {Array} `events` Event names to bubble up + * @api public + */ - return collection; +cu.bubble = function(Parent, events) { + events = events || []; + Parent.bubble = function(Child, arr) { + if (Array.isArray(arr)) { + events = utils.union([], events, arr); + } + var len = events.length; + var idx = -1; + while (++idx < len) { + var name = events[idx]; + Parent.on(name, Child.emit.bind(Child, name)); + } + cu.bubble(Child, events); + }; }; /***/ }), -/* 773 */ +/* 788 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * object-visit - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ +var utils = {}; -var isObject = __webpack_require__(747); -module.exports = function visit(thisArg, method, target, val) { - if (!isObject(thisArg) && typeof thisArg !== 'function') { - throw new Error('object-visit expects `thisArg` to be an object.'); - } - if (typeof method !== 'string') { - throw new Error('object-visit expects `method` name to be a string'); - } +/** + * Lazily required module dependencies + */ - if (typeof thisArg[method] !== 'function') { - return thisArg; - } +utils.union = __webpack_require__(772); +utils.define = __webpack_require__(724); +utils.isObj = __webpack_require__(742); +utils.staticExtend = __webpack_require__(789); - var args = [].slice.call(arguments, 3); - target = target || {}; - for (var key in target) { - var arr = [key, target[key]].concat(args); - thisArg[method].apply(thisArg, arr); - } - return thisArg; -}; +/** + * Expose `utils` + */ + +module.exports = utils; /***/ }), -/* 774 */ +/* 789 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * static-extend + * + * Copyright (c) 2016, Jon Schlinkert. + * Licensed under the MIT License. + */ + +var copy = __webpack_require__(790); +var define = __webpack_require__(724); var util = __webpack_require__(29); -var visit = __webpack_require__(773); /** - * Map `visit` over an array of objects. + * Returns a function for extending the static properties, + * prototype properties, and descriptors from the `Parent` + * constructor onto `Child` constructors. * - * @param {Object} `collection` The context in which to invoke `method` - * @param {String} `method` Name of the method to call on `collection` - * @param {Object} `arr` Array of objects. + * ```js + * var extend = require('static-extend'); + * Parent.extend = extend(Parent); + * + * // optionally pass a custom merge function as the second arg + * Parent.extend = extend(Parent, function(Child) { + * Child.prototype.mixin = function(key, val) { + * Child.prototype[key] = val; + * }; + * }); + * + * // extend "child" constructors + * Parent.extend(Child); + * + * // optionally define prototype methods as the second arg + * Parent.extend(Child, { + * foo: function() {}, + * bar: function() {} + * }); + * ``` + * @param {Function} `Parent` Parent ctor + * @param {Function} `extendFn` Optional extend function for handling any necessary custom merging. Useful when updating methods that require a specific prototype. + * @param {Function} `Child` Child ctor + * @param {Object} `proto` Optionally pass additional prototype properties to inherit. + * @return {Object} + * @api public */ -module.exports = function mapVisit(collection, method, val) { - if (isObject(val)) { - return visit.apply(null, arguments); - } - - if (!Array.isArray(val)) { - throw new TypeError('expected an array: ' + util.inspect(val)); +function extend(Parent, extendFn) { + if (typeof Parent !== 'function') { + throw new TypeError('expected Parent to be a function.'); } - var args = [].slice.call(arguments, 3); - - for (var i = 0; i < val.length; i++) { - var ele = val[i]; - if (isObject(ele)) { - visit.apply(null, [collection, method, ele].concat(args)); - } else { - collection[method].apply(collection, [ele].concat(args)); + return function(Ctor, proto) { + if (typeof Ctor !== 'function') { + throw new TypeError('expected Ctor to be a function.'); } - } -}; - -function isObject(val) { - return val && (typeof val === 'function' || (!Array.isArray(val) && typeof val === 'object')); -} - -/***/ }), -/* 775 */ -/***/ (function(module, exports, __webpack_require__) { + util.inherits(Ctor, Parent); + copy(Ctor, Parent); -"use strict"; -/*! - * to-object-path - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ + // proto can be null or a plain object + if (typeof proto === 'object') { + var obj = Object.create(proto); + for (var k in obj) { + Ctor.prototype[k] = obj[k]; + } + } + // keep a reference to the parent prototype + define(Ctor.prototype, '_parent_', { + configurable: true, + set: function() {}, + get: function() { + return Parent.prototype; + } + }); -var typeOf = __webpack_require__(752); + if (typeof extendFn === 'function') { + extendFn(Ctor, Parent); + } -module.exports = function toPath(args) { - if (typeOf(args) !== 'arguments') { - args = arguments; - } - return filter(args).join('.'); + Ctor.extend = extend(Ctor, extendFn); + }; }; -function filter(arr) { - var len = arr.length; - var idx = -1; - var res = []; +/** + * Expose `extend` + */ - while (++idx < len) { - var ele = arr[idx]; - if (typeOf(ele) === 'arguments' || Array.isArray(ele)) { - res.push.apply(res, filter(ele)); - } else if (typeof ele === 'string') { - res.push(ele); - } - } - return res; -} +module.exports = extend; /***/ }), -/* 776 */ +/* 790 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -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)) { - throw new TypeError('union-value expects the first argument to be an object.'); - } - - if (typeof prop !== 'string') { - throw new TypeError('union-value expects `prop` to be a string.'); - } +var typeOf = __webpack_require__(747); +var copyDescriptor = __webpack_require__(791); +var define = __webpack_require__(724); - var arr = arrayify(get(obj, prop)); - set(obj, prop, union(arr, arrayify(value))); - return obj; -}; +/** + * Copy static properties, prototype properties, and descriptors from one object to another. + * + * ```js + * function App() {} + * var proto = App.prototype; + * App.prototype.set = function() {}; + * App.prototype.get = function() {}; + * + * var obj = {}; + * copy(obj, proto); + * ``` + * @param {Object} `receiver` + * @param {Object} `provider` + * @param {String|Array} `omit` One or more properties to omit + * @return {Object} + * @api public + */ -function arrayify(val) { - if (val === null || typeof val === 'undefined') { - return []; +function copy(receiver, provider, omit) { + if (!isObject(receiver)) { + throw new TypeError('expected receiving object to be an object.'); } - if (Array.isArray(val)) { - return val; + if (!isObject(provider)) { + throw new TypeError('expected providing object to be an object.'); } - return [val]; -} + var props = nativeKeys(provider); + var keys = Object.keys(provider); + var len = props.length; + omit = arrayify(omit); -/***/ }), -/* 777 */ -/***/ (function(module, exports, __webpack_require__) { + while (len--) { + var key = props[len]; -"use strict"; + if (has(keys, key)) { + define(receiver, key, provider[key]); + } else if (!(key in receiver) && !has(omit, key)) { + copyDescriptor(receiver, provider, key); + } + } +}; +/** + * Return true if the given value is an object or function + */ -module.exports = function union(init) { - if (!Array.isArray(init)) { - throw new TypeError('arr-union expects the first argument to be an array.'); - } +function isObject(val) { + return typeOf(val) === 'object' || typeof val === 'function'; +} - var len = arguments.length; - var i = 0; +/** + * Returns true if an array has any of the given elements, or an + * object has any of the give keys. + * + * ```js + * has(['a', 'b', 'c'], 'c'); + * //=> true + * + * has(['a', 'b', 'c'], ['c', 'z']); + * //=> true + * + * has({a: 'b', c: 'd'}, ['c', 'z']); + * //=> true + * ``` + * @param {Object} `obj` + * @param {String|Array} `val` + * @return {Boolean} + */ - while (++i < len) { - var arg = arguments[i]; - if (!arg) continue; +function has(obj, val) { + val = arrayify(val); + var len = val.length; - if (!Array.isArray(arg)) { - arg = [arg]; + if (isObject(obj)) { + for (var key in obj) { + if (val.indexOf(key) > -1) { + return true; + } } - for (var j = 0; j < arg.length; j++) { - var ele = arg[j]; + var keys = nativeKeys(obj); + return has(keys, val); + } - if (init.indexOf(ele) >= 0) { - continue; + if (Array.isArray(obj)) { + var arr = obj; + while (len--) { + if (arr.indexOf(val[len]) > -1) { + return true; } - init.push(ele); } + return false; } - return init; -}; + throw new TypeError('expected an array or object.'); +} -/***/ }), -/* 778 */ -/***/ (function(module, exports) { - -/*! - * get-value +/** + * Cast the given value to an array. * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. + * ```js + * arrayify('foo'); + * //=> ['foo'] + * + * arrayify(['foo']); + * //=> ['foo'] + * ``` + * + * @param {String|Array} `val` + * @return {Array} */ -module.exports = function(obj, prop, a, b, c) { - if (!isObject(obj) || !prop) { - return obj; - } +function arrayify(val) { + return val ? (Array.isArray(val) ? val : [val]) : []; +} - prop = toString(prop); +/** + * Returns true if a value has a `contructor` + * + * ```js + * hasConstructor({}); + * //=> true + * + * hasConstructor(Object.create(null)); + * //=> false + * ``` + * @param {Object} `value` + * @return {Boolean} + */ - // allowing for multiple properties to be passed as - // a string or array, but much faster (3-4x) than doing - // `[].slice.call(arguments)` - if (a) prop += '.' + toString(a); - if (b) prop += '.' + toString(b); - if (c) prop += '.' + toString(c); +function hasConstructor(val) { + return isObject(val) && typeof val.constructor !== 'undefined'; +} - if (prop in obj) { - return obj[prop]; - } +/** + * Get the native `ownPropertyNames` from the constructor of the + * given `object`. An empty array is returned if the object does + * not have a constructor. + * + * ```js + * nativeKeys({a: 'b', b: 'c', c: 'd'}) + * //=> ['a', 'b', 'c'] + * + * nativeKeys(function(){}) + * //=> ['length', 'caller'] + * ``` + * + * @param {Object} `obj` Object that has a `constructor`. + * @return {Array} Array of keys. + */ - var segs = prop.split('.'); - var len = segs.length; - var i = -1; +function nativeKeys(val) { + if (!hasConstructor(val)) return []; + return Object.getOwnPropertyNames(val); +} - while (obj && (++i < len)) { - var key = segs[i]; - while (key[key.length - 1] === '\\') { - key = key.slice(0, -1) + '.' + segs[++i]; - } - obj = obj[key]; - } - return obj; -}; +/** + * Expose `copy` + */ -function isObject(val) { - return val !== null && (typeof val === 'object' || typeof val === 'function'); -} +module.exports = copy; -function toString(val) { - if (!val) return ''; - if (Array.isArray(val)) { - return val.join('.'); - } - return val; -} +/** + * Expose `copy.has` for tests + */ + +module.exports.has = has; /***/ }), -/* 779 */ +/* 791 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * set-value + * copy-descriptor * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. - * Released under the MIT License. + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. */ -var split = __webpack_require__(743); -var extend = __webpack_require__(737); -var isPlainObject = __webpack_require__(746); -var isObject = __webpack_require__(738); +/** + * Copy a descriptor from one object to another. + * + * ```js + * function App() { + * this.cache = {}; + * } + * App.prototype.set = function(key, val) { + * this.cache[key] = val; + * return this; + * }; + * Object.defineProperty(App.prototype, 'count', { + * get: function() { + * return Object.keys(this.cache).length; + * } + * }); + * + * copy(App.prototype, 'count', 'len'); + * + * // create an instance + * var app = new App(); + * + * app.set('a', true); + * app.set('b', true); + * app.set('c', true); + * + * console.log(app.count); + * //=> 3 + * console.log(app.len); + * //=> 3 + * ``` + * @name copy + * @param {Object} `receiver` The target object + * @param {Object} `provider` The provider object + * @param {String} `from` The key to copy on provider. + * @param {String} `to` Optionally specify a new key name to use. + * @return {Object} + * @api public + */ -module.exports = function(obj, prop, val) { - if (!isObject(obj)) { - return obj; +module.exports = function copyDescriptor(receiver, provider, from, to) { + if (!isObject(provider) && typeof provider !== 'function') { + to = from; + from = provider; + provider = receiver; + } + if (!isObject(receiver) && typeof receiver !== 'function') { + throw new TypeError('expected the first argument to be an object'); } - - if (Array.isArray(prop)) { - prop = [].concat.apply([], prop).join('.'); + if (!isObject(provider) && typeof provider !== 'function') { + throw new TypeError('expected provider to be an object'); } - if (typeof prop !== 'string') { - return obj; + if (typeof to !== 'string') { + to = from; + } + if (typeof from !== 'string') { + throw new TypeError('expected key to be a string'); } - var keys = split(prop, {sep: '.', brackets: true}).filter(isValidKey); - var len = keys.length; - var idx = -1; - var current = obj; - - while (++idx < len) { - var key = keys[idx]; - if (idx !== len - 1) { - if (!isObject(current[key])) { - current[key] = {}; - } - current = current[key]; - continue; - } - - if (isPlainObject(current[key]) && isPlainObject(val)) { - current[key] = extend({}, current[key], val); - } else { - current[key] = val; - } + if (!(from in provider)) { + throw new Error('property "' + from + '" does not exist'); } - return obj; + var val = Object.getOwnPropertyDescriptor(provider, from); + if (val) Object.defineProperty(receiver, to, val); }; -function isValidKey(key) { - return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; +function isObject(val) { + return {}.toString.call(val) === '[object Object]'; } + /***/ }), -/* 780 */ +/* 792 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/*! - * unset-value - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ +var use = __webpack_require__(793); +var define = __webpack_require__(724); +var debug = __webpack_require__(795)('snapdragon:compiler'); +var utils = __webpack_require__(801); -var isObject = __webpack_require__(747); -var has = __webpack_require__(781); - -module.exports = function unset(obj, prop) { - if (!isObject(obj)) { - throw new TypeError('expected an object.'); - } - if (obj.hasOwnProperty(prop)) { - delete obj[prop]; - return true; - } - - if (has(obj, prop)) { - var segs = prop.split('.'); - var last = segs.pop(); - while (segs.length && segs[segs.length - 1].slice(-1) === '\\') { - last = segs.pop().slice(0, -1) + '.' + last; - } - while (segs.length) obj = obj[prop = segs.shift()]; - return (delete obj[last]); - } - return true; -}; - +/** + * Create a new `Compiler` with the given `options`. + * @param {Object} `options` + */ -/***/ }), -/* 781 */ -/***/ (function(module, exports, __webpack_require__) { +function Compiler(options, state) { + debug('initializing', __filename); + this.options = utils.extend({source: 'string'}, options); + this.state = state || {}; + this.compilers = {}; + this.output = ''; + this.set('eos', function(node) { + return this.emit(node.val, node); + }); + this.set('noop', function(node) { + return this.emit(node.val, node); + }); + this.set('bos', function(node) { + return this.emit(node.val, node); + }); + use(this); +} -"use strict"; -/*! - * has-value - * - * Copyright (c) 2014-2016, Jon Schlinkert. - * Licensed under the MIT License. +/** + * Prototype methods */ +Compiler.prototype = { + /** + * Throw an error message with details including the cursor position. + * @param {String} `msg` Message to use in the Error. + */ -var isObject = __webpack_require__(782); -var hasValues = __webpack_require__(784); -var get = __webpack_require__(778); - -module.exports = function(obj, prop, noZero) { - if (isObject(obj)) { - return hasValues(get(obj, prop), noZero); - } - return hasValues(obj, prop); -}; + error: function(msg, node) { + var pos = node.position || {start: {column: 0}}; + var message = this.options.source + ' column:' + pos.start.column + ': ' + msg; + var err = new Error(message); + err.reason = msg; + err.column = pos.start.column; + err.source = this.pattern; -/***/ }), -/* 782 */ -/***/ (function(module, exports, __webpack_require__) { + if (this.options.silent) { + this.errors.push(err); + } else { + throw err; + } + }, -"use strict"; -/*! - * isobject - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ + /** + * Define a non-enumberable property on the `Compiler` instance. + * + * ```js + * compiler.define('foo', 'bar'); + * ``` + * @name .define + * @param {String} `key` propery name + * @param {any} `val` property value + * @return {Object} Returns the Compiler instance for chaining. + * @api public + */ + define: function(key, val) { + define(this, key, val); + return this; + }, + /** + * Emit `node.val` + */ -var isArray = __webpack_require__(783); + emit: function(str, node) { + this.output += str; + return str; + }, -module.exports = function isObject(val) { - return val != null && typeof val === 'object' && isArray(val) === false; -}; + /** + * Add a compiler `fn` with the given `name` + */ + set: function(name, fn) { + this.compilers[name] = fn; + return this; + }, -/***/ }), -/* 783 */ -/***/ (function(module, exports) { + /** + * Get compiler `name`. + */ -var toString = {}.toString; + get: function(name) { + return this.compilers[name]; + }, -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; + /** + * Get the previous AST node. + */ + prev: function(n) { + return this.ast.nodes[this.idx - (n || 1)] || { type: 'bos', val: '' }; + }, -/***/ }), -/* 784 */ -/***/ (function(module, exports, __webpack_require__) { + /** + * Get the next AST node. + */ -"use strict"; -/*! - * has-values - * - * Copyright (c) 2014-2015, Jon Schlinkert. - * Licensed under the MIT License. - */ + next: function(n) { + return this.ast.nodes[this.idx + (n || 1)] || { type: 'eos', val: '' }; + }, + /** + * Visit `node`. + */ + visit: function(node, nodes, i) { + var fn = this.compilers[node.type]; + this.idx = i; -module.exports = function hasValue(o, noZero) { - if (o === null || o === undefined) { - return false; - } + if (typeof fn !== 'function') { + throw this.error('compiler "' + node.type + '" is not registered', node); + } + return fn.call(this, node, nodes, i); + }, - if (typeof o === 'boolean') { - return true; - } + /** + * Map visit over array of `nodes`. + */ - if (typeof o === 'number') { - if (o === 0 && noZero === true) { - return false; + mapVisit: function(nodes) { + if (!Array.isArray(nodes)) { + throw new TypeError('expected an array'); } - return true; - } + var len = nodes.length; + var idx = -1; + while (++idx < len) { + this.visit(nodes[idx], nodes, idx); + } + return this; + }, - if (o.length !== undefined) { - return o.length !== 0; - } + /** + * Compile `ast`. + */ - for (var key in o) { - if (o.hasOwnProperty(key)) { - return true; + compile: function(ast, options) { + var opts = utils.extend({}, this.options, options); + this.ast = ast; + this.parsingErrors = this.ast.errors; + this.output = ''; + + // source map support + if (opts.sourcemap) { + var sourcemaps = __webpack_require__(820); + sourcemaps(this); + this.mapVisit(this.ast.nodes); + this.applySourceMaps(); + this.map = opts.sourcemap === 'generator' ? this.map : this.map.toJSON(); + return this; } + + this.mapVisit(this.ast.nodes); + return this; } - return false; }; - -/***/ }), -/* 785 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * has-value - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Licensed under the MIT License. +/** + * Expose `Compiler` */ - - -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); -}; +module.exports = Compiler; /***/ }), -/* 786 */ +/* 793 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * has-values + * use * - * Copyright (c) 2014-2015, 2017, Jon Schlinkert. + * Copyright (c) 2015, 2017, Jon Schlinkert. * Released under the MIT License. */ -var typeOf = __webpack_require__(787); -var isNumber = __webpack_require__(751); - -module.exports = function hasValue(val) { - // is-number checks for NaN and other edge cases - if (isNumber(val)) { - return true; - } +var utils = __webpack_require__(794); - switch (typeOf(val)) { - case 'null': - case 'boolean': - case 'function': - return true; - case 'string': - case 'arguments': - return val.length !== 0; - case 'error': - return val.message !== ''; - case 'array': - var len = val.length; - if (len === 0) { - return false; - } - for (var i = 0; i < len; i++) { - if (hasValue(val[i])) { - return true; - } - } - return false; - case 'file': - case 'map': - case 'set': - return val.size !== 0; - case 'object': - var keys = Object.keys(val); - if (keys.length === 0) { - return false; - } - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - if (hasValue(val[key])) { - return true; - } - } - return false; - default: { - return false; - } +module.exports = function base(app, opts) { + if (!utils.isObject(app) && typeof app !== 'function') { + throw new TypeError('use: expect `app` be an object or function'); } -}; - - -/***/ }), -/* 787 */ -/***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(734); -var toString = Object.prototype.toString; - -/** - * Get the native `typeof` a value. - * - * @param {*} `val` - * @return {*} Native javascript type - */ - -module.exports = function kindOf(val) { - // primitivies - if (typeof val === 'undefined') { - return 'undefined'; - } - if (val === null) { - return 'null'; - } - if (val === true || val === false || val instanceof Boolean) { - return 'boolean'; - } - if (typeof val === 'string' || val instanceof String) { - return 'string'; - } - if (typeof val === 'number' || val instanceof Number) { - return 'number'; + if (!utils.isObject(opts)) { + opts = {}; } - // functions - if (typeof val === 'function' || val instanceof Function) { - return 'function'; + var prop = utils.isString(opts.prop) ? opts.prop : 'fns'; + if (!Array.isArray(app[prop])) { + utils.define(app, prop, []); } - // array - if (typeof Array.isArray !== 'undefined' && Array.isArray(val)) { - return 'array'; - } + /** + * Define a plugin function to be passed to use. The only + * parameter exposed to the plugin is `app`, the object or function. + * passed to `use(app)`. `app` is also exposed as `this` in plugins. + * + * Additionally, **if a plugin returns a function, the function will + * be pushed onto the `fns` array**, allowing the plugin to be + * called at a later point by the `run` method. + * + * ```js + * var use = require('use'); + * + * // define a plugin + * function foo(app) { + * // do stuff + * } + * + * var app = function(){}; + * use(app); + * + * // register plugins + * app.use(foo); + * app.use(bar); + * app.use(baz); + * ``` + * @name .use + * @param {Function} `fn` plugin function to call + * @api public + */ - // check for instances of RegExp and Date before calling `toString` - if (val instanceof RegExp) { - return 'regexp'; - } - if (val instanceof Date) { - return 'date'; - } + utils.define(app, 'use', use); - // other objects - var type = toString.call(val); + /** + * Run all plugins on `fns`. Any plugin that returns a function + * when called by `use` is pushed onto the `fns` array. + * + * ```js + * var config = {}; + * app.run(config); + * ``` + * @name .run + * @param {Object} `value` Object to be modified by plugins. + * @return {Object} Returns the object passed to `run` + * @api public + */ - if (type === '[object RegExp]') { - return 'regexp'; - } - if (type === '[object Date]') { - return 'date'; - } - if (type === '[object Arguments]') { - return 'arguments'; - } - if (type === '[object Error]') { - return 'error'; - } - if (type === '[object Promise]') { - return 'promise'; - } + utils.define(app, 'run', function(val) { + if (!utils.isObject(val)) return; + decorate(val); - // buffer - if (isBuffer(val)) { - return 'buffer'; - } + var self = this || app; + var fns = self[prop]; + var len = fns.length; + var idx = -1; - // es6: Map, WeakMap, Set, WeakSet - if (type === '[object Set]') { - return 'set'; - } - if (type === '[object WeakSet]') { - return 'weakset'; - } - if (type === '[object Map]') { - return 'map'; - } - if (type === '[object WeakMap]') { - return 'weakmap'; - } - if (type === '[object Symbol]') { - return 'symbol'; - } + while (++idx < len) { + val.use(fns[idx]); + } + return val; + }); - // typed arrays - if (type === '[object Int8Array]') { - return 'int8array'; - } - if (type === '[object Uint8Array]') { - return 'uint8array'; - } - if (type === '[object Uint8ClampedArray]') { - return 'uint8clampedarray'; - } - if (type === '[object Int16Array]') { - return 'int16array'; - } - if (type === '[object Uint16Array]') { - return 'uint16array'; - } - if (type === '[object Int32Array]') { - return 'int32array'; - } - if (type === '[object Uint32Array]') { - return 'uint32array'; - } - if (type === '[object Float32Array]') { - return 'float32array'; + /** + * Call plugin `fn`. If a function is returned push it into the + * `fns` array to be called by the `run` method. + */ + + function use(fn, options) { + if (typeof fn !== 'function') { + throw new TypeError('.use expects `fn` be a function'); + } + + var self = this || app; + if (typeof opts.fn === 'function') { + opts.fn.call(self, self, options); + } + + var plugin = fn.call(self, self); + if (typeof plugin === 'function') { + var fns = self[prop]; + fns.push(plugin); + } + return self; } - if (type === '[object Float64Array]') { - return 'float64array'; + + /** + * Ensure the `.use` method exists on `val` + */ + + function decorate(val) { + if (!val.use || !val.run) { + base(val); + } } - // must be a plain object - return 'object'; + return app; }; /***/ }), -/* 788 */ +/* 794 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(789); -var forIn = __webpack_require__(790); +var utils = {}; + -function mixinDeep(target, objects) { - var len = arguments.length, i = 0; - while (++i < len) { - var obj = arguments[i]; - if (isObject(obj)) { - forIn(obj, copy, target); - } - } - return target; -} /** - * Copy properties from the source object to the - * target object. - * - * @param {*} `val` - * @param {String} `key` + * Lazily required module dependencies */ -function copy(val, key) { - if (!isValidKey(key)) { - return; - } +utils.define = __webpack_require__(724); +utils.isObject = __webpack_require__(742); - var obj = this[key]; - if (isObject(val) && isObject(obj)) { - mixinDeep(obj, val); - } else { - this[key] = val; - } -} + +utils.isString = function(val) { + return val && typeof val === 'string'; +}; /** - * Returns true if `val` is an object or function. - * - * @param {any} val - * @return {Boolean} + * Expose `utils` modules */ -function isObject(val) { - return isExtendable(val) && !Array.isArray(val); +module.exports = utils; + + +/***/ }), +/* 795 */ +/***/ (function(module, exports, __webpack_require__) { + +/** + * Detect Electron renderer process, which is node, but we should + * treat as a browser. + */ + +if (typeof process !== 'undefined' && process.type === 'renderer') { + module.exports = __webpack_require__(796); +} else { + module.exports = __webpack_require__(799); } + +/***/ }), +/* 796 */ +/***/ (function(module, exports, __webpack_require__) { + /** - * Returns true if `key` is a valid key to use when extending objects. + * This is the web browser implementation of `debug()`. * - * @param {String} `key` - * @return {Boolean} + * Expose `debug()` as the module. */ -function isValidKey(key) { - return key !== '__proto__' && key !== 'constructor' && key !== 'prototype'; -}; +exports = module.exports = __webpack_require__(797); +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = 'undefined' != typeof chrome + && 'undefined' != typeof chrome.storage + ? chrome.storage.local + : localstorage(); /** - * Expose `mixinDeep` + * Colors. */ -module.exports = mixinDeep; +exports.colors = [ + 'lightseagreen', + 'forestgreen', + 'goldenrod', + 'dodgerblue', + 'darkorchid', + 'crimson' +]; + +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { + return true; + } -/***/ }), -/* 789 */ -/***/ (function(module, exports, __webpack_require__) { + // is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} -"use strict"; -/*! - * is-extendable +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +exports.formatters.j = function(v) { + try { + return JSON.stringify(v); + } catch (err) { + return '[UnexpectedJSONParseError]: ' + err.message; + } +}; + + +/** + * Colorize log arguments if enabled. * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * @api public */ +function formatArgs(args) { + var useColors = this.useColors; + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); -var isPlainObject = __webpack_require__(746); + if (!useColors) return; -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit') + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); -/***/ }), -/* 790 */ -/***/ (function(module, exports, __webpack_require__) { + args.splice(lastC, 0, c); +} -"use strict"; -/*! - * for-in +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. + * @api public */ +function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); +} +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ -module.exports = function forIn(obj, fn, thisArg) { - for (var key in obj) { - if (fn.call(thisArg, obj[key], key, obj) === false) { - break; +function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; } + } catch(e) {} +} + +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ + +function load() { + var r; + try { + r = exports.storage.debug; + } catch(e) {} + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; } -}; + return r; +} -/***/ }), -/* 791 */ -/***/ (function(module, exports) { +/** + * Enable namespaces listed in `localStorage.debug` initially. + */ -/*! - * pascalcase +exports.enable(load()); + +/** + * Localstorage attempts to return the localstorage. * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private */ -function pascalcase(str) { - if (typeof str !== 'string') { - throw new TypeError('expected a string.'); - } - str = str.replace(/([A-Z])/g, ' $1'); - if (str.length === 1) { return str.toUpperCase(); } - str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase(); - str = str.charAt(0).toUpperCase() + str.slice(1); - return str.replace(/[\W_]+(\w|$)/g, function (_, ch) { - return ch.toUpperCase(); - }); +function localstorage() { + try { + return window.localStorage; + } catch (e) {} } -module.exports = pascalcase; - /***/ }), -/* 792 */ +/* 797 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. + */ -var util = __webpack_require__(29); -var utils = __webpack_require__(793); +exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; +exports.coerce = coerce; +exports.disable = disable; +exports.enable = enable; +exports.enabled = enabled; +exports.humanize = __webpack_require__(798); /** - * Expose class utils + * The currently active debug mode names, and names to skip. */ -var cu = module.exports; +exports.names = []; +exports.skips = []; /** - * Expose class utils: `cu` + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". */ -cu.isObject = function isObject(val) { - return utils.isObj(val) || typeof val === 'function'; -}; +exports.formatters = {}; /** - * Returns true if an array has any of the given elements, or an - * object has any of the give keys. - * - * ```js - * cu.has(['a', 'b', 'c'], 'c'); - * //=> true - * - * cu.has(['a', 'b', 'c'], ['c', 'z']); - * //=> true - * - * cu.has({a: 'b', c: 'd'}, ['c', 'z']); - * //=> true - * ``` - * @param {Object} `obj` - * @param {String|Array} `val` - * @return {Boolean} - * @api public + * Previous log timestamp. */ -cu.has = function has(obj, val) { - val = cu.arrayify(val); - var len = val.length; +var prevTime; - if (cu.isObject(obj)) { - for (var key in obj) { - if (val.indexOf(key) > -1) { - return true; - } - } +/** + * Select a color. + * @param {String} namespace + * @return {Number} + * @api private + */ - var keys = cu.nativeKeys(obj); - return cu.has(keys, val); - } +function selectColor(namespace) { + var hash = 0, i; - if (Array.isArray(obj)) { - var arr = obj; - while (len--) { - if (arr.indexOf(val[len]) > -1) { - return true; - } - } - return false; + for (i in namespace) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer } - throw new TypeError('expected an array or object.'); -}; + return exports.colors[Math.abs(hash) % exports.colors.length]; +} /** - * Returns true if an array or object has all of the given values. - * - * ```js - * cu.hasAll(['a', 'b', 'c'], 'c'); - * //=> true - * - * cu.hasAll(['a', 'b', 'c'], ['c', 'z']); - * //=> false + * Create a debugger with the given `namespace`. * - * cu.hasAll({a: 'b', c: 'd'}, ['c', 'z']); - * //=> false - * ``` - * @param {Object|Array} `val` - * @param {String|Array} `values` - * @return {Boolean} + * @param {String} namespace + * @return {Function} * @api public */ -cu.hasAll = function hasAll(val, values) { - values = cu.arrayify(values); - var len = values.length; - while (len--) { - if (!cu.has(val, values[len])) { - return false; +function createDebug(namespace) { + + function debug() { + // disabled? + if (!debug.enabled) return; + + var self = debug; + + // set `diff` timestamp + var curr = +new Date(); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + // turn the `arguments` into a proper Array + var args = new Array(arguments.length); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; + } + + args[0] = exports.coerce(args[0]); + + if ('string' !== typeof args[0]) { + // anything else let's inspect with %O + args.unshift('%O'); } + + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); + + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); + + // apply env-specific formatting (colors, etc.) + exports.formatArgs.call(self, args); + + var logFn = debug.log || exports.log || console.log.bind(console); + logFn.apply(self, args); } - return true; -}; + + debug.namespace = namespace; + debug.enabled = exports.enabled(namespace); + debug.useColors = exports.useColors(); + debug.color = selectColor(namespace); + + // env-specific initialization logic for debug instances + if ('function' === typeof exports.init) { + exports.init(debug); + } + + return debug; +} /** - * Cast the given value to an array. - * - * ```js - * cu.arrayify('foo'); - * //=> ['foo'] - * - * cu.arrayify(['foo']); - * //=> ['foo'] - * ``` + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. * - * @param {String|Array} `val` - * @return {Array} + * @param {String} namespaces * @api public */ -cu.arrayify = function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -}; +function enable(namespaces) { + exports.save(namespaces); -/** - * Noop - */ + exports.names = []; + exports.skips = []; -cu.noop = function noop() { - return; -}; + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; + + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + exports.names.push(new RegExp('^' + namespaces + '$')); + } + } +} /** - * Returns the first argument passed to the function. + * Disable debug output. + * + * @api public */ -cu.identity = function identity(val) { - return val; -}; +function disable() { + exports.enable(''); +} /** - * Returns true if a value has a `contructor` - * - * ```js - * cu.hasConstructor({}); - * //=> true + * Returns true if the given mode name is enabled, false otherwise. * - * cu.hasConstructor(Object.create(null)); - * //=> false - * ``` - * @param {Object} `value` + * @param {String} name * @return {Boolean} * @api public */ -cu.hasConstructor = function hasConstructor(val) { - return cu.isObject(val) && typeof val.constructor !== 'undefined'; -}; +function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; + } + } + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; + } + } + return false; +} /** - * Get the native `ownPropertyNames` from the constructor of the - * given `object`. An empty array is returned if the object does - * not have a constructor. - * - * ```js - * cu.nativeKeys({a: 'b', b: 'c', c: 'd'}) - * //=> ['a', 'b', 'c'] - * - * cu.nativeKeys(function(){}) - * //=> ['length', 'caller'] - * ``` + * Coerce `val`. * - * @param {Object} `obj` Object that has a `constructor`. - * @return {Array} Array of keys. - * @api public + * @param {Mixed} val + * @return {Mixed} + * @api private */ -cu.nativeKeys = function nativeKeys(val) { - if (!cu.hasConstructor(val)) return []; - return Object.getOwnPropertyNames(val); -}; +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} + + +/***/ }), +/* 798 */ +/***/ (function(module, exports) { /** - * Returns property descriptor `key` if it's an "own" property - * of the given object. + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. * - * ```js - * function App() {} - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this).length; - * } - * }); - * cu.getDescriptor(App.prototype, 'count'); - * // returns: - * // { - * // get: [Function], - * // set: undefined, - * // enumerable: false, - * // configurable: false - * // } - * ``` + * Options: * - * @param {Object} `obj` - * @param {String} `key` - * @return {Object} Returns descriptor `key` + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} * @api public */ -cu.getDescriptor = function getDescriptor(obj, key) { - if (!cu.isObject(obj)) { - throw new TypeError('expected an object.'); - } - if (typeof key !== 'string') { - throw new TypeError('expected key to be a string.'); +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); } - return Object.getOwnPropertyDescriptor(obj, key); + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); }; /** - * Copy a descriptor from one object to another. + * Parse the given `str` and return milliseconds. * - * ```js - * function App() {} - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this).length; - * } - * }); - * var obj = {}; - * cu.copyDescriptor(obj, App.prototype, 'count'); - * ``` - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String} `name` - * @return {Object} - * @api public + * @param {String} str + * @return {Number} + * @api private */ -cu.copyDescriptor = function copyDescriptor(receiver, provider, name) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); +function parse(str) { + str = String(str); + if (str.length > 100) { + return; } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); + var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; } - if (typeof name !== 'string') { - throw new TypeError('expected name to be a string.'); + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; } - - var val = cu.getDescriptor(provider, name); - if (val) Object.defineProperty(receiver, name, val); -}; +} /** - * Copy static properties, prototype properties, and descriptors - * from one object to another. + * Short format for `ms`. * - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public + * @param {Number} ms + * @return {String} + * @api private */ -cu.copy = function copy(receiver, provider, omit) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); +function fmtShort(ms) { + if (ms >= d) { + return Math.round(ms / d) + 'd'; } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); + if (ms >= h) { + return Math.round(ms / h) + 'h'; } - var props = Object.getOwnPropertyNames(provider); - var keys = Object.keys(provider); - var len = props.length, - key; - omit = cu.arrayify(omit); - - while (len--) { - key = props[len]; - - if (cu.has(keys, key)) { - utils.define(receiver, key, provider[key]); - } else if (!(key in receiver) && !cu.has(omit, key)) { - cu.copyDescriptor(receiver, provider, key); - } + if (ms >= m) { + return Math.round(ms / m) + 'm'; } -}; + if (ms >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} /** - * Inherit the static properties, prototype properties, and descriptors - * from of an object. + * Long format for `ms`. * - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public + * @param {Number} ms + * @return {String} + * @api private */ -cu.inherit = function inherit(receiver, provider, omit) { - if (!cu.isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!cu.isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); - } +function fmtLong(ms) { + return plural(ms, d, 'day') || + plural(ms, h, 'hour') || + plural(ms, m, 'minute') || + plural(ms, s, 'second') || + ms + ' ms'; +} - var keys = []; - for (var key in provider) { - keys.push(key); - receiver[key] = provider[key]; +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) { + return; + } + if (ms < n * 1.5) { + return Math.floor(ms / n) + ' ' + name; } + return Math.ceil(ms / n) + ' ' + name + 's'; +} - keys = keys.concat(cu.arrayify(omit)); - var a = provider.prototype || provider; - var b = receiver.prototype || receiver; - cu.copy(b, a, keys); -}; +/***/ }), +/* 799 */ +/***/ (function(module, exports, __webpack_require__) { /** - * Returns a function for extending the static properties, - * prototype properties, and descriptors from the `Parent` - * constructor onto `Child` constructors. - * - * ```js - * var extend = cu.extend(Parent); - * Parent.extend(Child); - * - * // optional methods - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @param {Function} `Parent` Parent ctor - * @param {Function} `extend` Optional extend function to handle custom extensions. Useful when updating methods that require a specific prototype. - * @param {Function} `Child` Child ctor - * @param {Object} `proto` Optionally pass additional prototype properties to inherit. - * @return {Object} - * @api public + * Module dependencies. */ -cu.extend = function() { - // keep it lazy, instead of assigning to `cu.extend` - return utils.staticExtend.apply(null, arguments); -}; +var tty = __webpack_require__(480); +var util = __webpack_require__(29); /** - * Bubble up events emitted from static methods on the Parent ctor. + * This is the Node.js implementation of `debug()`. * - * @param {Object} `Parent` - * @param {Array} `events` Event names to bubble up - * @api public + * Expose `debug()` as the module. */ -cu.bubble = function(Parent, events) { - events = events || []; - Parent.bubble = function(Child, arr) { - if (Array.isArray(arr)) { - events = utils.union([], events, arr); - } - var len = events.length; - var idx = -1; - while (++idx < len) { - var name = events[idx]; - Parent.on(name, Child.emit.bind(Child, name)); - } - cu.bubble(Child, events); - }; -}; - +exports = module.exports = __webpack_require__(797); +exports.init = init; +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; -/***/ }), -/* 793 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * Colors. + */ -"use strict"; +exports.colors = [6, 2, 3, 4, 5, 1]; +/** + * Build up the default `inspectOpts` object from the environment variables. + * + * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js + */ -var utils = {}; +exports.inspectOpts = Object.keys(process.env).filter(function (key) { + return /^debug_/i.test(key); +}).reduce(function (obj, key) { + // camel-case + var prop = key + .substring(6) + .toLowerCase() + .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); + // coerce string value into JS value + var val = process.env[key]; + if (/^(yes|on|true|enabled)$/i.test(val)) val = true; + else if (/^(no|off|false|disabled)$/i.test(val)) val = false; + else if (val === 'null') val = null; + else val = Number(val); + obj[prop] = val; + return obj; +}, {}); /** - * Lazily required module dependencies + * The file descriptor to write the `debug()` calls to. + * Set the `DEBUG_FD` env variable to override with another value. i.e.: + * + * $ DEBUG_FD=3 node script.js 3>debug.log */ -utils.union = __webpack_require__(777); -utils.define = __webpack_require__(729); -utils.isObj = __webpack_require__(747); -utils.staticExtend = __webpack_require__(794); +var fd = parseInt(process.env.DEBUG_FD, 10) || 2; + +if (1 !== fd && 2 !== fd) { + util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')() +} +var stream = 1 === fd ? process.stdout : + 2 === fd ? process.stderr : + createWritableStdioStream(fd); /** - * Expose `utils` + * Is stdout a TTY? Colored output is enabled when `true`. */ -module.exports = utils; - - -/***/ }), -/* 794 */ -/***/ (function(module, exports, __webpack_require__) { +function useColors() { + return 'colors' in exports.inspectOpts + ? Boolean(exports.inspectOpts.colors) + : tty.isatty(fd); +} -"use strict"; -/*! - * static-extend - * - * Copyright (c) 2016, Jon Schlinkert. - * Licensed under the MIT License. +/** + * Map %o to `util.inspect()`, all on a single line. */ +exports.formatters.o = function(v) { + this.inspectOpts.colors = this.useColors; + return util.inspect(v, this.inspectOpts) + .split('\n').map(function(str) { + return str.trim() + }).join(' '); +}; +/** + * Map %o to `util.inspect()`, allowing multiple lines if needed. + */ -var copy = __webpack_require__(795); -var define = __webpack_require__(729); -var util = __webpack_require__(29); +exports.formatters.O = function(v) { + this.inspectOpts.colors = this.useColors; + return util.inspect(v, this.inspectOpts); +}; /** - * Returns a function for extending the static properties, - * prototype properties, and descriptors from the `Parent` - * constructor onto `Child` constructors. - * - * ```js - * var extend = require('static-extend'); - * Parent.extend = extend(Parent); - * - * // optionally pass a custom merge function as the second arg - * Parent.extend = extend(Parent, function(Child) { - * Child.prototype.mixin = function(key, val) { - * Child.prototype[key] = val; - * }; - * }); - * - * // extend "child" constructors - * Parent.extend(Child); + * Adds ANSI color escape codes if enabled. * - * // optionally define prototype methods as the second arg - * Parent.extend(Child, { - * foo: function() {}, - * bar: function() {} - * }); - * ``` - * @param {Function} `Parent` Parent ctor - * @param {Function} `extendFn` Optional extend function for handling any necessary custom merging. Useful when updating methods that require a specific prototype. - * @param {Function} `Child` Child ctor - * @param {Object} `proto` Optionally pass additional prototype properties to inherit. - * @return {Object} * @api public */ -function extend(Parent, extendFn) { - if (typeof Parent !== 'function') { - throw new TypeError('expected Parent to be a function.'); - } +function formatArgs(args) { + var name = this.namespace; + var useColors = this.useColors; - return function(Ctor, proto) { - if (typeof Ctor !== 'function') { - throw new TypeError('expected Ctor to be a function.'); - } + if (useColors) { + var c = this.color; + var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; - util.inherits(Ctor, Parent); - copy(Ctor, Parent); + args[0] = prefix + args[0].split('\n').join('\n' + prefix); + args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); + } else { + args[0] = new Date().toUTCString() + + ' ' + name + ' ' + args[0]; + } +} - // proto can be null or a plain object - if (typeof proto === 'object') { - var obj = Object.create(proto); +/** + * Invokes `util.format()` with the specified arguments and writes to `stream`. + */ - for (var k in obj) { - Ctor.prototype[k] = obj[k]; - } - } +function log() { + return stream.write(util.format.apply(util, arguments) + '\n'); +} - // keep a reference to the parent prototype - define(Ctor.prototype, '_parent_', { - configurable: true, - set: function() {}, - get: function() { - return Parent.prototype; - } - }); +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ + +function save(namespaces) { + if (null == namespaces) { + // If you set a process.env field to null or undefined, it gets cast to the + // string 'null' or 'undefined'. Just delete instead. + delete process.env.DEBUG; + } else { + process.env.DEBUG = namespaces; + } +} - if (typeof extendFn === 'function') { - extendFn(Ctor, Parent); - } +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ - Ctor.extend = extend(Ctor, extendFn); - }; -}; +function load() { + return process.env.DEBUG; +} /** - * Expose `extend` + * Copied from `node/src/node.js`. + * + * XXX: It's lame that node doesn't expose this API out-of-the-box. It also + * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. */ -module.exports = extend; +function createWritableStdioStream (fd) { + var stream; + var tty_wrap = process.binding('tty_wrap'); + // Note stream._type is used for test-module-load-list.js -/***/ }), -/* 795 */ -/***/ (function(module, exports, __webpack_require__) { + switch (tty_wrap.guessHandleType(fd)) { + case 'TTY': + stream = new tty.WriteStream(fd); + stream._type = 'tty'; -"use strict"; + // Hack to have stream not keep the event loop alive. + // See https://github.com/joyent/node/issues/1726 + if (stream._handle && stream._handle.unref) { + stream._handle.unref(); + } + break; + case 'FILE': + var fs = __webpack_require__(23); + stream = new fs.SyncWriteStream(fd, { autoClose: false }); + stream._type = 'fs'; + break; -var typeOf = __webpack_require__(752); -var copyDescriptor = __webpack_require__(796); -var define = __webpack_require__(729); + case 'PIPE': + case 'TCP': + var net = __webpack_require__(800); + stream = new net.Socket({ + fd: fd, + readable: false, + writable: true + }); -/** - * Copy static properties, prototype properties, and descriptors from one object to another. - * - * ```js - * function App() {} - * var proto = App.prototype; - * App.prototype.set = function() {}; - * App.prototype.get = function() {}; - * - * var obj = {}; - * copy(obj, proto); - * ``` - * @param {Object} `receiver` - * @param {Object} `provider` - * @param {String|Array} `omit` One or more properties to omit - * @return {Object} - * @api public - */ + // FIXME Should probably have an option in net.Socket to create a + // stream from an existing fd which is writable only. But for now + // we'll just add this hack and set the `readable` member to false. + // Test: ./node test/fixtures/echo.js < /etc/passwd + stream.readable = false; + stream.read = null; + stream._type = 'pipe'; -function copy(receiver, provider, omit) { - if (!isObject(receiver)) { - throw new TypeError('expected receiving object to be an object.'); - } - if (!isObject(provider)) { - throw new TypeError('expected providing object to be an object.'); + // FIXME Hack to have stream not keep the event loop alive. + // See https://github.com/joyent/node/issues/1726 + if (stream._handle && stream._handle.unref) { + stream._handle.unref(); + } + break; + + default: + // Probably an error on in uv_guess_handle() + throw new Error('Implement me. Unknown stream file type!'); } - var props = nativeKeys(provider); - var keys = Object.keys(provider); - var len = props.length; - omit = arrayify(omit); + // For supporting legacy API we put the FD here. + stream.fd = fd; - while (len--) { - var key = props[len]; + stream._isStdio = true; - if (has(keys, key)) { - define(receiver, key, provider[key]); - } else if (!(key in receiver) && !has(omit, key)) { - copyDescriptor(receiver, provider, key); - } - } -}; + return stream; +} /** - * Return true if the given value is an object or function + * Init logic for `debug` instances. + * + * Create a new `inspectOpts` object in case `useColors` is set + * differently for a particular `debug` instance. */ -function isObject(val) { - return typeOf(val) === 'object' || typeof val === 'function'; +function init (debug) { + debug.inspectOpts = {}; + + var keys = Object.keys(exports.inspectOpts); + for (var i = 0; i < keys.length; i++) { + debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; + } } /** - * Returns true if an array has any of the given elements, or an - * object has any of the give keys. - * - * ```js - * has(['a', 'b', 'c'], 'c'); - * //=> true - * - * has(['a', 'b', 'c'], ['c', 'z']); - * //=> true - * - * has({a: 'b', c: 'd'}, ['c', 'z']); - * //=> true - * ``` - * @param {Object} `obj` - * @param {String|Array} `val` - * @return {Boolean} + * Enable namespaces listed in `process.env.DEBUG` initially. */ -function has(obj, val) { - val = arrayify(val); - var len = val.length; +exports.enable(load()); - if (isObject(obj)) { - for (var key in obj) { - if (val.indexOf(key) > -1) { - return true; - } - } - var keys = nativeKeys(obj); - return has(keys, val); - } +/***/ }), +/* 800 */ +/***/ (function(module, exports) { - if (Array.isArray(obj)) { - var arr = obj; - while (len--) { - if (arr.indexOf(val[len]) > -1) { - return true; - } - } - return false; - } +module.exports = require("net"); + +/***/ }), +/* 801 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; - throw new TypeError('expected an array or object.'); -} /** - * Cast the given value to an array. - * - * ```js - * arrayify('foo'); - * //=> ['foo'] - * - * arrayify(['foo']); - * //=> ['foo'] - * ``` - * - * @param {String|Array} `val` - * @return {Array} + * Module dependencies */ -function arrayify(val) { - return val ? (Array.isArray(val) ? val : [val]) : []; -} +exports.extend = __webpack_require__(732); +exports.SourceMap = __webpack_require__(802); +exports.sourceMapResolve = __webpack_require__(813); /** - * Returns true if a value has a `contructor` - * - * ```js - * hasConstructor({}); - * //=> true - * - * hasConstructor(Object.create(null)); - * //=> false - * ``` - * @param {Object} `value` - * @return {Boolean} + * Convert backslash in the given string to forward slashes */ -function hasConstructor(val) { - return isObject(val) && typeof val.constructor !== 'undefined'; -} +exports.unixify = function(fp) { + return fp.split(/\\+/).join('/'); +}; /** - * Get the native `ownPropertyNames` from the constructor of the - * given `object`. An empty array is returned if the object does - * not have a constructor. - * - * ```js - * nativeKeys({a: 'b', b: 'c', c: 'd'}) - * //=> ['a', 'b', 'c'] - * - * nativeKeys(function(){}) - * //=> ['length', 'caller'] - * ``` + * Return true if `val` is a non-empty string * - * @param {Object} `obj` Object that has a `constructor`. - * @return {Array} Array of keys. + * @param {String} `str` + * @return {Boolean} */ -function nativeKeys(val) { - if (!hasConstructor(val)) return []; - return Object.getOwnPropertyNames(val); -} +exports.isString = function(str) { + return str && typeof str === 'string'; +}; /** - * Expose `copy` + * Cast `val` to an array + * @return {Array} */ -module.exports = copy; +exports.arrayify = function(val) { + if (typeof val === 'string') return [val]; + return val ? (Array.isArray(val) ? val : [val]) : []; +}; /** - * Expose `copy.has` for tests + * Get the last `n` element from the given `array` + * @param {Array} `array` + * @return {*} */ -module.exports.has = has; +exports.last = function(arr, n) { + return arr[arr.length - (n || 1)]; +}; /***/ }), -/* 796 */ +/* 802 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; -/*! - * copy-descriptor - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. +/* + * Copyright 2009-2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE.txt or: + * http://opensource.org/licenses/BSD-3-Clause */ +exports.SourceMapGenerator = __webpack_require__(803).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(809).SourceMapConsumer; +exports.SourceNode = __webpack_require__(812).SourceNode; + + +/***/ }), +/* 803 */ +/***/ (function(module, exports, __webpack_require__) { +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ +var base64VLQ = __webpack_require__(804); +var util = __webpack_require__(806); +var ArraySet = __webpack_require__(807).ArraySet; +var MappingList = __webpack_require__(808).MappingList; /** - * Copy a descriptor from one object to another. - * - * ```js - * function App() { - * this.cache = {}; - * } - * App.prototype.set = function(key, val) { - * this.cache[key] = val; - * return this; - * }; - * Object.defineProperty(App.prototype, 'count', { - * get: function() { - * return Object.keys(this.cache).length; - * } - * }); - * - * copy(App.prototype, 'count', 'len'); + * An instance of the SourceMapGenerator represents a source map which is + * being built incrementally. You may pass an object with the following + * properties: * - * // create an instance - * var app = new App(); + * - file: The filename of the generated source. + * - sourceRoot: A root for all relative URLs in this source map. + */ +function SourceMapGenerator(aArgs) { + if (!aArgs) { + aArgs = {}; + } + this._file = util.getArg(aArgs, 'file', null); + this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); + this._skipValidation = util.getArg(aArgs, 'skipValidation', false); + this._sources = new ArraySet(); + this._names = new ArraySet(); + this._mappings = new MappingList(); + this._sourcesContents = null; +} + +SourceMapGenerator.prototype._version = 3; + +/** + * Creates a new SourceMapGenerator based on a SourceMapConsumer * - * app.set('a', true); - * app.set('b', true); - * app.set('c', true); + * @param aSourceMapConsumer The SourceMap. + */ +SourceMapGenerator.fromSourceMap = + function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { + var sourceRoot = aSourceMapConsumer.sourceRoot; + var generator = new SourceMapGenerator({ + file: aSourceMapConsumer.file, + sourceRoot: sourceRoot + }); + aSourceMapConsumer.eachMapping(function (mapping) { + var newMapping = { + generated: { + line: mapping.generatedLine, + column: mapping.generatedColumn + } + }; + + if (mapping.source != null) { + newMapping.source = mapping.source; + if (sourceRoot != null) { + newMapping.source = util.relative(sourceRoot, newMapping.source); + } + + newMapping.original = { + line: mapping.originalLine, + column: mapping.originalColumn + }; + + if (mapping.name != null) { + newMapping.name = mapping.name; + } + } + + generator.addMapping(newMapping); + }); + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content != null) { + generator.setSourceContent(sourceFile, content); + } + }); + return generator; + }; + +/** + * Add a single mapping from original source line and column to the generated + * source's line and column for this source map being created. The mapping + * object should have the following properties: * - * console.log(app.count); - * //=> 3 - * console.log(app.len); - * //=> 3 - * ``` - * @name copy - * @param {Object} `receiver` The target object - * @param {Object} `provider` The provider object - * @param {String} `from` The key to copy on provider. - * @param {String} `to` Optionally specify a new key name to use. - * @return {Object} - * @api public + * - generated: An object with the generated line and column positions. + * - original: An object with the original line and column positions. + * - source: The original source file (relative to the sourceRoot). + * - name: An optional original token name for this mapping. */ +SourceMapGenerator.prototype.addMapping = + function SourceMapGenerator_addMapping(aArgs) { + var generated = util.getArg(aArgs, 'generated'); + var original = util.getArg(aArgs, 'original', null); + var source = util.getArg(aArgs, 'source', null); + var name = util.getArg(aArgs, 'name', null); -module.exports = function copyDescriptor(receiver, provider, from, to) { - if (!isObject(provider) && typeof provider !== 'function') { - to = from; - from = provider; - provider = receiver; - } - if (!isObject(receiver) && typeof receiver !== 'function') { - throw new TypeError('expected the first argument to be an object'); - } - if (!isObject(provider) && typeof provider !== 'function') { - throw new TypeError('expected provider to be an object'); - } + if (!this._skipValidation) { + this._validateMapping(generated, original, source, name); + } - if (typeof to !== 'string') { - to = from; - } - if (typeof from !== 'string') { - throw new TypeError('expected key to be a string'); - } + if (source != null) { + source = String(source); + if (!this._sources.has(source)) { + this._sources.add(source); + } + } - if (!(from in provider)) { - throw new Error('property "' + from + '" does not exist'); - } + if (name != null) { + name = String(name); + if (!this._names.has(name)) { + this._names.add(name); + } + } - var val = Object.getOwnPropertyDescriptor(provider, from); - if (val) Object.defineProperty(receiver, to, val); -}; + this._mappings.add({ + generatedLine: generated.line, + generatedColumn: generated.column, + originalLine: original != null && original.line, + originalColumn: original != null && original.column, + source: source, + name: name + }); + }; -function isObject(val) { - return {}.toString.call(val) === '[object Object]'; -} +/** + * Set the source content for a source file. + */ +SourceMapGenerator.prototype.setSourceContent = + function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { + var source = aSourceFile; + if (this._sourceRoot != null) { + source = util.relative(this._sourceRoot, source); + } + + if (aSourceContent != null) { + // Add the source content to the _sourcesContents map. + // Create a new _sourcesContents map if the property is null. + if (!this._sourcesContents) { + this._sourcesContents = Object.create(null); + } + this._sourcesContents[util.toSetString(source)] = aSourceContent; + } else if (this._sourcesContents) { + // Remove the source file from the _sourcesContents map. + // If the _sourcesContents map is empty, set the property to null. + delete this._sourcesContents[util.toSetString(source)]; + if (Object.keys(this._sourcesContents).length === 0) { + this._sourcesContents = null; + } + } + }; +/** + * Applies the mappings of a sub-source-map for a specific source file to the + * source map being generated. Each mapping to the supplied source file is + * rewritten using the supplied source map. Note: The resolution for the + * resulting mappings is the minimium of this map and the supplied map. + * + * @param aSourceMapConsumer The source map to be applied. + * @param aSourceFile Optional. The filename of the source file. + * If omitted, SourceMapConsumer's file property will be used. + * @param aSourceMapPath Optional. The dirname of the path to the source map + * to be applied. If relative, it is relative to the SourceMapConsumer. + * This parameter is needed when the two source maps aren't in the same + * directory, and the source map to be applied contains relative source + * paths. If so, those relative source paths need to be rewritten + * relative to the SourceMapGenerator. + */ +SourceMapGenerator.prototype.applySourceMap = + function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { + var sourceFile = aSourceFile; + // If aSourceFile is omitted, we will use the file property of the SourceMap + if (aSourceFile == null) { + if (aSourceMapConsumer.file == null) { + throw new Error( + 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + + 'or the source map\'s "file" property. Both were omitted.' + ); + } + sourceFile = aSourceMapConsumer.file; + } + var sourceRoot = this._sourceRoot; + // Make "sourceFile" relative if an absolute Url is passed. + if (sourceRoot != null) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + // Applying the SourceMap can add and remove items from the sources and + // the names array. + var newSources = new ArraySet(); + var newNames = new ArraySet(); + // Find mappings for the "sourceFile" + this._mappings.unsortedForEach(function (mapping) { + if (mapping.source === sourceFile && mapping.originalLine != null) { + // Check if it can be mapped by the source map, then update the mapping. + var original = aSourceMapConsumer.originalPositionFor({ + line: mapping.originalLine, + column: mapping.originalColumn + }); + if (original.source != null) { + // Copy mapping + mapping.source = original.source; + if (aSourceMapPath != null) { + mapping.source = util.join(aSourceMapPath, mapping.source) + } + if (sourceRoot != null) { + mapping.source = util.relative(sourceRoot, mapping.source); + } + mapping.originalLine = original.line; + mapping.originalColumn = original.column; + if (original.name != null) { + mapping.name = original.name; + } + } + } -/***/ }), -/* 797 */ -/***/ (function(module, exports, __webpack_require__) { + var source = mapping.source; + if (source != null && !newSources.has(source)) { + newSources.add(source); + } -"use strict"; + var name = mapping.name; + if (name != null && !newNames.has(name)) { + newNames.add(name); + } + }, this); + this._sources = newSources; + this._names = newNames; -var use = __webpack_require__(798); -var define = __webpack_require__(729); -var debug = __webpack_require__(800)('snapdragon:compiler'); -var utils = __webpack_require__(806); + // Copy sourcesContents of applied map. + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content != null) { + if (aSourceMapPath != null) { + sourceFile = util.join(aSourceMapPath, sourceFile); + } + if (sourceRoot != null) { + sourceFile = util.relative(sourceRoot, sourceFile); + } + this.setSourceContent(sourceFile, content); + } + }, this); + }; /** - * Create a new `Compiler` with the given `options`. - * @param {Object} `options` + * A mapping can have one of the three levels of data: + * + * 1. Just the generated position. + * 2. The Generated position, original position, and original source. + * 3. Generated and original position, original source, as well as a name + * token. + * + * To maintain consistency, we validate that any new mapping being added falls + * in to one of these categories. */ +SourceMapGenerator.prototype._validateMapping = + function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, + aName) { + // When aOriginal is truthy but has empty values for .line and .column, + // it is most likely a programmer error. In this case we throw a very + // specific error message to try to guide them the right way. + // For example: https://github.com/Polymer/polymer-bundler/pull/519 + if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') { + throw new Error( + 'original.line and original.column are not numbers -- you probably meant to omit ' + + 'the original mapping entirely and only map the generated position. If so, pass ' + + 'null for the original mapping instead of an object with empty or null values.' + ); + } -function Compiler(options, state) { - debug('initializing', __filename); - this.options = utils.extend({source: 'string'}, options); - this.state = state || {}; - this.compilers = {}; - this.output = ''; - this.set('eos', function(node) { - return this.emit(node.val, node); - }); - this.set('noop', function(node) { - return this.emit(node.val, node); - }); - this.set('bos', function(node) { - return this.emit(node.val, node); - }); - use(this); -} + if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aGenerated.line > 0 && aGenerated.column >= 0 + && !aOriginal && !aSource && !aName) { + // Case 1. + return; + } + else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated + && aOriginal && 'line' in aOriginal && 'column' in aOriginal + && aGenerated.line > 0 && aGenerated.column >= 0 + && aOriginal.line > 0 && aOriginal.column >= 0 + && aSource) { + // Cases 2 and 3. + return; + } + else { + throw new Error('Invalid mapping: ' + JSON.stringify({ + generated: aGenerated, + source: aSource, + original: aOriginal, + name: aName + })); + } + }; /** - * Prototype methods + * Serialize the accumulated mappings in to the stream of base 64 VLQs + * specified by the source map format. */ +SourceMapGenerator.prototype._serializeMappings = + function SourceMapGenerator_serializeMappings() { + var previousGeneratedColumn = 0; + var previousGeneratedLine = 1; + var previousOriginalColumn = 0; + var previousOriginalLine = 0; + var previousName = 0; + var previousSource = 0; + var result = ''; + var next; + var mapping; + var nameIdx; + var sourceIdx; -Compiler.prototype = { - - /** - * Throw an error message with details including the cursor position. - * @param {String} `msg` Message to use in the Error. - */ - - error: function(msg, node) { - var pos = node.position || {start: {column: 0}}; - var message = this.options.source + ' column:' + pos.start.column + ': ' + msg; - - var err = new Error(message); - err.reason = msg; - err.column = pos.start.column; - err.source = this.pattern; - - if (this.options.silent) { - this.errors.push(err); - } else { - throw err; - } - }, - - /** - * Define a non-enumberable property on the `Compiler` instance. - * - * ```js - * compiler.define('foo', 'bar'); - * ``` - * @name .define - * @param {String} `key` propery name - * @param {any} `val` property value - * @return {Object} Returns the Compiler instance for chaining. - * @api public - */ - - define: function(key, val) { - define(this, key, val); - return this; - }, - - /** - * Emit `node.val` - */ - - emit: function(str, node) { - this.output += str; - return str; - }, - - /** - * Add a compiler `fn` with the given `name` - */ - - set: function(name, fn) { - this.compilers[name] = fn; - return this; - }, - - /** - * Get compiler `name`. - */ - - get: function(name) { - return this.compilers[name]; - }, + var mappings = this._mappings.toArray(); + for (var i = 0, len = mappings.length; i < len; i++) { + mapping = mappings[i]; + next = '' - /** - * Get the previous AST node. - */ + if (mapping.generatedLine !== previousGeneratedLine) { + previousGeneratedColumn = 0; + while (mapping.generatedLine !== previousGeneratedLine) { + next += ';'; + previousGeneratedLine++; + } + } + else { + if (i > 0) { + if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) { + continue; + } + next += ','; + } + } - prev: function(n) { - return this.ast.nodes[this.idx - (n || 1)] || { type: 'bos', val: '' }; - }, + next += base64VLQ.encode(mapping.generatedColumn + - previousGeneratedColumn); + previousGeneratedColumn = mapping.generatedColumn; - /** - * Get the next AST node. - */ + if (mapping.source != null) { + sourceIdx = this._sources.indexOf(mapping.source); + next += base64VLQ.encode(sourceIdx - previousSource); + previousSource = sourceIdx; - next: function(n) { - return this.ast.nodes[this.idx + (n || 1)] || { type: 'eos', val: '' }; - }, + // lines are stored 0-based in SourceMap spec version 3 + next += base64VLQ.encode(mapping.originalLine - 1 + - previousOriginalLine); + previousOriginalLine = mapping.originalLine - 1; - /** - * Visit `node`. - */ + next += base64VLQ.encode(mapping.originalColumn + - previousOriginalColumn); + previousOriginalColumn = mapping.originalColumn; - visit: function(node, nodes, i) { - var fn = this.compilers[node.type]; - this.idx = i; + if (mapping.name != null) { + nameIdx = this._names.indexOf(mapping.name); + next += base64VLQ.encode(nameIdx - previousName); + previousName = nameIdx; + } + } - if (typeof fn !== 'function') { - throw this.error('compiler "' + node.type + '" is not registered', node); + result += next; } - return fn.call(this, node, nodes, i); - }, - /** - * Map visit over array of `nodes`. - */ + return result; + }; - mapVisit: function(nodes) { - if (!Array.isArray(nodes)) { - throw new TypeError('expected an array'); +SourceMapGenerator.prototype._generateSourcesContent = + function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { + return aSources.map(function (source) { + if (!this._sourcesContents) { + return null; + } + if (aSourceRoot != null) { + source = util.relative(aSourceRoot, source); + } + var key = util.toSetString(source); + return Object.prototype.hasOwnProperty.call(this._sourcesContents, key) + ? this._sourcesContents[key] + : null; + }, this); + }; + +/** + * Externalize the source map. + */ +SourceMapGenerator.prototype.toJSON = + function SourceMapGenerator_toJSON() { + var map = { + version: this._version, + sources: this._sources.toArray(), + names: this._names.toArray(), + mappings: this._serializeMappings() + }; + if (this._file != null) { + map.file = this._file; } - var len = nodes.length; - var idx = -1; - while (++idx < len) { - this.visit(nodes[idx], nodes, idx); + if (this._sourceRoot != null) { + map.sourceRoot = this._sourceRoot; } - return this; - }, - - /** - * Compile `ast`. - */ - - compile: function(ast, options) { - var opts = utils.extend({}, this.options, options); - this.ast = ast; - this.parsingErrors = this.ast.errors; - this.output = ''; - - // source map support - if (opts.sourcemap) { - var sourcemaps = __webpack_require__(825); - sourcemaps(this); - this.mapVisit(this.ast.nodes); - this.applySourceMaps(); - this.map = opts.sourcemap === 'generator' ? this.map : this.map.toJSON(); - return this; + if (this._sourcesContents) { + map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); } - this.mapVisit(this.ast.nodes); - return this; - } -}; + return map; + }; /** - * Expose `Compiler` + * Render the source map being generated to a string. */ +SourceMapGenerator.prototype.toString = + function SourceMapGenerator_toString() { + return JSON.stringify(this.toJSON()); + }; -module.exports = Compiler; +exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 798 */ +/* 804 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; -/*! - * use +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. + * Based on the Base 64 VLQ implementation in Closure Compiler: + * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java + * + * Copyright 2011 The Closure Compiler Authors. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +var base64 = __webpack_require__(805); +// 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, +// the next four bits are the actual value, and the 6th bit is the +// continuation bit. The continuation bit tells us whether there are more +// digits in this value following this digit. +// +// Continuation +// | Sign +// | | +// V V +// 101011 -var utils = __webpack_require__(799); - -module.exports = function base(app, opts) { - if (!utils.isObject(app) && typeof app !== 'function') { - throw new TypeError('use: expect `app` be an object or function'); - } - - if (!utils.isObject(opts)) { - opts = {}; - } - - var prop = utils.isString(opts.prop) ? opts.prop : 'fns'; - if (!Array.isArray(app[prop])) { - utils.define(app, prop, []); - } - - /** - * Define a plugin function to be passed to use. The only - * parameter exposed to the plugin is `app`, the object or function. - * passed to `use(app)`. `app` is also exposed as `this` in plugins. - * - * Additionally, **if a plugin returns a function, the function will - * be pushed onto the `fns` array**, allowing the plugin to be - * called at a later point by the `run` method. - * - * ```js - * var use = require('use'); - * - * // define a plugin - * function foo(app) { - * // do stuff - * } - * - * var app = function(){}; - * use(app); - * - * // register plugins - * app.use(foo); - * app.use(bar); - * app.use(baz); - * ``` - * @name .use - * @param {Function} `fn` plugin function to call - * @api public - */ - - utils.define(app, 'use', use); - - /** - * Run all plugins on `fns`. Any plugin that returns a function - * when called by `use` is pushed onto the `fns` array. - * - * ```js - * var config = {}; - * app.run(config); - * ``` - * @name .run - * @param {Object} `value` Object to be modified by plugins. - * @return {Object} Returns the object passed to `run` - * @api public - */ - - utils.define(app, 'run', function(val) { - if (!utils.isObject(val)) return; - decorate(val); +var VLQ_BASE_SHIFT = 5; - var self = this || app; - var fns = self[prop]; - var len = fns.length; - var idx = -1; +// binary: 100000 +var VLQ_BASE = 1 << VLQ_BASE_SHIFT; - while (++idx < len) { - val.use(fns[idx]); - } - return val; - }); +// binary: 011111 +var VLQ_BASE_MASK = VLQ_BASE - 1; - /** - * Call plugin `fn`. If a function is returned push it into the - * `fns` array to be called by the `run` method. - */ +// binary: 100000 +var VLQ_CONTINUATION_BIT = VLQ_BASE; - function use(fn, options) { - if (typeof fn !== 'function') { - throw new TypeError('.use expects `fn` be a function'); - } +/** + * Converts from a two-complement value to a value where the sign bit is + * placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + */ +function toVLQSigned(aValue) { + return aValue < 0 + ? ((-aValue) << 1) + 1 + : (aValue << 1) + 0; +} - var self = this || app; - if (typeof opts.fn === 'function') { - opts.fn.call(self, self, options); - } +/** + * Converts to a two-complement value from a value where the sign bit is + * placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + */ +function fromVLQSigned(aValue) { + var isNegative = (aValue & 1) === 1; + var shifted = aValue >> 1; + return isNegative + ? -shifted + : shifted; +} - var plugin = fn.call(self, self); - if (typeof plugin === 'function') { - var fns = self[prop]; - fns.push(plugin); - } - return self; - } +/** + * Returns the base 64 VLQ encoded value. + */ +exports.encode = function base64VLQ_encode(aValue) { + var encoded = ""; + var digit; - /** - * Ensure the `.use` method exists on `val` - */ + var vlq = toVLQSigned(aValue); - function decorate(val) { - if (!val.use || !val.run) { - base(val); + do { + digit = vlq & VLQ_BASE_MASK; + vlq >>>= VLQ_BASE_SHIFT; + if (vlq > 0) { + // There are still more digits in this value, so we must make sure the + // continuation bit is marked. + digit |= VLQ_CONTINUATION_BIT; } - } + encoded += base64.encode(digit); + } while (vlq > 0); - return app; + return encoded; }; +/** + * Decodes the next base 64 VLQ value from the given string and returns the + * value and the rest of the string via the out parameter. + */ +exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { + var strLen = aStr.length; + var result = 0; + var shift = 0; + var continuation, digit; -/***/ }), -/* 799 */ -/***/ (function(module, exports, __webpack_require__) { + do { + if (aIndex >= strLen) { + throw new Error("Expected more digits in base 64 VLQ value."); + } -"use strict"; + digit = base64.decode(aStr.charCodeAt(aIndex++)); + if (digit === -1) { + throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1)); + } + continuation = !!(digit & VLQ_CONTINUATION_BIT); + digit &= VLQ_BASE_MASK; + result = result + (digit << shift); + shift += VLQ_BASE_SHIFT; + } while (continuation); -var utils = {}; + aOutParam.value = fromVLQSigned(result); + aOutParam.rest = aIndex; +}; +/***/ }), +/* 805 */ +/***/ (function(module, exports) { -/** - * Lazily required module dependencies +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause */ -utils.define = __webpack_require__(729); -utils.isObject = __webpack_require__(747); - +var intToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); -utils.isString = function(val) { - return val && typeof val === 'string'; +/** + * Encode an integer in the range of 0 to 63 to a single base 64 digit. + */ +exports.encode = function (number) { + if (0 <= number && number < intToCharMap.length) { + return intToCharMap[number]; + } + throw new TypeError("Must be between 0 and 63: " + number); }; /** - * Expose `utils` modules + * Decode a single base 64 character code digit to an integer. Returns -1 on + * failure. */ +exports.decode = function (charCode) { + var bigA = 65; // 'A' + var bigZ = 90; // 'Z' -module.exports = utils; + var littleA = 97; // 'a' + var littleZ = 122; // 'z' + var zero = 48; // '0' + var nine = 57; // '9' -/***/ }), -/* 800 */ -/***/ (function(module, exports, __webpack_require__) { + var plus = 43; // '+' + var slash = 47; // '/' -/** - * Detect Electron renderer process, which is node, but we should - * treat as a browser. - */ + var littleOffset = 26; + var numberOffset = 52; -if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(801); -} else { - module.exports = __webpack_require__(804); -} + // 0 - 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ + if (bigA <= charCode && charCode <= bigZ) { + return (charCode - bigA); + } + // 26 - 51: abcdefghijklmnopqrstuvwxyz + if (littleA <= charCode && charCode <= littleZ) { + return (charCode - littleA + littleOffset); + } -/***/ }), -/* 801 */ -/***/ (function(module, exports, __webpack_require__) { + // 52 - 61: 0123456789 + if (zero <= charCode && charCode <= nine) { + return (charCode - zero + numberOffset); + } -/** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. - */ + // 62: + + if (charCode == plus) { + return 62; + } -exports = module.exports = __webpack_require__(802); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); + // 63: / + if (charCode == slash) { + return 63; + } -/** - * Colors. - */ + // Invalid base64 digit. + return -1; +}; -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; + +/***/ }), +/* 806 */ +/***/ (function(module, exports) { + +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ /** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. + * This is a helper function for getting values from parameter/options + * objects. * - * TODO: add a `localStorage` variable to explicitly enable/disable colors + * @param args The object we are extracting values from + * @param name The name of the property we are getting. + * @param defaultValue An optional value to return if the property is missing + * from the object. If this is not specified and the property is missing, an + * error will be thrown. */ +function getArg(aArgs, aName, aDefaultValue) { + if (aName in aArgs) { + return aArgs[aName]; + } else if (arguments.length === 3) { + return aDefaultValue; + } else { + throw new Error('"' + aName + '" is a required argument.'); + } +} +exports.getArg = getArg; -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; +var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/; +var dataUrlRegexp = /^data:.+\,.+$/; + +function urlParse(aUrl) { + var match = aUrl.match(urlRegexp); + if (!match) { + return null; } + return { + scheme: match[1], + auth: match[2], + host: match[3], + port: match[4], + path: match[5] + }; +} +exports.urlParse = urlParse; - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +function urlGenerate(aParsedUrl) { + var url = ''; + if (aParsedUrl.scheme) { + url += aParsedUrl.scheme + ':'; + } + url += '//'; + if (aParsedUrl.auth) { + url += aParsedUrl.auth + '@'; + } + if (aParsedUrl.host) { + url += aParsedUrl.host; + } + if (aParsedUrl.port) { + url += ":" + aParsedUrl.port + } + if (aParsedUrl.path) { + url += aParsedUrl.path; + } + return url; } +exports.urlGenerate = urlGenerate; /** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + * Normalizes a path, or the path portion of a URL: + * + * - Replaces consecutive slashes with one slash. + * - Removes unnecessary '.' parts. + * - Removes unnecessary '/..' parts. + * + * Based on code in the Node.js 'path' core module. + * + * @param aPath The path or url to normalize. */ +function normalize(aPath) { + var path = aPath; + var url = urlParse(aPath); + if (url) { + if (!url.path) { + return aPath; + } + path = url.path; + } + var isAbsolute = exports.isAbsolute(path); -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; + var parts = path.split(/\/+/); + for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { + part = parts[i]; + if (part === '.') { + parts.splice(i, 1); + } else if (part === '..') { + up++; + } else if (up > 0) { + if (part === '') { + // The first part is blank if the path is absolute. Trying to go + // above the root is a no-op. Therefore we can remove all '..' parts + // directly after the root. + parts.splice(i + 1, up); + up = 0; + } else { + parts.splice(i, 2); + up--; + } + } + } + path = parts.join('/'); + + if (path === '') { + path = isAbsolute ? '/' : '.'; } -}; + if (url) { + url.path = path; + return urlGenerate(url); + } + return path; +} +exports.normalize = normalize; /** - * Colorize log arguments if enabled. + * Joins two paths/URLs. * - * @api public + * @param aRoot The root path or URL. + * @param aPath The path or URL to be joined with the root. + * + * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a + * scheme-relative URL: Then the scheme of aRoot, if any, is prepended + * first. + * - Otherwise aPath is a path. If aRoot is a URL, then its path portion + * is updated with the result and aRoot is returned. Otherwise the result + * is returned. + * - If aPath is absolute, the result is aPath. + * - Otherwise the two paths are joined with a slash. + * - Joining for example 'http://' and 'www.example.com' is also supported. */ +function join(aRoot, aPath) { + if (aRoot === "") { + aRoot = "."; + } + if (aPath === "") { + aPath = "."; + } + var aPathUrl = urlParse(aPath); + var aRootUrl = urlParse(aRoot); + if (aRootUrl) { + aRoot = aRootUrl.path || '/'; + } -function formatArgs(args) { - var useColors = this.useColors; - - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); + // `join(foo, '//www.example.org')` + if (aPathUrl && !aPathUrl.scheme) { + if (aRootUrl) { + aPathUrl.scheme = aRootUrl.scheme; + } + return urlGenerate(aPathUrl); + } - if (!useColors) return; + if (aPathUrl || aPath.match(dataUrlRegexp)) { + return aPath; + } - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit') + // `join('http://', 'www.example.com')` + if (aRootUrl && !aRootUrl.host && !aRootUrl.path) { + aRootUrl.host = aPath; + return urlGenerate(aRootUrl); + } - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); + var joined = aPath.charAt(0) === '/' + ? aPath + : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); - args.splice(lastC, 0, c); + if (aRootUrl) { + aRootUrl.path = joined; + return urlGenerate(aRootUrl); + } + return joined; } +exports.join = join; -/** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public - */ - -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} +exports.isAbsolute = function (aPath) { + return aPath.charAt(0) === '/' || !!aPath.match(urlRegexp); +}; /** - * Save `namespaces`. + * Make a path relative to a URL or another path. * - * @param {String} namespaces - * @api private + * @param aRoot The root path or URL. + * @param aPath The path or URL to be made relative to aRoot. */ +function relative(aRoot, aPath) { + if (aRoot === "") { + aRoot = "."; + } -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} + aRoot = aRoot.replace(/\/$/, ''); -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ + // It is possible for the path to be above the root. In this case, simply + // checking whether the root is a prefix of the path won't work. Instead, we + // need to remove components from the root one by one, until either we find + // a prefix that fits, or we run out of components to remove. + var level = 0; + while (aPath.indexOf(aRoot + '/') !== 0) { + var index = aRoot.lastIndexOf("/"); + if (index < 0) { + return aPath; + } -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} + // If the only part of the root that is left is the scheme (i.e. http://, + // file:///, etc.), one or more slashes (/), or simply nothing at all, we + // have exhausted all components, so the path is not relative to the root. + aRoot = aRoot.slice(0, index); + if (aRoot.match(/^([^\/]+:\/)?\/*$/)) { + return aPath; + } - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; + ++level; } - return r; + // Make sure we add a "../" for each component we removed from the root. + return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1); } +exports.relative = relative; -/** - * Enable namespaces listed in `localStorage.debug` initially. - */ +var supportsNullProto = (function () { + var obj = Object.create(null); + return !('__proto__' in obj); +}()); -exports.enable(load()); +function identity (s) { + return s; +} /** - * Localstorage attempts to return the localstorage. + * Because behavior goes wacky when you set `__proto__` on objects, we + * have to prefix all the strings in our set with an arbitrary character. * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. + * See https://github.com/mozilla/source-map/pull/31 and + * https://github.com/mozilla/source-map/issues/30 * - * @return {LocalStorage} - * @api private + * @param String aStr */ +function toSetString(aStr) { + if (isProtoString(aStr)) { + return '$' + aStr; + } -function localstorage() { - try { - return window.localStorage; - } catch (e) {} + return aStr; +} +exports.toSetString = supportsNullProto ? identity : toSetString; + +function fromSetString(aStr) { + if (isProtoString(aStr)) { + return aStr.slice(1); + } + + return aStr; } +exports.fromSetString = supportsNullProto ? identity : fromSetString; + +function isProtoString(s) { + if (!s) { + return false; + } + var length = s.length; -/***/ }), -/* 802 */ -/***/ (function(module, exports, __webpack_require__) { + if (length < 9 /* "__proto__".length */) { + return false; + } + + if (s.charCodeAt(length - 1) !== 95 /* '_' */ || + s.charCodeAt(length - 2) !== 95 /* '_' */ || + s.charCodeAt(length - 3) !== 111 /* 'o' */ || + s.charCodeAt(length - 4) !== 116 /* 't' */ || + s.charCodeAt(length - 5) !== 111 /* 'o' */ || + s.charCodeAt(length - 6) !== 114 /* 'r' */ || + s.charCodeAt(length - 7) !== 112 /* 'p' */ || + s.charCodeAt(length - 8) !== 95 /* '_' */ || + s.charCodeAt(length - 9) !== 95 /* '_' */) { + return false; + } + + for (var i = length - 10; i >= 0; i--) { + if (s.charCodeAt(i) !== 36 /* '$' */) { + return false; + } + } + return true; +} /** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. + * Comparator between two mappings where the original positions are compared. * - * Expose `debug()` as the module. + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same original source/line/column, but different generated + * line and column the same. Useful when searching for a mapping with a + * stubbed out mapping. */ +function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { + var cmp = mappingA.source - mappingB.source; + if (cmp !== 0) { + return cmp; + } -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = __webpack_require__(803); + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp !== 0) { + return cmp; + } -/** - * The currently active debug mode names, and names to skip. - */ + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp !== 0 || onlyCompareOriginal) { + return cmp; + } -exports.names = []; -exports.skips = []; + cmp = mappingA.generatedColumn - mappingB.generatedColumn; + if (cmp !== 0) { + return cmp; + } + + cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp !== 0) { + return cmp; + } + + return mappingA.name - mappingB.name; +} +exports.compareByOriginalPositions = compareByOriginalPositions; /** - * Map of special "%n" handling functions, for the debug "format" argument. + * Comparator between two mappings with deflated source and name indices where + * the generated positions are compared. * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + * Optionally pass in `true` as `onlyCompareGenerated` to consider two + * mappings with the same generated line and column, but different + * source/name/original line and column the same. Useful when searching for a + * mapping with a stubbed out mapping. */ +function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) { + var cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp !== 0) { + return cmp; + } -exports.formatters = {}; + cmp = mappingA.generatedColumn - mappingB.generatedColumn; + if (cmp !== 0 || onlyCompareGenerated) { + return cmp; + } -/** - * Previous log timestamp. - */ + cmp = mappingA.source - mappingB.source; + if (cmp !== 0) { + return cmp; + } -var prevTime; + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp !== 0) { + return cmp; + } -/** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private - */ + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp !== 0) { + return cmp; + } -function selectColor(namespace) { - var hash = 0, i; + return mappingA.name - mappingB.name; +} +exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated; - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer +function strcmp(aStr1, aStr2) { + if (aStr1 === aStr2) { + return 0; } - return exports.colors[Math.abs(hash) % exports.colors.length]; + if (aStr1 > aStr2) { + return 1; + } + + return -1; } /** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace - * @return {Function} - * @api public + * Comparator between two mappings with inflated source and name strings where + * the generated positions are compared. */ +function compareByGeneratedPositionsInflated(mappingA, mappingB) { + var cmp = mappingA.generatedLine - mappingB.generatedLine; + if (cmp !== 0) { + return cmp; + } -function createDebug(namespace) { - - function debug() { - // disabled? - if (!debug.enabled) return; - - var self = debug; + cmp = mappingA.generatedColumn - mappingB.generatedColumn; + if (cmp !== 0) { + return cmp; + } - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; + cmp = strcmp(mappingA.source, mappingB.source); + if (cmp !== 0) { + return cmp; + } - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } + cmp = mappingA.originalLine - mappingB.originalLine; + if (cmp !== 0) { + return cmp; + } - args[0] = exports.coerce(args[0]); + cmp = mappingA.originalColumn - mappingB.originalColumn; + if (cmp !== 0) { + return cmp; + } - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } + return strcmp(mappingA.name, mappingB.name); +} +exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated; - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); +/***/ }), +/* 807 */ +/***/ (function(module, exports, __webpack_require__) { - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } +var util = __webpack_require__(806); +var has = Object.prototype.hasOwnProperty; +var hasNativeMap = typeof Map !== "undefined"; - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); +/** + * A data structure which is a combination of an array and a set. Adding a new + * member is O(1), testing for membership is O(1), and finding the index of an + * element is O(1). Removing elements from the set is not supported. Only + * strings are supported for membership. + */ +function ArraySet() { + this._array = []; + this._set = hasNativeMap ? new Map() : Object.create(null); +} - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); +/** + * Static method for creating ArraySet instances from an existing array. + */ +ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { + var set = new ArraySet(); + for (var i = 0, len = aArray.length; i < len; i++) { + set.add(aArray[i], aAllowDuplicates); } - - return debug; -} + return set; +}; /** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. + * Return how many unique items are in this ArraySet. If duplicates have been + * added, than those do not count towards the size. * - * @param {String} namespaces - * @api public + * @returns Number */ +ArraySet.prototype.size = function ArraySet_size() { + return hasNativeMap ? this._set.size : Object.getOwnPropertyNames(this._set).length; +}; -function enable(namespaces) { - exports.save(namespaces); - - exports.names = []; - exports.skips = []; - - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; - - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); +/** + * Add the given string to this set. + * + * @param String aStr + */ +ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { + var sStr = hasNativeMap ? aStr : util.toSetString(aStr); + var isDuplicate = hasNativeMap ? this.has(aStr) : has.call(this._set, sStr); + var idx = this._array.length; + if (!isDuplicate || aAllowDuplicates) { + this._array.push(aStr); + } + if (!isDuplicate) { + if (hasNativeMap) { + this._set.set(aStr, idx); } else { - exports.names.push(new RegExp('^' + namespaces + '$')); + this._set[sStr] = idx; } } -} +}; /** - * Disable debug output. + * Is the given string a member of this set? * - * @api public + * @param String aStr */ - -function disable() { - exports.enable(''); -} +ArraySet.prototype.has = function ArraySet_has(aStr) { + if (hasNativeMap) { + return this._set.has(aStr); + } else { + var sStr = util.toSetString(aStr); + return has.call(this._set, sStr); + } +}; /** - * Returns true if the given mode name is enabled, false otherwise. + * What is the index of the given string in the array? * - * @param {String} name - * @return {Boolean} - * @api public + * @param String aStr */ - -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; +ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { + if (hasNativeMap) { + var idx = this._set.get(aStr); + if (idx >= 0) { + return idx; } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { - return true; + } else { + var sStr = util.toSetString(aStr); + if (has.call(this._set, sStr)) { + return this._set[sStr]; } } - return false; -} + + throw new Error('"' + aStr + '" is not in the set.'); +}; /** - * Coerce `val`. + * What is the element at the given index? * - * @param {Mixed} val - * @return {Mixed} - * @api private + * @param Number aIdx + */ +ArraySet.prototype.at = function ArraySet_at(aIdx) { + if (aIdx >= 0 && aIdx < this._array.length) { + return this._array[aIdx]; + } + throw new Error('No element indexed by ' + aIdx); +}; + +/** + * Returns the array representation of this set (which has the proper indices + * indicated by indexOf). Note that this is a copy of the internal array used + * for storing the members so that no one can mess with internal state. */ +ArraySet.prototype.toArray = function ArraySet_toArray() { + return this._array.slice(); +}; -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; -} +exports.ArraySet = ArraySet; /***/ }), -/* 803 */ -/***/ (function(module, exports) { +/* 808 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Helpers. +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2014 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause */ -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; +var util = __webpack_require__(806); /** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public + * Determine whether mappingB is after mappingA with respect to generated + * position. */ +function generatedPositionAfter(mappingA, mappingB) { + // Optimized for most common case + var lineA = mappingA.generatedLine; + var lineB = mappingB.generatedLine; + var columnA = mappingA.generatedColumn; + var columnB = mappingB.generatedColumn; + return lineB > lineA || lineB == lineA && columnB >= columnA || + util.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0; +} -module.exports = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); -}; +/** + * A data structure to provide a sorted view of accumulated mappings in a + * performance conscious manner. It trades a neglibable overhead in general + * case for a large speedup in case of mappings being added in order. + */ +function MappingList() { + this._array = []; + this._sorted = true; + // Serves as infimum + this._last = {generatedLine: -1, generatedColumn: 0}; +} /** - * Parse the given `str` and return milliseconds. + * Iterate through internal items. This method takes the same arguments that + * `Array.prototype.forEach` takes. * - * @param {String} str - * @return {Number} - * @api private + * NOTE: The order of the mappings is NOT guaranteed. */ +MappingList.prototype.unsortedForEach = + function MappingList_forEach(aCallback, aThisArg) { + this._array.forEach(aCallback, aThisArg); + }; -function parse(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; +/** + * Add the given source mapping. + * + * @param Object aMapping + */ +MappingList.prototype.add = function MappingList_add(aMapping) { + if (generatedPositionAfter(this._last, aMapping)) { + this._last = aMapping; + this._array.push(aMapping); + } else { + this._sorted = false; + this._array.push(aMapping); } -} +}; /** - * Short format for `ms`. + * Returns the flat, sorted array of mappings. The mappings are sorted by + * generated position. * - * @param {Number} ms - * @return {String} - * @api private + * WARNING: This method returns internal data without copying, for + * performance. The return value must NOT be mutated, and should be treated as + * an immutable borrow. If you want to take ownership, you must make your own + * copy. */ - -function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; +MappingList.prototype.toArray = function MappingList_toArray() { + if (!this._sorted) { + this._array.sort(util.compareByGeneratedPositionsInflated); + this._sorted = true; } - return ms + 'ms'; -} + return this._array; +}; + +exports.MappingList = MappingList; + + +/***/ }), +/* 809 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause */ -function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; +var util = __webpack_require__(806); +var binarySearch = __webpack_require__(810); +var ArraySet = __webpack_require__(807).ArraySet; +var base64VLQ = __webpack_require__(804); +var quickSort = __webpack_require__(811).quickSort; + +function SourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } + + return sourceMap.sections != null + ? new IndexedSourceMapConsumer(sourceMap) + : new BasicSourceMapConsumer(sourceMap); +} + +SourceMapConsumer.fromSourceMap = function(aSourceMap) { + return BasicSourceMapConsumer.fromSourceMap(aSourceMap); } /** - * Pluralization helper. + * The version of the source mapping spec that we are consuming. */ +SourceMapConsumer.prototype._version = 3; -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; +// `__generatedMappings` and `__originalMappings` are arrays that hold the +// parsed mapping coordinates from the source map's "mappings" attribute. They +// are lazily instantiated, accessed via the `_generatedMappings` and +// `_originalMappings` getters respectively, and we only parse the mappings +// and create these arrays once queried for a source location. We jump through +// these hoops because there can be many thousands of mappings, and parsing +// them is expensive, so we only want to do it if we must. +// +// Each object in the arrays is of the form: +// +// { +// generatedLine: The line number in the generated code, +// generatedColumn: The column number in the generated code, +// source: The path to the original source file that generated this +// chunk of code, +// originalLine: The line number in the original source that +// corresponds to this chunk of generated code, +// originalColumn: The column number in the original source that +// corresponds to this chunk of generated code, +// name: The name of the original symbol which generated this chunk of +// code. +// } +// +// All properties except for `generatedLine` and `generatedColumn` can be +// `null`. +// +// `_generatedMappings` is ordered by the generated positions. +// +// `_originalMappings` is ordered by the original positions. + +SourceMapConsumer.prototype.__generatedMappings = null; +Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', { + get: function () { + if (!this.__generatedMappings) { + this._parseMappings(this._mappings, this.sourceRoot); + } + + return this.__generatedMappings; } - return Math.ceil(ms / n) + ' ' + name + 's'; -} +}); + +SourceMapConsumer.prototype.__originalMappings = null; +Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', { + get: function () { + if (!this.__originalMappings) { + this._parseMappings(this._mappings, this.sourceRoot); + } + return this.__originalMappings; + } +}); -/***/ }), -/* 804 */ -/***/ (function(module, exports, __webpack_require__) { +SourceMapConsumer.prototype._charIsMappingSeparator = + function SourceMapConsumer_charIsMappingSeparator(aStr, index) { + var c = aStr.charAt(index); + return c === ";" || c === ","; + }; /** - * Module dependencies. + * Parse the mappings in a string in to a data structure which we can easily + * query (the ordered arrays in the `this.__generatedMappings` and + * `this.__originalMappings` properties). */ +SourceMapConsumer.prototype._parseMappings = + function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + throw new Error("Subclasses must implement _parseMappings"); + }; -var tty = __webpack_require__(480); -var util = __webpack_require__(29); +SourceMapConsumer.GENERATED_ORDER = 1; +SourceMapConsumer.ORIGINAL_ORDER = 2; + +SourceMapConsumer.GREATEST_LOWER_BOUND = 1; +SourceMapConsumer.LEAST_UPPER_BOUND = 2; /** - * This is the Node.js implementation of `debug()`. + * Iterate over each mapping between an original source/line/column and a + * generated line/column in this source map. * - * Expose `debug()` as the module. + * @param Function aCallback + * The function that is called with each mapping. + * @param Object aContext + * Optional. If specified, this object will be the value of `this` every + * time that `aCallback` is called. + * @param aOrder + * Either `SourceMapConsumer.GENERATED_ORDER` or + * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to + * iterate over the mappings sorted by the generated file's line/column + * order or the original's source/line/column order, respectively. Defaults to + * `SourceMapConsumer.GENERATED_ORDER`. */ +SourceMapConsumer.prototype.eachMapping = + function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { + var context = aContext || null; + var order = aOrder || SourceMapConsumer.GENERATED_ORDER; -exports = module.exports = __webpack_require__(802); -exports.init = init; -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; - -/** - * Colors. - */ + var mappings; + switch (order) { + case SourceMapConsumer.GENERATED_ORDER: + mappings = this._generatedMappings; + break; + case SourceMapConsumer.ORIGINAL_ORDER: + mappings = this._originalMappings; + break; + default: + throw new Error("Unknown order of iteration."); + } -exports.colors = [6, 2, 3, 4, 5, 1]; + var sourceRoot = this.sourceRoot; + mappings.map(function (mapping) { + var source = mapping.source === null ? null : this._sources.at(mapping.source); + if (source != null && sourceRoot != null) { + source = util.join(sourceRoot, source); + } + return { + source: source, + generatedLine: mapping.generatedLine, + generatedColumn: mapping.generatedColumn, + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: mapping.name === null ? null : this._names.at(mapping.name) + }; + }, this).forEach(aCallback, context); + }; /** - * Build up the default `inspectOpts` object from the environment variables. + * Returns all generated line and column information for the original source, + * line, and column provided. If no column is provided, returns all mappings + * corresponding to a either the line we are searching for or the next + * closest line that has any mappings. Otherwise, returns all mappings + * corresponding to the given line and either the column we are searching for + * or the next closest column that has any offsets. * - * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js + * The only argument is an object with the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: Optional. the column number in the original source. + * + * and an array of objects is returned, each with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. */ +SourceMapConsumer.prototype.allGeneratedPositionsFor = + function SourceMapConsumer_allGeneratedPositionsFor(aArgs) { + var line = util.getArg(aArgs, 'line'); -exports.inspectOpts = Object.keys(process.env).filter(function (key) { - return /^debug_/i.test(key); -}).reduce(function (obj, key) { - // camel-case - var prop = key - .substring(6) - .toLowerCase() - .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); + // When there is no exact match, BasicSourceMapConsumer.prototype._findMapping + // returns the index of the closest mapping less than the needle. By + // setting needle.originalColumn to 0, we thus find the last mapping for + // the given line, provided such a mapping exists. + var needle = { + source: util.getArg(aArgs, 'source'), + originalLine: line, + originalColumn: util.getArg(aArgs, 'column', 0) + }; - // coerce string value into JS value - var val = process.env[key]; - if (/^(yes|on|true|enabled)$/i.test(val)) val = true; - else if (/^(no|off|false|disabled)$/i.test(val)) val = false; - else if (val === 'null') val = null; - else val = Number(val); + if (this.sourceRoot != null) { + needle.source = util.relative(this.sourceRoot, needle.source); + } + if (!this._sources.has(needle.source)) { + return []; + } + needle.source = this._sources.indexOf(needle.source); - obj[prop] = val; - return obj; -}, {}); + var mappings = []; + + var index = this._findMapping(needle, + this._originalMappings, + "originalLine", + "originalColumn", + util.compareByOriginalPositions, + binarySearch.LEAST_UPPER_BOUND); + if (index >= 0) { + var mapping = this._originalMappings[index]; + + if (aArgs.column === undefined) { + var originalLine = mapping.originalLine; + + // Iterate until either we run out of mappings, or we run into + // a mapping for a different line than the one we found. Since + // mappings are sorted, this is guaranteed to find all mappings for + // the line we found. + while (mapping && mapping.originalLine === originalLine) { + mappings.push({ + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null), + lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) + }); + + mapping = this._originalMappings[++index]; + } + } else { + var originalColumn = mapping.originalColumn; + + // Iterate until either we run out of mappings, or we run into + // a mapping for a different line than the one we were searching for. + // Since mappings are sorted, this is guaranteed to find all mappings for + // the line we are searching for. + while (mapping && + mapping.originalLine === line && + mapping.originalColumn == originalColumn) { + mappings.push({ + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null), + lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) + }); + + mapping = this._originalMappings[++index]; + } + } + } + + return mappings; + }; + +exports.SourceMapConsumer = SourceMapConsumer; /** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: + * A BasicSourceMapConsumer instance represents a parsed source map which we can + * query for information about the original file positions by giving it a file + * position in the generated source. * - * $ DEBUG_FD=3 node script.js 3>debug.log + * The only parameter is the raw source map (either as a JSON string, or + * already parsed to an object). According to the spec, source maps have the + * following attributes: + * + * - version: Which version of the source map spec this map is following. + * - sources: An array of URLs to the original source files. + * - names: An array of identifiers which can be referrenced by individual mappings. + * - sourceRoot: Optional. The URL root from which all sources are relative. + * - sourcesContent: Optional. An array of contents of the original source files. + * - mappings: A string of base64 VLQs which contain the actual mappings. + * - file: Optional. The generated file this source map is associated with. + * + * Here is an example source map, taken from the source map spec[0]: + * + * { + * version : 3, + * file: "out.js", + * sourceRoot : "", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AA,AB;;ABCDE;" + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# */ +function BasicSourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); + } -var fd = parseInt(process.env.DEBUG_FD, 10) || 2; + var version = util.getArg(sourceMap, 'version'); + var sources = util.getArg(sourceMap, 'sources'); + // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which + // requires the array) to play nice here. + var names = util.getArg(sourceMap, 'names', []); + var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); + var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); + var mappings = util.getArg(sourceMap, 'mappings'); + var file = util.getArg(sourceMap, 'file', null); -if (1 !== fd && 2 !== fd) { - util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')() -} + // Once again, Sass deviates from the spec and supplies the version as a + // string rather than a number, so we use loose equality checking here. + if (version != this._version) { + throw new Error('Unsupported version: ' + version); + } -var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); + sources = sources + .map(String) + // Some source maps produce relative source paths like "./foo.js" instead of + // "foo.js". Normalize these first so that future comparisons will succeed. + // See bugzil.la/1090768. + .map(util.normalize) + // Always ensure that absolute sources are internally stored relative to + // the source root, if the source root is absolute. Not doing this would + // be particularly problematic when the source root is a prefix of the + // source (valid, but why??). See github issue #199 and bugzil.la/1188982. + .map(function (source) { + return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source) + ? util.relative(sourceRoot, source) + : source; + }); -/** - * Is stdout a TTY? Colored output is enabled when `true`. - */ + // Pass `true` below to allow duplicate names and sources. While source maps + // are intended to be compressed and deduplicated, the TypeScript compiler + // sometimes generates source maps with duplicates in them. See Github issue + // #72 and bugzil.la/889492. + this._names = ArraySet.fromArray(names.map(String), true); + this._sources = ArraySet.fromArray(sources, true); -function useColors() { - return 'colors' in exports.inspectOpts - ? Boolean(exports.inspectOpts.colors) - : tty.isatty(fd); + this.sourceRoot = sourceRoot; + this.sourcesContent = sourcesContent; + this._mappings = mappings; + this.file = file; } +BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); +BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer; + /** - * Map %o to `util.inspect()`, all on a single line. + * Create a BasicSourceMapConsumer from a SourceMapGenerator. + * + * @param SourceMapGenerator aSourceMap + * The source map that will be consumed. + * @returns BasicSourceMapConsumer */ +BasicSourceMapConsumer.fromSourceMap = + function SourceMapConsumer_fromSourceMap(aSourceMap) { + var smc = Object.create(BasicSourceMapConsumer.prototype); -exports.formatters.o = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts) - .split('\n').map(function(str) { - return str.trim() - }).join(' '); -}; + var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); + var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); + smc.sourceRoot = aSourceMap._sourceRoot; + smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), + smc.sourceRoot); + smc.file = aSourceMap._file; -/** - * Map %o to `util.inspect()`, allowing multiple lines if needed. - */ + // Because we are modifying the entries (by converting string sources and + // names to indices into the sources and names ArraySets), we have to make + // a copy of the entry or else bad things happen. Shared mutable state + // strikes again! See github issue #191. -exports.formatters.O = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts); -}; + var generatedMappings = aSourceMap._mappings.toArray().slice(); + var destGeneratedMappings = smc.__generatedMappings = []; + var destOriginalMappings = smc.__originalMappings = []; -/** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ + for (var i = 0, length = generatedMappings.length; i < length; i++) { + var srcMapping = generatedMappings[i]; + var destMapping = new Mapping; + destMapping.generatedLine = srcMapping.generatedLine; + destMapping.generatedColumn = srcMapping.generatedColumn; -function formatArgs(args) { - var name = this.namespace; - var useColors = this.useColors; + if (srcMapping.source) { + destMapping.source = sources.indexOf(srcMapping.source); + destMapping.originalLine = srcMapping.originalLine; + destMapping.originalColumn = srcMapping.originalColumn; - if (useColors) { - var c = this.color; - var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; + if (srcMapping.name) { + destMapping.name = names.indexOf(srcMapping.name); + } - args[0] = prefix + args[0].split('\n').join('\n' + prefix); - args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } -} + destOriginalMappings.push(destMapping); + } + + destGeneratedMappings.push(destMapping); + } + + quickSort(smc.__originalMappings, util.compareByOriginalPositions); + + return smc; + }; /** - * Invokes `util.format()` with the specified arguments and writes to `stream`. + * The version of the source mapping spec that we are consuming. + */ +BasicSourceMapConsumer.prototype._version = 3; + +/** + * The list of original sources. */ +Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', { + get: function () { + return this._sources.toArray().map(function (s) { + return this.sourceRoot != null ? util.join(this.sourceRoot, s) : s; + }, this); + } +}); -function log() { - return stream.write(util.format.apply(util, arguments) + '\n'); +/** + * Provide the JIT with a nice shape / hidden class. + */ +function Mapping() { + this.generatedLine = 0; + this.generatedColumn = 0; + this.source = null; + this.originalLine = null; + this.originalColumn = null; + this.name = null; } /** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private + * Parse the mappings in a string in to a data structure which we can easily + * query (the ordered arrays in the `this.__generatedMappings` and + * `this.__originalMappings` properties). */ +BasicSourceMapConsumer.prototype._parseMappings = + function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { + var generatedLine = 1; + var previousGeneratedColumn = 0; + var previousOriginalLine = 0; + var previousOriginalColumn = 0; + var previousSource = 0; + var previousName = 0; + var length = aStr.length; + var index = 0; + var cachedSegments = {}; + var temp = {}; + var originalMappings = []; + var generatedMappings = []; + var mapping, str, segment, end, value; -function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; - } -} + while (index < length) { + if (aStr.charAt(index) === ';') { + generatedLine++; + index++; + previousGeneratedColumn = 0; + } + else if (aStr.charAt(index) === ',') { + index++; + } + else { + mapping = new Mapping(); + mapping.generatedLine = generatedLine; -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ + // Because each offset is encoded relative to the previous one, + // many segments often have the same encoding. We can exploit this + // fact by caching the parsed variable length fields of each segment, + // allowing us to avoid a second parse if we encounter the same + // segment again. + for (end = index; end < length; end++) { + if (this._charIsMappingSeparator(aStr, end)) { + break; + } + } + str = aStr.slice(index, end); -function load() { - return process.env.DEBUG; -} + segment = cachedSegments[str]; + if (segment) { + index += str.length; + } else { + segment = []; + while (index < end) { + base64VLQ.decode(aStr, index, temp); + value = temp.value; + index = temp.rest; + segment.push(value); + } -/** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ + if (segment.length === 2) { + throw new Error('Found a source, but no line and column'); + } -function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); + if (segment.length === 3) { + throw new Error('Found a source and line, but no column'); + } - // Note stream._type is used for test-module-load-list.js + cachedSegments[str] = segment; + } - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; + // Generated column. + mapping.generatedColumn = previousGeneratedColumn + segment[0]; + previousGeneratedColumn = mapping.generatedColumn; - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); - } - break; + if (segment.length > 1) { + // Original source. + mapping.source = previousSource + segment[1]; + previousSource += segment[1]; - case 'FILE': - var fs = __webpack_require__(23); - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; + // Original line. + mapping.originalLine = previousOriginalLine + segment[2]; + previousOriginalLine = mapping.originalLine; + // Lines are stored 0-based + mapping.originalLine += 1; - case 'PIPE': - case 'TCP': - var net = __webpack_require__(805); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); + // Original column. + mapping.originalColumn = previousOriginalColumn + segment[3]; + previousOriginalColumn = mapping.originalColumn; - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; + if (segment.length > 4) { + // Original name. + mapping.name = previousName + segment[4]; + previousName += segment[4]; + } + } - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); + generatedMappings.push(mapping); + if (typeof mapping.originalLine === 'number') { + originalMappings.push(mapping); + } } - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); - } - - // For supporting legacy API we put the FD here. - stream.fd = fd; + } - stream._isStdio = true; + quickSort(generatedMappings, util.compareByGeneratedPositionsDeflated); + this.__generatedMappings = generatedMappings; - return stream; -} + quickSort(originalMappings, util.compareByOriginalPositions); + this.__originalMappings = originalMappings; + }; /** - * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. + * Find the mapping that best matches the hypothetical "needle" mapping that + * we are searching for in the given "haystack" of mappings. */ +BasicSourceMapConsumer.prototype._findMapping = + function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, + aColumnName, aComparator, aBias) { + // To return the position we are searching for, we must first find the + // mapping for the given position and then return the opposite position it + // points to. Because the mappings are sorted, we can use binary search to + // find the best mapping. -function init (debug) { - debug.inspectOpts = {}; + if (aNeedle[aLineName] <= 0) { + throw new TypeError('Line must be greater than or equal to 1, got ' + + aNeedle[aLineName]); + } + if (aNeedle[aColumnName] < 0) { + throw new TypeError('Column must be greater than or equal to 0, got ' + + aNeedle[aColumnName]); + } - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; - } -} + return binarySearch.search(aNeedle, aMappings, aComparator, aBias); + }; /** - * Enable namespaces listed in `process.env.DEBUG` initially. + * Compute the last column for each generated mapping. The last column is + * inclusive. */ +BasicSourceMapConsumer.prototype.computeColumnSpans = + function SourceMapConsumer_computeColumnSpans() { + for (var index = 0; index < this._generatedMappings.length; ++index) { + var mapping = this._generatedMappings[index]; -exports.enable(load()); + // Mappings do not contain a field for the last generated columnt. We + // can come up with an optimistic estimate, however, by assuming that + // mappings are contiguous (i.e. given two consecutive mappings, the + // first mapping ends where the second one starts). + if (index + 1 < this._generatedMappings.length) { + var nextMapping = this._generatedMappings[index + 1]; + if (mapping.generatedLine === nextMapping.generatedLine) { + mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1; + continue; + } + } -/***/ }), -/* 805 */ -/***/ (function(module, exports) { + // The last mapping for each line spans the entire line. + mapping.lastGeneratedColumn = Infinity; + } + }; -module.exports = require("net"); +/** + * Returns the original source, line, and column information for the generated + * source's line and column positions provided. The only argument is an object + * with the following properties: + * + * - line: The line number in the generated source. + * - column: The column number in the generated source. + * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or + * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the + * closest element that is smaller than or greater than the one we are + * searching for, respectively, if the exact element cannot be found. + * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. + * + * and an object is returned with the following properties: + * + * - source: The original source file, or null. + * - line: The line number in the original source, or null. + * - column: The column number in the original source, or null. + * - name: The original identifier, or null. + */ +BasicSourceMapConsumer.prototype.originalPositionFor = + function SourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; -/***/ }), -/* 806 */ -/***/ (function(module, exports, __webpack_require__) { + var index = this._findMapping( + needle, + this._generatedMappings, + "generatedLine", + "generatedColumn", + util.compareByGeneratedPositionsDeflated, + util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) + ); -"use strict"; + if (index >= 0) { + var mapping = this._generatedMappings[index]; + if (mapping.generatedLine === needle.generatedLine) { + var source = util.getArg(mapping, 'source', null); + if (source !== null) { + source = this._sources.at(source); + if (this.sourceRoot != null) { + source = util.join(this.sourceRoot, source); + } + } + var name = util.getArg(mapping, 'name', null); + if (name !== null) { + name = this._names.at(name); + } + return { + source: source, + line: util.getArg(mapping, 'originalLine', null), + column: util.getArg(mapping, 'originalColumn', null), + name: name + }; + } + } + + return { + source: null, + line: null, + column: null, + name: null + }; + }; /** - * Module dependencies + * Return true if we have the source content for every source in the source + * map, false otherwise. */ - -exports.extend = __webpack_require__(737); -exports.SourceMap = __webpack_require__(807); -exports.sourceMapResolve = __webpack_require__(818); +BasicSourceMapConsumer.prototype.hasContentsOfAllSources = + function BasicSourceMapConsumer_hasContentsOfAllSources() { + if (!this.sourcesContent) { + return false; + } + return this.sourcesContent.length >= this._sources.size() && + !this.sourcesContent.some(function (sc) { return sc == null; }); + }; /** - * Convert backslash in the given string to forward slashes + * Returns the original source content. The only argument is the url of the + * original source file. Returns null if no original source content is + * available. */ +BasicSourceMapConsumer.prototype.sourceContentFor = + function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { + if (!this.sourcesContent) { + return null; + } -exports.unixify = function(fp) { - return fp.split(/\\+/).join('/'); -}; + if (this.sourceRoot != null) { + aSource = util.relative(this.sourceRoot, aSource); + } -/** - * Return true if `val` is a non-empty string - * - * @param {String} `str` - * @return {Boolean} - */ + if (this._sources.has(aSource)) { + return this.sourcesContent[this._sources.indexOf(aSource)]; + } -exports.isString = function(str) { - return str && typeof str === 'string'; -}; + var url; + if (this.sourceRoot != null + && (url = util.urlParse(this.sourceRoot))) { + // XXX: file:// URIs and absolute paths lead to unexpected behavior for + // many users. We can help them out when they expect file:// URIs to + // behave like it would if they were running a local HTTP server. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. + var fileUriAbsPath = aSource.replace(/^file:\/\//, ""); + if (url.scheme == "file" + && this._sources.has(fileUriAbsPath)) { + return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] + } -/** - * Cast `val` to an array - * @return {Array} - */ + if ((!url.path || url.path == "/") + && this._sources.has("/" + aSource)) { + return this.sourcesContent[this._sources.indexOf("/" + aSource)]; + } + } -exports.arrayify = function(val) { - if (typeof val === 'string') return [val]; - return val ? (Array.isArray(val) ? val : [val]) : []; -}; + // This function is used recursively from + // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we + // don't want to throw if we can't find the source - we just want to + // return null, so we provide a flag to exit gracefully. + if (nullOnMissing) { + return null; + } + else { + throw new Error('"' + aSource + '" is not in the SourceMap.'); + } + }; /** - * Get the last `n` element from the given `array` - * @param {Array} `array` - * @return {*} + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or + * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the + * closest element that is smaller than or greater than the one we are + * searching for, respectively, if the exact element cannot be found. + * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. */ +BasicSourceMapConsumer.prototype.generatedPositionFor = + function SourceMapConsumer_generatedPositionFor(aArgs) { + var source = util.getArg(aArgs, 'source'); + if (this.sourceRoot != null) { + source = util.relative(this.sourceRoot, source); + } + if (!this._sources.has(source)) { + return { + line: null, + column: null, + lastColumn: null + }; + } + source = this._sources.indexOf(source); -exports.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; - - -/***/ }), -/* 807 */ -/***/ (function(module, exports, __webpack_require__) { + var needle = { + source: source, + originalLine: util.getArg(aArgs, 'line'), + originalColumn: util.getArg(aArgs, 'column') + }; -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ -exports.SourceMapGenerator = __webpack_require__(808).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(814).SourceMapConsumer; -exports.SourceNode = __webpack_require__(817).SourceNode; + var index = this._findMapping( + needle, + this._originalMappings, + "originalLine", + "originalColumn", + util.compareByOriginalPositions, + util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) + ); + if (index >= 0) { + var mapping = this._originalMappings[index]; -/***/ }), -/* 808 */ -/***/ (function(module, exports, __webpack_require__) { + if (mapping.source === needle.source) { + return { + line: util.getArg(mapping, 'generatedLine', null), + column: util.getArg(mapping, 'generatedColumn', null), + lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) + }; + } + } -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ + return { + line: null, + column: null, + lastColumn: null + }; + }; -var base64VLQ = __webpack_require__(809); -var util = __webpack_require__(811); -var ArraySet = __webpack_require__(812).ArraySet; -var MappingList = __webpack_require__(813).MappingList; +exports.BasicSourceMapConsumer = BasicSourceMapConsumer; /** - * An instance of the SourceMapGenerator represents a source map which is - * being built incrementally. You may pass an object with the following - * properties: + * An IndexedSourceMapConsumer instance represents a parsed source map which + * we can query for information. It differs from BasicSourceMapConsumer in + * that it takes "indexed" source maps (i.e. ones with a "sections" field) as + * input. * - * - file: The filename of the generated source. - * - sourceRoot: A root for all relative URLs in this source map. + * The only parameter is a raw source map (either as a JSON string, or already + * parsed to an object). According to the spec for indexed source maps, they + * have the following attributes: + * + * - version: Which version of the source map spec this map is following. + * - file: Optional. The generated file this source map is associated with. + * - sections: A list of section definitions. + * + * Each value under the "sections" field has two fields: + * - offset: The offset into the original specified at which this section + * begins to apply, defined as an object with a "line" and "column" + * field. + * - map: A source map definition. This source map could also be indexed, + * but doesn't have to be. + * + * Instead of the "map" field, it's also possible to have a "url" field + * specifying a URL to retrieve a source map from, but that's currently + * unsupported. + * + * Here's an example source map, taken from the source map spec[0], but + * modified to omit a section which uses the "url" field. + * + * { + * version : 3, + * file: "app.js", + * sections: [{ + * offset: {line:100, column:10}, + * map: { + * version : 3, + * file: "section.js", + * sources: ["foo.js", "bar.js"], + * names: ["src", "maps", "are", "fun"], + * mappings: "AAAA,E;;ABCDE;" + * } + * }], + * } + * + * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt */ -function SourceMapGenerator(aArgs) { - if (!aArgs) { - aArgs = {}; +function IndexedSourceMapConsumer(aSourceMap) { + var sourceMap = aSourceMap; + if (typeof aSourceMap === 'string') { + sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); } - this._file = util.getArg(aArgs, 'file', null); - this._sourceRoot = util.getArg(aArgs, 'sourceRoot', null); - this._skipValidation = util.getArg(aArgs, 'skipValidation', false); + + var version = util.getArg(sourceMap, 'version'); + var sections = util.getArg(sourceMap, 'sections'); + + if (version != this._version) { + throw new Error('Unsupported version: ' + version); + } + this._sources = new ArraySet(); this._names = new ArraySet(); - this._mappings = new MappingList(); - this._sourcesContents = null; + + var lastOffset = { + line: -1, + column: 0 + }; + this._sections = sections.map(function (s) { + if (s.url) { + // The url field will require support for asynchronicity. + // See https://github.com/mozilla/source-map/issues/16 + throw new Error('Support for url field in sections not implemented.'); + } + var offset = util.getArg(s, 'offset'); + var offsetLine = util.getArg(offset, 'line'); + var offsetColumn = util.getArg(offset, 'column'); + + if (offsetLine < lastOffset.line || + (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) { + throw new Error('Section offsets must be ordered and non-overlapping.'); + } + lastOffset = offset; + + return { + generatedOffset: { + // The offset fields are 0-based, but we use 1-based indices when + // encoding/decoding from VLQ. + generatedLine: offsetLine + 1, + generatedColumn: offsetColumn + 1 + }, + consumer: new SourceMapConsumer(util.getArg(s, 'map')) + } + }); } -SourceMapGenerator.prototype._version = 3; +IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); +IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer; + +/** + * The version of the source mapping spec that we are consuming. + */ +IndexedSourceMapConsumer.prototype._version = 3; /** - * Creates a new SourceMapGenerator based on a SourceMapConsumer + * The list of original sources. + */ +Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', { + get: function () { + var sources = []; + for (var i = 0; i < this._sections.length; i++) { + for (var j = 0; j < this._sections[i].consumer.sources.length; j++) { + sources.push(this._sections[i].consumer.sources[j]); + } + } + return sources; + } +}); + +/** + * Returns the original source, line, and column information for the generated + * source's line and column positions provided. The only argument is an object + * with the following properties: * - * @param aSourceMapConsumer The SourceMap. + * - line: The line number in the generated source. + * - column: The column number in the generated source. + * + * and an object is returned with the following properties: + * + * - source: The original source file, or null. + * - line: The line number in the original source, or null. + * - column: The column number in the original source, or null. + * - name: The original identifier, or null. */ -SourceMapGenerator.fromSourceMap = - function SourceMapGenerator_fromSourceMap(aSourceMapConsumer) { - var sourceRoot = aSourceMapConsumer.sourceRoot; - var generator = new SourceMapGenerator({ - file: aSourceMapConsumer.file, - sourceRoot: sourceRoot - }); - aSourceMapConsumer.eachMapping(function (mapping) { - var newMapping = { - generated: { - line: mapping.generatedLine, - column: mapping.generatedColumn - } - }; +IndexedSourceMapConsumer.prototype.originalPositionFor = + function IndexedSourceMapConsumer_originalPositionFor(aArgs) { + var needle = { + generatedLine: util.getArg(aArgs, 'line'), + generatedColumn: util.getArg(aArgs, 'column') + }; - if (mapping.source != null) { - newMapping.source = mapping.source; - if (sourceRoot != null) { - newMapping.source = util.relative(sourceRoot, newMapping.source); + // Find the section containing the generated position we're trying to map + // to an original position. + var sectionIndex = binarySearch.search(needle, this._sections, + function(needle, section) { + var cmp = needle.generatedLine - section.generatedOffset.generatedLine; + if (cmp) { + return cmp; } - newMapping.original = { - line: mapping.originalLine, - column: mapping.originalColumn - }; + return (needle.generatedColumn - + section.generatedOffset.generatedColumn); + }); + var section = this._sections[sectionIndex]; - if (mapping.name != null) { - newMapping.name = mapping.name; - } - } + if (!section) { + return { + source: null, + line: null, + column: null, + name: null + }; + } - generator.addMapping(newMapping); - }); - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content != null) { - generator.setSourceContent(sourceFile, content); - } + return section.consumer.originalPositionFor({ + line: needle.generatedLine - + (section.generatedOffset.generatedLine - 1), + column: needle.generatedColumn - + (section.generatedOffset.generatedLine === needle.generatedLine + ? section.generatedOffset.generatedColumn - 1 + : 0), + bias: aArgs.bias }); - return generator; }; /** - * Add a single mapping from original source line and column to the generated - * source's line and column for this source map being created. The mapping - * object should have the following properties: - * - * - generated: An object with the generated line and column positions. - * - original: An object with the original line and column positions. - * - source: The original source file (relative to the sourceRoot). - * - name: An optional original token name for this mapping. + * Return true if we have the source content for every source in the source + * map, false otherwise. */ -SourceMapGenerator.prototype.addMapping = - function SourceMapGenerator_addMapping(aArgs) { - var generated = util.getArg(aArgs, 'generated'); - var original = util.getArg(aArgs, 'original', null); - var source = util.getArg(aArgs, 'source', null); - var name = util.getArg(aArgs, 'name', null); +IndexedSourceMapConsumer.prototype.hasContentsOfAllSources = + function IndexedSourceMapConsumer_hasContentsOfAllSources() { + return this._sections.every(function (s) { + return s.consumer.hasContentsOfAllSources(); + }); + }; - if (!this._skipValidation) { - this._validateMapping(generated, original, source, name); - } +/** + * Returns the original source content. The only argument is the url of the + * original source file. Returns null if no original source content is + * available. + */ +IndexedSourceMapConsumer.prototype.sourceContentFor = + function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { + for (var i = 0; i < this._sections.length; i++) { + var section = this._sections[i]; - if (source != null) { - source = String(source); - if (!this._sources.has(source)) { - this._sources.add(source); + var content = section.consumer.sourceContentFor(aSource, true); + if (content) { + return content; } } - - if (name != null) { - name = String(name); - if (!this._names.has(name)) { - this._names.add(name); - } + if (nullOnMissing) { + return null; + } + else { + throw new Error('"' + aSource + '" is not in the SourceMap.'); } - - this._mappings.add({ - generatedLine: generated.line, - generatedColumn: generated.column, - originalLine: original != null && original.line, - originalColumn: original != null && original.column, - source: source, - name: name - }); }; /** - * Set the source content for a source file. + * Returns the generated line and column information for the original source, + * line, and column positions provided. The only argument is an object with + * the following properties: + * + * - source: The filename of the original source. + * - line: The line number in the original source. + * - column: The column number in the original source. + * + * and an object is returned with the following properties: + * + * - line: The line number in the generated source, or null. + * - column: The column number in the generated source, or null. */ -SourceMapGenerator.prototype.setSourceContent = - function SourceMapGenerator_setSourceContent(aSourceFile, aSourceContent) { - var source = aSourceFile; - if (this._sourceRoot != null) { - source = util.relative(this._sourceRoot, source); - } +IndexedSourceMapConsumer.prototype.generatedPositionFor = + function IndexedSourceMapConsumer_generatedPositionFor(aArgs) { + for (var i = 0; i < this._sections.length; i++) { + var section = this._sections[i]; - if (aSourceContent != null) { - // Add the source content to the _sourcesContents map. - // Create a new _sourcesContents map if the property is null. - if (!this._sourcesContents) { - this._sourcesContents = Object.create(null); + // Only consider this section if the requested source is in the list of + // sources of the consumer. + if (section.consumer.sources.indexOf(util.getArg(aArgs, 'source')) === -1) { + continue; } - this._sourcesContents[util.toSetString(source)] = aSourceContent; - } else if (this._sourcesContents) { - // Remove the source file from the _sourcesContents map. - // If the _sourcesContents map is empty, set the property to null. - delete this._sourcesContents[util.toSetString(source)]; - if (Object.keys(this._sourcesContents).length === 0) { - this._sourcesContents = null; + var generatedPosition = section.consumer.generatedPositionFor(aArgs); + if (generatedPosition) { + var ret = { + line: generatedPosition.line + + (section.generatedOffset.generatedLine - 1), + column: generatedPosition.column + + (section.generatedOffset.generatedLine === generatedPosition.line + ? section.generatedOffset.generatedColumn - 1 + : 0) + }; + return ret; } } + + return { + line: null, + column: null + }; }; /** - * Applies the mappings of a sub-source-map for a specific source file to the - * source map being generated. Each mapping to the supplied source file is - * rewritten using the supplied source map. Note: The resolution for the - * resulting mappings is the minimium of this map and the supplied map. - * - * @param aSourceMapConsumer The source map to be applied. - * @param aSourceFile Optional. The filename of the source file. - * If omitted, SourceMapConsumer's file property will be used. - * @param aSourceMapPath Optional. The dirname of the path to the source map - * to be applied. If relative, it is relative to the SourceMapConsumer. - * This parameter is needed when the two source maps aren't in the same - * directory, and the source map to be applied contains relative source - * paths. If so, those relative source paths need to be rewritten - * relative to the SourceMapGenerator. + * Parse the mappings in a string in to a data structure which we can easily + * query (the ordered arrays in the `this.__generatedMappings` and + * `this.__originalMappings` properties). */ -SourceMapGenerator.prototype.applySourceMap = - function SourceMapGenerator_applySourceMap(aSourceMapConsumer, aSourceFile, aSourceMapPath) { - var sourceFile = aSourceFile; - // If aSourceFile is omitted, we will use the file property of the SourceMap - if (aSourceFile == null) { - if (aSourceMapConsumer.file == null) { - throw new Error( - 'SourceMapGenerator.prototype.applySourceMap requires either an explicit source file, ' + - 'or the source map\'s "file" property. Both were omitted.' - ); - } - sourceFile = aSourceMapConsumer.file; - } - var sourceRoot = this._sourceRoot; - // Make "sourceFile" relative if an absolute Url is passed. - if (sourceRoot != null) { - sourceFile = util.relative(sourceRoot, sourceFile); - } - // Applying the SourceMap can add and remove items from the sources and - // the names array. - var newSources = new ArraySet(); - var newNames = new ArraySet(); +IndexedSourceMapConsumer.prototype._parseMappings = + function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) { + this.__generatedMappings = []; + this.__originalMappings = []; + for (var i = 0; i < this._sections.length; i++) { + var section = this._sections[i]; + var sectionMappings = section.consumer._generatedMappings; + for (var j = 0; j < sectionMappings.length; j++) { + var mapping = sectionMappings[j]; - // Find mappings for the "sourceFile" - this._mappings.unsortedForEach(function (mapping) { - if (mapping.source === sourceFile && mapping.originalLine != null) { - // Check if it can be mapped by the source map, then update the mapping. - var original = aSourceMapConsumer.originalPositionFor({ - line: mapping.originalLine, - column: mapping.originalColumn - }); - if (original.source != null) { - // Copy mapping - mapping.source = original.source; - if (aSourceMapPath != null) { - mapping.source = util.join(aSourceMapPath, mapping.source) - } - if (sourceRoot != null) { - mapping.source = util.relative(sourceRoot, mapping.source); - } - mapping.originalLine = original.line; - mapping.originalColumn = original.column; - if (original.name != null) { - mapping.name = original.name; - } + var source = section.consumer._sources.at(mapping.source); + if (section.consumer.sourceRoot !== null) { + source = util.join(section.consumer.sourceRoot, source); } - } - - var source = mapping.source; - if (source != null && !newSources.has(source)) { - newSources.add(source); - } + this._sources.add(source); + source = this._sources.indexOf(source); - var name = mapping.name; - if (name != null && !newNames.has(name)) { - newNames.add(name); - } + var name = section.consumer._names.at(mapping.name); + this._names.add(name); + name = this._names.indexOf(name); - }, this); - this._sources = newSources; - this._names = newNames; + // The mappings coming from the consumer for the section have + // generated positions relative to the start of the section, so we + // need to offset them to be relative to the start of the concatenated + // generated file. + var adjustedMapping = { + source: source, + generatedLine: mapping.generatedLine + + (section.generatedOffset.generatedLine - 1), + generatedColumn: mapping.generatedColumn + + (section.generatedOffset.generatedLine === mapping.generatedLine + ? section.generatedOffset.generatedColumn - 1 + : 0), + originalLine: mapping.originalLine, + originalColumn: mapping.originalColumn, + name: name + }; - // Copy sourcesContents of applied map. - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content != null) { - if (aSourceMapPath != null) { - sourceFile = util.join(aSourceMapPath, sourceFile); - } - if (sourceRoot != null) { - sourceFile = util.relative(sourceRoot, sourceFile); + this.__generatedMappings.push(adjustedMapping); + if (typeof adjustedMapping.originalLine === 'number') { + this.__originalMappings.push(adjustedMapping); } - this.setSourceContent(sourceFile, content); } - }, this); + } + + quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated); + quickSort(this.__originalMappings, util.compareByOriginalPositions); }; +exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; + + +/***/ }), +/* 810 */ +/***/ (function(module, exports) { + +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ + +exports.GREATEST_LOWER_BOUND = 1; +exports.LEAST_UPPER_BOUND = 2; + /** - * A mapping can have one of the three levels of data: - * - * 1. Just the generated position. - * 2. The Generated position, original position, and original source. - * 3. Generated and original position, original source, as well as a name - * token. + * Recursive implementation of binary search. * - * To maintain consistency, we validate that any new mapping being added falls - * in to one of these categories. + * @param aLow Indices here and lower do not contain the needle. + * @param aHigh Indices here and higher do not contain the needle. + * @param aNeedle The element being searched for. + * @param aHaystack The non-empty array being searched. + * @param aCompare Function which takes two elements and returns -1, 0, or 1. + * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or + * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the + * closest element that is smaller than or greater than the one we are + * searching for, respectively, if the exact element cannot be found. */ -SourceMapGenerator.prototype._validateMapping = - function SourceMapGenerator_validateMapping(aGenerated, aOriginal, aSource, - aName) { - // When aOriginal is truthy but has empty values for .line and .column, - // it is most likely a programmer error. In this case we throw a very - // specific error message to try to guide them the right way. - // For example: https://github.com/Polymer/polymer-bundler/pull/519 - if (aOriginal && typeof aOriginal.line !== 'number' && typeof aOriginal.column !== 'number') { - throw new Error( - 'original.line and original.column are not numbers -- you probably meant to omit ' + - 'the original mapping entirely and only map the generated position. If so, pass ' + - 'null for the original mapping instead of an object with empty or null values.' - ); +function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) { + // This function terminates when one of the following is true: + // + // 1. We find the exact element we are looking for. + // + // 2. We did not find the exact element, but we can return the index of + // the next-closest element. + // + // 3. We did not find the exact element, and there is no next-closest + // element than the one we are searching for, so we return -1. + var mid = Math.floor((aHigh - aLow) / 2) + aLow; + var cmp = aCompare(aNeedle, aHaystack[mid], true); + if (cmp === 0) { + // Found the element we are looking for. + return mid; + } + else if (cmp > 0) { + // Our needle is greater than aHaystack[mid]. + if (aHigh - mid > 1) { + // The element is in the upper half. + return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare, aBias); } - if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aGenerated.line > 0 && aGenerated.column >= 0 - && !aOriginal && !aSource && !aName) { - // Case 1. - return; + // The exact needle element was not found in this haystack. Determine if + // we are in termination case (3) or (2) and return the appropriate thing. + if (aBias == exports.LEAST_UPPER_BOUND) { + return aHigh < aHaystack.length ? aHigh : -1; + } else { + return mid; } - else if (aGenerated && 'line' in aGenerated && 'column' in aGenerated - && aOriginal && 'line' in aOriginal && 'column' in aOriginal - && aGenerated.line > 0 && aGenerated.column >= 0 - && aOriginal.line > 0 && aOriginal.column >= 0 - && aSource) { - // Cases 2 and 3. - return; + } + else { + // Our needle is less than aHaystack[mid]. + if (mid - aLow > 1) { + // The element is in the lower half. + return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias); } - else { - throw new Error('Invalid mapping: ' + JSON.stringify({ - generated: aGenerated, - source: aSource, - original: aOriginal, - name: aName - })); + + // we are in termination case (3) or (2) and return the appropriate thing. + if (aBias == exports.LEAST_UPPER_BOUND) { + return mid; + } else { + return aLow < 0 ? -1 : aLow; } - }; + } +} /** - * Serialize the accumulated mappings in to the stream of base 64 VLQs - * specified by the source map format. + * This is an implementation of binary search which will always try and return + * the index of the closest element if there is no exact hit. This is because + * mappings between original and generated line/col pairs are single points, + * and there is an implicit region between each of them, so a miss just means + * that you aren't on the very start of a region. + * + * @param aNeedle The element you are looking for. + * @param aHaystack The array that is being searched. + * @param aCompare A function which takes the needle and an element in the + * array and returns -1, 0, or 1 depending on whether the needle is less + * than, equal to, or greater than the element, respectively. + * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or + * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the + * closest element that is smaller than or greater than the one we are + * searching for, respectively, if the exact element cannot be found. + * Defaults to 'binarySearch.GREATEST_LOWER_BOUND'. */ -SourceMapGenerator.prototype._serializeMappings = - function SourceMapGenerator_serializeMappings() { - var previousGeneratedColumn = 0; - var previousGeneratedLine = 1; - var previousOriginalColumn = 0; - var previousOriginalLine = 0; - var previousName = 0; - var previousSource = 0; - var result = ''; - var next; - var mapping; - var nameIdx; - var sourceIdx; - - var mappings = this._mappings.toArray(); - for (var i = 0, len = mappings.length; i < len; i++) { - mapping = mappings[i]; - next = '' +exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { + if (aHaystack.length === 0) { + return -1; + } - if (mapping.generatedLine !== previousGeneratedLine) { - previousGeneratedColumn = 0; - while (mapping.generatedLine !== previousGeneratedLine) { - next += ';'; - previousGeneratedLine++; - } - } - else { - if (i > 0) { - if (!util.compareByGeneratedPositionsInflated(mapping, mappings[i - 1])) { - continue; - } - next += ','; - } - } + var index = recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, + aCompare, aBias || exports.GREATEST_LOWER_BOUND); + if (index < 0) { + return -1; + } - next += base64VLQ.encode(mapping.generatedColumn - - previousGeneratedColumn); - previousGeneratedColumn = mapping.generatedColumn; + // We have found either the exact element, or the next-closest element than + // the one we are searching for. However, there may be more than one such + // element. Make sure we always return the smallest of these. + while (index - 1 >= 0) { + if (aCompare(aHaystack[index], aHaystack[index - 1], true) !== 0) { + break; + } + --index; + } - if (mapping.source != null) { - sourceIdx = this._sources.indexOf(mapping.source); - next += base64VLQ.encode(sourceIdx - previousSource); - previousSource = sourceIdx; + return index; +}; - // lines are stored 0-based in SourceMap spec version 3 - next += base64VLQ.encode(mapping.originalLine - 1 - - previousOriginalLine); - previousOriginalLine = mapping.originalLine - 1; - next += base64VLQ.encode(mapping.originalColumn - - previousOriginalColumn); - previousOriginalColumn = mapping.originalColumn; +/***/ }), +/* 811 */ +/***/ (function(module, exports) { - if (mapping.name != null) { - nameIdx = this._names.indexOf(mapping.name); - next += base64VLQ.encode(nameIdx - previousName); - previousName = nameIdx; - } - } +/* -*- Mode: js; js-indent-level: 2; -*- */ +/* + * Copyright 2011 Mozilla Foundation and contributors + * Licensed under the New BSD license. See LICENSE or: + * http://opensource.org/licenses/BSD-3-Clause + */ - result += next; - } +// It turns out that some (most?) JavaScript engines don't self-host +// `Array.prototype.sort`. This makes sense because C++ will likely remain +// faster than JS when doing raw CPU-intensive sorting. However, when using a +// custom comparator function, calling back and forth between the VM's C++ and +// JIT'd JS is rather slow *and* loses JIT type information, resulting in +// worse generated code for the comparator function than would be optimal. In +// fact, when sorting with a comparator, these costs outweigh the benefits of +// sorting in C++. By using our own JS-implemented Quick Sort (below), we get +// a ~3500ms mean speed-up in `bench/bench.html`. - return result; - }; +/** + * Swap the elements indexed by `x` and `y` in the array `ary`. + * + * @param {Array} ary + * The array. + * @param {Number} x + * The index of the first item. + * @param {Number} y + * The index of the second item. + */ +function swap(ary, x, y) { + var temp = ary[x]; + ary[x] = ary[y]; + ary[y] = temp; +} -SourceMapGenerator.prototype._generateSourcesContent = - function SourceMapGenerator_generateSourcesContent(aSources, aSourceRoot) { - return aSources.map(function (source) { - if (!this._sourcesContents) { - return null; - } - if (aSourceRoot != null) { - source = util.relative(aSourceRoot, source); - } - var key = util.toSetString(source); - return Object.prototype.hasOwnProperty.call(this._sourcesContents, key) - ? this._sourcesContents[key] - : null; - }, this); - }; +/** + * Returns a random integer within the range `low .. high` inclusive. + * + * @param {Number} low + * The lower bound on the range. + * @param {Number} high + * The upper bound on the range. + */ +function randomIntInRange(low, high) { + return Math.round(low + (Math.random() * (high - low))); +} /** - * Externalize the source map. + * The Quick Sort algorithm. + * + * @param {Array} ary + * An array to sort. + * @param {function} comparator + * Function to use to compare two items. + * @param {Number} p + * Start index of the array + * @param {Number} r + * End index of the array */ -SourceMapGenerator.prototype.toJSON = - function SourceMapGenerator_toJSON() { - var map = { - version: this._version, - sources: this._sources.toArray(), - names: this._names.toArray(), - mappings: this._serializeMappings() - }; - if (this._file != null) { - map.file = this._file; - } - if (this._sourceRoot != null) { - map.sourceRoot = this._sourceRoot; - } - if (this._sourcesContents) { - map.sourcesContent = this._generateSourcesContent(map.sources, map.sourceRoot); +function doQuickSort(ary, comparator, p, r) { + // If our lower bound is less than our upper bound, we (1) partition the + // array into two pieces and (2) recurse on each half. If it is not, this is + // the empty array and our base case. + + if (p < r) { + // (1) Partitioning. + // + // The partitioning chooses a pivot between `p` and `r` and moves all + // elements that are less than or equal to the pivot to the before it, and + // all the elements that are greater than it after it. The effect is that + // once partition is done, the pivot is in the exact place it will be when + // the array is put in sorted order, and it will not need to be moved + // again. This runs in O(n) time. + + // Always choose a random pivot so that an input array which is reverse + // sorted does not cause O(n^2) running time. + var pivotIndex = randomIntInRange(p, r); + var i = p - 1; + + swap(ary, pivotIndex, r); + var pivot = ary[r]; + + // Immediately after `j` is incremented in this loop, the following hold + // true: + // + // * Every element in `ary[p .. i]` is less than or equal to the pivot. + // + // * Every element in `ary[i+1 .. j-1]` is greater than the pivot. + for (var j = p; j < r; j++) { + if (comparator(ary[j], pivot) <= 0) { + i += 1; + swap(ary, i, j); + } } - return map; - }; + swap(ary, i + 1, j); + var q = i + 1; + + // (2) Recurse on each half. + + doQuickSort(ary, comparator, p, q - 1); + doQuickSort(ary, comparator, q + 1, r); + } +} /** - * Render the source map being generated to a string. + * Sort the given array in-place with the given comparator function. + * + * @param {Array} ary + * An array to sort. + * @param {function} comparator + * Function to use to compare two items. */ -SourceMapGenerator.prototype.toString = - function SourceMapGenerator_toString() { - return JSON.stringify(this.toJSON()); - }; - -exports.SourceMapGenerator = SourceMapGenerator; +exports.quickSort = function (ary, comparator) { + doQuickSort(ary, comparator, 0, ary.length - 1); +}; /***/ }), -/* 809 */ +/* 812 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94417,9075 +94351,8219 @@ exports.SourceMapGenerator = SourceMapGenerator; * Copyright 2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE or: * http://opensource.org/licenses/BSD-3-Clause + */ + +var SourceMapGenerator = __webpack_require__(803).SourceMapGenerator; +var util = __webpack_require__(806); + +// Matches a Windows-style `\r\n` newline or a `\n` newline used by all other +// operating systems these days (capturing the result). +var REGEX_NEWLINE = /(\r?\n)/; + +// Newline character code for charCodeAt() comparisons +var NEWLINE_CODE = 10; + +// Private symbol for identifying `SourceNode`s when multiple versions of +// the source-map library are loaded. This MUST NOT CHANGE across +// versions! +var isSourceNode = "$$$isSourceNode$$$"; + +/** + * SourceNodes provide a way to abstract over interpolating/concatenating + * snippets of generated JavaScript source code while maintaining the line and + * column information associated with the original source code. * - * Based on the Base 64 VLQ implementation in Closure Compiler: - * https://code.google.com/p/closure-compiler/source/browse/trunk/src/com/google/debugging/sourcemap/Base64VLQ.java - * - * Copyright 2011 The Closure Compiler Authors. All rights reserved. - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of Google Inc. nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * @param aLine The original line number. + * @param aColumn The original column number. + * @param aSource The original source's filename. + * @param aChunks Optional. An array of strings which are snippets of + * generated JS, or other SourceNodes. + * @param aName The original identifier. + */ +function SourceNode(aLine, aColumn, aSource, aChunks, aName) { + this.children = []; + this.sourceContents = {}; + this.line = aLine == null ? null : aLine; + this.column = aColumn == null ? null : aColumn; + this.source = aSource == null ? null : aSource; + this.name = aName == null ? null : aName; + this[isSourceNode] = true; + if (aChunks != null) this.add(aChunks); +} + +/** + * Creates a SourceNode from generated code and a SourceMapConsumer. * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * @param aGeneratedCode The generated code + * @param aSourceMapConsumer The SourceMap for the generated code + * @param aRelativePath Optional. The path that relative sources in the + * SourceMapConsumer should be relative to. */ +SourceNode.fromStringWithSourceMap = + function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) { + // The SourceNode we want to fill with the generated code + // and the SourceMap + var node = new SourceNode(); -var base64 = __webpack_require__(810); + // All even indices of this array are one line of the generated code, + // while all odd indices are the newlines between two adjacent lines + // (since `REGEX_NEWLINE` captures its match). + // Processed fragments are accessed by calling `shiftNextLine`. + var remainingLines = aGeneratedCode.split(REGEX_NEWLINE); + var remainingLinesIndex = 0; + var shiftNextLine = function() { + var lineContents = getNextLine(); + // The last line of a file might not have a newline. + var newLine = getNextLine() || ""; + return lineContents + newLine; -// 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, -// the next four bits are the actual value, and the 6th bit is the -// continuation bit. The continuation bit tells us whether there are more -// digits in this value following this digit. -// -// Continuation -// | Sign -// | | -// V V -// 101011 + function getNextLine() { + return remainingLinesIndex < remainingLines.length ? + remainingLines[remainingLinesIndex++] : undefined; + } + }; -var VLQ_BASE_SHIFT = 5; + // We need to remember the position of "remainingLines" + var lastGeneratedLine = 1, lastGeneratedColumn = 0; -// binary: 100000 -var VLQ_BASE = 1 << VLQ_BASE_SHIFT; + // The generate SourceNodes we need a code range. + // To extract it current and last mapping is used. + // Here we store the last mapping. + var lastMapping = null; -// binary: 011111 -var VLQ_BASE_MASK = VLQ_BASE - 1; + aSourceMapConsumer.eachMapping(function (mapping) { + if (lastMapping !== null) { + // We add the code from "lastMapping" to "mapping": + // First check if there is a new line in between. + if (lastGeneratedLine < mapping.generatedLine) { + // Associate first line with "lastMapping" + addMappingWithCode(lastMapping, shiftNextLine()); + lastGeneratedLine++; + lastGeneratedColumn = 0; + // The remaining code is added without mapping + } else { + // There is no new line in between. + // Associate the code between "lastGeneratedColumn" and + // "mapping.generatedColumn" with "lastMapping" + var nextLine = remainingLines[remainingLinesIndex]; + var code = nextLine.substr(0, mapping.generatedColumn - + lastGeneratedColumn); + remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn - + lastGeneratedColumn); + lastGeneratedColumn = mapping.generatedColumn; + addMappingWithCode(lastMapping, code); + // No more remaining code, continue + lastMapping = mapping; + return; + } + } + // We add the generated code until the first mapping + // to the SourceNode without any mapping. + // Each line is added as separate string. + while (lastGeneratedLine < mapping.generatedLine) { + node.add(shiftNextLine()); + lastGeneratedLine++; + } + if (lastGeneratedColumn < mapping.generatedColumn) { + var nextLine = remainingLines[remainingLinesIndex]; + node.add(nextLine.substr(0, mapping.generatedColumn)); + remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn); + lastGeneratedColumn = mapping.generatedColumn; + } + lastMapping = mapping; + }, this); + // We have processed all mappings. + if (remainingLinesIndex < remainingLines.length) { + if (lastMapping) { + // Associate the remaining code in the current line with "lastMapping" + addMappingWithCode(lastMapping, shiftNextLine()); + } + // and add the remaining lines without any mapping + node.add(remainingLines.splice(remainingLinesIndex).join("")); + } -// binary: 100000 -var VLQ_CONTINUATION_BIT = VLQ_BASE; + // Copy sourcesContent into SourceNode + aSourceMapConsumer.sources.forEach(function (sourceFile) { + var content = aSourceMapConsumer.sourceContentFor(sourceFile); + if (content != null) { + if (aRelativePath != null) { + sourceFile = util.join(aRelativePath, sourceFile); + } + node.setSourceContent(sourceFile, content); + } + }); + + return node; + + function addMappingWithCode(mapping, code) { + if (mapping === null || mapping.source === undefined) { + node.add(code); + } else { + var source = aRelativePath + ? util.join(aRelativePath, mapping.source) + : mapping.source; + node.add(new SourceNode(mapping.originalLine, + mapping.originalColumn, + source, + code, + mapping.name)); + } + } + }; /** - * Converts from a two-complement value to a value where the sign bit is - * placed in the least significant bit. For example, as decimals: - * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) - * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + * Add a chunk of generated JS to this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. */ -function toVLQSigned(aValue) { - return aValue < 0 - ? ((-aValue) << 1) + 1 - : (aValue << 1) + 0; -} +SourceNode.prototype.add = function SourceNode_add(aChunk) { + if (Array.isArray(aChunk)) { + aChunk.forEach(function (chunk) { + this.add(chunk); + }, this); + } + else if (aChunk[isSourceNode] || typeof aChunk === "string") { + if (aChunk) { + this.children.push(aChunk); + } + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; +}; /** - * Converts to a two-complement value from a value where the sign bit is - * placed in the least significant bit. For example, as decimals: - * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 - * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + * Add a chunk of generated JS to the beginning of this source node. + * + * @param aChunk A string snippet of generated JS code, another instance of + * SourceNode, or an array where each member is one of those things. */ -function fromVLQSigned(aValue) { - var isNegative = (aValue & 1) === 1; - var shifted = aValue >> 1; - return isNegative - ? -shifted - : shifted; -} +SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { + if (Array.isArray(aChunk)) { + for (var i = aChunk.length-1; i >= 0; i--) { + this.prepend(aChunk[i]); + } + } + else if (aChunk[isSourceNode] || typeof aChunk === "string") { + this.children.unshift(aChunk); + } + else { + throw new TypeError( + "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk + ); + } + return this; +}; /** - * Returns the base 64 VLQ encoded value. + * Walk over the tree of JS snippets in this node and its children. The + * walking function is called once for each snippet of JS and is passed that + * snippet and the its original associated source's line/column location. + * + * @param aFn The traversal function. */ -exports.encode = function base64VLQ_encode(aValue) { - var encoded = ""; - var digit; - - var vlq = toVLQSigned(aValue); +SourceNode.prototype.walk = function SourceNode_walk(aFn) { + var chunk; + for (var i = 0, len = this.children.length; i < len; i++) { + chunk = this.children[i]; + if (chunk[isSourceNode]) { + chunk.walk(aFn); + } + else { + if (chunk !== '') { + aFn(chunk, { source: this.source, + line: this.line, + column: this.column, + name: this.name }); + } + } + } +}; - do { - digit = vlq & VLQ_BASE_MASK; - vlq >>>= VLQ_BASE_SHIFT; - if (vlq > 0) { - // There are still more digits in this value, so we must make sure the - // continuation bit is marked. - digit |= VLQ_CONTINUATION_BIT; +/** + * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between + * each of `this.children`. + * + * @param aSep The separator. + */ +SourceNode.prototype.join = function SourceNode_join(aSep) { + var newChildren; + var i; + var len = this.children.length; + if (len > 0) { + newChildren = []; + for (i = 0; i < len-1; i++) { + newChildren.push(this.children[i]); + newChildren.push(aSep); } - encoded += base64.encode(digit); - } while (vlq > 0); + newChildren.push(this.children[i]); + this.children = newChildren; + } + return this; +}; - return encoded; +/** + * Call String.prototype.replace on the very right-most source snippet. Useful + * for trimming whitespace from the end of a source node, etc. + * + * @param aPattern The pattern to replace. + * @param aReplacement The thing to replace the pattern with. + */ +SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { + var lastChild = this.children[this.children.length - 1]; + if (lastChild[isSourceNode]) { + lastChild.replaceRight(aPattern, aReplacement); + } + else if (typeof lastChild === 'string') { + this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + } + else { + this.children.push(''.replace(aPattern, aReplacement)); + } + return this; }; /** - * Decodes the next base 64 VLQ value from the given string and returns the - * value and the rest of the string via the out parameter. + * Set the source content for a source file. This will be added to the SourceMapGenerator + * in the sourcesContent field. + * + * @param aSourceFile The filename of the source file + * @param aSourceContent The content of the source file */ -exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { - var strLen = aStr.length; - var result = 0; - var shift = 0; - var continuation, digit; +SourceNode.prototype.setSourceContent = + function SourceNode_setSourceContent(aSourceFile, aSourceContent) { + this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; + }; - do { - if (aIndex >= strLen) { - throw new Error("Expected more digits in base 64 VLQ value."); +/** + * Walk over the tree of SourceNodes. The walking function is called for each + * source file content and is passed the filename and source content. + * + * @param aFn The traversal function. + */ +SourceNode.prototype.walkSourceContents = + function SourceNode_walkSourceContents(aFn) { + for (var i = 0, len = this.children.length; i < len; i++) { + if (this.children[i][isSourceNode]) { + this.children[i].walkSourceContents(aFn); + } } - digit = base64.decode(aStr.charCodeAt(aIndex++)); - if (digit === -1) { - throw new Error("Invalid base64 digit: " + aStr.charAt(aIndex - 1)); + var sources = Object.keys(this.sourceContents); + for (var i = 0, len = sources.length; i < len; i++) { + aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); } - - continuation = !!(digit & VLQ_CONTINUATION_BIT); - digit &= VLQ_BASE_MASK; - result = result + (digit << shift); - shift += VLQ_BASE_SHIFT; - } while (continuation); - - aOutParam.value = fromVLQSigned(result); - aOutParam.rest = aIndex; -}; - - -/***/ }), -/* 810 */ -/***/ (function(module, exports) { - -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -var intToCharMap = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); + }; /** - * Encode an integer in the range of 0 to 63 to a single base 64 digit. + * Return the string representation of this source node. Walks over the tree + * and concatenates all the various snippets together to one string. */ -exports.encode = function (number) { - if (0 <= number && number < intToCharMap.length) { - return intToCharMap[number]; - } - throw new TypeError("Must be between 0 and 63: " + number); +SourceNode.prototype.toString = function SourceNode_toString() { + var str = ""; + this.walk(function (chunk) { + str += chunk; + }); + return str; }; /** - * Decode a single base 64 character code digit to an integer. Returns -1 on - * failure. + * Returns the string representation of this source node along with a source + * map. */ -exports.decode = function (charCode) { - var bigA = 65; // 'A' - var bigZ = 90; // 'Z' - - var littleA = 97; // 'a' - var littleZ = 122; // 'z' - - var zero = 48; // '0' - var nine = 57; // '9' - - var plus = 43; // '+' - var slash = 47; // '/' - - var littleOffset = 26; - var numberOffset = 52; - - // 0 - 25: ABCDEFGHIJKLMNOPQRSTUVWXYZ - if (bigA <= charCode && charCode <= bigZ) { - return (charCode - bigA); - } +SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { + var generated = { + code: "", + line: 1, + column: 0 + }; + var map = new SourceMapGenerator(aArgs); + var sourceMappingActive = false; + var lastOriginalSource = null; + var lastOriginalLine = null; + var lastOriginalColumn = null; + var lastOriginalName = null; + this.walk(function (chunk, original) { + generated.code += chunk; + if (original.source !== null + && original.line !== null + && original.column !== null) { + if(lastOriginalSource !== original.source + || lastOriginalLine !== original.line + || lastOriginalColumn !== original.column + || lastOriginalName !== original.name) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } + lastOriginalSource = original.source; + lastOriginalLine = original.line; + lastOriginalColumn = original.column; + lastOriginalName = original.name; + sourceMappingActive = true; + } else if (sourceMappingActive) { + map.addMapping({ + generated: { + line: generated.line, + column: generated.column + } + }); + lastOriginalSource = null; + sourceMappingActive = false; + } + for (var idx = 0, length = chunk.length; idx < length; idx++) { + if (chunk.charCodeAt(idx) === NEWLINE_CODE) { + generated.line++; + generated.column = 0; + // Mappings end at eol + if (idx + 1 === length) { + lastOriginalSource = null; + sourceMappingActive = false; + } else if (sourceMappingActive) { + map.addMapping({ + source: original.source, + original: { + line: original.line, + column: original.column + }, + generated: { + line: generated.line, + column: generated.column + }, + name: original.name + }); + } + } else { + generated.column++; + } + } + }); + this.walkSourceContents(function (sourceFile, sourceContent) { + map.setSourceContent(sourceFile, sourceContent); + }); - // 26 - 51: abcdefghijklmnopqrstuvwxyz - if (littleA <= charCode && charCode <= littleZ) { - return (charCode - littleA + littleOffset); - } + return { code: generated.code, map: map }; +}; - // 52 - 61: 0123456789 - if (zero <= charCode && charCode <= nine) { - return (charCode - zero + numberOffset); - } +exports.SourceNode = SourceNode; - // 62: + - if (charCode == plus) { - return 62; - } - // 63: / - if (charCode == slash) { - return 63; - } +/***/ }), +/* 813 */ +/***/ (function(module, exports, __webpack_require__) { - // Invalid base64 digit. - return -1; -}; +// Copyright 2014, 2015, 2016, 2017 Simon Lydell +// X11 (“MIT”) Licensed. (See LICENSE.) +var sourceMappingURL = __webpack_require__(814) +var resolveUrl = __webpack_require__(815) +var decodeUriComponent = __webpack_require__(816) +var urix = __webpack_require__(818) +var atob = __webpack_require__(819) -/***/ }), -/* 811 */ -/***/ (function(module, exports) { -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ -/** - * This is a helper function for getting values from parameter/options - * objects. - * - * @param args The object we are extracting values from - * @param name The name of the property we are getting. - * @param defaultValue An optional value to return if the property is missing - * from the object. If this is not specified and the property is missing, an - * error will be thrown. - */ -function getArg(aArgs, aName, aDefaultValue) { - if (aName in aArgs) { - return aArgs[aName]; - } else if (arguments.length === 3) { - return aDefaultValue; - } else { - throw new Error('"' + aName + '" is a required argument.'); - } +function callbackAsync(callback, error, result) { + setImmediate(function() { callback(error, result) }) } -exports.getArg = getArg; - -var urlRegexp = /^(?:([\w+\-.]+):)?\/\/(?:(\w+:\w+)@)?([\w.]*)(?::(\d+))?(\S*)$/; -var dataUrlRegexp = /^data:.+\,.+$/; -function urlParse(aUrl) { - var match = aUrl.match(urlRegexp); - if (!match) { - return null; +function parseMapToJSON(string, data) { + try { + return JSON.parse(string.replace(/^\)\]\}'/, "")) + } catch (error) { + error.sourceMapData = data + throw error } - return { - scheme: match[1], - auth: match[2], - host: match[3], - port: match[4], - path: match[5] - }; } -exports.urlParse = urlParse; -function urlGenerate(aParsedUrl) { - var url = ''; - if (aParsedUrl.scheme) { - url += aParsedUrl.scheme + ':'; - } - url += '//'; - if (aParsedUrl.auth) { - url += aParsedUrl.auth + '@'; - } - if (aParsedUrl.host) { - url += aParsedUrl.host; - } - if (aParsedUrl.port) { - url += ":" + aParsedUrl.port - } - if (aParsedUrl.path) { - url += aParsedUrl.path; +function readSync(read, url, data) { + var readUrl = decodeUriComponent(url) + try { + return String(read(readUrl)) + } catch (error) { + error.sourceMapData = data + throw error } - return url; } -exports.urlGenerate = urlGenerate; -/** - * Normalizes a path, or the path portion of a URL: - * - * - Replaces consecutive slashes with one slash. - * - Removes unnecessary '.' parts. - * - Removes unnecessary '/..' parts. - * - * Based on code in the Node.js 'path' core module. - * - * @param aPath The path or url to normalize. - */ -function normalize(aPath) { - var path = aPath; - var url = urlParse(aPath); - if (url) { - if (!url.path) { - return aPath; - } - path = url.path; - } - var isAbsolute = exports.isAbsolute(path); - var parts = path.split(/\/+/); - for (var part, up = 0, i = parts.length - 1; i >= 0; i--) { - part = parts[i]; - if (part === '.') { - parts.splice(i, 1); - } else if (part === '..') { - up++; - } else if (up > 0) { - if (part === '') { - // The first part is blank if the path is absolute. Trying to go - // above the root is a no-op. Therefore we can remove all '..' parts - // directly after the root. - parts.splice(i + 1, up); - up = 0; - } else { - parts.splice(i, 2); - up--; - } - } - } - path = parts.join('/'); - if (path === '') { - path = isAbsolute ? '/' : '.'; +function resolveSourceMap(code, codeUrl, read, callback) { + var mapData + try { + mapData = resolveSourceMapHelper(code, codeUrl) + } catch (error) { + return callbackAsync(callback, error) } - - if (url) { - url.path = path; - return urlGenerate(url); + if (!mapData || mapData.map) { + return callbackAsync(callback, null, mapData) } - return path; + var readUrl = decodeUriComponent(mapData.url) + read(readUrl, function(error, result) { + if (error) { + error.sourceMapData = mapData + return callback(error) + } + mapData.map = String(result) + try { + mapData.map = parseMapToJSON(mapData.map, mapData) + } catch (error) { + return callback(error) + } + callback(null, mapData) + }) } -exports.normalize = normalize; -/** - * Joins two paths/URLs. - * - * @param aRoot The root path or URL. - * @param aPath The path or URL to be joined with the root. - * - * - If aPath is a URL or a data URI, aPath is returned, unless aPath is a - * scheme-relative URL: Then the scheme of aRoot, if any, is prepended - * first. - * - Otherwise aPath is a path. If aRoot is a URL, then its path portion - * is updated with the result and aRoot is returned. Otherwise the result - * is returned. - * - If aPath is absolute, the result is aPath. - * - Otherwise the two paths are joined with a slash. - * - Joining for example 'http://' and 'www.example.com' is also supported. - */ -function join(aRoot, aPath) { - if (aRoot === "") { - aRoot = "."; - } - if (aPath === "") { - aPath = "."; - } - var aPathUrl = urlParse(aPath); - var aRootUrl = urlParse(aRoot); - if (aRootUrl) { - aRoot = aRootUrl.path || '/'; +function resolveSourceMapSync(code, codeUrl, read) { + var mapData = resolveSourceMapHelper(code, codeUrl) + if (!mapData || mapData.map) { + return mapData } + mapData.map = readSync(read, mapData.url, mapData) + mapData.map = parseMapToJSON(mapData.map, mapData) + return mapData +} - // `join(foo, '//www.example.org')` - if (aPathUrl && !aPathUrl.scheme) { - if (aRootUrl) { - aPathUrl.scheme = aRootUrl.scheme; - } - return urlGenerate(aPathUrl); - } +var dataUriRegex = /^data:([^,;]*)(;[^,;]*)*(?:,(.*))?$/ +var jsonMimeTypeRegex = /^(?:application|text)\/json$/ - if (aPathUrl || aPath.match(dataUrlRegexp)) { - return aPath; - } +function resolveSourceMapHelper(code, codeUrl) { + codeUrl = urix(codeUrl) - // `join('http://', 'www.example.com')` - if (aRootUrl && !aRootUrl.host && !aRootUrl.path) { - aRootUrl.host = aPath; - return urlGenerate(aRootUrl); + var url = sourceMappingURL.getFrom(code) + if (!url) { + return null } - var joined = aPath.charAt(0) === '/' - ? aPath - : normalize(aRoot.replace(/\/+$/, '') + '/' + aPath); + var dataUri = url.match(dataUriRegex) + if (dataUri) { + var mimeType = dataUri[1] + var lastParameter = dataUri[2] || "" + var encoded = dataUri[3] || "" + var data = { + sourceMappingURL: url, + url: null, + sourcesRelativeTo: codeUrl, + map: encoded + } + if (!jsonMimeTypeRegex.test(mimeType)) { + var error = new Error("Unuseful data uri mime type: " + (mimeType || "text/plain")) + error.sourceMapData = data + throw error + } + data.map = parseMapToJSON( + lastParameter === ";base64" ? atob(encoded) : decodeURIComponent(encoded), + data + ) + return data + } - if (aRootUrl) { - aRootUrl.path = joined; - return urlGenerate(aRootUrl); + var mapUrl = resolveUrl(codeUrl, url) + return { + sourceMappingURL: url, + url: mapUrl, + sourcesRelativeTo: mapUrl, + map: null } - return joined; } -exports.join = join; -exports.isAbsolute = function (aPath) { - return aPath.charAt(0) === '/' || !!aPath.match(urlRegexp); -}; -/** - * Make a path relative to a URL or another path. - * - * @param aRoot The root path or URL. - * @param aPath The path or URL to be made relative to aRoot. - */ -function relative(aRoot, aPath) { - if (aRoot === "") { - aRoot = "."; + +function resolveSources(map, mapUrl, read, options, callback) { + if (typeof options === "function") { + callback = options + options = {} + } + var pending = map.sources ? map.sources.length : 0 + var result = { + sourcesResolved: [], + sourcesContent: [] } - aRoot = aRoot.replace(/\/$/, ''); + if (pending === 0) { + callbackAsync(callback, null, result) + return + } - // It is possible for the path to be above the root. In this case, simply - // checking whether the root is a prefix of the path won't work. Instead, we - // need to remove components from the root one by one, until either we find - // a prefix that fits, or we run out of components to remove. - var level = 0; - while (aPath.indexOf(aRoot + '/') !== 0) { - var index = aRoot.lastIndexOf("/"); - if (index < 0) { - return aPath; + var done = function() { + pending-- + if (pending === 0) { + callback(null, result) } + } - // If the only part of the root that is left is the scheme (i.e. http://, - // file:///, etc.), one or more slashes (/), or simply nothing at all, we - // have exhausted all components, so the path is not relative to the root. - aRoot = aRoot.slice(0, index); - if (aRoot.match(/^([^\/]+:\/)?\/*$/)) { - return aPath; + resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { + result.sourcesResolved[index] = fullUrl + if (typeof sourceContent === "string") { + result.sourcesContent[index] = sourceContent + callbackAsync(done, null) + } else { + var readUrl = decodeUriComponent(fullUrl) + read(readUrl, function(error, source) { + result.sourcesContent[index] = error ? error : String(source) + done() + }) } + }) +} - ++level; +function resolveSourcesSync(map, mapUrl, read, options) { + var result = { + sourcesResolved: [], + sourcesContent: [] } - // Make sure we add a "../" for each component we removed from the root. - return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1); -} -exports.relative = relative; + if (!map.sources || map.sources.length === 0) { + return result + } -var supportsNullProto = (function () { - var obj = Object.create(null); - return !('__proto__' in obj); -}()); + resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { + result.sourcesResolved[index] = fullUrl + if (read !== null) { + if (typeof sourceContent === "string") { + result.sourcesContent[index] = sourceContent + } else { + var readUrl = decodeUriComponent(fullUrl) + try { + result.sourcesContent[index] = String(read(readUrl)) + } catch (error) { + result.sourcesContent[index] = error + } + } + } + }) -function identity (s) { - return s; + return result } -/** - * Because behavior goes wacky when you set `__proto__` on objects, we - * have to prefix all the strings in our set with an arbitrary character. - * - * See https://github.com/mozilla/source-map/pull/31 and - * https://github.com/mozilla/source-map/issues/30 - * - * @param String aStr - */ -function toSetString(aStr) { - if (isProtoString(aStr)) { - return '$' + aStr; - } - - return aStr; -} -exports.toSetString = supportsNullProto ? identity : toSetString; +var endingSlash = /\/?$/ -function fromSetString(aStr) { - if (isProtoString(aStr)) { - return aStr.slice(1); +function resolveSourcesHelper(map, mapUrl, options, fn) { + options = options || {} + mapUrl = urix(mapUrl) + var fullUrl + var sourceContent + var sourceRoot + for (var index = 0, len = map.sources.length; index < len; index++) { + sourceRoot = null + if (typeof options.sourceRoot === "string") { + sourceRoot = options.sourceRoot + } else if (typeof map.sourceRoot === "string" && options.sourceRoot !== false) { + sourceRoot = map.sourceRoot + } + // If the sourceRoot is the empty string, it is equivalent to not setting + // the property at all. + if (sourceRoot === null || sourceRoot === '') { + fullUrl = resolveUrl(mapUrl, map.sources[index]) + } else { + // Make sure that the sourceRoot ends with a slash, so that `/scripts/subdir` becomes + // `/scripts/subdir/`, not `/scripts/`. Pointing to a file as source root + // does not make sense. + fullUrl = resolveUrl(mapUrl, sourceRoot.replace(endingSlash, "/"), map.sources[index]) + } + sourceContent = (map.sourcesContent || [])[index] + fn(fullUrl, sourceContent, index) } - - return aStr; } -exports.fromSetString = supportsNullProto ? identity : fromSetString; -function isProtoString(s) { - if (!s) { - return false; - } - var length = s.length; - if (length < 9 /* "__proto__".length */) { - return false; +function resolve(code, codeUrl, read, options, callback) { + if (typeof options === "function") { + callback = options + options = {} + } + if (code === null) { + var mapUrl = codeUrl + var data = { + sourceMappingURL: null, + url: mapUrl, + sourcesRelativeTo: mapUrl, + map: null + } + var readUrl = decodeUriComponent(mapUrl) + read(readUrl, function(error, result) { + if (error) { + error.sourceMapData = data + return callback(error) + } + data.map = String(result) + try { + data.map = parseMapToJSON(data.map, data) + } catch (error) { + return callback(error) + } + _resolveSources(data) + }) + } else { + resolveSourceMap(code, codeUrl, read, function(error, mapData) { + if (error) { + return callback(error) + } + if (!mapData) { + return callback(null, null) + } + _resolveSources(mapData) + }) } - if (s.charCodeAt(length - 1) !== 95 /* '_' */ || - s.charCodeAt(length - 2) !== 95 /* '_' */ || - s.charCodeAt(length - 3) !== 111 /* 'o' */ || - s.charCodeAt(length - 4) !== 116 /* 't' */ || - s.charCodeAt(length - 5) !== 111 /* 'o' */ || - s.charCodeAt(length - 6) !== 114 /* 'r' */ || - s.charCodeAt(length - 7) !== 112 /* 'p' */ || - s.charCodeAt(length - 8) !== 95 /* '_' */ || - s.charCodeAt(length - 9) !== 95 /* '_' */) { - return false; + function _resolveSources(mapData) { + resolveSources(mapData.map, mapData.sourcesRelativeTo, read, options, function(error, result) { + if (error) { + return callback(error) + } + mapData.sourcesResolved = result.sourcesResolved + mapData.sourcesContent = result.sourcesContent + callback(null, mapData) + }) } +} - for (var i = length - 10; i >= 0; i--) { - if (s.charCodeAt(i) !== 36 /* '$' */) { - return false; +function resolveSync(code, codeUrl, read, options) { + var mapData + if (code === null) { + var mapUrl = codeUrl + mapData = { + sourceMappingURL: null, + url: mapUrl, + sourcesRelativeTo: mapUrl, + map: null + } + mapData.map = readSync(read, mapUrl, mapData) + mapData.map = parseMapToJSON(mapData.map, mapData) + } else { + mapData = resolveSourceMapSync(code, codeUrl, read) + if (!mapData) { + return null } } + var result = resolveSourcesSync(mapData.map, mapData.sourcesRelativeTo, read, options) + mapData.sourcesResolved = result.sourcesResolved + mapData.sourcesContent = result.sourcesContent + return mapData +} - return true; + + +module.exports = { + resolveSourceMap: resolveSourceMap, + resolveSourceMapSync: resolveSourceMapSync, + resolveSources: resolveSources, + resolveSourcesSync: resolveSourcesSync, + resolve: resolve, + resolveSync: resolveSync, + parseMapToJSON: parseMapToJSON } -/** - * Comparator between two mappings where the original positions are compared. - * - * Optionally pass in `true` as `onlyCompareGenerated` to consider two - * mappings with the same original source/line/column, but different generated - * line and column the same. Useful when searching for a mapping with a - * stubbed out mapping. - */ -function compareByOriginalPositions(mappingA, mappingB, onlyCompareOriginal) { - var cmp = mappingA.source - mappingB.source; - if (cmp !== 0) { - return cmp; - } - cmp = mappingA.originalLine - mappingB.originalLine; - if (cmp !== 0) { - return cmp; - } +/***/ }), +/* 814 */ +/***/ (function(module, exports, __webpack_require__) { - cmp = mappingA.originalColumn - mappingB.originalColumn; - if (cmp !== 0 || onlyCompareOriginal) { - return cmp; - } +var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell +// X11 (“MIT”) Licensed. (See LICENSE.) - cmp = mappingA.generatedColumn - mappingB.generatedColumn; - if (cmp !== 0) { - return cmp; - } +void (function(root, factory) { + if (true) { + !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : + __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)) + } else {} +}(this, function() { - cmp = mappingA.generatedLine - mappingB.generatedLine; - if (cmp !== 0) { - return cmp; - } + var innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/ - return mappingA.name - mappingB.name; -} -exports.compareByOriginalPositions = compareByOriginalPositions; + var regex = RegExp( + "(?:" + + "/\\*" + + "(?:\\s*\r?\n(?://)?)?" + + "(?:" + innerRegex.source + ")" + + "\\s*" + + "\\*/" + + "|" + + "//(?:" + innerRegex.source + ")" + + ")" + + "\\s*" + ) -/** - * Comparator between two mappings with deflated source and name indices where - * the generated positions are compared. - * - * Optionally pass in `true` as `onlyCompareGenerated` to consider two - * mappings with the same generated line and column, but different - * source/name/original line and column the same. Useful when searching for a - * mapping with a stubbed out mapping. - */ -function compareByGeneratedPositionsDeflated(mappingA, mappingB, onlyCompareGenerated) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - if (cmp !== 0) { - return cmp; - } + return { - cmp = mappingA.generatedColumn - mappingB.generatedColumn; - if (cmp !== 0 || onlyCompareGenerated) { - return cmp; - } + regex: regex, + _innerRegex: innerRegex, - cmp = mappingA.source - mappingB.source; - if (cmp !== 0) { - return cmp; - } + getFrom: function(code) { + var match = code.match(regex) + return (match ? match[1] || match[2] || "" : null) + }, - cmp = mappingA.originalLine - mappingB.originalLine; - if (cmp !== 0) { - return cmp; - } + existsIn: function(code) { + return regex.test(code) + }, - cmp = mappingA.originalColumn - mappingB.originalColumn; - if (cmp !== 0) { - return cmp; + removeFrom: function(code) { + return code.replace(regex, "") + }, + + insertBefore: function(code, string) { + var match = code.match(regex) + if (match) { + return code.slice(0, match.index) + string + code.slice(match.index) + } else { + return code + string + } + } } - return mappingA.name - mappingB.name; -} -exports.compareByGeneratedPositionsDeflated = compareByGeneratedPositionsDeflated; +})); -function strcmp(aStr1, aStr2) { - if (aStr1 === aStr2) { - return 0; - } - if (aStr1 > aStr2) { - return 1; - } +/***/ }), +/* 815 */ +/***/ (function(module, exports, __webpack_require__) { - return -1; +// Copyright 2014 Simon Lydell +// X11 (“MIT”) Licensed. (See LICENSE.) + +var url = __webpack_require__(454) + +function resolveUrl(/* ...urls */) { + return Array.prototype.reduce.call(arguments, function(resolved, nextUrl) { + return url.resolve(resolved, nextUrl) + }) } -/** - * Comparator between two mappings with inflated source and name strings where - * the generated positions are compared. - */ -function compareByGeneratedPositionsInflated(mappingA, mappingB) { - var cmp = mappingA.generatedLine - mappingB.generatedLine; - if (cmp !== 0) { - return cmp; - } +module.exports = resolveUrl - cmp = mappingA.generatedColumn - mappingB.generatedColumn; - if (cmp !== 0) { - return cmp; - } - cmp = strcmp(mappingA.source, mappingB.source); - if (cmp !== 0) { - return cmp; - } +/***/ }), +/* 816 */ +/***/ (function(module, exports, __webpack_require__) { - cmp = mappingA.originalLine - mappingB.originalLine; - if (cmp !== 0) { - return cmp; - } +// Copyright 2017 Simon Lydell +// X11 (“MIT”) Licensed. (See LICENSE.) - cmp = mappingA.originalColumn - mappingB.originalColumn; - if (cmp !== 0) { - return cmp; - } +var decodeUriComponent = __webpack_require__(817) - return strcmp(mappingA.name, mappingB.name); +function customDecodeUriComponent(string) { + // `decodeUriComponent` turns `+` into ` `, but that's not wanted. + return decodeUriComponent(string.replace(/\+/g, "%2B")) } -exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflated; + +module.exports = customDecodeUriComponent /***/ }), -/* 812 */ +/* 817 */ /***/ (function(module, exports, __webpack_require__) { -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ +"use strict"; -var util = __webpack_require__(811); -var has = Object.prototype.hasOwnProperty; -var hasNativeMap = typeof Map !== "undefined"; +var token = '%[a-f0-9]{2}'; +var singleMatcher = new RegExp(token, 'gi'); +var multiMatcher = new RegExp('(' + token + ')+', 'gi'); -/** - * A data structure which is a combination of an array and a set. Adding a new - * member is O(1), testing for membership is O(1), and finding the index of an - * element is O(1). Removing elements from the set is not supported. Only - * strings are supported for membership. - */ -function ArraySet() { - this._array = []; - this._set = hasNativeMap ? new Map() : Object.create(null); -} +function decodeComponents(components, split) { + try { + // Try to decode the entire string first + return decodeURIComponent(components.join('')); + } catch (err) { + // Do nothing + } -/** - * Static method for creating ArraySet instances from an existing array. - */ -ArraySet.fromArray = function ArraySet_fromArray(aArray, aAllowDuplicates) { - var set = new ArraySet(); - for (var i = 0, len = aArray.length; i < len; i++) { - set.add(aArray[i], aAllowDuplicates); - } - return set; -}; + if (components.length === 1) { + return components; + } -/** - * Return how many unique items are in this ArraySet. If duplicates have been - * added, than those do not count towards the size. - * - * @returns Number - */ -ArraySet.prototype.size = function ArraySet_size() { - return hasNativeMap ? this._set.size : Object.getOwnPropertyNames(this._set).length; -}; + split = split || 1; -/** - * Add the given string to this set. - * - * @param String aStr - */ -ArraySet.prototype.add = function ArraySet_add(aStr, aAllowDuplicates) { - var sStr = hasNativeMap ? aStr : util.toSetString(aStr); - var isDuplicate = hasNativeMap ? this.has(aStr) : has.call(this._set, sStr); - var idx = this._array.length; - if (!isDuplicate || aAllowDuplicates) { - this._array.push(aStr); - } - if (!isDuplicate) { - if (hasNativeMap) { - this._set.set(aStr, idx); - } else { - this._set[sStr] = idx; - } - } -}; + // Split the array in 2 parts + var left = components.slice(0, split); + var right = components.slice(split); -/** - * Is the given string a member of this set? - * - * @param String aStr - */ -ArraySet.prototype.has = function ArraySet_has(aStr) { - if (hasNativeMap) { - return this._set.has(aStr); - } else { - var sStr = util.toSetString(aStr); - return has.call(this._set, sStr); - } -}; + return Array.prototype.concat.call([], decodeComponents(left), decodeComponents(right)); +} -/** - * What is the index of the given string in the array? - * - * @param String aStr - */ -ArraySet.prototype.indexOf = function ArraySet_indexOf(aStr) { - if (hasNativeMap) { - var idx = this._set.get(aStr); - if (idx >= 0) { - return idx; - } - } else { - var sStr = util.toSetString(aStr); - if (has.call(this._set, sStr)) { - return this._set[sStr]; - } - } +function decode(input) { + try { + return decodeURIComponent(input); + } catch (err) { + var tokens = input.match(singleMatcher); - throw new Error('"' + aStr + '" is not in the set.'); -}; + for (var i = 1; i < tokens.length; i++) { + input = decodeComponents(tokens, i).join(''); -/** - * What is the element at the given index? - * - * @param Number aIdx - */ -ArraySet.prototype.at = function ArraySet_at(aIdx) { - if (aIdx >= 0 && aIdx < this._array.length) { - return this._array[aIdx]; - } - throw new Error('No element indexed by ' + aIdx); -}; + tokens = input.match(singleMatcher); + } -/** - * Returns the array representation of this set (which has the proper indices - * indicated by indexOf). Note that this is a copy of the internal array used - * for storing the members so that no one can mess with internal state. - */ -ArraySet.prototype.toArray = function ArraySet_toArray() { - return this._array.slice(); -}; + return input; + } +} -exports.ArraySet = ArraySet; +function customDecodeURIComponent(input) { + // Keep track of all the replacements and prefill the map with the `BOM` + var replaceMap = { + '%FE%FF': '\uFFFD\uFFFD', + '%FF%FE': '\uFFFD\uFFFD' + }; + + var match = multiMatcher.exec(input); + while (match) { + try { + // Decode as big chunks as possible + replaceMap[match[0]] = decodeURIComponent(match[0]); + } catch (err) { + var result = decode(match[0]); + if (result !== match[0]) { + replaceMap[match[0]] = result; + } + } -/***/ }), -/* 813 */ -/***/ (function(module, exports, __webpack_require__) { + match = multiMatcher.exec(input); + } -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2014 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ + // Add `%C2` at the end of the map to make sure it does not replace the combinator before everything else + replaceMap['%C2'] = '\uFFFD'; -var util = __webpack_require__(811); + var entries = Object.keys(replaceMap); -/** - * Determine whether mappingB is after mappingA with respect to generated - * position. - */ -function generatedPositionAfter(mappingA, mappingB) { - // Optimized for most common case - var lineA = mappingA.generatedLine; - var lineB = mappingB.generatedLine; - var columnA = mappingA.generatedColumn; - var columnB = mappingB.generatedColumn; - return lineB > lineA || lineB == lineA && columnB >= columnA || - util.compareByGeneratedPositionsInflated(mappingA, mappingB) <= 0; -} + for (var i = 0; i < entries.length; i++) { + // Replace all decoded components + var key = entries[i]; + input = input.replace(new RegExp(key, 'g'), replaceMap[key]); + } -/** - * A data structure to provide a sorted view of accumulated mappings in a - * performance conscious manner. It trades a neglibable overhead in general - * case for a large speedup in case of mappings being added in order. - */ -function MappingList() { - this._array = []; - this._sorted = true; - // Serves as infimum - this._last = {generatedLine: -1, generatedColumn: 0}; + return input; } -/** - * Iterate through internal items. This method takes the same arguments that - * `Array.prototype.forEach` takes. - * - * NOTE: The order of the mappings is NOT guaranteed. - */ -MappingList.prototype.unsortedForEach = - function MappingList_forEach(aCallback, aThisArg) { - this._array.forEach(aCallback, aThisArg); - }; +module.exports = function (encodedURI) { + if (typeof encodedURI !== 'string') { + throw new TypeError('Expected `encodedURI` to be of type `string`, got `' + typeof encodedURI + '`'); + } -/** - * Add the given source mapping. - * - * @param Object aMapping - */ -MappingList.prototype.add = function MappingList_add(aMapping) { - if (generatedPositionAfter(this._last, aMapping)) { - this._last = aMapping; - this._array.push(aMapping); - } else { - this._sorted = false; - this._array.push(aMapping); - } -}; + try { + encodedURI = encodedURI.replace(/\+/g, ' '); -/** - * Returns the flat, sorted array of mappings. The mappings are sorted by - * generated position. - * - * WARNING: This method returns internal data without copying, for - * performance. The return value must NOT be mutated, and should be treated as - * an immutable borrow. If you want to take ownership, you must make your own - * copy. - */ -MappingList.prototype.toArray = function MappingList_toArray() { - if (!this._sorted) { - this._array.sort(util.compareByGeneratedPositionsInflated); - this._sorted = true; - } - return this._array; + // Try the built in decoder first + return decodeURIComponent(encodedURI); + } catch (err) { + // Fallback to a more advanced decoder + return customDecodeURIComponent(encodedURI); + } }; -exports.MappingList = MappingList; - /***/ }), -/* 814 */ +/* 818 */ /***/ (function(module, exports, __webpack_require__) { -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ +// Copyright 2014 Simon Lydell +// X11 (“MIT”) Licensed. (See LICENSE.) + +var path = __webpack_require__(16) + +"use strict" + +function urix(aPath) { + if (path.sep === "\\") { + return aPath + .replace(/\\/g, "/") + .replace(/^[a-z]:\/?/i, "/") + } + return aPath +} + +module.exports = urix -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; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } +/***/ }), +/* 819 */ +/***/ (function(module, exports, __webpack_require__) { - return sourceMap.sections != null - ? new IndexedSourceMapConsumer(sourceMap) - : new BasicSourceMapConsumer(sourceMap); -} +"use strict"; -SourceMapConsumer.fromSourceMap = function(aSourceMap) { - return BasicSourceMapConsumer.fromSourceMap(aSourceMap); -} -/** - * The version of the source mapping spec that we are consuming. - */ -SourceMapConsumer.prototype._version = 3; +function atob(str) { + return Buffer.from(str, 'base64').toString('binary'); +} -// `__generatedMappings` and `__originalMappings` are arrays that hold the -// parsed mapping coordinates from the source map's "mappings" attribute. They -// are lazily instantiated, accessed via the `_generatedMappings` and -// `_originalMappings` getters respectively, and we only parse the mappings -// and create these arrays once queried for a source location. We jump through -// these hoops because there can be many thousands of mappings, and parsing -// them is expensive, so we only want to do it if we must. -// -// Each object in the arrays is of the form: -// -// { -// generatedLine: The line number in the generated code, -// generatedColumn: The column number in the generated code, -// source: The path to the original source file that generated this -// chunk of code, -// originalLine: The line number in the original source that -// corresponds to this chunk of generated code, -// originalColumn: The column number in the original source that -// corresponds to this chunk of generated code, -// name: The name of the original symbol which generated this chunk of -// code. -// } -// -// All properties except for `generatedLine` and `generatedColumn` can be -// `null`. -// -// `_generatedMappings` is ordered by the generated positions. -// -// `_originalMappings` is ordered by the original positions. +module.exports = atob.atob = atob; -SourceMapConsumer.prototype.__generatedMappings = null; -Object.defineProperty(SourceMapConsumer.prototype, '_generatedMappings', { - get: function () { - if (!this.__generatedMappings) { - this._parseMappings(this._mappings, this.sourceRoot); - } - return this.__generatedMappings; - } -}); +/***/ }), +/* 820 */ +/***/ (function(module, exports, __webpack_require__) { -SourceMapConsumer.prototype.__originalMappings = null; -Object.defineProperty(SourceMapConsumer.prototype, '_originalMappings', { - get: function () { - if (!this.__originalMappings) { - this._parseMappings(this._mappings, this.sourceRoot); - } +"use strict"; - return this.__originalMappings; - } -}); -SourceMapConsumer.prototype._charIsMappingSeparator = - function SourceMapConsumer_charIsMappingSeparator(aStr, index) { - var c = aStr.charAt(index); - return c === ";" || c === ","; - }; +var fs = __webpack_require__(23); +var path = __webpack_require__(16); +var define = __webpack_require__(724); +var utils = __webpack_require__(801); /** - * Parse the mappings in a string in to a data structure which we can easily - * query (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). + * Expose `mixin()`. + * This code is based on `source-maps-support.js` in reworkcss/css + * https://github.com/reworkcss/css/blob/master/lib/stringify/source-map-support.js + * Copyright (c) 2012 TJ Holowaychuk */ -SourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - throw new Error("Subclasses must implement _parseMappings"); - }; - -SourceMapConsumer.GENERATED_ORDER = 1; -SourceMapConsumer.ORIGINAL_ORDER = 2; -SourceMapConsumer.GREATEST_LOWER_BOUND = 1; -SourceMapConsumer.LEAST_UPPER_BOUND = 2; +module.exports = mixin; /** - * Iterate over each mapping between an original source/line/column and a - * generated line/column in this source map. + * Mixin source map support into `compiler`. * - * @param Function aCallback - * The function that is called with each mapping. - * @param Object aContext - * Optional. If specified, this object will be the value of `this` every - * time that `aCallback` is called. - * @param aOrder - * Either `SourceMapConsumer.GENERATED_ORDER` or - * `SourceMapConsumer.ORIGINAL_ORDER`. Specifies whether you want to - * iterate over the mappings sorted by the generated file's line/column - * order or the original's source/line/column order, respectively. Defaults to - * `SourceMapConsumer.GENERATED_ORDER`. + * @param {Object} `compiler` + * @api public */ -SourceMapConsumer.prototype.eachMapping = - function SourceMapConsumer_eachMapping(aCallback, aContext, aOrder) { - var context = aContext || null; - var order = aOrder || SourceMapConsumer.GENERATED_ORDER; - var mappings; - switch (order) { - case SourceMapConsumer.GENERATED_ORDER: - mappings = this._generatedMappings; - break; - case SourceMapConsumer.ORIGINAL_ORDER: - mappings = this._originalMappings; - break; - default: - throw new Error("Unknown order of iteration."); - } +function mixin(compiler) { + define(compiler, '_comment', compiler.comment); + compiler.map = new utils.SourceMap.SourceMapGenerator(); + compiler.position = { line: 1, column: 1 }; + compiler.content = {}; + compiler.files = {}; - var sourceRoot = this.sourceRoot; - mappings.map(function (mapping) { - var source = mapping.source === null ? null : this._sources.at(mapping.source); - if (source != null && sourceRoot != null) { - source = util.join(sourceRoot, source); - } - return { - source: source, - generatedLine: mapping.generatedLine, - generatedColumn: mapping.generatedColumn, - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: mapping.name === null ? null : this._names.at(mapping.name) - }; - }, this).forEach(aCallback, context); - }; + for (var key in exports) { + define(compiler, key, exports[key]); + } +} /** - * Returns all generated line and column information for the original source, - * line, and column provided. If no column is provided, returns all mappings - * corresponding to a either the line we are searching for or the next - * closest line that has any mappings. Otherwise, returns all mappings - * corresponding to the given line and either the column we are searching for - * or the next closest column that has any offsets. - * - * The only argument is an object with the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: Optional. the column number in the original source. - * - * and an array of objects is returned, each with the following properties: + * Update position. * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. + * @param {String} str */ -SourceMapConsumer.prototype.allGeneratedPositionsFor = - function SourceMapConsumer_allGeneratedPositionsFor(aArgs) { - var line = util.getArg(aArgs, 'line'); - - // When there is no exact match, BasicSourceMapConsumer.prototype._findMapping - // returns the index of the closest mapping less than the needle. By - // setting needle.originalColumn to 0, we thus find the last mapping for - // the given line, provided such a mapping exists. - var needle = { - source: util.getArg(aArgs, 'source'), - originalLine: line, - originalColumn: util.getArg(aArgs, 'column', 0) - }; - - if (this.sourceRoot != null) { - needle.source = util.relative(this.sourceRoot, needle.source); - } - if (!this._sources.has(needle.source)) { - return []; - } - needle.source = this._sources.indexOf(needle.source); - var mappings = []; - - var index = this._findMapping(needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions, - binarySearch.LEAST_UPPER_BOUND); - if (index >= 0) { - var mapping = this._originalMappings[index]; - - if (aArgs.column === undefined) { - var originalLine = mapping.originalLine; - - // Iterate until either we run out of mappings, or we run into - // a mapping for a different line than the one we found. Since - // mappings are sorted, this is guaranteed to find all mappings for - // the line we found. - while (mapping && mapping.originalLine === originalLine) { - mappings.push({ - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }); - - mapping = this._originalMappings[++index]; - } - } else { - var originalColumn = mapping.originalColumn; - - // Iterate until either we run out of mappings, or we run into - // a mapping for a different line than the one we were searching for. - // Since mappings are sorted, this is guaranteed to find all mappings for - // the line we are searching for. - while (mapping && - mapping.originalLine === line && - mapping.originalColumn == originalColumn) { - mappings.push({ - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }); - - mapping = this._originalMappings[++index]; - } - } - } - - return mappings; - }; - -exports.SourceMapConsumer = SourceMapConsumer; +exports.updatePosition = function(str) { + var lines = str.match(/\n/g); + if (lines) this.position.line += lines.length; + var i = str.lastIndexOf('\n'); + this.position.column = ~i ? str.length - i : this.position.column + str.length; +}; /** - * A BasicSourceMapConsumer instance represents a parsed source map which we can - * query for information about the original file positions by giving it a file - * position in the generated source. - * - * The only parameter is the raw source map (either as a JSON string, or - * already parsed to an object). According to the spec, source maps have the - * following attributes: - * - * - version: Which version of the source map spec this map is following. - * - sources: An array of URLs to the original source files. - * - names: An array of identifiers which can be referrenced by individual mappings. - * - sourceRoot: Optional. The URL root from which all sources are relative. - * - sourcesContent: Optional. An array of contents of the original source files. - * - mappings: A string of base64 VLQs which contain the actual mappings. - * - file: Optional. The generated file this source map is associated with. - * - * Here is an example source map, taken from the source map spec[0]: - * - * { - * version : 3, - * file: "out.js", - * sourceRoot : "", - * sources: ["foo.js", "bar.js"], - * names: ["src", "maps", "are", "fun"], - * mappings: "AA,AB;;ABCDE;" - * } + * Emit `str` with `position`. * - * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?pli=1# + * @param {String} str + * @param {Object} [pos] + * @return {String} */ -function BasicSourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } - - var version = util.getArg(sourceMap, 'version'); - var sources = util.getArg(sourceMap, 'sources'); - // Sass 3.3 leaves out the 'names' array, so we deviate from the spec (which - // requires the array) to play nice here. - var names = util.getArg(sourceMap, 'names', []); - var sourceRoot = util.getArg(sourceMap, 'sourceRoot', null); - var sourcesContent = util.getArg(sourceMap, 'sourcesContent', null); - var mappings = util.getArg(sourceMap, 'mappings'); - var file = util.getArg(sourceMap, 'file', null); - // Once again, Sass deviates from the spec and supplies the version as a - // string rather than a number, so we use loose equality checking here. - if (version != this._version) { - throw new Error('Unsupported version: ' + version); - } +exports.emit = function(str, node) { + var position = node.position || {}; + var source = position.source; + if (source) { + if (position.filepath) { + source = utils.unixify(position.filepath); + } - sources = sources - .map(String) - // Some source maps produce relative source paths like "./foo.js" instead of - // "foo.js". Normalize these first so that future comparisons will succeed. - // See bugzil.la/1090768. - .map(util.normalize) - // Always ensure that absolute sources are internally stored relative to - // the source root, if the source root is absolute. Not doing this would - // be particularly problematic when the source root is a prefix of the - // source (valid, but why??). See github issue #199 and bugzil.la/1188982. - .map(function (source) { - return sourceRoot && util.isAbsolute(sourceRoot) && util.isAbsolute(source) - ? util.relative(sourceRoot, source) - : source; + this.map.addMapping({ + source: source, + generated: { + line: this.position.line, + column: Math.max(this.position.column - 1, 0) + }, + original: { + line: position.start.line, + column: position.start.column - 1 + } }); - // Pass `true` below to allow duplicate names and sources. While source maps - // are intended to be compressed and deduplicated, the TypeScript compiler - // sometimes generates source maps with duplicates in them. See Github issue - // #72 and bugzil.la/889492. - this._names = ArraySet.fromArray(names.map(String), true); - this._sources = ArraySet.fromArray(sources, true); - - this.sourceRoot = sourceRoot; - this.sourcesContent = sourcesContent; - this._mappings = mappings; - this.file = file; -} + if (position.content) { + this.addContent(source, position); + } + if (position.filepath) { + this.addFile(source, position); + } -BasicSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); -BasicSourceMapConsumer.prototype.consumer = SourceMapConsumer; + this.updatePosition(str); + this.output += str; + } + return str; +}; /** - * Create a BasicSourceMapConsumer from a SourceMapGenerator. - * - * @param SourceMapGenerator aSourceMap - * The source map that will be consumed. - * @returns BasicSourceMapConsumer + * Adds a file to the source map output if it has not already been added + * @param {String} `file` + * @param {Object} `pos` */ -BasicSourceMapConsumer.fromSourceMap = - function SourceMapConsumer_fromSourceMap(aSourceMap) { - var smc = Object.create(BasicSourceMapConsumer.prototype); - var names = smc._names = ArraySet.fromArray(aSourceMap._names.toArray(), true); - var sources = smc._sources = ArraySet.fromArray(aSourceMap._sources.toArray(), true); - smc.sourceRoot = aSourceMap._sourceRoot; - smc.sourcesContent = aSourceMap._generateSourcesContent(smc._sources.toArray(), - smc.sourceRoot); - smc.file = aSourceMap._file; - - // Because we are modifying the entries (by converting string sources and - // names to indices into the sources and names ArraySets), we have to make - // a copy of the entry or else bad things happen. Shared mutable state - // strikes again! See github issue #191. +exports.addFile = function(file, position) { + if (typeof position.content !== 'string') return; + if (Object.prototype.hasOwnProperty.call(this.files, file)) return; + this.files[file] = position.content; +}; - var generatedMappings = aSourceMap._mappings.toArray().slice(); - var destGeneratedMappings = smc.__generatedMappings = []; - var destOriginalMappings = smc.__originalMappings = []; +/** + * Adds a content source to the source map output if it has not already been added + * @param {String} `source` + * @param {Object} `position` + */ - for (var i = 0, length = generatedMappings.length; i < length; i++) { - var srcMapping = generatedMappings[i]; - var destMapping = new Mapping; - destMapping.generatedLine = srcMapping.generatedLine; - destMapping.generatedColumn = srcMapping.generatedColumn; +exports.addContent = function(source, position) { + if (typeof position.content !== 'string') return; + if (Object.prototype.hasOwnProperty.call(this.content, source)) return; + this.map.setSourceContent(source, position.content); +}; - if (srcMapping.source) { - destMapping.source = sources.indexOf(srcMapping.source); - destMapping.originalLine = srcMapping.originalLine; - destMapping.originalColumn = srcMapping.originalColumn; +/** + * Applies any original source maps to the output and embeds the source file + * contents in the source map. + */ - if (srcMapping.name) { - destMapping.name = names.indexOf(srcMapping.name); - } +exports.applySourceMaps = function() { + Object.keys(this.files).forEach(function(file) { + var content = this.files[file]; + this.map.setSourceContent(file, content); - destOriginalMappings.push(destMapping); + if (this.options.inputSourcemaps === true) { + var originalMap = utils.sourceMapResolve.resolveSync(content, file, fs.readFileSync); + if (originalMap) { + var map = new utils.SourceMap.SourceMapConsumer(originalMap.map); + var relativeTo = originalMap.sourcesRelativeTo; + this.map.applySourceMap(map, file, utils.unixify(path.dirname(relativeTo))); } - - destGeneratedMappings.push(destMapping); } - - quickSort(smc.__originalMappings, util.compareByOriginalPositions); - - return smc; - }; + }, this); +}; /** - * The version of the source mapping spec that we are consuming. + * Process comments, drops sourceMap comments. + * @param {Object} node */ -BasicSourceMapConsumer.prototype._version = 3; -/** - * The list of original sources. - */ -Object.defineProperty(BasicSourceMapConsumer.prototype, 'sources', { - get: function () { - return this._sources.toArray().map(function (s) { - return this.sourceRoot != null ? util.join(this.sourceRoot, s) : s; - }, this); +exports.comment = function(node) { + if (/^# sourceMappingURL=/.test(node.comment)) { + return this.emit('', node.position); } -}); + return this._comment(node); +}; + + +/***/ }), +/* 821 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var use = __webpack_require__(793); +var util = __webpack_require__(29); +var Cache = __webpack_require__(822); +var define = __webpack_require__(724); +var debug = __webpack_require__(795)('snapdragon:parser'); +var Position = __webpack_require__(823); +var utils = __webpack_require__(801); /** - * Provide the JIT with a nice shape / hidden class. + * Create a new `Parser` with the given `input` and `options`. + * @param {String} `input` + * @param {Object} `options` + * @api public */ -function Mapping() { - this.generatedLine = 0; - this.generatedColumn = 0; - this.source = null; - this.originalLine = null; - this.originalColumn = null; - this.name = null; + +function Parser(options) { + debug('initializing', __filename); + this.options = utils.extend({source: 'string'}, options); + this.init(this.options); + use(this); } /** - * Parse the mappings in a string in to a data structure which we can easily - * query (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). + * Prototype methods */ -BasicSourceMapConsumer.prototype._parseMappings = - function SourceMapConsumer_parseMappings(aStr, aSourceRoot) { - var generatedLine = 1; - var previousGeneratedColumn = 0; - var previousOriginalLine = 0; - var previousOriginalColumn = 0; - var previousSource = 0; - var previousName = 0; - var length = aStr.length; - var index = 0; - var cachedSegments = {}; - var temp = {}; - var originalMappings = []; - var generatedMappings = []; - var mapping, str, segment, end, value; - while (index < length) { - if (aStr.charAt(index) === ';') { - generatedLine++; - index++; - previousGeneratedColumn = 0; - } - else if (aStr.charAt(index) === ',') { - index++; - } - else { - mapping = new Mapping(); - mapping.generatedLine = generatedLine; +Parser.prototype = { + constructor: Parser, - // Because each offset is encoded relative to the previous one, - // many segments often have the same encoding. We can exploit this - // fact by caching the parsed variable length fields of each segment, - // allowing us to avoid a second parse if we encounter the same - // segment again. - for (end = index; end < length; end++) { - if (this._charIsMappingSeparator(aStr, end)) { - break; - } - } - str = aStr.slice(index, end); + init: function(options) { + this.orig = ''; + this.input = ''; + this.parsed = ''; - segment = cachedSegments[str]; - if (segment) { - index += str.length; - } else { - segment = []; - while (index < end) { - base64VLQ.decode(aStr, index, temp); - value = temp.value; - index = temp.rest; - segment.push(value); - } + this.column = 1; + this.line = 1; - if (segment.length === 2) { - throw new Error('Found a source, but no line and column'); - } + this.regex = new Cache(); + this.errors = this.errors || []; + this.parsers = this.parsers || {}; + this.types = this.types || []; + this.sets = this.sets || {}; + this.fns = this.fns || []; + this.currentType = 'root'; - if (segment.length === 3) { - throw new Error('Found a source and line, but no column'); - } + var pos = this.position(); + this.bos = pos({type: 'bos', val: ''}); - cachedSegments[str] = segment; - } + this.ast = { + type: 'root', + errors: this.errors, + nodes: [this.bos] + }; - // Generated column. - mapping.generatedColumn = previousGeneratedColumn + segment[0]; - previousGeneratedColumn = mapping.generatedColumn; + define(this.bos, 'parent', this.ast); + this.nodes = [this.ast]; - if (segment.length > 1) { - // Original source. - mapping.source = previousSource + segment[1]; - previousSource += segment[1]; + this.count = 0; + this.setCount = 0; + this.stack = []; + }, - // Original line. - mapping.originalLine = previousOriginalLine + segment[2]; - previousOriginalLine = mapping.originalLine; - // Lines are stored 0-based - mapping.originalLine += 1; + /** + * Throw a formatted error with the cursor column and `msg`. + * @param {String} `msg` Message to use in the Error. + */ - // Original column. - mapping.originalColumn = previousOriginalColumn + segment[3]; - previousOriginalColumn = mapping.originalColumn; + error: function(msg, node) { + var pos = node.position || {start: {column: 0, line: 0}}; + var line = pos.start.line; + var column = pos.start.column; + var source = this.options.source; - if (segment.length > 4) { - // Original name. - mapping.name = previousName + segment[4]; - previousName += segment[4]; - } - } + var message = source + ' : ' + msg; + var err = new Error(message); + err.source = source; + err.reason = msg; + err.pos = pos; - generatedMappings.push(mapping); - if (typeof mapping.originalLine === 'number') { - originalMappings.push(mapping); - } - } + if (this.options.silent) { + this.errors.push(err); + } else { + throw err; } + }, - quickSort(generatedMappings, util.compareByGeneratedPositionsDeflated); - this.__generatedMappings = generatedMappings; + /** + * Define a non-enumberable property on the `Parser` instance. + * + * ```js + * parser.define('foo', 'bar'); + * ``` + * @name .define + * @param {String} `key` propery name + * @param {any} `val` property value + * @return {Object} Returns the Parser instance for chaining. + * @api public + */ - quickSort(originalMappings, util.compareByOriginalPositions); - this.__originalMappings = originalMappings; - }; + define: function(key, val) { + define(this, key, val); + return this; + }, -/** - * Find the mapping that best matches the hypothetical "needle" mapping that - * we are searching for in the given "haystack" of mappings. - */ -BasicSourceMapConsumer.prototype._findMapping = - function SourceMapConsumer_findMapping(aNeedle, aMappings, aLineName, - aColumnName, aComparator, aBias) { - // To return the position we are searching for, we must first find the - // mapping for the given position and then return the opposite position it - // points to. Because the mappings are sorted, we can use binary search to - // find the best mapping. + /** + * Mark position and patch `node.position`. + */ - if (aNeedle[aLineName] <= 0) { - throw new TypeError('Line must be greater than or equal to 1, got ' - + aNeedle[aLineName]); - } - if (aNeedle[aColumnName] < 0) { - throw new TypeError('Column must be greater than or equal to 0, got ' - + aNeedle[aColumnName]); + position: function() { + var start = { line: this.line, column: this.column }; + var self = this; + + return function(node) { + define(node, 'position', new Position(start, self)); + return node; + }; + }, + + /** + * Set parser `name` with the given `fn` + * @param {String} `name` + * @param {Function} `fn` + * @api public + */ + + set: function(type, fn) { + if (this.types.indexOf(type) === -1) { + this.types.push(type); } + this.parsers[type] = fn.bind(this); + return this; + }, - return binarySearch.search(aNeedle, aMappings, aComparator, aBias); - }; + /** + * Get parser `name` + * @param {String} `name` + * @api public + */ -/** - * Compute the last column for each generated mapping. The last column is - * inclusive. - */ -BasicSourceMapConsumer.prototype.computeColumnSpans = - function SourceMapConsumer_computeColumnSpans() { - for (var index = 0; index < this._generatedMappings.length; ++index) { - var mapping = this._generatedMappings[index]; + get: function(name) { + return this.parsers[name]; + }, - // Mappings do not contain a field for the last generated columnt. We - // can come up with an optimistic estimate, however, by assuming that - // mappings are contiguous (i.e. given two consecutive mappings, the - // first mapping ends where the second one starts). - if (index + 1 < this._generatedMappings.length) { - var nextMapping = this._generatedMappings[index + 1]; + /** + * Push a `token` onto the `type` stack. + * + * @param {String} `type` + * @return {Object} `token` + * @api public + */ - if (mapping.generatedLine === nextMapping.generatedLine) { - mapping.lastGeneratedColumn = nextMapping.generatedColumn - 1; - continue; - } - } + push: function(type, token) { + this.sets[type] = this.sets[type] || []; + this.count++; + this.stack.push(token); + return this.sets[type].push(token); + }, - // The last mapping for each line spans the entire line. - mapping.lastGeneratedColumn = Infinity; - } - }; + /** + * Pop a token off of the `type` stack + * @param {String} `type` + * @returns {Object} Returns a token + * @api public + */ -/** - * Returns the original source, line, and column information for the generated - * source's line and column positions provided. The only argument is an object - * with the following properties: - * - * - line: The line number in the generated source. - * - column: The column number in the generated source. - * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or - * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. - * - * and an object is returned with the following properties: - * - * - source: The original source file, or null. - * - line: The line number in the original source, or null. - * - column: The column number in the original source, or null. - * - name: The original identifier, or null. - */ -BasicSourceMapConsumer.prototype.originalPositionFor = - function SourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; + pop: function(type) { + this.sets[type] = this.sets[type] || []; + this.count--; + this.stack.pop(); + return this.sets[type].pop(); + }, - var index = this._findMapping( - needle, - this._generatedMappings, - "generatedLine", - "generatedColumn", - util.compareByGeneratedPositionsDeflated, - util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) - ); + /** + * Return true if inside a `stack` node. Types are `braces`, `parens` or `brackets`. + * + * @param {String} `type` + * @return {Boolean} + * @api public + */ - if (index >= 0) { - var mapping = this._generatedMappings[index]; + isInside: function(type) { + this.sets[type] = this.sets[type] || []; + return this.sets[type].length > 0; + }, - if (mapping.generatedLine === needle.generatedLine) { - var source = util.getArg(mapping, 'source', null); - if (source !== null) { - source = this._sources.at(source); - if (this.sourceRoot != null) { - source = util.join(this.sourceRoot, source); - } - } - var name = util.getArg(mapping, 'name', null); - if (name !== null) { - name = this._names.at(name); - } - return { - source: source, - line: util.getArg(mapping, 'originalLine', null), - column: util.getArg(mapping, 'originalColumn', null), - name: name - }; - } - } + /** + * Return true if `node` is the given `type`. + * + * ```js + * parser.isType(node, 'brace'); + * ``` + * @param {Object} `node` + * @param {String} `type` + * @return {Boolean} + * @api public + */ - return { - source: null, - line: null, - column: null, - name: null - }; - }; + isType: function(node, type) { + return node && node.type === type; + }, -/** - * Return true if we have the source content for every source in the source - * map, false otherwise. - */ -BasicSourceMapConsumer.prototype.hasContentsOfAllSources = - function BasicSourceMapConsumer_hasContentsOfAllSources() { - if (!this.sourcesContent) { - return false; + /** + * Get the previous AST node + * @return {Object} + */ + + prev: function(n) { + return this.stack.length > 0 + ? utils.last(this.stack, n) + : utils.last(this.nodes, n); + }, + + /** + * Update line and column based on `str`. + */ + + consume: function(len) { + this.input = this.input.substr(len); + }, + + /** + * Update column based on `str`. + */ + + updatePosition: function(str, len) { + var lines = str.match(/\n/g); + if (lines) this.line += lines.length; + var i = str.lastIndexOf('\n'); + this.column = ~i ? len - i : this.column + len; + this.parsed += str; + this.consume(len); + }, + + /** + * Match `regex`, return captures, and update the cursor position by `match[0]` length. + * @param {RegExp} `regex` + * @return {Object} + */ + + match: function(regex) { + var m = regex.exec(this.input); + if (m) { + this.updatePosition(m[0], m[0].length); + return m; } - return this.sourcesContent.length >= this._sources.size() && - !this.sourcesContent.some(function (sc) { return sc == null; }); - }; + }, -/** - * Returns the original source content. The only argument is the url of the - * original source file. Returns null if no original source content is - * available. - */ -BasicSourceMapConsumer.prototype.sourceContentFor = - function SourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { - if (!this.sourcesContent) { - return null; + /** + * Capture `type` with the given regex. + * @param {String} `type` + * @param {RegExp} `regex` + * @return {Function} + */ + + capture: function(type, regex) { + if (typeof regex === 'function') { + return this.set.apply(this, arguments); } - if (this.sourceRoot != null) { - aSource = util.relative(this.sourceRoot, aSource); - } + this.regex.set(type, regex); + this.set(type, function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(regex); + if (!m || !m[0]) return; - if (this._sources.has(aSource)) { - return this.sourcesContent[this._sources.indexOf(aSource)]; - } + var prev = this.prev(); + var node = pos({ + type: type, + val: m[0], + parsed: parsed, + rest: this.input + }); - var url; - if (this.sourceRoot != null - && (url = util.urlParse(this.sourceRoot))) { - // XXX: file:// URIs and absolute paths lead to unexpected behavior for - // many users. We can help them out when they expect file:// URIs to - // behave like it would if they were running a local HTTP server. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=885597. - var fileUriAbsPath = aSource.replace(/^file:\/\//, ""); - if (url.scheme == "file" - && this._sources.has(fileUriAbsPath)) { - return this.sourcesContent[this._sources.indexOf(fileUriAbsPath)] + if (m[1]) { + node.inner = m[1]; } - if ((!url.path || url.path == "/") - && this._sources.has("/" + aSource)) { - return this.sourcesContent[this._sources.indexOf("/" + aSource)]; - } - } + define(node, 'inside', this.stack.length > 0); + define(node, 'parent', prev); + prev.nodes.push(node); + }.bind(this)); + return this; + }, - // This function is used recursively from - // IndexedSourceMapConsumer.prototype.sourceContentFor. In that case, we - // don't want to throw if we can't find the source - we just want to - // return null, so we provide a flag to exit gracefully. - if (nullOnMissing) { - return null; - } - else { - throw new Error('"' + aSource + '" is not in the SourceMap.'); - } - }; + /** + * Create a parser with open and close for parens, + * brackets or braces + */ -/** - * Returns the generated line and column information for the original source, - * line, and column positions provided. The only argument is an object with - * the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: The column number in the original source. - * - bias: Either 'SourceMapConsumer.GREATEST_LOWER_BOUND' or - * 'SourceMapConsumer.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - * Defaults to 'SourceMapConsumer.GREATEST_LOWER_BOUND'. - * - * and an object is returned with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ -BasicSourceMapConsumer.prototype.generatedPositionFor = - function SourceMapConsumer_generatedPositionFor(aArgs) { - var source = util.getArg(aArgs, 'source'); - if (this.sourceRoot != null) { - source = util.relative(this.sourceRoot, source); - } - if (!this._sources.has(source)) { - return { - line: null, - column: null, - lastColumn: null - }; - } - source = this._sources.indexOf(source); + capturePair: function(type, openRegex, closeRegex, fn) { + this.sets[type] = this.sets[type] || []; - var needle = { - source: source, - originalLine: util.getArg(aArgs, 'line'), - originalColumn: util.getArg(aArgs, 'column') - }; + /** + * Open + */ - var index = this._findMapping( - needle, - this._originalMappings, - "originalLine", - "originalColumn", - util.compareByOriginalPositions, - util.getArg(aArgs, 'bias', SourceMapConsumer.GREATEST_LOWER_BOUND) - ); + this.set(type + '.open', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(openRegex); + if (!m || !m[0]) return; - if (index >= 0) { - var mapping = this._originalMappings[index]; + var val = m[0]; + this.setCount++; + this.specialChars = true; + var open = pos({ + type: type + '.open', + val: val, + rest: this.input + }); - if (mapping.source === needle.source) { - return { - line: util.getArg(mapping, 'generatedLine', null), - column: util.getArg(mapping, 'generatedColumn', null), - lastColumn: util.getArg(mapping, 'lastGeneratedColumn', null) - }; + if (typeof m[1] !== 'undefined') { + open.inner = m[1]; } - } - return { - line: null, - column: null, - lastColumn: null - }; - }; + var prev = this.prev(); + var node = pos({ + type: type, + nodes: [open] + }); -exports.BasicSourceMapConsumer = BasicSourceMapConsumer; + define(node, 'rest', this.input); + define(node, 'parsed', parsed); + define(node, 'prefix', m[1]); + define(node, 'parent', prev); + define(open, 'parent', node); -/** - * An IndexedSourceMapConsumer instance represents a parsed source map which - * we can query for information. It differs from BasicSourceMapConsumer in - * that it takes "indexed" source maps (i.e. ones with a "sections" field) as - * input. - * - * The only parameter is a raw source map (either as a JSON string, or already - * parsed to an object). According to the spec for indexed source maps, they - * have the following attributes: - * - * - version: Which version of the source map spec this map is following. - * - file: Optional. The generated file this source map is associated with. - * - sections: A list of section definitions. - * - * Each value under the "sections" field has two fields: - * - offset: The offset into the original specified at which this section - * begins to apply, defined as an object with a "line" and "column" - * field. - * - map: A source map definition. This source map could also be indexed, - * but doesn't have to be. - * - * Instead of the "map" field, it's also possible to have a "url" field - * specifying a URL to retrieve a source map from, but that's currently - * unsupported. - * - * Here's an example source map, taken from the source map spec[0], but - * modified to omit a section which uses the "url" field. - * - * { - * version : 3, - * file: "app.js", - * sections: [{ - * offset: {line:100, column:10}, - * map: { - * version : 3, - * file: "section.js", - * sources: ["foo.js", "bar.js"], - * names: ["src", "maps", "are", "fun"], - * mappings: "AAAA,E;;ABCDE;" - * } - * }], - * } - * - * [0]: https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit#heading=h.535es3xeprgt - */ -function IndexedSourceMapConsumer(aSourceMap) { - var sourceMap = aSourceMap; - if (typeof aSourceMap === 'string') { - sourceMap = JSON.parse(aSourceMap.replace(/^\)\]\}'/, '')); - } + if (typeof fn === 'function') { + fn.call(this, open, node); + } - var version = util.getArg(sourceMap, 'version'); - var sections = util.getArg(sourceMap, 'sections'); + this.push(type, node); + prev.nodes.push(node); + }); - if (version != this._version) { - throw new Error('Unsupported version: ' + version); - } + /** + * Close + */ - this._sources = new ArraySet(); - this._names = new ArraySet(); + this.set(type + '.close', function() { + var pos = this.position(); + var m = this.match(closeRegex); + if (!m || !m[0]) return; - var lastOffset = { - line: -1, - column: 0 - }; - this._sections = sections.map(function (s) { - if (s.url) { - // The url field will require support for asynchronicity. - // See https://github.com/mozilla/source-map/issues/16 - throw new Error('Support for url field in sections not implemented.'); - } - var offset = util.getArg(s, 'offset'); - var offsetLine = util.getArg(offset, 'line'); - var offsetColumn = util.getArg(offset, 'column'); + var parent = this.pop(type); + var node = pos({ + type: type + '.close', + rest: this.input, + suffix: m[1], + val: m[0] + }); - if (offsetLine < lastOffset.line || - (offsetLine === lastOffset.line && offsetColumn < lastOffset.column)) { - throw new Error('Section offsets must be ordered and non-overlapping.'); - } - lastOffset = offset; + if (!this.isType(parent, type)) { + if (this.options.strict) { + throw new Error('missing opening "' + type + '"'); + } - return { - generatedOffset: { - // The offset fields are 0-based, but we use 1-based indices when - // encoding/decoding from VLQ. - generatedLine: offsetLine + 1, - generatedColumn: offsetColumn + 1 - }, - consumer: new SourceMapConsumer(util.getArg(s, 'map')) - } - }); -} + this.setCount--; + node.escaped = true; + return node; + } -IndexedSourceMapConsumer.prototype = Object.create(SourceMapConsumer.prototype); -IndexedSourceMapConsumer.prototype.constructor = SourceMapConsumer; + if (node.suffix === '\\') { + parent.escaped = true; + node.escaped = true; + } -/** - * The version of the source mapping spec that we are consuming. - */ -IndexedSourceMapConsumer.prototype._version = 3; + parent.nodes.push(node); + define(node, 'parent', parent); + }); -/** - * The list of original sources. - */ -Object.defineProperty(IndexedSourceMapConsumer.prototype, 'sources', { - get: function () { - var sources = []; - for (var i = 0; i < this._sections.length; i++) { - for (var j = 0; j < this._sections[i].consumer.sources.length; j++) { - sources.push(this._sections[i].consumer.sources[j]); + return this; + }, + + /** + * Capture end-of-string + */ + + eos: function() { + var pos = this.position(); + if (this.input) return; + var prev = this.prev(); + + while (prev.type !== 'root' && !prev.visited) { + if (this.options.strict === true) { + throw new SyntaxError('invalid syntax:' + util.inspect(prev, null, 2)); } - } - return sources; - } -}); -/** - * Returns the original source, line, and column information for the generated - * source's line and column positions provided. The only argument is an object - * with the following properties: - * - * - line: The line number in the generated source. - * - column: The column number in the generated source. - * - * and an object is returned with the following properties: - * - * - source: The original source file, or null. - * - line: The line number in the original source, or null. - * - column: The column number in the original source, or null. - * - name: The original identifier, or null. - */ -IndexedSourceMapConsumer.prototype.originalPositionFor = - function IndexedSourceMapConsumer_originalPositionFor(aArgs) { - var needle = { - generatedLine: util.getArg(aArgs, 'line'), - generatedColumn: util.getArg(aArgs, 'column') - }; + if (!hasDelims(prev)) { + prev.parent.escaped = true; + prev.escaped = true; + } - // Find the section containing the generated position we're trying to map - // to an original position. - var sectionIndex = binarySearch.search(needle, this._sections, - function(needle, section) { - var cmp = needle.generatedLine - section.generatedOffset.generatedLine; - if (cmp) { - return cmp; + visit(prev, function(node) { + if (!hasDelims(node.parent)) { + node.parent.escaped = true; + node.escaped = true; } - - return (needle.generatedColumn - - section.generatedOffset.generatedColumn); }); - var section = this._sections[sectionIndex]; - if (!section) { - return { - source: null, - line: null, - column: null, - name: null - }; + prev = prev.parent; } - return section.consumer.originalPositionFor({ - line: needle.generatedLine - - (section.generatedOffset.generatedLine - 1), - column: needle.generatedColumn - - (section.generatedOffset.generatedLine === needle.generatedLine - ? section.generatedOffset.generatedColumn - 1 - : 0), - bias: aArgs.bias - }); - }; - -/** - * Return true if we have the source content for every source in the source - * map, false otherwise. - */ -IndexedSourceMapConsumer.prototype.hasContentsOfAllSources = - function IndexedSourceMapConsumer_hasContentsOfAllSources() { - return this._sections.every(function (s) { - return s.consumer.hasContentsOfAllSources(); + var tok = pos({ + type: 'eos', + val: this.append || '' }); - }; -/** - * Returns the original source content. The only argument is the url of the - * original source file. Returns null if no original source content is - * available. - */ -IndexedSourceMapConsumer.prototype.sourceContentFor = - function IndexedSourceMapConsumer_sourceContentFor(aSource, nullOnMissing) { - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; + define(tok, 'parent', this.ast); + return tok; + }, - var content = section.consumer.sourceContentFor(aSource, true); - if (content) { - return content; - } - } - if (nullOnMissing) { - return null; - } - else { - throw new Error('"' + aSource + '" is not in the SourceMap.'); - } - }; + /** + * Run parsers to advance the cursor position + */ -/** - * Returns the generated line and column information for the original source, - * line, and column positions provided. The only argument is an object with - * the following properties: - * - * - source: The filename of the original source. - * - line: The line number in the original source. - * - column: The column number in the original source. - * - * and an object is returned with the following properties: - * - * - line: The line number in the generated source, or null. - * - column: The column number in the generated source, or null. - */ -IndexedSourceMapConsumer.prototype.generatedPositionFor = - function IndexedSourceMapConsumer_generatedPositionFor(aArgs) { - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; + next: function() { + var parsed = this.parsed; + var len = this.types.length; + var idx = -1; + var tok; - // Only consider this section if the requested source is in the list of - // sources of the consumer. - if (section.consumer.sources.indexOf(util.getArg(aArgs, 'source')) === -1) { - continue; - } - var generatedPosition = section.consumer.generatedPositionFor(aArgs); - if (generatedPosition) { - var ret = { - line: generatedPosition.line + - (section.generatedOffset.generatedLine - 1), - column: generatedPosition.column + - (section.generatedOffset.generatedLine === generatedPosition.line - ? section.generatedOffset.generatedColumn - 1 - : 0) - }; - return ret; + while (++idx < len) { + if ((tok = this.parsers[this.types[idx]].call(this))) { + define(tok, 'rest', this.input); + define(tok, 'parsed', parsed); + this.last = tok; + return tok; } } + }, - return { - line: null, - column: null - }; - }; + /** + * Parse the given string. + * @return {Array} + */ -/** - * Parse the mappings in a string in to a data structure which we can easily - * query (the ordered arrays in the `this.__generatedMappings` and - * `this.__originalMappings` properties). - */ -IndexedSourceMapConsumer.prototype._parseMappings = - function IndexedSourceMapConsumer_parseMappings(aStr, aSourceRoot) { - this.__generatedMappings = []; - this.__originalMappings = []; - for (var i = 0; i < this._sections.length; i++) { - var section = this._sections[i]; - var sectionMappings = section.consumer._generatedMappings; - for (var j = 0; j < sectionMappings.length; j++) { - var mapping = sectionMappings[j]; + parse: function(input) { + if (typeof input !== 'string') { + throw new TypeError('expected a string'); + } - var source = section.consumer._sources.at(mapping.source); - if (section.consumer.sourceRoot !== null) { - source = util.join(section.consumer.sourceRoot, source); - } - this._sources.add(source); - source = this._sources.indexOf(source); + this.init(this.options); + this.orig = input; + this.input = input; + var self = this; - var name = section.consumer._names.at(mapping.name); - this._names.add(name); - name = this._names.indexOf(name); + function parse() { + // check input before calling `.next()` + input = self.input; - // The mappings coming from the consumer for the section have - // generated positions relative to the start of the section, so we - // need to offset them to be relative to the start of the concatenated - // generated file. - var adjustedMapping = { - source: source, - generatedLine: mapping.generatedLine + - (section.generatedOffset.generatedLine - 1), - generatedColumn: mapping.generatedColumn + - (section.generatedOffset.generatedLine === mapping.generatedLine - ? section.generatedOffset.generatedColumn - 1 - : 0), - originalLine: mapping.originalLine, - originalColumn: mapping.originalColumn, - name: name - }; + // get the next AST ndoe + var node = self.next(); + if (node) { + var prev = self.prev(); + if (prev) { + define(node, 'parent', prev); + if (prev.nodes) { + prev.nodes.push(node); + } + } - this.__generatedMappings.push(adjustedMapping); - if (typeof adjustedMapping.originalLine === 'number') { - this.__originalMappings.push(adjustedMapping); + if (self.sets.hasOwnProperty(prev.type)) { + self.currentType = prev.type; } } - } - quickSort(this.__generatedMappings, util.compareByGeneratedPositionsDeflated); - quickSort(this.__originalMappings, util.compareByOriginalPositions); - }; + // if we got here but input is not changed, throw an error + if (self.input && input === self.input) { + throw new Error('no parsers registered for: "' + self.input.slice(0, 5) + '"'); + } + } -exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; + while (this.input) parse(); + if (this.stack.length && this.options.strict) { + var node = this.stack.pop(); + throw this.error('missing opening ' + node.type + ': "' + this.orig + '"'); + } + var eos = this.eos(); + var tok = this.prev(); + if (tok.type !== 'eos') { + this.ast.nodes.push(eos); + } -/***/ }), -/* 815 */ -/***/ (function(module, exports) { + return this.ast; + } +}; -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause +/** + * Visit `node` with the given `fn` */ -exports.GREATEST_LOWER_BOUND = 1; -exports.LEAST_UPPER_BOUND = 2; +function visit(node, fn) { + if (!node.visited) { + define(node, 'visited', true); + return node.nodes ? mapVisit(node.nodes, fn) : fn(node); + } + return node; +} /** - * Recursive implementation of binary search. - * - * @param aLow Indices here and lower do not contain the needle. - * @param aHigh Indices here and higher do not contain the needle. - * @param aNeedle The element being searched for. - * @param aHaystack The non-empty array being searched. - * @param aCompare Function which takes two elements and returns -1, 0, or 1. - * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or - * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. + * Map visit over array of `nodes`. */ -function recursiveSearch(aLow, aHigh, aNeedle, aHaystack, aCompare, aBias) { - // This function terminates when one of the following is true: - // - // 1. We find the exact element we are looking for. - // - // 2. We did not find the exact element, but we can return the index of - // the next-closest element. - // - // 3. We did not find the exact element, and there is no next-closest - // element than the one we are searching for, so we return -1. - var mid = Math.floor((aHigh - aLow) / 2) + aLow; - var cmp = aCompare(aNeedle, aHaystack[mid], true); - if (cmp === 0) { - // Found the element we are looking for. - return mid; - } - else if (cmp > 0) { - // Our needle is greater than aHaystack[mid]. - if (aHigh - mid > 1) { - // The element is in the upper half. - return recursiveSearch(mid, aHigh, aNeedle, aHaystack, aCompare, aBias); - } - // The exact needle element was not found in this haystack. Determine if - // we are in termination case (3) or (2) and return the appropriate thing. - if (aBias == exports.LEAST_UPPER_BOUND) { - return aHigh < aHaystack.length ? aHigh : -1; - } else { - return mid; - } +function mapVisit(nodes, fn) { + var len = nodes.length; + var idx = -1; + while (++idx < len) { + visit(nodes[idx], fn); } - else { - // Our needle is less than aHaystack[mid]. - if (mid - aLow > 1) { - // The element is in the lower half. - return recursiveSearch(aLow, mid, aNeedle, aHaystack, aCompare, aBias); - } +} - // we are in termination case (3) or (2) and return the appropriate thing. - if (aBias == exports.LEAST_UPPER_BOUND) { - return mid; - } else { - return aLow < 0 ? -1 : aLow; - } - } +function hasOpen(node) { + return node.nodes && node.nodes[0].type === (node.type + '.open'); } -/** - * This is an implementation of binary search which will always try and return - * the index of the closest element if there is no exact hit. This is because - * mappings between original and generated line/col pairs are single points, - * and there is an implicit region between each of them, so a miss just means - * that you aren't on the very start of a region. - * - * @param aNeedle The element you are looking for. - * @param aHaystack The array that is being searched. - * @param aCompare A function which takes the needle and an element in the - * array and returns -1, 0, or 1 depending on whether the needle is less - * than, equal to, or greater than the element, respectively. - * @param aBias Either 'binarySearch.GREATEST_LOWER_BOUND' or - * 'binarySearch.LEAST_UPPER_BOUND'. Specifies whether to return the - * closest element that is smaller than or greater than the one we are - * searching for, respectively, if the exact element cannot be found. - * Defaults to 'binarySearch.GREATEST_LOWER_BOUND'. - */ -exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { - if (aHaystack.length === 0) { - return -1; - } +function hasClose(node) { + return node.nodes && utils.last(node.nodes).type === (node.type + '.close'); +} - var index = recursiveSearch(-1, aHaystack.length, aNeedle, aHaystack, - aCompare, aBias || exports.GREATEST_LOWER_BOUND); - if (index < 0) { - return -1; - } +function hasDelims(node) { + return hasOpen(node) && hasClose(node); +} - // We have found either the exact element, or the next-closest element than - // the one we are searching for. However, there may be more than one such - // element. Make sure we always return the smallest of these. - while (index - 1 >= 0) { - if (aCompare(aHaystack[index], aHaystack[index - 1], true) !== 0) { - break; - } - --index; - } +/** + * Expose `Parser` + */ - return index; -}; +module.exports = Parser; /***/ }), -/* 816 */ -/***/ (function(module, exports) { +/* 822 */ +/***/ (function(module, exports, __webpack_require__) { -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause +"use strict"; +/*! + * map-cache + * + * Copyright (c) 2015, Jon Schlinkert. + * Licensed under the MIT License. */ -// It turns out that some (most?) JavaScript engines don't self-host -// `Array.prototype.sort`. This makes sense because C++ will likely remain -// faster than JS when doing raw CPU-intensive sorting. However, when using a -// custom comparator function, calling back and forth between the VM's C++ and -// JIT'd JS is rather slow *and* loses JIT type information, resulting in -// worse generated code for the comparator function than would be optimal. In -// fact, when sorting with a comparator, these costs outweigh the benefits of -// sorting in C++. By using our own JS-implemented Quick Sort (below), we get -// a ~3500ms mean speed-up in `bench/bench.html`. + + +var hasOwn = Object.prototype.hasOwnProperty; /** - * Swap the elements indexed by `x` and `y` in the array `ary`. - * - * @param {Array} ary - * The array. - * @param {Number} x - * The index of the first item. - * @param {Number} y - * The index of the second item. + * Expose `MapCache` */ -function swap(ary, x, y) { - var temp = ary[x]; - ary[x] = ary[y]; - ary[y] = temp; -} + +module.exports = MapCache; /** - * Returns a random integer within the range `low .. high` inclusive. + * Creates a cache object to store key/value pairs. * - * @param {Number} low - * The lower bound on the range. - * @param {Number} high - * The upper bound on the range. + * ```js + * var cache = new MapCache(); + * ``` + * + * @api public */ -function randomIntInRange(low, high) { - return Math.round(low + (Math.random() * (high - low))); + +function MapCache(data) { + this.__data__ = data || {}; } /** - * The Quick Sort algorithm. + * Adds `value` to `key` on the cache. * - * @param {Array} ary - * An array to sort. - * @param {function} comparator - * Function to use to compare two items. - * @param {Number} p - * Start index of the array - * @param {Number} r - * End index of the array + * ```js + * cache.set('foo', 'bar'); + * ``` + * + * @param {String} `key` The key of the value to cache. + * @param {*} `value` The value to cache. + * @returns {Object} Returns the `Cache` object for chaining. + * @api public */ -function doQuickSort(ary, comparator, p, r) { - // If our lower bound is less than our upper bound, we (1) partition the - // array into two pieces and (2) recurse on each half. If it is not, this is - // the empty array and our base case. - - if (p < r) { - // (1) Partitioning. - // - // The partitioning chooses a pivot between `p` and `r` and moves all - // elements that are less than or equal to the pivot to the before it, and - // all the elements that are greater than it after it. The effect is that - // once partition is done, the pivot is in the exact place it will be when - // the array is put in sorted order, and it will not need to be moved - // again. This runs in O(n) time. - // Always choose a random pivot so that an input array which is reverse - // sorted does not cause O(n^2) running time. - var pivotIndex = randomIntInRange(p, r); - var i = p - 1; - - swap(ary, pivotIndex, r); - var pivot = ary[r]; +MapCache.prototype.set = function mapSet(key, value) { + if (key !== '__proto__') { + this.__data__[key] = value; + } + return this; +}; - // Immediately after `j` is incremented in this loop, the following hold - // true: - // - // * Every element in `ary[p .. i]` is less than or equal to the pivot. - // - // * Every element in `ary[i+1 .. j-1]` is greater than the pivot. - for (var j = p; j < r; j++) { - if (comparator(ary[j], pivot) <= 0) { - i += 1; - swap(ary, i, j); - } - } +/** + * Gets the cached value for `key`. + * + * ```js + * cache.get('foo'); + * //=> 'bar' + * ``` + * + * @param {String} `key` The key of the value to get. + * @returns {*} Returns the cached value. + * @api public + */ - swap(ary, i + 1, j); - var q = i + 1; +MapCache.prototype.get = function mapGet(key) { + return key === '__proto__' ? undefined : this.__data__[key]; +}; - // (2) Recurse on each half. +/** + * Checks if a cached value for `key` exists. + * + * ```js + * cache.has('foo'); + * //=> true + * ``` + * + * @param {String} `key` The key of the entry to check. + * @returns {Boolean} Returns `true` if an entry for `key` exists, else `false`. + * @api public + */ - doQuickSort(ary, comparator, p, q - 1); - doQuickSort(ary, comparator, q + 1, r); - } -} +MapCache.prototype.has = function mapHas(key) { + return key !== '__proto__' && hasOwn.call(this.__data__, key); +}; /** - * Sort the given array in-place with the given comparator function. + * Removes `key` and its value from the cache. * - * @param {Array} ary - * An array to sort. - * @param {function} comparator - * Function to use to compare two items. + * ```js + * cache.del('foo'); + * ``` + * @title .del + * @param {String} `key` The key of the value to remove. + * @returns {Boolean} Returns `true` if the entry was removed successfully, else `false`. + * @api public */ -exports.quickSort = function (ary, comparator) { - doQuickSort(ary, comparator, 0, ary.length - 1); + +MapCache.prototype.del = function mapDelete(key) { + return this.has(key) && delete this.__data__[key]; }; /***/ }), -/* 817 */ +/* 823 */ /***/ (function(module, exports, __webpack_require__) { -/* -*- Mode: js; js-indent-level: 2; -*- */ -/* - * Copyright 2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -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). -var REGEX_NEWLINE = /(\r?\n)/; - -// Newline character code for charCodeAt() comparisons -var NEWLINE_CODE = 10; +"use strict"; -// Private symbol for identifying `SourceNode`s when multiple versions of -// the source-map library are loaded. This MUST NOT CHANGE across -// versions! -var isSourceNode = "$$$isSourceNode$$$"; -/** - * SourceNodes provide a way to abstract over interpolating/concatenating - * snippets of generated JavaScript source code while maintaining the line and - * column information associated with the original source code. - * - * @param aLine The original line number. - * @param aColumn The original column number. - * @param aSource The original source's filename. - * @param aChunks Optional. An array of strings which are snippets of - * generated JS, or other SourceNodes. - * @param aName The original identifier. - */ -function SourceNode(aLine, aColumn, aSource, aChunks, aName) { - this.children = []; - this.sourceContents = {}; - this.line = aLine == null ? null : aLine; - this.column = aColumn == null ? null : aColumn; - this.source = aSource == null ? null : aSource; - this.name = aName == null ? null : aName; - this[isSourceNode] = true; - if (aChunks != null) this.add(aChunks); -} +var define = __webpack_require__(724); /** - * Creates a SourceNode from generated code and a SourceMapConsumer. - * - * @param aGeneratedCode The generated code - * @param aSourceMapConsumer The SourceMap for the generated code - * @param aRelativePath Optional. The path that relative sources in the - * SourceMapConsumer should be relative to. + * Store position for a node */ -SourceNode.fromStringWithSourceMap = - function SourceNode_fromStringWithSourceMap(aGeneratedCode, aSourceMapConsumer, aRelativePath) { - // The SourceNode we want to fill with the generated code - // and the SourceMap - var node = new SourceNode(); - // All even indices of this array are one line of the generated code, - // while all odd indices are the newlines between two adjacent lines - // (since `REGEX_NEWLINE` captures its match). - // Processed fragments are accessed by calling `shiftNextLine`. - var remainingLines = aGeneratedCode.split(REGEX_NEWLINE); - var remainingLinesIndex = 0; - var shiftNextLine = function() { - var lineContents = getNextLine(); - // The last line of a file might not have a newline. - var newLine = getNextLine() || ""; - return lineContents + newLine; +module.exports = function Position(start, parser) { + this.start = start; + this.end = { line: parser.line, column: parser.column }; + define(this, 'content', parser.orig); + define(this, 'source', parser.options.source); +}; - function getNextLine() { - return remainingLinesIndex < remainingLines.length ? - remainingLines[remainingLinesIndex++] : undefined; - } - }; - // We need to remember the position of "remainingLines" - var lastGeneratedLine = 1, lastGeneratedColumn = 0; +/***/ }), +/* 824 */ +/***/ (function(module, exports, __webpack_require__) { - // The generate SourceNodes we need a code range. - // To extract it current and last mapping is used. - // Here we store the last mapping. - var lastMapping = null; +"use strict"; - aSourceMapConsumer.eachMapping(function (mapping) { - if (lastMapping !== null) { - // We add the code from "lastMapping" to "mapping": - // First check if there is a new line in between. - if (lastGeneratedLine < mapping.generatedLine) { - // Associate first line with "lastMapping" - addMappingWithCode(lastMapping, shiftNextLine()); - lastGeneratedLine++; - lastGeneratedColumn = 0; - // The remaining code is added without mapping - } else { - // There is no new line in between. - // Associate the code between "lastGeneratedColumn" and - // "mapping.generatedColumn" with "lastMapping" - var nextLine = remainingLines[remainingLinesIndex]; - var code = nextLine.substr(0, mapping.generatedColumn - - lastGeneratedColumn); - remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn - - lastGeneratedColumn); - lastGeneratedColumn = mapping.generatedColumn; - addMappingWithCode(lastMapping, code); - // No more remaining code, continue - lastMapping = mapping; - return; - } - } - // We add the generated code until the first mapping - // to the SourceNode without any mapping. - // Each line is added as separate string. - while (lastGeneratedLine < mapping.generatedLine) { - node.add(shiftNextLine()); - lastGeneratedLine++; - } - if (lastGeneratedColumn < mapping.generatedColumn) { - var nextLine = remainingLines[remainingLinesIndex]; - node.add(nextLine.substr(0, mapping.generatedColumn)); - remainingLines[remainingLinesIndex] = nextLine.substr(mapping.generatedColumn); - lastGeneratedColumn = mapping.generatedColumn; - } - lastMapping = mapping; - }, this); - // We have processed all mappings. - if (remainingLinesIndex < remainingLines.length) { - if (lastMapping) { - // Associate the remaining code in the current line with "lastMapping" - addMappingWithCode(lastMapping, shiftNextLine()); - } - // and add the remaining lines without any mapping - node.add(remainingLines.splice(remainingLinesIndex).join("")); - } - // Copy sourcesContent into SourceNode - aSourceMapConsumer.sources.forEach(function (sourceFile) { - var content = aSourceMapConsumer.sourceContentFor(sourceFile); - if (content != null) { - if (aRelativePath != null) { - sourceFile = util.join(aRelativePath, sourceFile); - } - node.setSourceContent(sourceFile, content); - } - }); +var safe = __webpack_require__(825); +var define = __webpack_require__(831); +var extend = __webpack_require__(832); +var not = __webpack_require__(834); +var MAX_LENGTH = 1024 * 64; - return node; +/** + * Session cache + */ - function addMappingWithCode(mapping, code) { - if (mapping === null || mapping.source === undefined) { - node.add(code); - } else { - var source = aRelativePath - ? util.join(aRelativePath, mapping.source) - : mapping.source; - node.add(new SourceNode(mapping.originalLine, - mapping.originalColumn, - source, - code, - mapping.name)); - } - } - }; +var cache = {}; /** - * Add a chunk of generated JS to this source node. + * Create a regular expression from the given `pattern` string. * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. + * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. + * @param {Object} `options` + * @return {RegExp} + * @api public */ -SourceNode.prototype.add = function SourceNode_add(aChunk) { - if (Array.isArray(aChunk)) { - aChunk.forEach(function (chunk) { - this.add(chunk); - }, this); - } - else if (aChunk[isSourceNode] || typeof aChunk === "string") { - if (aChunk) { - this.children.push(aChunk); - } - } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); + +module.exports = function(patterns, options) { + if (!Array.isArray(patterns)) { + return makeRe(patterns, options); } - return this; + return makeRe(patterns.join('|'), options); }; /** - * Add a chunk of generated JS to the beginning of this source node. + * Create a regular expression from the given `pattern` string. * - * @param aChunk A string snippet of generated JS code, another instance of - * SourceNode, or an array where each member is one of those things. + * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. + * @param {Object} `options` + * @return {RegExp} + * @api public */ -SourceNode.prototype.prepend = function SourceNode_prepend(aChunk) { - if (Array.isArray(aChunk)) { - for (var i = aChunk.length-1; i >= 0; i--) { - this.prepend(aChunk[i]); - } + +function makeRe(pattern, options) { + if (pattern instanceof RegExp) { + return pattern; } - else if (aChunk[isSourceNode] || typeof aChunk === "string") { - this.children.unshift(aChunk); + + if (typeof pattern !== 'string') { + throw new TypeError('expected a string'); } - else { - throw new TypeError( - "Expected a SourceNode, string, or an array of SourceNodes and strings. Got " + aChunk - ); + + if (pattern.length > MAX_LENGTH) { + throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); } - return this; -}; -/** - * Walk over the tree of JS snippets in this node and its children. The - * walking function is called once for each snippet of JS and is passed that - * snippet and the its original associated source's line/column location. - * - * @param aFn The traversal function. - */ -SourceNode.prototype.walk = function SourceNode_walk(aFn) { - var chunk; - for (var i = 0, len = this.children.length; i < len; i++) { - chunk = this.children[i]; - if (chunk[isSourceNode]) { - chunk.walk(aFn); - } - else { - if (chunk !== '') { - aFn(chunk, { source: this.source, - line: this.line, - column: this.column, - name: this.name }); - } + var key = pattern; + // do this before shallow cloning options, it's a lot faster + if (!options || (options && options.cache !== false)) { + key = createKey(pattern, options); + + if (cache.hasOwnProperty(key)) { + return cache[key]; } } -}; -/** - * Like `String.prototype.join` except for SourceNodes. Inserts `aStr` between - * each of `this.children`. - * - * @param aSep The separator. - */ -SourceNode.prototype.join = function SourceNode_join(aSep) { - var newChildren; - var i; - var len = this.children.length; - if (len > 0) { - newChildren = []; - for (i = 0; i < len-1; i++) { - newChildren.push(this.children[i]); - newChildren.push(aSep); + var opts = extend({}, options); + if (opts.contains === true) { + if (opts.negate === true) { + opts.strictNegate = false; + } else { + opts.strict = false; } - newChildren.push(this.children[i]); - this.children = newChildren; } - return this; -}; -/** - * Call String.prototype.replace on the very right-most source snippet. Useful - * for trimming whitespace from the end of a source node, etc. - * - * @param aPattern The pattern to replace. - * @param aReplacement The thing to replace the pattern with. - */ -SourceNode.prototype.replaceRight = function SourceNode_replaceRight(aPattern, aReplacement) { - var lastChild = this.children[this.children.length - 1]; - if (lastChild[isSourceNode]) { - lastChild.replaceRight(aPattern, aReplacement); + if (opts.strict === false) { + opts.strictOpen = false; + opts.strictClose = false; } - else if (typeof lastChild === 'string') { - this.children[this.children.length - 1] = lastChild.replace(aPattern, aReplacement); + + var open = opts.strictOpen !== false ? '^' : ''; + var close = opts.strictClose !== false ? '$' : ''; + var flags = opts.flags || ''; + var regex; + + if (opts.nocase === true && !/i/.test(flags)) { + flags += 'i'; } - else { - this.children.push(''.replace(aPattern, aReplacement)); + + try { + if (opts.negate || typeof opts.strictNegate === 'boolean') { + pattern = not.create(pattern, opts); + } + + var str = open + '(?:' + pattern + ')' + close; + regex = new RegExp(str, flags); + + if (opts.safe === true && safe(regex) === false) { + throw new Error('potentially unsafe regular expression: ' + regex.source); + } + + } catch (err) { + if (opts.strictErrors === true || opts.safe === true) { + err.key = key; + err.pattern = pattern; + err.originalOptions = options; + err.createdOptions = opts; + throw err; + } + + try { + regex = new RegExp('^' + pattern.replace(/(\W)/g, '\\$1') + '$'); + } catch (err) { + regex = /.^/; //<= match nothing + } } - return this; -}; + + if (opts.cache !== false) { + memoize(regex, key, pattern, opts); + } + return regex; +} /** - * Set the source content for a source file. This will be added to the SourceMapGenerator - * in the sourcesContent field. - * - * @param aSourceFile The filename of the source file - * @param aSourceContent The content of the source file + * Memoize generated regex. This can result in dramatic speed improvements + * and simplify debugging by adding options and pattern to the regex. It can be + * disabled by passing setting `options.cache` to false. */ -SourceNode.prototype.setSourceContent = - function SourceNode_setSourceContent(aSourceFile, aSourceContent) { - this.sourceContents[util.toSetString(aSourceFile)] = aSourceContent; - }; + +function memoize(regex, key, pattern, options) { + define(regex, 'cached', true); + define(regex, 'pattern', pattern); + define(regex, 'options', options); + define(regex, 'key', key); + cache[key] = regex; +} /** - * Walk over the tree of SourceNodes. The walking function is called for each - * source file content and is passed the filename and source content. - * - * @param aFn The traversal function. + * Create the key to use for memoization. The key is generated + * by iterating over the options and concatenating key-value pairs + * to the pattern string. */ -SourceNode.prototype.walkSourceContents = - function SourceNode_walkSourceContents(aFn) { - for (var i = 0, len = this.children.length; i < len; i++) { - if (this.children[i][isSourceNode]) { - this.children[i].walkSourceContents(aFn); - } - } - var sources = Object.keys(this.sourceContents); - for (var i = 0, len = sources.length; i < len; i++) { - aFn(util.fromSetString(sources[i]), this.sourceContents[sources[i]]); +function createKey(pattern, options) { + if (!options) return pattern; + var key = pattern; + for (var prop in options) { + if (options.hasOwnProperty(prop)) { + key += ';' + prop + '=' + String(options[prop]); } - }; + } + return key; +} /** - * Return the string representation of this source node. Walks over the tree - * and concatenates all the various snippets together to one string. + * Expose `makeRe` */ -SourceNode.prototype.toString = function SourceNode_toString() { - var str = ""; - this.walk(function (chunk) { - str += chunk; - }); - return str; -}; -/** - * Returns the string representation of this source node along with a source - * map. - */ -SourceNode.prototype.toStringWithSourceMap = function SourceNode_toStringWithSourceMap(aArgs) { - var generated = { - code: "", - line: 1, - column: 0 - }; - var map = new SourceMapGenerator(aArgs); - var sourceMappingActive = false; - var lastOriginalSource = null; - var lastOriginalLine = null; - var lastOriginalColumn = null; - var lastOriginalName = null; - this.walk(function (chunk, original) { - generated.code += chunk; - if (original.source !== null - && original.line !== null - && original.column !== null) { - if(lastOriginalSource !== original.source - || lastOriginalLine !== original.line - || lastOriginalColumn !== original.column - || lastOriginalName !== original.name) { - map.addMapping({ - source: original.source, - original: { - line: original.line, - column: original.column - }, - generated: { - line: generated.line, - column: generated.column - }, - name: original.name - }); - } - lastOriginalSource = original.source; - lastOriginalLine = original.line; - lastOriginalColumn = original.column; - lastOriginalName = original.name; - sourceMappingActive = true; - } else if (sourceMappingActive) { - map.addMapping({ - generated: { - line: generated.line, - column: generated.column +module.exports.makeRe = makeRe; + + +/***/ }), +/* 825 */ +/***/ (function(module, exports, __webpack_require__) { + +var parse = __webpack_require__(826); +var types = parse.types; + +module.exports = function (re, opts) { + if (!opts) opts = {}; + var replimit = opts.limit === undefined ? 25 : opts.limit; + + if (isRegExp(re)) re = re.source; + else if (typeof re !== 'string') re = String(re); + + try { re = parse(re) } + catch (err) { return false } + + var reps = 0; + return (function walk (node, starHeight) { + if (node.type === types.REPETITION) { + starHeight ++; + reps ++; + if (starHeight > 1) return false; + if (reps > replimit) return false; } - }); - lastOriginalSource = null; - sourceMappingActive = false; - } - for (var idx = 0, length = chunk.length; idx < length; idx++) { - if (chunk.charCodeAt(idx) === NEWLINE_CODE) { - generated.line++; - generated.column = 0; - // Mappings end at eol - if (idx + 1 === length) { - lastOriginalSource = null; - sourceMappingActive = false; - } else if (sourceMappingActive) { - map.addMapping({ - source: original.source, - original: { - line: original.line, - column: original.column - }, - generated: { - line: generated.line, - column: generated.column - }, - name: original.name - }); + + if (node.options) { + for (var i = 0, len = node.options.length; i < len; i++) { + var ok = walk({ stack: node.options[i] }, starHeight); + if (!ok) return false; + } } - } else { - generated.column++; - } - } - }); - this.walkSourceContents(function (sourceFile, sourceContent) { - map.setSourceContent(sourceFile, sourceContent); - }); - - return { code: generated.code, map: map }; + var stack = node.stack || (node.value && node.value.stack); + if (!stack) return true; + + for (var i = 0; i < stack.length; i++) { + var ok = walk(stack[i], starHeight); + if (!ok) return false; + } + + return true; + })(re, 0); }; -exports.SourceNode = SourceNode; +function isRegExp (x) { + return {}.toString.call(x) === '[object RegExp]'; +} /***/ }), -/* 818 */ +/* 826 */ /***/ (function(module, exports, __webpack_require__) { -// Copyright 2014, 2015, 2016, 2017 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) +var util = __webpack_require__(827); +var types = __webpack_require__(828); +var sets = __webpack_require__(829); +var positions = __webpack_require__(830); -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) +module.exports = function(regexpStr) { + var i = 0, l, c, + start = { type: types.ROOT, stack: []}, + // Keep track of last clause/group and stack. + lastGroup = start, + last = start.stack, + groupStack = []; -function callbackAsync(callback, error, result) { - setImmediate(function() { callback(error, result) }) -} -function parseMapToJSON(string, data) { - try { - return JSON.parse(string.replace(/^\)\]\}'/, "")) - } catch (error) { - error.sourceMapData = data - throw error - } -} + var repeatErr = function(i) { + util.error(regexpStr, 'Nothing to repeat at column ' + (i - 1)); + }; -function readSync(read, url, data) { - var readUrl = decodeUriComponent(url) - try { - return String(read(readUrl)) - } catch (error) { - error.sourceMapData = data - throw error - } -} + // Decode a few escaped characters. + var str = util.strToChars(regexpStr); + l = str.length; + // Iterate through each character in string. + while (i < l) { + c = str[i++]; + switch (c) { + // Handle escaped characters, inclues a few sets. + case '\\': + c = str[i++]; -function resolveSourceMap(code, codeUrl, read, callback) { - var mapData - try { - mapData = resolveSourceMapHelper(code, codeUrl) - } catch (error) { - return callbackAsync(callback, error) - } - if (!mapData || mapData.map) { - return callbackAsync(callback, null, mapData) - } - var readUrl = decodeUriComponent(mapData.url) - read(readUrl, function(error, result) { - if (error) { - error.sourceMapData = mapData - return callback(error) - } - mapData.map = String(result) - try { - mapData.map = parseMapToJSON(mapData.map, mapData) - } catch (error) { - return callback(error) - } - callback(null, mapData) - }) -} + switch (c) { + case 'b': + last.push(positions.wordBoundary()); + break; -function resolveSourceMapSync(code, codeUrl, read) { - var mapData = resolveSourceMapHelper(code, codeUrl) - if (!mapData || mapData.map) { - return mapData - } - mapData.map = readSync(read, mapData.url, mapData) - mapData.map = parseMapToJSON(mapData.map, mapData) - return mapData -} + case 'B': + last.push(positions.nonWordBoundary()); + break; -var dataUriRegex = /^data:([^,;]*)(;[^,;]*)*(?:,(.*))?$/ -var jsonMimeTypeRegex = /^(?:application|text)\/json$/ + case 'w': + last.push(sets.words()); + break; -function resolveSourceMapHelper(code, codeUrl) { - codeUrl = urix(codeUrl) + case 'W': + last.push(sets.notWords()); + break; - var url = sourceMappingURL.getFrom(code) - if (!url) { - return null - } + case 'd': + last.push(sets.ints()); + break; - var dataUri = url.match(dataUriRegex) - if (dataUri) { - var mimeType = dataUri[1] - var lastParameter = dataUri[2] || "" - var encoded = dataUri[3] || "" - var data = { - sourceMappingURL: url, - url: null, - sourcesRelativeTo: codeUrl, - map: encoded - } - if (!jsonMimeTypeRegex.test(mimeType)) { - var error = new Error("Unuseful data uri mime type: " + (mimeType || "text/plain")) - error.sourceMapData = data - throw error - } - data.map = parseMapToJSON( - lastParameter === ";base64" ? atob(encoded) : decodeURIComponent(encoded), - data - ) - return data - } + case 'D': + last.push(sets.notInts()); + break; - var mapUrl = resolveUrl(codeUrl, url) - return { - sourceMappingURL: url, - url: mapUrl, - sourcesRelativeTo: mapUrl, - map: null - } -} + case 's': + last.push(sets.whitespace()); + break; + + case 'S': + last.push(sets.notWhitespace()); + break; + + default: + // Check if c is integer. + // In which case it's a reference. + if (/\d/.test(c)) { + last.push({ type: types.REFERENCE, value: parseInt(c, 10) }); + + // Escaped character. + } else { + last.push({ type: types.CHAR, value: c.charCodeAt(0) }); + } + } + + break; + + + // Positionals. + case '^': + last.push(positions.begin()); + break; + case '$': + last.push(positions.end()); + break; -function resolveSources(map, mapUrl, read, options, callback) { - if (typeof options === "function") { - callback = options - options = {} - } - var pending = map.sources ? map.sources.length : 0 - var result = { - sourcesResolved: [], - sourcesContent: [] - } + // Handle custom sets. + case '[': + // Check if this class is 'anti' i.e. [^abc]. + var not; + if (str[i] === '^') { + not = true; + i++; + } else { + not = false; + } - if (pending === 0) { - callbackAsync(callback, null, result) - return - } + // Get all the characters in class. + var classTokens = util.tokenizeClass(str.slice(i), regexpStr); - var done = function() { - pending-- - if (pending === 0) { - callback(null, result) - } - } + // Increase index by length of class. + i += classTokens[1]; + last.push({ + type: types.SET, + set: classTokens[0], + not: not, + }); - resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { - result.sourcesResolved[index] = fullUrl - if (typeof sourceContent === "string") { - result.sourcesContent[index] = sourceContent - callbackAsync(done, null) - } else { - var readUrl = decodeUriComponent(fullUrl) - read(readUrl, function(error, source) { - result.sourcesContent[index] = error ? error : String(source) - done() - }) - } - }) -} + break; -function resolveSourcesSync(map, mapUrl, read, options) { - var result = { - sourcesResolved: [], - sourcesContent: [] - } - if (!map.sources || map.sources.length === 0) { - return result - } + // Class of any character except \n. + case '.': + last.push(sets.anyChar()); + break; - resolveSourcesHelper(map, mapUrl, options, function(fullUrl, sourceContent, index) { - result.sourcesResolved[index] = fullUrl - if (read !== null) { - if (typeof sourceContent === "string") { - result.sourcesContent[index] = sourceContent - } else { - var readUrl = decodeUriComponent(fullUrl) - try { - result.sourcesContent[index] = String(read(readUrl)) - } catch (error) { - result.sourcesContent[index] = error - } - } - } - }) - return result -} + // Push group onto stack. + case '(': + // Create group. + var group = { + type: types.GROUP, + stack: [], + remember: true, + }; -var endingSlash = /\/?$/ + c = str[i]; -function resolveSourcesHelper(map, mapUrl, options, fn) { - options = options || {} - mapUrl = urix(mapUrl) - var fullUrl - var sourceContent - var sourceRoot - for (var index = 0, len = map.sources.length; index < len; index++) { - sourceRoot = null - if (typeof options.sourceRoot === "string") { - sourceRoot = options.sourceRoot - } else if (typeof map.sourceRoot === "string" && options.sourceRoot !== false) { - sourceRoot = map.sourceRoot - } - // If the sourceRoot is the empty string, it is equivalent to not setting - // the property at all. - if (sourceRoot === null || sourceRoot === '') { - fullUrl = resolveUrl(mapUrl, map.sources[index]) - } else { - // Make sure that the sourceRoot ends with a slash, so that `/scripts/subdir` becomes - // `/scripts/subdir/`, not `/scripts/`. Pointing to a file as source root - // does not make sense. - fullUrl = resolveUrl(mapUrl, sourceRoot.replace(endingSlash, "/"), map.sources[index]) - } - sourceContent = (map.sourcesContent || [])[index] - fn(fullUrl, sourceContent, index) - } -} + // If if this is a special kind of group. + if (c === '?') { + c = str[i + 1]; + i += 2; + // Match if followed by. + if (c === '=') { + group.followedBy = true; + // Match if not followed by. + } else if (c === '!') { + group.notFollowedBy = true; -function resolve(code, codeUrl, read, options, callback) { - if (typeof options === "function") { - callback = options - options = {} - } - if (code === null) { - var mapUrl = codeUrl - var data = { - sourceMappingURL: null, - url: mapUrl, - sourcesRelativeTo: mapUrl, - map: null - } - var readUrl = decodeUriComponent(mapUrl) - read(readUrl, function(error, result) { - if (error) { - error.sourceMapData = data - return callback(error) - } - data.map = String(result) - try { - data.map = parseMapToJSON(data.map, data) - } catch (error) { - return callback(error) - } - _resolveSources(data) - }) - } else { - resolveSourceMap(code, codeUrl, read, function(error, mapData) { - if (error) { - return callback(error) - } - if (!mapData) { - return callback(null, null) - } - _resolveSources(mapData) - }) - } + } else if (c !== ':') { + util.error(regexpStr, + 'Invalid group, character \'' + c + + '\' after \'?\' at column ' + (i - 1)); + } - function _resolveSources(mapData) { - resolveSources(mapData.map, mapData.sourcesRelativeTo, read, options, function(error, result) { - if (error) { - return callback(error) - } - mapData.sourcesResolved = result.sourcesResolved - mapData.sourcesContent = result.sourcesContent - callback(null, mapData) - }) - } -} + group.remember = false; + } -function resolveSync(code, codeUrl, read, options) { - var mapData - if (code === null) { - var mapUrl = codeUrl - mapData = { - sourceMappingURL: null, - url: mapUrl, - sourcesRelativeTo: mapUrl, - map: null - } - mapData.map = readSync(read, mapUrl, mapData) - mapData.map = parseMapToJSON(mapData.map, mapData) - } else { - mapData = resolveSourceMapSync(code, codeUrl, read) - if (!mapData) { - return null - } - } - var result = resolveSourcesSync(mapData.map, mapData.sourcesRelativeTo, read, options) - mapData.sourcesResolved = result.sourcesResolved - mapData.sourcesContent = result.sourcesContent - return mapData -} + // Insert subgroup into current group stack. + last.push(group); + // Remember the current group for when the group closes. + groupStack.push(lastGroup); + // Make this new group the current group. + lastGroup = group; + last = group.stack; + break; -module.exports = { - resolveSourceMap: resolveSourceMap, - resolveSourceMapSync: resolveSourceMapSync, - resolveSources: resolveSources, - resolveSourcesSync: resolveSourcesSync, - resolve: resolve, - resolveSync: resolveSync, - parseMapToJSON: parseMapToJSON -} + // Pop group out of stack. + case ')': + if (groupStack.length === 0) { + util.error(regexpStr, 'Unmatched ) at column ' + (i - 1)); + } + lastGroup = groupStack.pop(); -/***/ }), -/* 819 */ -/***/ (function(module, exports, __webpack_require__) { + // Check if this group has a PIPE. + // To get back the correct last stack. + last = lastGroup.options ? + lastGroup.options[lastGroup.options.length - 1] : lastGroup.stack; + break; -var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) -void (function(root, factory) { - if (true) { - !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : - __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)) - } else {} -}(this, function() { + // Use pipe character to give more choices. + case '|': + // Create array where options are if this is the first PIPE + // in this clause. + if (!lastGroup.options) { + lastGroup.options = [lastGroup.stack]; + delete lastGroup.stack; + } - var innerRegex = /[#@] sourceMappingURL=([^\s'"]*)/ + // Create a new stack and add to options for rest of clause. + var stack = []; + lastGroup.options.push(stack); + last = stack; + break; - var regex = RegExp( - "(?:" + - "/\\*" + - "(?:\\s*\r?\n(?://)?)?" + - "(?:" + innerRegex.source + ")" + - "\\s*" + - "\\*/" + - "|" + - "//(?:" + innerRegex.source + ")" + - ")" + - "\\s*" - ) - return { + // Repetition. + // For every repetition, remove last element from last stack + // then insert back a RANGE object. + // This design is chosen because there could be more than + // one repetition symbols in a regex i.e. `a?+{2,3}`. + case '{': + var rs = /^(\d+)(,(\d+)?)?\}/.exec(str.slice(i)), min, max; + if (rs !== null) { + if (last.length === 0) { + repeatErr(i); + } + min = parseInt(rs[1], 10); + max = rs[2] ? rs[3] ? parseInt(rs[3], 10) : Infinity : min; + i += rs[0].length; - regex: regex, - _innerRegex: innerRegex, + last.push({ + type: types.REPETITION, + min: min, + max: max, + value: last.pop(), + }); + } else { + last.push({ + type: types.CHAR, + value: 123, + }); + } + break; - getFrom: function(code) { - var match = code.match(regex) - return (match ? match[1] || match[2] || "" : null) - }, + case '?': + if (last.length === 0) { + repeatErr(i); + } + last.push({ + type: types.REPETITION, + min: 0, + max: 1, + value: last.pop(), + }); + break; - existsIn: function(code) { - return regex.test(code) - }, + case '+': + if (last.length === 0) { + repeatErr(i); + } + last.push({ + type: types.REPETITION, + min: 1, + max: Infinity, + value: last.pop(), + }); + break; - removeFrom: function(code) { - return code.replace(regex, "") - }, + case '*': + if (last.length === 0) { + repeatErr(i); + } + last.push({ + type: types.REPETITION, + min: 0, + max: Infinity, + value: last.pop(), + }); + break; - insertBefore: function(code, string) { - var match = code.match(regex) - if (match) { - return code.slice(0, match.index) + string + code.slice(match.index) - } else { - return code + string - } + + // Default is a character that is not `\[](){}?+*^$`. + default: + last.push({ + type: types.CHAR, + value: c.charCodeAt(0), + }); } + } -})); + // Check if any groups have not been closed. + if (groupStack.length !== 0) { + util.error(regexpStr, 'Unterminated group'); + } + + return start; +}; + +module.exports.types = types; /***/ }), -/* 820 */ +/* 827 */ /***/ (function(module, exports, __webpack_require__) { -// Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) +var types = __webpack_require__(828); +var sets = __webpack_require__(829); -var url = __webpack_require__(454) -function resolveUrl(/* ...urls */) { - return Array.prototype.reduce.call(arguments, function(resolved, nextUrl) { - return url.resolve(resolved, nextUrl) - }) -} +// All of these are private and only used by randexp. +// It's assumed that they will always be called with the correct input. -module.exports = resolveUrl +var CTRL = '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ ?'; +var SLSH = { '0': 0, 't': 9, 'n': 10, 'v': 11, 'f': 12, 'r': 13 }; +/** + * Finds character representations in str and convert all to + * their respective characters + * + * @param {String} str + * @return {String} + */ +exports.strToChars = function(str) { + /* jshint maxlen: false */ + var chars_regex = /(\[\\b\])|(\\)?\\(?:u([A-F0-9]{4})|x([A-F0-9]{2})|(0?[0-7]{2})|c([@A-Z\[\\\]\^?])|([0tnvfr]))/g; + str = str.replace(chars_regex, function(s, b, lbs, a16, b16, c8, dctrl, eslsh) { + if (lbs) { + return s; + } -/***/ }), -/* 821 */ -/***/ (function(module, exports, __webpack_require__) { + var code = b ? 8 : + a16 ? parseInt(a16, 16) : + b16 ? parseInt(b16, 16) : + c8 ? parseInt(c8, 8) : + dctrl ? CTRL.indexOf(dctrl) : + SLSH[eslsh]; -// Copyright 2017 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) + var c = String.fromCharCode(code); -var decodeUriComponent = __webpack_require__(822) + // Escape special regex characters. + if (/[\[\]{}\^$.|?*+()]/.test(c)) { + c = '\\' + c; + } -function customDecodeUriComponent(string) { - // `decodeUriComponent` turns `+` into ` `, but that's not wanted. - return decodeUriComponent(string.replace(/\+/g, "%2B")) -} + return c; + }); -module.exports = customDecodeUriComponent + return str; +}; -/***/ }), -/* 822 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * turns class into tokens + * reads str until it encounters a ] not preceeded by a \ + * + * @param {String} str + * @param {String} regexpStr + * @return {Array., Number>} + */ +exports.tokenizeClass = function(str, regexpStr) { + /* jshint maxlen: false */ + var tokens = []; + var regexp = /\\(?:(w)|(d)|(s)|(W)|(D)|(S))|((?:(?:\\)(.)|([^\]\\]))-(?:\\)?([^\]]))|(\])|(?:\\)?(.)/g; + var rs, c; -"use strict"; -var token = '%[a-f0-9]{2}'; -var singleMatcher = new RegExp(token, 'gi'); -var multiMatcher = new RegExp('(' + token + ')+', 'gi'); + while ((rs = regexp.exec(str)) != null) { + if (rs[1]) { + tokens.push(sets.words()); -function decodeComponents(components, split) { - try { - // Try to decode the entire string first - return decodeURIComponent(components.join('')); - } catch (err) { - // Do nothing - } + } else if (rs[2]) { + tokens.push(sets.ints()); - if (components.length === 1) { - return components; - } + } else if (rs[3]) { + tokens.push(sets.whitespace()); - split = split || 1; + } else if (rs[4]) { + tokens.push(sets.notWords()); - // Split the array in 2 parts - var left = components.slice(0, split); - var right = components.slice(split); + } else if (rs[5]) { + tokens.push(sets.notInts()); - return Array.prototype.concat.call([], decodeComponents(left), decodeComponents(right)); -} + } else if (rs[6]) { + tokens.push(sets.notWhitespace()); -function decode(input) { - try { - return decodeURIComponent(input); - } catch (err) { - var tokens = input.match(singleMatcher); + } else if (rs[7]) { + tokens.push({ + type: types.RANGE, + from: (rs[8] || rs[9]).charCodeAt(0), + to: rs[10].charCodeAt(0), + }); + + } else if (c = rs[12]) { + tokens.push({ + type: types.CHAR, + value: c.charCodeAt(0), + }); + + } else { + return [tokens, regexp.lastIndex]; + } + } + + exports.error(regexpStr, 'Unterminated character class'); +}; + + +/** + * Shortcut to throw errors. + * + * @param {String} regexp + * @param {String} msg + */ +exports.error = function(regexp, msg) { + throw new SyntaxError('Invalid regular expression: /' + regexp + '/: ' + msg); +}; - for (var i = 1; i < tokens.length; i++) { - input = decodeComponents(tokens, i).join(''); - tokens = input.match(singleMatcher); - } +/***/ }), +/* 828 */ +/***/ (function(module, exports) { - return input; - } -} +module.exports = { + ROOT : 0, + GROUP : 1, + POSITION : 2, + SET : 3, + RANGE : 4, + REPETITION : 5, + REFERENCE : 6, + CHAR : 7, +}; -function customDecodeURIComponent(input) { - // Keep track of all the replacements and prefill the map with the `BOM` - var replaceMap = { - '%FE%FF': '\uFFFD\uFFFD', - '%FF%FE': '\uFFFD\uFFFD' - }; - var match = multiMatcher.exec(input); - while (match) { - try { - // Decode as big chunks as possible - replaceMap[match[0]] = decodeURIComponent(match[0]); - } catch (err) { - var result = decode(match[0]); +/***/ }), +/* 829 */ +/***/ (function(module, exports, __webpack_require__) { - if (result !== match[0]) { - replaceMap[match[0]] = result; - } - } +var types = __webpack_require__(828); - match = multiMatcher.exec(input); - } +var INTS = function() { + return [{ type: types.RANGE , from: 48, to: 57 }]; +}; - // Add `%C2` at the end of the map to make sure it does not replace the combinator before everything else - replaceMap['%C2'] = '\uFFFD'; +var WORDS = function() { + return [ + { type: types.CHAR, value: 95 }, + { type: types.RANGE, from: 97, to: 122 }, + { type: types.RANGE, from: 65, to: 90 } + ].concat(INTS()); +}; - var entries = Object.keys(replaceMap); +var WHITESPACE = function() { + return [ + { type: types.CHAR, value: 9 }, + { type: types.CHAR, value: 10 }, + { type: types.CHAR, value: 11 }, + { type: types.CHAR, value: 12 }, + { type: types.CHAR, value: 13 }, + { type: types.CHAR, value: 32 }, + { type: types.CHAR, value: 160 }, + { type: types.CHAR, value: 5760 }, + { type: types.CHAR, value: 6158 }, + { type: types.CHAR, value: 8192 }, + { type: types.CHAR, value: 8193 }, + { type: types.CHAR, value: 8194 }, + { type: types.CHAR, value: 8195 }, + { type: types.CHAR, value: 8196 }, + { type: types.CHAR, value: 8197 }, + { type: types.CHAR, value: 8198 }, + { type: types.CHAR, value: 8199 }, + { type: types.CHAR, value: 8200 }, + { type: types.CHAR, value: 8201 }, + { type: types.CHAR, value: 8202 }, + { type: types.CHAR, value: 8232 }, + { type: types.CHAR, value: 8233 }, + { type: types.CHAR, value: 8239 }, + { type: types.CHAR, value: 8287 }, + { type: types.CHAR, value: 12288 }, + { type: types.CHAR, value: 65279 } + ]; +}; - for (var i = 0; i < entries.length; i++) { - // Replace all decoded components - var key = entries[i]; - input = input.replace(new RegExp(key, 'g'), replaceMap[key]); - } +var NOTANYCHAR = function() { + return [ + { type: types.CHAR, value: 10 }, + { type: types.CHAR, value: 13 }, + { type: types.CHAR, value: 8232 }, + { type: types.CHAR, value: 8233 }, + ]; +}; - return input; -} +// Predefined class objects. +exports.words = function() { + return { type: types.SET, set: WORDS(), not: false }; +}; -module.exports = function (encodedURI) { - if (typeof encodedURI !== 'string') { - throw new TypeError('Expected `encodedURI` to be of type `string`, got `' + typeof encodedURI + '`'); - } +exports.notWords = function() { + return { type: types.SET, set: WORDS(), not: true }; +}; - try { - encodedURI = encodedURI.replace(/\+/g, ' '); +exports.ints = function() { + return { type: types.SET, set: INTS(), not: false }; +}; - // Try the built in decoder first - return decodeURIComponent(encodedURI); - } catch (err) { - // Fallback to a more advanced decoder - return customDecodeURIComponent(encodedURI); - } +exports.notInts = function() { + return { type: types.SET, set: INTS(), not: true }; }; +exports.whitespace = function() { + return { type: types.SET, set: WHITESPACE(), not: false }; +}; -/***/ }), -/* 823 */ -/***/ (function(module, exports, __webpack_require__) { +exports.notWhitespace = function() { + return { type: types.SET, set: WHITESPACE(), not: true }; +}; -// Copyright 2014 Simon Lydell -// X11 (“MIT”) Licensed. (See LICENSE.) - -var path = __webpack_require__(16) - -"use strict" - -function urix(aPath) { - if (path.sep === "\\") { - return aPath - .replace(/\\/g, "/") - .replace(/^[a-z]:\/?/i, "/") - } - return aPath -} - -module.exports = urix +exports.anyChar = function() { + return { type: types.SET, set: NOTANYCHAR(), not: true }; +}; /***/ }), -/* 824 */ +/* 830 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; +var types = __webpack_require__(828); +exports.wordBoundary = function() { + return { type: types.POSITION, value: 'b' }; +}; -function atob(str) { - return Buffer.from(str, 'base64').toString('binary'); -} +exports.nonWordBoundary = function() { + return { type: types.POSITION, value: 'B' }; +}; -module.exports = atob.atob = atob; +exports.begin = function() { + return { type: types.POSITION, value: '^' }; +}; + +exports.end = function() { + return { type: types.POSITION, value: '$' }; +}; /***/ }), -/* 825 */ +/* 831 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * define-property + * + * Copyright (c) 2015-2018, Jon Schlinkert. + * Released under the MIT License. + */ -var fs = __webpack_require__(23); -var path = __webpack_require__(16); -var define = __webpack_require__(729); -var utils = __webpack_require__(806); - -/** - * Expose `mixin()`. - * This code is based on `source-maps-support.js` in reworkcss/css - * https://github.com/reworkcss/css/blob/master/lib/stringify/source-map-support.js - * Copyright (c) 2012 TJ Holowaychuk - */ -module.exports = mixin; +var isobject = __webpack_require__(742); +var isDescriptor = __webpack_require__(754); +var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) + ? Reflect.defineProperty + : Object.defineProperty; -/** - * Mixin source map support into `compiler`. - * - * @param {Object} `compiler` - * @api public - */ +module.exports = function defineProperty(obj, key, val) { + if (!isobject(obj) && typeof obj !== 'function' && !Array.isArray(obj)) { + throw new TypeError('expected an object, function, or array'); + } -function mixin(compiler) { - define(compiler, '_comment', compiler.comment); - compiler.map = new utils.SourceMap.SourceMapGenerator(); - compiler.position = { line: 1, column: 1 }; - compiler.content = {}; - compiler.files = {}; + if (typeof key !== 'string') { + throw new TypeError('expected "key" to be a string'); + } - for (var key in exports) { - define(compiler, key, exports[key]); + if (isDescriptor(val)) { + define(obj, key, val); + return obj; } -} -/** - * Update position. - * - * @param {String} str - */ + define(obj, key, { + configurable: true, + enumerable: false, + writable: true, + value: val + }); -exports.updatePosition = function(str) { - var lines = str.match(/\n/g); - if (lines) this.position.line += lines.length; - var i = str.lastIndexOf('\n'); - this.position.column = ~i ? str.length - i : this.position.column + str.length; + return obj; }; -/** - * Emit `str` with `position`. - * - * @param {String} str - * @param {Object} [pos] - * @return {String} - */ -exports.emit = function(str, node) { - var position = node.position || {}; - var source = position.source; - if (source) { - if (position.filepath) { - source = utils.unixify(position.filepath); - } +/***/ }), +/* 832 */ +/***/ (function(module, exports, __webpack_require__) { - this.map.addMapping({ - source: source, - generated: { - line: this.position.line, - column: Math.max(this.position.column - 1, 0) - }, - original: { - line: position.start.line, - column: position.start.column - 1 - } - }); +"use strict"; - if (position.content) { - this.addContent(source, position); + +var isExtendable = __webpack_require__(833); +var assignSymbols = __webpack_require__(743); + +module.exports = Object.assign || function(obj/*, objects*/) { + if (obj === null || typeof obj === 'undefined') { + throw new TypeError('Cannot convert undefined or null to object'); + } + if (!isObject(obj)) { + obj = {}; + } + for (var i = 1; i < arguments.length; i++) { + var val = arguments[i]; + if (isString(val)) { + val = toObject(val); } - if (position.filepath) { - this.addFile(source, position); + if (isObject(val)) { + assign(obj, val); + assignSymbols(obj, val); } - - this.updatePosition(str); - this.output += str; } - return str; + return obj; }; -/** - * Adds a file to the source map output if it has not already been added - * @param {String} `file` - * @param {Object} `pos` - */ +function assign(a, b) { + for (var key in b) { + if (hasOwn(b, key)) { + a[key] = b[key]; + } + } +} -exports.addFile = function(file, position) { - if (typeof position.content !== 'string') return; - if (Object.prototype.hasOwnProperty.call(this.files, file)) return; - this.files[file] = position.content; -}; +function isString(val) { + return (val && typeof val === 'string'); +} -/** - * Adds a content source to the source map output if it has not already been added - * @param {String} `source` - * @param {Object} `position` - */ +function toObject(str) { + var obj = {}; + for (var i in str) { + obj[i] = str[i]; + } + return obj; +} -exports.addContent = function(source, position) { - if (typeof position.content !== 'string') return; - if (Object.prototype.hasOwnProperty.call(this.content, source)) return; - this.map.setSourceContent(source, position.content); -}; +function isObject(val) { + return (val && typeof val === 'object') || isExtendable(val); +} /** - * Applies any original source maps to the output and embeds the source file - * contents in the source map. + * Returns true if the given `key` is an own property of `obj`. */ -exports.applySourceMaps = function() { - Object.keys(this.files).forEach(function(file) { - var content = this.files[file]; - this.map.setSourceContent(file, content); +function hasOwn(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); +} - if (this.options.inputSourcemaps === true) { - var originalMap = utils.sourceMapResolve.resolveSync(content, file, fs.readFileSync); - if (originalMap) { - var map = new utils.SourceMap.SourceMapConsumer(originalMap.map); - var relativeTo = originalMap.sourcesRelativeTo; - this.map.applySourceMap(map, file, utils.unixify(path.dirname(relativeTo))); - } - } - }, this); -}; +function isEnum(obj, key) { + return Object.prototype.propertyIsEnumerable.call(obj, key); +} -/** - * Process comments, drops sourceMap comments. - * @param {Object} node + +/***/ }), +/* 833 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * is-extendable + * + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. */ -exports.comment = function(node) { - if (/^# sourceMappingURL=/.test(node.comment)) { - return this.emit('', node.position); - } - return this._comment(node); + + +var isPlainObject = __webpack_require__(741); + +module.exports = function isExtendable(val) { + return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); }; /***/ }), -/* 826 */ +/* 834 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(798); -var util = __webpack_require__(29); -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); +var extend = __webpack_require__(832); +var safe = __webpack_require__(825); /** - * Create a new `Parser` with the given `input` and `options`. - * @param {String} `input` + * The main export is a function that takes a `pattern` string and an `options` object. + * + * ```js + & var not = require('regex-not'); + & console.log(not('foo')); + & //=> /^(?:(?!^(?:foo)$).)*$/ + * ``` + * + * @param {String} `pattern` * @param {Object} `options` + * @return {RegExp} Converts the given `pattern` to a regex using the specified `options`. * @api public */ -function Parser(options) { - debug('initializing', __filename); - this.options = utils.extend({source: 'string'}, options); - this.init(this.options); - use(this); +function toRegex(pattern, options) { + return new RegExp(toRegex.create(pattern, options)); } /** - * Prototype methods + * Create a regex-compatible string from the given `pattern` and `options`. + * + * ```js + & var not = require('regex-not'); + & console.log(not.create('foo')); + & //=> '^(?:(?!^(?:foo)$).)*$' + * ``` + * @param {String} `pattern` + * @param {Object} `options` + * @return {String} + * @api public */ -Parser.prototype = { - constructor: Parser, +toRegex.create = function(pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected a string'); + } - init: function(options) { - this.orig = ''; - this.input = ''; - this.parsed = ''; + var opts = extend({}, options); + if (opts.contains === true) { + opts.strictNegate = false; + } - this.column = 1; - this.line = 1; + var open = opts.strictOpen !== false ? '^' : ''; + var close = opts.strictClose !== false ? '$' : ''; + var endChar = opts.endChar ? opts.endChar : '+'; + var str = pattern; - this.regex = new Cache(); - this.errors = this.errors || []; - this.parsers = this.parsers || {}; - this.types = this.types || []; - this.sets = this.sets || {}; - this.fns = this.fns || []; - this.currentType = 'root'; + if (opts.strictNegate === false) { + str = '(?:(?!(?:' + pattern + ')).)' + endChar; + } else { + str = '(?:(?!^(?:' + pattern + ')$).)' + endChar; + } - var pos = this.position(); - this.bos = pos({type: 'bos', val: ''}); + var res = open + str + close; + if (opts.safe === true && safe(res) === false) { + throw new Error('potentially unsafe regular expression: ' + res); + } - this.ast = { - type: 'root', - errors: this.errors, - nodes: [this.bos] - }; + return res; +}; - define(this.bos, 'parent', this.ast); - this.nodes = [this.ast]; +/** + * Expose `toRegex` + */ - this.count = 0; - this.setCount = 0; - this.stack = []; - }, +module.exports = toRegex; - /** - * Throw a formatted error with the cursor column and `msg`. - * @param {String} `msg` Message to use in the Error. - */ - error: function(msg, node) { - var pos = node.position || {start: {column: 0, line: 0}}; - var line = pos.start.line; - var column = pos.start.column; - var source = this.options.source; +/***/ }), +/* 835 */ +/***/ (function(module, exports, __webpack_require__) { - var message = source + ' : ' + msg; - var err = new Error(message); - err.source = source; - err.reason = msg; - err.pos = pos; +"use strict"; - if (this.options.silent) { - this.errors.push(err); - } else { - throw err; - } - }, - /** - * Define a non-enumberable property on the `Parser` instance. - * - * ```js - * parser.define('foo', 'bar'); - * ``` - * @name .define - * @param {String} `key` propery name - * @param {any} `val` property value - * @return {Object} Returns the Parser instance for chaining. - * @api public - */ +var nanomatch = __webpack_require__(836); +var extglob = __webpack_require__(851); + +module.exports = function(snapdragon) { + var compilers = snapdragon.compiler.compilers; + var opts = snapdragon.options; - define: function(key, val) { - define(this, key, val); - return this; - }, + // register nanomatch compilers + snapdragon.use(nanomatch.compilers); - /** - * Mark position and patch `node.position`. - */ + // get references to some specific nanomatch compilers before they + // are overridden by the extglob and/or custom compilers + var escape = compilers.escape; + var qmark = compilers.qmark; + var slash = compilers.slash; + var star = compilers.star; + var text = compilers.text; + var plus = compilers.plus; + var dot = compilers.dot; - position: function() { - var start = { line: this.line, column: this.column }; - var self = this; + // register extglob compilers or escape exglobs if disabled + if (opts.extglob === false || opts.noext === true) { + snapdragon.compiler.use(escapeExtglobs); + } else { + snapdragon.use(extglob.compilers); + } - return function(node) { - define(node, 'position', new Position(start, self)); - return node; + snapdragon.use(function() { + this.options.star = this.options.star || function(/*node*/) { + return '[^\\\\/]*?'; }; - }, + }); - /** - * Set parser `name` with the given `fn` - * @param {String} `name` - * @param {Function} `fn` - * @api public - */ + // custom micromatch compilers + snapdragon.compiler - set: function(type, fn) { - if (this.types.indexOf(type) === -1) { - this.types.push(type); - } - this.parsers[type] = fn.bind(this); - return this; - }, + // reset referenced compiler + .set('dot', dot) + .set('escape', escape) + .set('plus', plus) + .set('slash', slash) + .set('qmark', qmark) + .set('star', star) + .set('text', text); +}; + +function escapeExtglobs(compiler) { + compiler.set('paren', function(node) { + var val = ''; + visit(node, function(tok) { + if (tok.val) val += (/^\W/.test(tok.val) ? '\\' : '') + tok.val; + }); + return this.emit(val, node); + }); /** - * Get parser `name` - * @param {String} `name` - * @api public + * Visit `node` with the given `fn` */ - get: function(name) { - return this.parsers[name]; - }, + function visit(node, fn) { + return node.nodes ? mapVisit(node.nodes, fn) : fn(node); + } /** - * Push a `token` onto the `type` stack. - * - * @param {String} `type` - * @return {Object} `token` - * @api public + * Map visit over array of `nodes`. */ - push: function(type, token) { - this.sets[type] = this.sets[type] || []; - this.count++; - this.stack.push(token); - return this.sets[type].push(token); - }, + function mapVisit(nodes, fn) { + var len = nodes.length; + var idx = -1; + while (++idx < len) { + visit(nodes[idx], fn); + } + } +} - /** - * Pop a token off of the `type` stack - * @param {String} `type` - * @returns {Object} Returns a token - * @api public - */ - pop: function(type) { - this.sets[type] = this.sets[type] || []; - this.count--; - this.stack.pop(); - return this.sets[type].pop(); - }, +/***/ }), +/* 836 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * Return true if inside a `stack` node. Types are `braces`, `parens` or `brackets`. - * - * @param {String} `type` - * @return {Boolean} - * @api public - */ +"use strict"; - isInside: function(type) { - this.sets[type] = this.sets[type] || []; - return this.sets[type].length > 0; - }, - /** - * Return true if `node` is the given `type`. - * - * ```js - * parser.isType(node, 'brace'); - * ``` - * @param {Object} `node` - * @param {String} `type` - * @return {Boolean} - * @api public - */ +/** + * Module dependencies + */ - isType: function(node, type) { - return node && node.type === type; - }, +var util = __webpack_require__(29); +var toRegex = __webpack_require__(723); +var extend = __webpack_require__(837); - /** - * Get the previous AST node - * @return {Object} - */ +/** + * Local dependencies + */ - prev: function(n) { - return this.stack.length > 0 - ? utils.last(this.stack, n) - : utils.last(this.nodes, n); - }, +var compilers = __webpack_require__(839); +var parsers = __webpack_require__(840); +var cache = __webpack_require__(843); +var utils = __webpack_require__(845); +var MAX_LENGTH = 1024 * 64; - /** - * Update line and column based on `str`. - */ +/** + * The main function takes a list of strings and one or more + * glob patterns to use for matching. + * + * ```js + * var nm = require('nanomatch'); + * nm(list, patterns[, options]); + * + * console.log(nm(['a.js', 'a.txt'], ['*.js'])); + * //=> [ 'a.js' ] + * ``` + * @param {Array} `list` A 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) for changing how matches are performed + * @return {Array} Returns an array of matches + * @summary false + * @api public + */ - consume: function(len) { - this.input = this.input.substr(len); - }, +function nanomatch(list, patterns, options) { + patterns = utils.arrayify(patterns); + list = utils.arrayify(list); - /** - * Update column based on `str`. - */ + var len = patterns.length; + if (list.length === 0 || len === 0) { + return []; + } - updatePosition: function(str, len) { - var lines = str.match(/\n/g); - if (lines) this.line += lines.length; - var i = str.lastIndexOf('\n'); - this.column = ~i ? len - i : this.column + len; - this.parsed += str; - this.consume(len); - }, + if (len === 1) { + return nanomatch.match(list, patterns[0], options); + } - /** - * Match `regex`, return captures, and update the cursor position by `match[0]` length. - * @param {RegExp} `regex` - * @return {Object} - */ + var negated = false; + var omit = []; + var keep = []; + var idx = -1; - match: function(regex) { - var m = regex.exec(this.input); - if (m) { - this.updatePosition(m[0], m[0].length); - return m; - } - }, + while (++idx < len) { + var pattern = patterns[idx]; - /** - * Capture `type` with the given regex. - * @param {String} `type` - * @param {RegExp} `regex` - * @return {Function} - */ + if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) { + omit.push.apply(omit, nanomatch.match(list, pattern.slice(1), options)); + negated = true; + } else { + keep.push.apply(keep, nanomatch.match(list, pattern, options)); + } + } - capture: function(type, regex) { - if (typeof regex === 'function') { - return this.set.apply(this, arguments); + // minimatch.match parity + if (negated && keep.length === 0) { + if (options && options.unixify === false) { + keep = list.slice(); + } else { + var unixify = utils.unixify(options); + for (var i = 0; i < list.length; i++) { + keep.push(unixify(list[i])); + } } + } - this.regex.set(type, regex); - this.set(type, function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(regex); - if (!m || !m[0]) return; + var matches = utils.diff(keep, omit); + if (!options || options.nodupes !== false) { + return utils.unique(matches); + } - var prev = this.prev(); - var node = pos({ - type: type, - val: m[0], - parsed: parsed, - rest: this.input - }); + return matches; +} - if (m[1]) { - node.inner = m[1]; - } +/** + * Similar to the main function, but `pattern` must be a string. + * + * ```js + * var nm = require('nanomatch'); + * nm.match(list, pattern[, options]); + * + * console.log(nm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); + * //=> ['a.a', 'a.aa'] + * ``` + * @param {Array} `list` Array of strings to match + * @param {String} `pattern` 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 matches + * @api public + */ - define(node, 'inside', this.stack.length > 0); - define(node, 'parent', prev); - prev.nodes.push(node); - }.bind(this)); - return this; - }, +nanomatch.match = function(list, pattern, options) { + if (Array.isArray(pattern)) { + throw new TypeError('expected pattern to be a string'); + } - /** - * Create a parser with open and close for parens, - * brackets or braces - */ + var unixify = utils.unixify(options); + var isMatch = memoize('match', pattern, options, nanomatch.matcher); + var matches = []; - capturePair: function(type, openRegex, closeRegex, fn) { - this.sets[type] = this.sets[type] || []; + list = utils.arrayify(list); + var len = list.length; + var idx = -1; - /** - * Open - */ + while (++idx < len) { + var ele = list[idx]; + if (ele === pattern || isMatch(ele)) { + matches.push(utils.value(ele, unixify, options)); + } + } - this.set(type + '.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(openRegex); - if (!m || !m[0]) return; + // if no options were passed, uniquify results and return + if (typeof options === 'undefined') { + return utils.unique(matches); + } - var val = m[0]; - this.setCount++; - this.specialChars = true; - var open = pos({ - type: type + '.open', - val: val, - rest: this.input - }); + if (matches.length === 0) { + if (options.failglob === true) { + throw new Error('no matches found for "' + pattern + '"'); + } + if (options.nonull === true || options.nullglob === true) { + return [options.unescape ? utils.unescape(pattern) : pattern]; + } + } - if (typeof m[1] !== 'undefined') { - open.inner = m[1]; - } + // if `opts.ignore` was defined, diff ignored list + if (options.ignore) { + matches = nanomatch.not(matches, options.ignore, options); + } - var prev = this.prev(); - var node = pos({ - type: type, - nodes: [open] - }); + return options.nodupes !== false ? utils.unique(matches) : matches; +}; - define(node, 'rest', this.input); - define(node, 'parsed', parsed); - define(node, 'prefix', m[1]); - define(node, 'parent', prev); - define(open, 'parent', node); +/** + * Returns true if the specified `string` matches the given glob `pattern`. + * + * ```js + * var nm = require('nanomatch'); + * nm.isMatch(string, pattern[, options]); + * + * console.log(nm.isMatch('a.a', '*.a')); + * //=> true + * console.log(nm.isMatch('a.b', '*.a')); + * //=> false + * ``` + * @param {String} `string` String to match + * @param {String} `pattern` 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 string matches the glob pattern. + * @api public + */ - if (typeof fn === 'function') { - fn.call(this, open, node); - } +nanomatch.isMatch = function(str, pattern, options) { + if (typeof str !== 'string') { + throw new TypeError('expected a string: "' + util.inspect(str) + '"'); + } - this.push(type, node); - prev.nodes.push(node); - }); + if (utils.isEmptyString(str) || utils.isEmptyString(pattern)) { + return false; + } - /** - * Close - */ + var equals = utils.equalsPattern(options); + if (equals(str)) { + return true; + } - this.set(type + '.close', function() { - var pos = this.position(); - var m = this.match(closeRegex); - if (!m || !m[0]) return; + var isMatch = memoize('isMatch', pattern, options, nanomatch.matcher); + return isMatch(str); +}; - var parent = this.pop(type); - var node = pos({ - type: type + '.close', - rest: this.input, - suffix: m[1], - val: m[0] - }); +/** + * Returns true if some of the elements in the given `list` match any of the + * given glob `patterns`. + * + * ```js + * var nm = require('nanomatch'); + * nm.some(list, patterns[, options]); + * + * console.log(nm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); + * // true + * console.log(nm.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 + */ - if (!this.isType(parent, type)) { - if (this.options.strict) { - throw new Error('missing opening "' + type + '"'); - } +nanomatch.some = function(list, patterns, options) { + if (typeof list === 'string') { + list = [list]; + } - this.setCount--; - node.escaped = true; - return node; - } + for (var i = 0; i < list.length; i++) { + if (nanomatch(list[i], patterns, options).length === 1) { + return true; + } + } - if (node.suffix === '\\') { - parent.escaped = true; - node.escaped = true; - } + return false; +}; - parent.nodes.push(node); - define(node, 'parent', parent); - }); +/** + * Returns true if every element in the given `list` matches + * at least one of the given glob `patterns`. + * + * ```js + * var nm = require('nanomatch'); + * nm.every(list, patterns[, options]); + * + * console.log(nm.every('foo.js', ['foo.js'])); + * // true + * console.log(nm.every(['foo.js', 'bar.js'], ['*.js'])); + * // true + * console.log(nm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); + * // false + * console.log(nm.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 + */ - return this; - }, +nanomatch.every = function(list, patterns, options) { + if (typeof list === 'string') { + list = [list]; + } - /** - * Capture end-of-string - */ + for (var i = 0; i < list.length; i++) { + if (nanomatch(list[i], patterns, options).length !== 1) { + return false; + } + } - eos: function() { - var pos = this.position(); - if (this.input) return; - var prev = this.prev(); + return true; +}; + +/** + * Returns true if **any** of the given glob `patterns` + * match the specified `string`. + * + * ```js + * var nm = require('nanomatch'); + * nm.any(string, patterns[, options]); + * + * console.log(nm.any('a.a', ['b.*', '*.a'])); + * //=> true + * console.log(nm.any('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) for changing how matches are performed + * @return {Boolean} Returns true if any patterns match `str` + * @api public + */ - while (prev.type !== 'root' && !prev.visited) { - if (this.options.strict === true) { - throw new SyntaxError('invalid syntax:' + util.inspect(prev, null, 2)); - } +nanomatch.any = function(str, patterns, options) { + if (typeof str !== 'string') { + throw new TypeError('expected a string: "' + util.inspect(str) + '"'); + } - if (!hasDelims(prev)) { - prev.parent.escaped = true; - prev.escaped = true; - } + if (utils.isEmptyString(str) || utils.isEmptyString(patterns)) { + return false; + } - visit(prev, function(node) { - if (!hasDelims(node.parent)) { - node.parent.escaped = true; - node.escaped = true; - } - }); + if (typeof patterns === 'string') { + patterns = [patterns]; + } - prev = prev.parent; + for (var i = 0; i < patterns.length; i++) { + if (nanomatch.isMatch(str, patterns[i], options)) { + return true; } + } + return false; +}; - var tok = pos({ - type: 'eos', - val: this.append || '' - }); - - define(tok, 'parent', this.ast); - return tok; - }, +/** + * Returns true if **all** of the given `patterns` + * match the specified string. + * + * ```js + * var nm = require('nanomatch'); + * nm.all(string, patterns[, options]); + * + * console.log(nm.all('foo.js', ['foo.js'])); + * // true + * + * console.log(nm.all('foo.js', ['*.js', '!foo.js'])); + * // false + * + * console.log(nm.all('foo.js', ['*.js', 'foo.js'])); + * // true + * + * console.log(nm.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 + */ - /** - * Run parsers to advance the cursor position - */ +nanomatch.all = function(str, patterns, options) { + if (typeof str !== 'string') { + throw new TypeError('expected a string: "' + util.inspect(str) + '"'); + } - next: function() { - var parsed = this.parsed; - var len = this.types.length; - var idx = -1; - var tok; + if (typeof patterns === 'string') { + patterns = [patterns]; + } - while (++idx < len) { - if ((tok = this.parsers[this.types[idx]].call(this))) { - define(tok, 'rest', this.input); - define(tok, 'parsed', parsed); - this.last = tok; - return tok; - } + for (var i = 0; i < patterns.length; i++) { + if (!nanomatch.isMatch(str, patterns[i], options)) { + return false; } - }, + } + return true; +}; - /** - * Parse the given string. - * @return {Array} - */ +/** + * Returns a list of strings that _**do not match any**_ of the given `patterns`. + * + * ```js + * var nm = require('nanomatch'); + * nm.not(list, patterns[, options]); + * + * console.log(nm.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 + */ - parse: function(input) { - if (typeof input !== 'string') { - throw new TypeError('expected a string'); - } +nanomatch.not = function(list, patterns, options) { + var opts = extend({}, options); + var ignore = opts.ignore; + delete opts.ignore; - this.init(this.options); - this.orig = input; - this.input = input; - var self = this; + list = utils.arrayify(list); - function parse() { - // check input before calling `.next()` - input = self.input; + var matches = utils.diff(list, nanomatch(list, patterns, opts)); + if (ignore) { + matches = utils.diff(matches, nanomatch(list, ignore)); + } - // get the next AST ndoe - var node = self.next(); - if (node) { - var prev = self.prev(); - if (prev) { - define(node, 'parent', prev); - if (prev.nodes) { - prev.nodes.push(node); - } - } + return opts.nodupes !== false ? utils.unique(matches) : matches; +}; - if (self.sets.hasOwnProperty(prev.type)) { - self.currentType = prev.type; - } - } +/** + * 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 nm = require('nanomatch'); + * nm.contains(string, pattern[, options]); + * + * console.log(nm.contains('aa/bb/cc', '*b')); + * //=> true + * console.log(nm.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 we got here but input is not changed, throw an error - if (self.input && input === self.input) { - throw new Error('no parsers registered for: "' + self.input.slice(0, 5) + '"'); - } - } +nanomatch.contains = function(str, patterns, options) { + if (typeof str !== 'string') { + throw new TypeError('expected a string: "' + util.inspect(str) + '"'); + } - while (this.input) parse(); - if (this.stack.length && this.options.strict) { - var node = this.stack.pop(); - throw this.error('missing opening ' + node.type + ': "' + this.orig + '"'); + if (typeof patterns === 'string') { + if (utils.isEmptyString(str) || utils.isEmptyString(patterns)) { + return false; } - var eos = this.eos(); - var tok = this.prev(); - if (tok.type !== 'eos') { - this.ast.nodes.push(eos); + var equals = utils.equalsPattern(patterns, options); + if (equals(str)) { + return true; + } + var contains = utils.containsPattern(patterns, options); + if (contains(str)) { + return true; } - - return this.ast; } + + var opts = extend({}, options, {contains: true}); + return nanomatch.any(str, patterns, opts); }; /** - * Visit `node` with the given `fn` + * Returns true if the given pattern and options should enable + * the `matchBase` option. + * @return {Boolean} + * @api private */ -function visit(node, fn) { - if (!node.visited) { - define(node, 'visited', true); - return node.nodes ? mapVisit(node.nodes, fn) : fn(node); - } - return node; -} +nanomatch.matchBase = function(pattern, options) { + if (pattern && pattern.indexOf('/') !== -1 || !options) return false; + return options.basename === true || options.matchBase === true; +}; /** - * Map visit over array of `nodes`. + * 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 + * var nm = require('nanomatch'); + * nm.matchKeys(object, patterns[, options]); + * + * var obj = { aa: 'a', ab: 'b', ac: 'c' }; + * console.log(nm.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 */ -function mapVisit(nodes, fn) { - var len = nodes.length; - var idx = -1; - while (++idx < len) { - visit(nodes[idx], fn); +nanomatch.matchKeys = function(obj, patterns, options) { + if (!utils.isObject(obj)) { + throw new TypeError('expected the first argument to be an object'); } -} + var keys = nanomatch(Object.keys(obj), patterns, options); + return utils.pick(obj, keys); +}; -function hasOpen(node) { - return node.nodes && node.nodes[0].type === (node.type + '.open'); -} +/** + * Returns a memoized 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 + * var nm = require('nanomatch'); + * nm.matcher(pattern[, options]); + * + * var isMatch = nm.matcher('*.!(*a)'); + * console.log(isMatch('a.a')); + * //=> false + * console.log(isMatch('a.b')); + * //=> true + * ``` + * @param {String} `pattern` Glob pattern + * @param {Object} `options` See available [options](#options) for changing how matches are performed. + * @return {Function} Returns a matcher function. + * @api public + */ -function hasClose(node) { - return node.nodes && utils.last(node.nodes).type === (node.type + '.close'); -} +nanomatch.matcher = function matcher(pattern, options) { + if (utils.isEmptyString(pattern)) { + return function() { + return false; + }; + } -function hasDelims(node) { - return hasOpen(node) && hasClose(node); -} + if (Array.isArray(pattern)) { + return compose(pattern, options, matcher); + } -/** - * Expose `Parser` - */ + // if pattern is a regex + if (pattern instanceof RegExp) { + return test(pattern); + } -module.exports = Parser; + // if pattern is invalid + if (!utils.isString(pattern)) { + throw new TypeError('expected pattern to be an array, string or regex'); + } + // if pattern is a non-glob string + if (!utils.hasSpecialChars(pattern)) { + if (options && options.nocase === true) { + pattern = pattern.toLowerCase(); + } + return utils.matchPath(pattern, options); + } -/***/ }), -/* 827 */ -/***/ (function(module, exports, __webpack_require__) { + // if pattern is a glob string + var re = nanomatch.makeRe(pattern, options); -"use strict"; -/*! - * map-cache - * - * Copyright (c) 2015, Jon Schlinkert. - * Licensed under the MIT License. - */ + // if `options.matchBase` or `options.basename` is defined + if (nanomatch.matchBase(pattern, options)) { + return utils.matchBasename(re, options); + } + + function test(regex) { + var equals = utils.equalsPattern(options); + var unixify = utils.unixify(options); + return function(str) { + if (equals(str)) { + return true; + } + if (regex.test(unixify(str))) { + return true; + } + return false; + }; + } -var hasOwn = Object.prototype.hasOwnProperty; + // create matcher function + var matcherFn = test(re); + // set result object from compiler on matcher function, + // as a non-enumerable property. useful for debugging + utils.define(matcherFn, 'result', re.result); + return matcherFn; +}; /** - * Expose `MapCache` + * Returns an array of matches captured by `pattern` in `string, or + * `null` if the pattern did not match. + * + * ```js + * var nm = require('nanomatch'); + * nm.capture(pattern, string[, options]); + * + * console.log(nm.capture('test/*.js', 'test/foo.js')); + * //=> ['foo'] + * console.log(nm.capture('test/*.js', 'foo/bar.css')); + * //=> null + * ``` + * @param {String} `pattern` Glob pattern to use for matching. + * @param {String} `string` 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 string matches the glob pattern, otherwise `null`. + * @api public */ -module.exports = MapCache; +nanomatch.capture = function(pattern, str, options) { + var re = nanomatch.makeRe(pattern, extend({capture: true}, options)); + var unixify = utils.unixify(options); + + function match() { + return function(string) { + var match = re.exec(unixify(string)); + if (!match) { + return null; + } + + return match.slice(1); + }; + } + + var capture = memoize('capture', pattern, options, match); + return capture(str); +}; /** - * Creates a cache object to store key/value pairs. + * Create a regular expression from the given glob `pattern`. * * ```js - * var cache = new MapCache(); - * ``` + * var nm = require('nanomatch'); + * nm.makeRe(pattern[, options]); * + * console.log(nm.makeRe('*.js')); + * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ + * ``` + * @param {String} `pattern` A glob pattern to convert to regex. + * @param {Object} `options` See available [options](#options) for changing how matches are performed. + * @return {RegExp} Returns a regex created from the given pattern. * @api public */ -function MapCache(data) { - this.__data__ = data || {}; -} +nanomatch.makeRe = function(pattern, options) { + if (pattern instanceof RegExp) { + return pattern; + } + + if (typeof pattern !== 'string') { + throw new TypeError('expected pattern to be a string'); + } + + if (pattern.length > MAX_LENGTH) { + throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); + } + + function makeRe() { + var opts = utils.extend({wrap: false}, options); + var result = nanomatch.create(pattern, opts); + var regex = toRegex(result.output, opts); + utils.define(regex, 'result', result); + return regex; + } + + return memoize('makeRe', pattern, options, makeRe); +}; /** - * Adds `value` to `key` on the cache. + * Parses the given glob `pattern` and returns an object with the compiled `output` + * and optional source `map`. * * ```js - * cache.set('foo', 'bar'); - * ``` + * var nm = require('nanomatch'); + * nm.create(pattern[, options]); * - * @param {String} `key` The key of the value to cache. - * @param {*} `value` The value to cache. - * @returns {Object} Returns the `Cache` object for chaining. + * console.log(nm.create('abc/*.js')); + * // { options: { source: 'string', sourcemap: true }, + * // state: {}, + * // compilers: + * // { ... }, + * // output: '(\\.[\\\\\\/])?abc\\/(?!\\.)(?=.)[^\\/]*?\\.js', + * // ast: + * // { type: 'root', + * // errors: [], + * // nodes: + * // [ ... ], + * // dot: false, + * // input: 'abc/*.js' }, + * // parsingErrors: [], + * // map: + * // { version: 3, + * // sources: [ 'string' ], + * // names: [], + * // mappings: 'AAAA,GAAG,EAAC,kBAAC,EAAC,EAAE', + * // sourcesContent: [ 'abc/*.js' ] }, + * // position: { line: 1, column: 28 }, + * // content: {}, + * // files: {}, + * // idx: 6 } + * ``` + * @param {String} `pattern` Glob pattern to parse and compile. + * @param {Object} `options` Any [options](#options) to change how parsing and compiling is performed. + * @return {Object} Returns an object with the parsed AST, compiled string and optional source map. * @api public */ -MapCache.prototype.set = function mapSet(key, value) { - if (key !== '__proto__') { - this.__data__[key] = value; +nanomatch.create = function(pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected a string'); } - return this; + function create() { + return nanomatch.compile(nanomatch.parse(pattern, options), options); + } + return memoize('create', pattern, options, create); }; /** - * Gets the cached value for `key`. + * Parse the given `str` with the given `options`. * * ```js - * cache.get('foo'); - * //=> 'bar' - * ``` + * var nm = require('nanomatch'); + * nm.parse(pattern[, options]); * - * @param {String} `key` The key of the value to get. - * @returns {*} Returns the cached value. + * var ast = nm.parse('a/{b,c}/d'); + * console.log(ast); + * // { type: 'root', + * // errors: [], + * // input: 'a/{b,c}/d', + * // nodes: + * // [ { type: 'bos', val: '' }, + * // { type: 'text', val: 'a/' }, + * // { type: 'brace', + * // nodes: + * // [ { type: 'brace.open', val: '{' }, + * // { type: 'text', val: 'b,c' }, + * // { type: 'brace.close', val: '}' } ] }, + * // { type: 'text', val: '/d' }, + * // { type: 'eos', val: '' } ] } + * ``` + * @param {String} `str` + * @param {Object} `options` + * @return {Object} Returns an AST * @api public */ -MapCache.prototype.get = function mapGet(key) { - return key === '__proto__' ? undefined : this.__data__[key]; +nanomatch.parse = function(pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected a string'); + } + + function parse() { + var snapdragon = utils.instantiate(null, options); + parsers(snapdragon, options); + + var ast = snapdragon.parse(pattern, options); + utils.define(ast, 'snapdragon', snapdragon); + ast.input = pattern; + return ast; + } + + return memoize('parse', pattern, options, parse); }; /** - * Checks if a cached value for `key` exists. + * Compile the given `ast` or string with the given `options`. * * ```js - * cache.has('foo'); - * //=> true - * ``` + * var nm = require('nanomatch'); + * nm.compile(ast[, options]); * - * @param {String} `key` The key of the entry to check. - * @returns {Boolean} Returns `true` if an entry for `key` exists, else `false`. + * var ast = nm.parse('a/{b,c}/d'); + * console.log(nm.compile(ast)); + * // { options: { source: 'string' }, + * // state: {}, + * // compilers: + * // { eos: [Function], + * // noop: [Function], + * // bos: [Function], + * // brace: [Function], + * // 'brace.open': [Function], + * // text: [Function], + * // 'brace.close': [Function] }, + * // output: [ 'a/(b|c)/d' ], + * // ast: + * // { ... }, + * // parsingErrors: [] } + * ``` + * @param {Object|String} `ast` + * @param {Object} `options` + * @return {Object} Returns an object that has an `output` property with the compiled string. * @api public */ -MapCache.prototype.has = function mapHas(key) { - return key !== '__proto__' && hasOwn.call(this.__data__, key); +nanomatch.compile = function(ast, options) { + if (typeof ast === 'string') { + ast = nanomatch.parse(ast, options); + } + + function compile() { + var snapdragon = utils.instantiate(ast, options); + compilers(snapdragon, options); + return snapdragon.compile(ast, options); + } + + return memoize('compile', ast.input, options, compile); }; /** - * Removes `key` and its value from the cache. + * Clear the regex cache. * * ```js - * cache.del('foo'); + * nm.clearCache(); * ``` - * @title .del - * @param {String} `key` The key of the value to remove. - * @returns {Boolean} Returns `true` if the entry was removed successfully, else `false`. * @api public */ -MapCache.prototype.del = function mapDelete(key) { - return this.has(key) && delete this.__data__[key]; +nanomatch.clearCache = function() { + nanomatch.cache.__data__ = {}; }; - -/***/ }), -/* 828 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -var define = __webpack_require__(729); - /** - * Store position for a node + * Compose a matcher function with the given patterns. + * This allows matcher functions to be compiled once and + * called multiple times. */ -module.exports = function Position(start, parser) { - this.start = start; - this.end = { line: parser.line, column: parser.column }; - define(this, 'content', parser.orig); - define(this, 'source', parser.options.source); -}; +function compose(patterns, options, matcher) { + var matchers; + return memoize('compose', String(patterns), options, function() { + return function(file) { + // delay composition until it's invoked the first time, + // after that it won't be called again + if (!matchers) { + matchers = []; + for (var i = 0; i < patterns.length; i++) { + matchers.push(matcher(patterns[i], options)); + } + } -/***/ }), -/* 829 */ -/***/ (function(module, exports, __webpack_require__) { + var len = matchers.length; + while (len--) { + if (matchers[len](file) === true) { + return true; + } + } + return false; + }; + }); +} -"use strict"; +/** + * Memoize a generated regex or function. A unique key is generated + * from the `type` (usually method name), the `pattern`, and + * user-defined options. + */ +function memoize(type, pattern, options, fn) { + var key = utils.createKey(type + '=' + pattern, options); -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; + if (options && options.cache === false) { + return fn(pattern, options); + } -/** - * Session cache - */ + if (cache.has(type, key)) { + return cache.get(type, key); + } -var cache = {}; + var val = fn(pattern, options); + cache.set(type, key, val); + return val; +} /** - * Create a regular expression from the given `pattern` string. - * - * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. - * @param {Object} `options` - * @return {RegExp} - * @api public + * Expose compiler, parser and cache on `nanomatch` */ -module.exports = function(patterns, options) { - if (!Array.isArray(patterns)) { - return makeRe(patterns, options); - } - return makeRe(patterns.join('|'), options); -}; +nanomatch.compilers = compilers; +nanomatch.parsers = parsers; +nanomatch.cache = cache; /** - * Create a regular expression from the given `pattern` string. - * - * @param {String|RegExp} `pattern` Pattern can be a string or regular expression. - * @param {Object} `options` - * @return {RegExp} - * @api public + * Expose `nanomatch` + * @type {Function} */ -function makeRe(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } +module.exports = nanomatch; - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); - } +/***/ }), +/* 837 */ +/***/ (function(module, exports, __webpack_require__) { - var key = pattern; - // do this before shallow cloning options, it's a lot faster - if (!options || (options && options.cache !== false)) { - key = createKey(pattern, options); +"use strict"; - if (cache.hasOwnProperty(key)) { - return cache[key]; - } - } - var opts = extend({}, options); - if (opts.contains === true) { - if (opts.negate === true) { - opts.strictNegate = false; - } else { - opts.strict = false; - } - } +var isExtendable = __webpack_require__(838); +var assignSymbols = __webpack_require__(743); - if (opts.strict === false) { - opts.strictOpen = false; - opts.strictClose = false; +module.exports = Object.assign || function(obj/*, objects*/) { + if (obj === null || typeof obj === 'undefined') { + throw new TypeError('Cannot convert undefined or null to object'); } - - var open = opts.strictOpen !== false ? '^' : ''; - var close = opts.strictClose !== false ? '$' : ''; - var flags = opts.flags || ''; - var regex; - - if (opts.nocase === true && !/i/.test(flags)) { - flags += 'i'; + if (!isObject(obj)) { + obj = {}; } - - try { - if (opts.negate || typeof opts.strictNegate === 'boolean') { - pattern = not.create(pattern, opts); - } - - var str = open + '(?:' + pattern + ')' + close; - regex = new RegExp(str, flags); - - if (opts.safe === true && safe(regex) === false) { - throw new Error('potentially unsafe regular expression: ' + regex.source); - } - - } catch (err) { - if (opts.strictErrors === true || opts.safe === true) { - err.key = key; - err.pattern = pattern; - err.originalOptions = options; - err.createdOptions = opts; - throw err; + for (var i = 1; i < arguments.length; i++) { + var val = arguments[i]; + if (isString(val)) { + val = toObject(val); } - - try { - regex = new RegExp('^' + pattern.replace(/(\W)/g, '\\$1') + '$'); - } catch (err) { - regex = /.^/; //<= match nothing + if (isObject(val)) { + assign(obj, val); + assignSymbols(obj, val); } } + return obj; +}; - if (opts.cache !== false) { - memoize(regex, key, pattern, opts); +function assign(a, b) { + for (var key in b) { + if (hasOwn(b, key)) { + a[key] = b[key]; + } } - return regex; } -/** - * Memoize generated regex. This can result in dramatic speed improvements - * and simplify debugging by adding options and pattern to the regex. It can be - * disabled by passing setting `options.cache` to false. - */ - -function memoize(regex, key, pattern, options) { - define(regex, 'cached', true); - define(regex, 'pattern', pattern); - define(regex, 'options', options); - define(regex, 'key', key); - cache[key] = regex; +function isString(val) { + return (val && typeof val === 'string'); } -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ - -function createKey(pattern, options) { - if (!options) return pattern; - var key = pattern; - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - key += ';' + prop + '=' + String(options[prop]); - } +function toObject(str) { + var obj = {}; + for (var i in str) { + obj[i] = str[i]; } - return key; + return obj; +} + +function isObject(val) { + return (val && typeof val === 'object') || isExtendable(val); } /** - * Expose `makeRe` + * Returns true if the given `key` is an own property of `obj`. */ -module.exports.makeRe = makeRe; - - -/***/ }), -/* 830 */ -/***/ (function(module, exports, __webpack_require__) { - -var parse = __webpack_require__(831); -var types = parse.types; - -module.exports = function (re, opts) { - if (!opts) opts = {}; - var replimit = opts.limit === undefined ? 25 : opts.limit; - - if (isRegExp(re)) re = re.source; - else if (typeof re !== 'string') re = String(re); - - try { re = parse(re) } - catch (err) { return false } - - var reps = 0; - return (function walk (node, starHeight) { - if (node.type === types.REPETITION) { - starHeight ++; - reps ++; - if (starHeight > 1) return false; - if (reps > replimit) return false; - } - - if (node.options) { - for (var i = 0, len = node.options.length; i < len; i++) { - var ok = walk({ stack: node.options[i] }, starHeight); - if (!ok) return false; - } - } - var stack = node.stack || (node.value && node.value.stack); - if (!stack) return true; - - for (var i = 0; i < stack.length; i++) { - var ok = walk(stack[i], starHeight); - if (!ok) return false; - } - - return true; - })(re, 0); -}; +function hasOwn(obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key); +} -function isRegExp (x) { - return {}.toString.call(x) === '[object RegExp]'; +function isEnum(obj, key) { + return Object.prototype.propertyIsEnumerable.call(obj, key); } /***/ }), -/* 831 */ +/* 838 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(832); -var types = __webpack_require__(833); -var sets = __webpack_require__(834); -var positions = __webpack_require__(835); - - -module.exports = function(regexpStr) { - var i = 0, l, c, - start = { type: types.ROOT, stack: []}, - - // Keep track of last clause/group and stack. - lastGroup = start, - last = start.stack, - groupStack = []; - - - var repeatErr = function(i) { - util.error(regexpStr, 'Nothing to repeat at column ' + (i - 1)); - }; - - // Decode a few escaped characters. - var str = util.strToChars(regexpStr); - l = str.length; - - // Iterate through each character in string. - while (i < l) { - c = str[i++]; - - switch (c) { - // Handle escaped characters, inclues a few sets. - case '\\': - c = str[i++]; - - switch (c) { - case 'b': - last.push(positions.wordBoundary()); - break; - - case 'B': - last.push(positions.nonWordBoundary()); - break; - - case 'w': - last.push(sets.words()); - break; - - case 'W': - last.push(sets.notWords()); - break; - - case 'd': - last.push(sets.ints()); - break; - - case 'D': - last.push(sets.notInts()); - break; - - case 's': - last.push(sets.whitespace()); - break; - - case 'S': - last.push(sets.notWhitespace()); - break; - - default: - // Check if c is integer. - // In which case it's a reference. - if (/\d/.test(c)) { - last.push({ type: types.REFERENCE, value: parseInt(c, 10) }); - - // Escaped character. - } else { - last.push({ type: types.CHAR, value: c.charCodeAt(0) }); - } - } - - break; - - - // Positionals. - case '^': - last.push(positions.begin()); - break; - - case '$': - last.push(positions.end()); - break; - - - // Handle custom sets. - case '[': - // Check if this class is 'anti' i.e. [^abc]. - var not; - if (str[i] === '^') { - not = true; - i++; - } else { - not = false; - } - - // Get all the characters in class. - var classTokens = util.tokenizeClass(str.slice(i), regexpStr); - - // Increase index by length of class. - i += classTokens[1]; - last.push({ - type: types.SET, - set: classTokens[0], - not: not, - }); - - break; - - - // Class of any character except \n. - case '.': - last.push(sets.anyChar()); - break; - - - // Push group onto stack. - case '(': - // Create group. - var group = { - type: types.GROUP, - stack: [], - remember: true, - }; - - c = str[i]; - - // If if this is a special kind of group. - if (c === '?') { - c = str[i + 1]; - i += 2; - - // Match if followed by. - if (c === '=') { - group.followedBy = true; - - // Match if not followed by. - } else if (c === '!') { - group.notFollowedBy = true; - - } else if (c !== ':') { - util.error(regexpStr, - 'Invalid group, character \'' + c + - '\' after \'?\' at column ' + (i - 1)); - } +"use strict"; +/*! + * is-extendable + * + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. + */ - group.remember = false; - } - // Insert subgroup into current group stack. - last.push(group); - // Remember the current group for when the group closes. - groupStack.push(lastGroup); +var isPlainObject = __webpack_require__(741); - // Make this new group the current group. - lastGroup = group; - last = group.stack; - break; +module.exports = function isExtendable(val) { + return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); +}; - // Pop group out of stack. - case ')': - if (groupStack.length === 0) { - util.error(regexpStr, 'Unmatched ) at column ' + (i - 1)); - } - lastGroup = groupStack.pop(); +/***/ }), +/* 839 */ +/***/ (function(module, exports, __webpack_require__) { - // Check if this group has a PIPE. - // To get back the correct last stack. - last = lastGroup.options ? - lastGroup.options[lastGroup.options.length - 1] : lastGroup.stack; - break; +"use strict"; - // Use pipe character to give more choices. - case '|': - // Create array where options are if this is the first PIPE - // in this clause. - if (!lastGroup.options) { - lastGroup.options = [lastGroup.stack]; - delete lastGroup.stack; - } +/** +* Nanomatch compilers +*/ - // Create a new stack and add to options for rest of clause. - var stack = []; - lastGroup.options.push(stack); - last = stack; - break; +module.exports = function(nanomatch, options) { + function slash() { + if (options && typeof options.slash === 'string') { + return options.slash; + } + if (options && typeof options.slash === 'function') { + return options.slash.call(nanomatch); + } + return '\\\\/'; + } + function star() { + if (options && typeof options.star === 'string') { + return options.star; + } + if (options && typeof options.star === 'function') { + return options.star.call(nanomatch); + } + return '[^' + slash() + ']*?'; + } - // Repetition. - // For every repetition, remove last element from last stack - // then insert back a RANGE object. - // This design is chosen because there could be more than - // one repetition symbols in a regex i.e. `a?+{2,3}`. - case '{': - var rs = /^(\d+)(,(\d+)?)?\}/.exec(str.slice(i)), min, max; - if (rs !== null) { - if (last.length === 0) { - repeatErr(i); - } - min = parseInt(rs[1], 10); - max = rs[2] ? rs[3] ? parseInt(rs[3], 10) : Infinity : min; - i += rs[0].length; + var ast = nanomatch.ast = nanomatch.parser.ast; + ast.state = nanomatch.parser.state; + nanomatch.compiler.state = ast.state; + nanomatch.compiler - last.push({ - type: types.REPETITION, - min: min, - max: max, - value: last.pop(), - }); - } else { - last.push({ - type: types.CHAR, - value: 123, - }); - } - break; + /** + * Negation / escaping + */ - case '?': - if (last.length === 0) { - repeatErr(i); - } - last.push({ - type: types.REPETITION, - min: 0, - max: 1, - value: last.pop(), - }); - break; + .set('not', function(node) { + var prev = this.prev(); + if (this.options.nonegate === true || prev.type !== 'bos') { + return this.emit('\\' + node.val, node); + } + return this.emit(node.val, node); + }) + .set('escape', function(node) { + if (this.options.unescape && /^[-\w_.]/.test(node.val)) { + return this.emit(node.val, node); + } + return this.emit('\\' + node.val, node); + }) + .set('quoted', function(node) { + return this.emit(node.val, node); + }) - case '+': - if (last.length === 0) { - repeatErr(i); - } - last.push({ - type: types.REPETITION, - min: 1, - max: Infinity, - value: last.pop(), - }); - break; + /** + * Regex + */ - case '*': - if (last.length === 0) { - repeatErr(i); - } - last.push({ - type: types.REPETITION, - min: 0, - max: Infinity, - value: last.pop(), - }); - break; + .set('dollar', function(node) { + if (node.parent.type === 'bracket') { + return this.emit(node.val, node); + } + return this.emit('\\' + node.val, node); + }) + /** + * Dot: "." + */ - // Default is a character that is not `\[](){}?+*^$`. - default: - last.push({ - type: types.CHAR, - value: c.charCodeAt(0), - }); - } + .set('dot', function(node) { + if (node.dotfiles === true) this.dotfiles = true; + return this.emit('\\' + node.val, node); + }) - } + /** + * Slashes: "/" and "\" + */ - // Check if any groups have not been closed. - if (groupStack.length !== 0) { - util.error(regexpStr, 'Unterminated group'); - } + .set('backslash', function(node) { + return this.emit(node.val, node); + }) + .set('slash', function(node, nodes, i) { + var val = '[' + slash() + ']'; + var parent = node.parent; + var prev = this.prev(); - return start; -}; + // set "node.hasSlash" to true on all ancestor parens nodes + while (parent.type === 'paren' && !parent.hasSlash) { + parent.hasSlash = true; + parent = parent.parent; + } -module.exports.types = types; + if (prev.addQmark) { + val += '?'; + } + // word boundary + if (node.rest.slice(0, 2) === '\\b') { + return this.emit(val, node); + } -/***/ }), -/* 832 */ -/***/ (function(module, exports, __webpack_require__) { + // globstars + if (node.parsed === '**' || node.parsed === './**') { + this.output = '(?:' + this.output; + return this.emit(val + ')?', node); + } -var types = __webpack_require__(833); -var sets = __webpack_require__(834); + // negation + if (node.parsed === '!**' && this.options.nonegate !== true) { + return this.emit(val + '?\\b', node); + } + return this.emit(val, node); + }) + /** + * Square brackets + */ -// All of these are private and only used by randexp. -// It's assumed that they will always be called with the correct input. + .set('bracket', function(node) { + var close = node.close; + var open = !node.escaped ? '[' : '\\['; + var negated = node.negated; + var inner = node.inner; + var val = node.val; -var CTRL = '@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ ?'; -var SLSH = { '0': 0, 't': 9, 'n': 10, 'v': 11, 'f': 12, 'r': 13 }; + if (node.escaped === true) { + inner = inner.replace(/\\?(\W)/g, '\\$1'); + negated = ''; + } -/** - * Finds character representations in str and convert all to - * their respective characters - * - * @param {String} str - * @return {String} - */ -exports.strToChars = function(str) { - /* jshint maxlen: false */ - var chars_regex = /(\[\\b\])|(\\)?\\(?:u([A-F0-9]{4})|x([A-F0-9]{2})|(0?[0-7]{2})|c([@A-Z\[\\\]\^?])|([0tnvfr]))/g; - str = str.replace(chars_regex, function(s, b, lbs, a16, b16, c8, dctrl, eslsh) { - if (lbs) { - return s; - } + if (inner === ']-') { + inner = '\\]\\-'; + } - var code = b ? 8 : - a16 ? parseInt(a16, 16) : - b16 ? parseInt(b16, 16) : - c8 ? parseInt(c8, 8) : - dctrl ? CTRL.indexOf(dctrl) : - SLSH[eslsh]; + if (negated && inner.indexOf('.') === -1) { + inner += '.'; + } + if (negated && inner.indexOf('/') === -1) { + inner += '/'; + } - var c = String.fromCharCode(code); + val = open + negated + inner + close; + return this.emit(val, node); + }) - // Escape special regex characters. - if (/[\[\]{}\^$.|?*+()]/.test(c)) { - c = '\\' + c; - } + /** + * Square: "[.]" (only matches a single character in brackets) + */ - return c; - }); + .set('square', function(node) { + var val = (/^\W/.test(node.val) ? '\\' : '') + node.val; + return this.emit(val, node); + }) - return str; -}; + /** + * Question mark: "?" + */ + .set('qmark', function(node) { + var prev = this.prev(); + // don't use "slash" variable so that we always avoid + // matching backslashes and slashes with a qmark + var val = '[^.\\\\/]'; + if (this.options.dot || (prev.type !== 'bos' && prev.type !== 'slash')) { + val = '[^\\\\/]'; + } -/** - * turns class into tokens - * reads str until it encounters a ] not preceeded by a \ - * - * @param {String} str - * @param {String} regexpStr - * @return {Array., Number>} - */ -exports.tokenizeClass = function(str, regexpStr) { - /* jshint maxlen: false */ - var tokens = []; - var regexp = /\\(?:(w)|(d)|(s)|(W)|(D)|(S))|((?:(?:\\)(.)|([^\]\\]))-(?:\\)?([^\]]))|(\])|(?:\\)?(.)/g; - var rs, c; + if (node.parsed.slice(-1) === '(') { + var ch = node.rest.charAt(0); + if (ch === '!' || ch === '=' || ch === ':') { + return this.emit(node.val, node); + } + } + if (node.val.length > 1) { + val += '{' + node.val.length + '}'; + } + return this.emit(val, node); + }) - while ((rs = regexp.exec(str)) != null) { - if (rs[1]) { - tokens.push(sets.words()); + /** + * Plus + */ - } else if (rs[2]) { - tokens.push(sets.ints()); + .set('plus', function(node) { + var prev = node.parsed.slice(-1); + if (prev === ']' || prev === ')') { + return this.emit(node.val, node); + } + if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) { + return this.emit('\\+', node); + } + var ch = this.output.slice(-1); + if (/\w/.test(ch) && !node.inside) { + return this.emit('+\\+?', node); + } + return this.emit('+', node); + }) - } else if (rs[3]) { - tokens.push(sets.whitespace()); + /** + * globstar: '**' + */ - } else if (rs[4]) { - tokens.push(sets.notWords()); + .set('globstar', function(node, nodes, i) { + if (!this.output) { + this.state.leadingGlobstar = true; + } - } else if (rs[5]) { - tokens.push(sets.notInts()); + var prev = this.prev(); + var before = this.prev(2); + var next = this.next(); + var after = this.next(2); + var type = prev.type; + var val = node.val; - } else if (rs[6]) { - tokens.push(sets.notWhitespace()); + if (prev.type === 'slash' && next.type === 'slash') { + if (before.type === 'text') { + this.output += '?'; - } else if (rs[7]) { - tokens.push({ - type: types.RANGE, - from: (rs[8] || rs[9]).charCodeAt(0), - to: rs[10].charCodeAt(0), - }); + if (after.type !== 'text') { + this.output += '\\b'; + } + } + } - } else if (c = rs[12]) { - tokens.push({ - type: types.CHAR, - value: c.charCodeAt(0), - }); + var parsed = node.parsed; + if (parsed.charAt(0) === '!') { + parsed = parsed.slice(1); + } - } else { - return [tokens, regexp.lastIndex]; - } - } + var isInside = node.isInside.paren || node.isInside.brace; + if (parsed && type !== 'slash' && type !== 'bos' && !isInside) { + val = star(); + } else { + val = this.options.dot !== true + ? '(?:(?!(?:[' + slash() + ']|^)\\.).)*?' + : '(?:(?!(?:[' + slash() + ']|^)(?:\\.{1,2})($|[' + slash() + ']))(?!\\.{2}).)*?'; + } - exports.error(regexpStr, 'Unterminated character class'); -}; + if ((type === 'slash' || type === 'bos') && this.options.dot !== true) { + val = '(?!\\.)' + val; + } + if (prev.type === 'slash' && next.type === 'slash' && before.type !== 'text') { + if (after.type === 'text' || after.type === 'star') { + node.addQmark = true; + } + } -/** - * Shortcut to throw errors. - * - * @param {String} regexp - * @param {String} msg - */ -exports.error = function(regexp, msg) { - throw new SyntaxError('Invalid regular expression: /' + regexp + '/: ' + msg); -}; + if (this.options.capture) { + val = '(' + val + ')'; + } + return this.emit(val, node); + }) -/***/ }), -/* 833 */ -/***/ (function(module, exports) { + /** + * Star: "*" + */ -module.exports = { - ROOT : 0, - GROUP : 1, - POSITION : 2, - SET : 3, - RANGE : 4, - REPETITION : 5, - REFERENCE : 6, - CHAR : 7, -}; + .set('star', function(node, nodes, i) { + var prior = nodes[i - 2] || {}; + var prev = this.prev(); + var next = this.next(); + var type = prev.type; + function isStart(n) { + return n.type === 'bos' || n.type === 'slash'; + } -/***/ }), -/* 834 */ -/***/ (function(module, exports, __webpack_require__) { + if (this.output === '' && this.options.contains !== true) { + this.output = '(?![' + slash() + '])'; + } -var types = __webpack_require__(833); + if (type === 'bracket' && this.options.bash === false) { + var str = next && next.type === 'bracket' ? star() : '*?'; + if (!prev.nodes || prev.nodes[1].type !== 'posix') { + return this.emit(str, node); + } + } -var INTS = function() { - return [{ type: types.RANGE , from: 48, to: 57 }]; -}; + var prefix = !this.dotfiles && type !== 'text' && type !== 'escape' + ? (this.options.dot ? '(?!(?:^|[' + slash() + '])\\.{1,2}(?:$|[' + slash() + ']))' : '(?!\\.)') + : ''; -var WORDS = function() { - return [ - { type: types.CHAR, value: 95 }, - { type: types.RANGE, from: 97, to: 122 }, - { type: types.RANGE, from: 65, to: 90 } - ].concat(INTS()); -}; + if (isStart(prev) || (isStart(prior) && type === 'not')) { + if (prefix !== '(?!\\.)') { + prefix += '(?!(\\.{2}|\\.[' + slash() + ']))(?=.)'; + } else { + prefix += '(?=.)'; + } + } else if (prefix === '(?!\\.)') { + prefix = ''; + } -var WHITESPACE = function() { - return [ - { type: types.CHAR, value: 9 }, - { type: types.CHAR, value: 10 }, - { type: types.CHAR, value: 11 }, - { type: types.CHAR, value: 12 }, - { type: types.CHAR, value: 13 }, - { type: types.CHAR, value: 32 }, - { type: types.CHAR, value: 160 }, - { type: types.CHAR, value: 5760 }, - { type: types.CHAR, value: 6158 }, - { type: types.CHAR, value: 8192 }, - { type: types.CHAR, value: 8193 }, - { type: types.CHAR, value: 8194 }, - { type: types.CHAR, value: 8195 }, - { type: types.CHAR, value: 8196 }, - { type: types.CHAR, value: 8197 }, - { type: types.CHAR, value: 8198 }, - { type: types.CHAR, value: 8199 }, - { type: types.CHAR, value: 8200 }, - { type: types.CHAR, value: 8201 }, - { type: types.CHAR, value: 8202 }, - { type: types.CHAR, value: 8232 }, - { type: types.CHAR, value: 8233 }, - { type: types.CHAR, value: 8239 }, - { type: types.CHAR, value: 8287 }, - { type: types.CHAR, value: 12288 }, - { type: types.CHAR, value: 65279 } - ]; -}; + if (prev.type === 'not' && prior.type === 'bos' && this.options.dot === true) { + this.output = '(?!\\.)' + this.output; + } -var NOTANYCHAR = function() { - return [ - { type: types.CHAR, value: 10 }, - { type: types.CHAR, value: 13 }, - { type: types.CHAR, value: 8232 }, - { type: types.CHAR, value: 8233 }, - ]; -}; + var output = prefix + star(); + if (this.options.capture) { + output = '(' + output + ')'; + } -// Predefined class objects. -exports.words = function() { - return { type: types.SET, set: WORDS(), not: false }; -}; + return this.emit(output, node); + }) + + /** + * Text + */ + + .set('text', function(node) { + return this.emit(node.val, node); + }) -exports.notWords = function() { - return { type: types.SET, set: WORDS(), not: true }; -}; + /** + * End-of-string + */ -exports.ints = function() { - return { type: types.SET, set: INTS(), not: false }; -}; + .set('eos', function(node) { + var prev = this.prev(); + var val = node.val; -exports.notInts = function() { - return { type: types.SET, set: INTS(), not: true }; -}; + this.output = '(?:\\.[' + slash() + '](?=.))?' + this.output; + if (this.state.metachar && prev.type !== 'qmark' && prev.type !== 'slash') { + val += (this.options.contains ? '[' + slash() + ']?' : '(?:[' + slash() + ']|$)'); + } -exports.whitespace = function() { - return { type: types.SET, set: WHITESPACE(), not: false }; -}; + return this.emit(val, node); + }); -exports.notWhitespace = function() { - return { type: types.SET, set: WHITESPACE(), not: true }; -}; + /** + * Allow custom compilers to be passed on options + */ -exports.anyChar = function() { - return { type: types.SET, set: NOTANYCHAR(), not: true }; + if (options && typeof options.compilers === 'function') { + options.compilers(nanomatch.compiler); + } }; + /***/ }), -/* 835 */ +/* 840 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(833); +"use strict"; -exports.wordBoundary = function() { - return { type: types.POSITION, value: 'b' }; -}; -exports.nonWordBoundary = function() { - return { type: types.POSITION, value: 'B' }; -}; +var regexNot = __webpack_require__(734); +var toRegex = __webpack_require__(723); +var isOdd = __webpack_require__(841); -exports.begin = function() { - return { type: types.POSITION, value: '^' }; -}; +/** + * Characters to use in negation regex (we want to "not" match + * characters that are matched by other parsers) + */ -exports.end = function() { - return { type: types.POSITION, value: '$' }; -}; +var cached; +var NOT_REGEX = '[\\[!*+?$^"\'.\\\\/]+'; +var not = createTextRegex(NOT_REGEX); +/** + * Nanomatch parsers + */ -/***/ }), -/* 836 */ -/***/ (function(module, exports, __webpack_require__) { +module.exports = function(nanomatch, options) { + var parser = nanomatch.parser; + var opts = parser.options; -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ + parser.state = { + slashes: 0, + paths: [] + }; + parser.ast.state = parser.state; + parser + /** + * Beginning-of-string + */ -var isobject = __webpack_require__(747); -var isDescriptor = __webpack_require__(759); -var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) - ? Reflect.defineProperty - : Object.defineProperty; + .capture('prefix', function() { + if (this.parsed) return; + var m = this.match(/^\.[\\/]/); + if (!m) return; + this.state.strictOpen = !!this.options.strictOpen; + this.state.addPrefix = true; + }) -module.exports = function defineProperty(obj, key, val) { - if (!isobject(obj) && typeof obj !== 'function' && !Array.isArray(obj)) { - throw new TypeError('expected an object, function, or array'); - } + /** + * Escape: "\\." + */ - if (typeof key !== 'string') { - throw new TypeError('expected "key" to be a string'); - } + .capture('escape', function() { + if (this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(/^(?:\\(.)|([$^]))/); + if (!m) return; - if (isDescriptor(val)) { - define(obj, key, val); - return obj; - } + return pos({ + type: 'escape', + val: m[2] || m[1] + }); + }) - define(obj, key, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); + /** + * Quoted strings + */ - return obj; -}; + .capture('quoted', function() { + var pos = this.position(); + var m = this.match(/^["']/); + if (!m) return; + var quote = m[0]; + if (this.input.indexOf(quote) === -1) { + return pos({ + type: 'escape', + val: quote + }); + } -/***/ }), -/* 837 */ -/***/ (function(module, exports, __webpack_require__) { + var tok = advanceTo(this.input, quote); + this.consume(tok.len); -"use strict"; + return pos({ + type: 'quoted', + val: tok.esc + }); + }) + /** + * Negations: "!" + */ -var isExtendable = __webpack_require__(838); -var assignSymbols = __webpack_require__(748); + .capture('not', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(this.notRegex || /^!+/); + if (!m) return; + var val = m[0]; -module.exports = Object.assign || function(obj/*, objects*/) { - if (obj === null || typeof obj === 'undefined') { - throw new TypeError('Cannot convert undefined or null to object'); - } - if (!isObject(obj)) { - obj = {}; - } - for (var i = 1; i < arguments.length; i++) { - var val = arguments[i]; - if (isString(val)) { - val = toObject(val); - } - if (isObject(val)) { - assign(obj, val); - assignSymbols(obj, val); - } - } - return obj; -}; + var isNegated = isOdd(val.length); + if (parsed === '' && !isNegated) { + val = ''; + } -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } - } -} + // if nothing has been parsed, we know `!` is at the start, + // so we need to wrap the result in a negation regex + if (parsed === '' && isNegated && this.options.nonegate !== true) { + this.bos.val = '(?!^(?:'; + this.append = ')$).*'; + val = ''; + } + return pos({ + type: 'not', + val: val + }); + }) -function isString(val) { - return (val && typeof val === 'string'); -} + /** + * Dot: "." + */ -function toObject(str) { - var obj = {}; - for (var i in str) { - obj[i] = str[i]; - } - return obj; -} + .capture('dot', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^\.+/); + if (!m) return; -function isObject(val) { - return (val && typeof val === 'object') || isExtendable(val); -} + var val = m[0]; + this.state.dot = val === '.' && (parsed === '' || parsed.slice(-1) === '/'); -/** - * Returns true if the given `key` is an own property of `obj`. - */ + return pos({ + type: 'dot', + dotfiles: this.state.dot, + val: val + }); + }) -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} + /** + * Plus: "+" + */ -function isEnum(obj, key) { - return Object.prototype.propertyIsEnumerable.call(obj, key); -} + .capture('plus', /^\+(?!\()/) + /** + * Question mark: "?" + */ -/***/ }), -/* 838 */ -/***/ (function(module, exports, __webpack_require__) { + .capture('qmark', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^\?+(?!\()/); + if (!m) return; -"use strict"; -/*! - * is-extendable - * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. - */ + this.state.metachar = true; + this.state.qmark = true; + return pos({ + type: 'qmark', + parsed: parsed, + val: m[0] + }); + }) + /** + * Globstar: "**" + */ -var isPlainObject = __webpack_require__(746); + .capture('globstar', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^\*{2}(?![*(])(?=[,)/]|$)/); + if (!m) return; -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); -}; + var type = opts.noglobstar !== true ? 'globstar' : 'star'; + var node = pos({type: type, parsed: parsed}); + this.state.metachar = true; + while (this.input.slice(0, 4) === '/**/') { + this.input = this.input.slice(3); + } -/***/ }), -/* 839 */ -/***/ (function(module, exports, __webpack_require__) { + node.isInside = { + brace: this.isInside('brace'), + paren: this.isInside('paren') + }; -"use strict"; + if (type === 'globstar') { + this.state.globstar = true; + node.val = '**'; + } else { + this.state.star = true; + node.val = '*'; + } -var extend = __webpack_require__(837); -var safe = __webpack_require__(830); + return node; + }) -/** - * The main export is a function that takes a `pattern` string and an `options` object. - * - * ```js - & var not = require('regex-not'); - & console.log(not('foo')); - & //=> /^(?:(?!^(?:foo)$).)*$/ - * ``` - * - * @param {String} `pattern` - * @param {Object} `options` - * @return {RegExp} Converts the given `pattern` to a regex using the specified `options`. - * @api public - */ + /** + * Star: "*" + */ -function toRegex(pattern, options) { - return new RegExp(toRegex.create(pattern, options)); -} + .capture('star', function() { + var pos = this.position(); + var starRe = /^(?:\*(?![*(])|[*]{3,}(?!\()|[*]{2}(?![(/]|$)|\*(?=\*\())/; + var m = this.match(starRe); + if (!m) return; -/** - * Create a regex-compatible string from the given `pattern` and `options`. - * - * ```js - & var not = require('regex-not'); - & console.log(not.create('foo')); - & //=> '^(?:(?!^(?:foo)$).)*$' - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {String} - * @api public - */ + this.state.metachar = true; + this.state.star = true; + return pos({ + type: 'star', + val: m[0] + }); + }) -toRegex.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } + /** + * Slash: "/" + */ - var opts = extend({}, options); - if (opts.contains === true) { - opts.strictNegate = false; - } + .capture('slash', function() { + var pos = this.position(); + var m = this.match(/^\//); + if (!m) return; - var open = opts.strictOpen !== false ? '^' : ''; - var close = opts.strictClose !== false ? '$' : ''; - var endChar = opts.endChar ? opts.endChar : '+'; - var str = pattern; + this.state.slashes++; + return pos({ + type: 'slash', + val: m[0] + }); + }) - if (opts.strictNegate === false) { - str = '(?:(?!(?:' + pattern + ')).)' + endChar; - } else { - str = '(?:(?!^(?:' + pattern + ')$).)' + endChar; - } + /** + * Backslash: "\\" + */ - var res = open + str + close; - if (opts.safe === true && safe(res) === false) { - throw new Error('potentially unsafe regular expression: ' + res); - } + .capture('backslash', function() { + var pos = this.position(); + var m = this.match(/^\\(?![*+?(){}[\]'"])/); + if (!m) return; - return res; -}; + var val = m[0]; -/** - * Expose `toRegex` - */ + if (this.isInside('bracket')) { + val = '\\'; + } else if (val.length > 1) { + val = '\\\\'; + } -module.exports = toRegex; + return pos({ + type: 'backslash', + val: val + }); + }) + /** + * Square: "[.]" + */ -/***/ }), -/* 840 */ -/***/ (function(module, exports, __webpack_require__) { + .capture('square', function() { + if (this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(/^\[([^!^\\])\]/); + if (!m) return; -"use strict"; + return pos({ + type: 'square', + val: m[1] + }); + }) + /** + * Brackets: "[...]" (basic, this can be overridden by other parsers) + */ -var nanomatch = __webpack_require__(841); -var extglob = __webpack_require__(856); + .capture('bracket', function() { + var pos = this.position(); + var m = this.match(/^(?:\[([!^]?)([^\]]+|\]-)(\]|[^*+?]+)|\[)/); + if (!m) return; -module.exports = function(snapdragon) { - var compilers = snapdragon.compiler.compilers; - var opts = snapdragon.options; + var val = m[0]; + var negated = m[1] ? '^' : ''; + var inner = (m[2] || '').replace(/\\\\+/, '\\\\'); + var close = m[3] || ''; - // register nanomatch compilers - snapdragon.use(nanomatch.compilers); + if (m[2] && inner.length < m[2].length) { + val = val.replace(/\\\\+/, '\\\\'); + } - // get references to some specific nanomatch compilers before they - // are overridden by the extglob and/or custom compilers - var escape = compilers.escape; - var qmark = compilers.qmark; - var slash = compilers.slash; - var star = compilers.star; - var text = compilers.text; - var plus = compilers.plus; - var dot = compilers.dot; + var esc = this.input.slice(0, 2); + if (inner === '' && esc === '\\]') { + inner += esc; + this.consume(2); - // register extglob compilers or escape exglobs if disabled - if (opts.extglob === false || opts.noext === true) { - snapdragon.compiler.use(escapeExtglobs); - } else { - snapdragon.use(extglob.compilers); - } + var str = this.input; + var idx = -1; + var ch; - snapdragon.use(function() { - this.options.star = this.options.star || function(/*node*/) { - return '[^\\\\/]*?'; - }; - }); + while ((ch = str[++idx])) { + this.consume(1); + if (ch === ']') { + close = ch; + break; + } + inner += ch; + } + } - // custom micromatch compilers - snapdragon.compiler + return pos({ + type: 'bracket', + val: val, + escaped: close !== ']', + negated: negated, + inner: inner, + close: close + }); + }) - // reset referenced compiler - .set('dot', dot) - .set('escape', escape) - .set('plus', plus) - .set('slash', slash) - .set('qmark', qmark) - .set('star', star) - .set('text', text); -}; + /** + * Text + */ -function escapeExtglobs(compiler) { - compiler.set('paren', function(node) { - var val = ''; - visit(node, function(tok) { - if (tok.val) val += (/^\W/.test(tok.val) ? '\\' : '') + tok.val; + .capture('text', function() { + if (this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(not); + if (!m || !m[0]) return; + + return pos({ + type: 'text', + val: m[0] + }); }); - return this.emit(val, node); - }); /** - * Visit `node` with the given `fn` + * Allow custom parsers to be passed on options */ - function visit(node, fn) { - return node.nodes ? mapVisit(node.nodes, fn) : fn(node); + if (options && typeof options.parsers === 'function') { + options.parsers(nanomatch.parser); } +}; - /** - * Map visit over array of `nodes`. - */ +/** + * Advance to the next non-escaped character + */ - function mapVisit(nodes, fn) { - var len = nodes.length; - var idx = -1; - while (++idx < len) { - visit(nodes[idx], fn); - } - } -} +function advanceTo(input, endChar) { + var ch = input.charAt(0); + var tok = { len: 1, val: '', esc: '' }; + var idx = 0; + function advance() { + if (ch !== '\\') { + tok.esc += '\\' + ch; + tok.val += ch; + } -/***/ }), -/* 841 */ -/***/ (function(module, exports, __webpack_require__) { + ch = input.charAt(++idx); + tok.len++; -"use strict"; + if (ch === '\\') { + advance(); + advance(); + } + } + while (ch && ch !== endChar) { + advance(); + } + return tok; +} /** - * Module dependencies + * Create text regex */ -var util = __webpack_require__(29); -var toRegex = __webpack_require__(728); -var extend = __webpack_require__(842); +function createTextRegex(pattern) { + if (cached) return cached; + var opts = {contains: true, strictClose: false}; + var not = regexNot.create(pattern, opts); + var re = toRegex('^(?:[*]\\((?=.)|' + not + ')', opts); + return (cached = re); +} /** - * Local dependencies + * Expose negation string */ -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; +module.exports.not = NOT_REGEX; -/** - * The main function takes a list of strings and one or more - * glob patterns to use for matching. - * - * ```js - * var nm = require('nanomatch'); - * nm(list, patterns[, options]); - * - * console.log(nm(['a.js', 'a.txt'], ['*.js'])); - * //=> [ 'a.js' ] - * ``` - * @param {Array} `list` A 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) for changing how matches are performed - * @return {Array} Returns an array of matches - * @summary false - * @api public - */ -function nanomatch(list, patterns, options) { - patterns = utils.arrayify(patterns); - list = utils.arrayify(list); +/***/ }), +/* 841 */ +/***/ (function(module, exports, __webpack_require__) { - var len = patterns.length; - if (list.length === 0 || len === 0) { - return []; - } +"use strict"; +/*! + * is-odd + * + * Copyright (c) 2015-2017, Jon Schlinkert. + * Released under the MIT License. + */ - if (len === 1) { - return nanomatch.match(list, patterns[0], options); - } - var negated = false; - var omit = []; - var keep = []; - var idx = -1; - while (++idx < len) { - var pattern = patterns[idx]; +var isNumber = __webpack_require__(842); - if (typeof pattern === 'string' && pattern.charCodeAt(0) === 33 /* ! */) { - omit.push.apply(omit, nanomatch.match(list, pattern.slice(1), options)); - negated = true; - } else { - keep.push.apply(keep, nanomatch.match(list, pattern, options)); - } +module.exports = function isOdd(i) { + if (!isNumber(i)) { + throw new TypeError('is-odd expects a number.'); } - - // minimatch.match parity - if (negated && keep.length === 0) { - if (options && options.unixify === false) { - keep = list.slice(); - } else { - var unixify = utils.unixify(options); - for (var i = 0; i < list.length; i++) { - keep.push(unixify(list[i])); - } - } + if (Number(i) !== Math.floor(i)) { + throw new RangeError('is-odd expects an integer.'); } + return !!(~~i & 1); +}; - var matches = utils.diff(keep, omit); - if (!options || options.nodupes !== false) { - return utils.unique(matches); - } - return matches; -} +/***/ }), +/* 842 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Similar to the main function, but `pattern` must be a string. - * - * ```js - * var nm = require('nanomatch'); - * nm.match(list, pattern[, options]); +"use strict"; +/*! + * is-number * - * console.log(nm.match(['a.a', 'a.aa', 'a.b', 'a.c'], '*.a')); - * //=> ['a.a', 'a.aa'] - * ``` - * @param {Array} `list` Array of strings to match - * @param {String} `pattern` 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 matches - * @api public + * Copyright (c) 2014-2017, Jon Schlinkert. + * Released under the MIT License. */ -nanomatch.match = function(list, pattern, options) { - if (Array.isArray(pattern)) { - throw new TypeError('expected pattern to be a string'); - } - var unixify = utils.unixify(options); - var isMatch = memoize('match', pattern, options, nanomatch.matcher); - var matches = []; - list = utils.arrayify(list); - var len = list.length; - var idx = -1; +module.exports = function isNumber(num) { + var type = typeof num; - while (++idx < len) { - var ele = list[idx]; - if (ele === pattern || isMatch(ele)) { - matches.push(utils.value(ele, unixify, options)); - } + if (type === 'string' || num instanceof String) { + // an empty string would be coerced to true with the below logic + if (!num.trim()) return false; + } else if (type !== 'number' && !(num instanceof Number)) { + return false; } - // if no options were passed, uniquify results and return - if (typeof options === 'undefined') { - return utils.unique(matches); - } + return (num - num + 1) >= 0; +}; - if (matches.length === 0) { - if (options.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - if (options.nonull === true || options.nullglob === true) { - return [options.unescape ? utils.unescape(pattern) : pattern]; - } - } - // if `opts.ignore` was defined, diff ignored list - if (options.ignore) { - matches = nanomatch.not(matches, options.ignore, options); - } +/***/ }), +/* 843 */ +/***/ (function(module, exports, __webpack_require__) { - return options.nodupes !== false ? utils.unique(matches) : matches; -}; +module.exports = new (__webpack_require__(844))(); -/** - * Returns true if the specified `string` matches the given glob `pattern`. - * - * ```js - * var nm = require('nanomatch'); - * nm.isMatch(string, pattern[, options]); + +/***/ }), +/* 844 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/*! + * fragment-cache * - * console.log(nm.isMatch('a.a', '*.a')); - * //=> true - * console.log(nm.isMatch('a.b', '*.a')); - * //=> false - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` 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 string matches the glob pattern. - * @api public + * Copyright (c) 2016-2017, Jon Schlinkert. + * Released under the MIT License. */ -nanomatch.isMatch = function(str, pattern, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } - - if (utils.isEmptyString(str) || utils.isEmptyString(pattern)) { - return false; - } - var equals = utils.equalsPattern(options); - if (equals(str)) { - return true; - } - var isMatch = memoize('isMatch', pattern, options, nanomatch.matcher); - return isMatch(str); -}; +var MapCache = __webpack_require__(822); /** - * Returns true if some of the elements in the given `list` match any of the - * given glob `patterns`. + * Create a new `FragmentCache` with an optional object to use for `caches`. * * ```js - * var nm = require('nanomatch'); - * nm.some(list, patterns[, options]); - * - * console.log(nm.some(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // true - * console.log(nm.some(['foo.js'], ['*.js', '!foo.js'])); - * // false + * var fragment = new FragmentCache(); * ``` - * @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` + * @name FragmentCache + * @param {String} `cacheName` + * @return {Object} Returns the [map-cache][] instance. * @api public */ -nanomatch.some = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } - - for (var i = 0; i < list.length; i++) { - if (nanomatch(list[i], patterns, options).length === 1) { - return true; - } - } - - return false; -}; +function FragmentCache(caches) { + this.caches = caches || {}; +} /** - * Returns true if every element in the given `list` matches - * at least one of the given glob `patterns`. - * - * ```js - * var nm = require('nanomatch'); - * nm.every(list, patterns[, options]); - * - * console.log(nm.every('foo.js', ['foo.js'])); - * // true - * console.log(nm.every(['foo.js', 'bar.js'], ['*.js'])); - * // true - * console.log(nm.every(['foo.js', 'bar.js'], ['*.js', '!foo.js'])); - * // false - * console.log(nm.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 + * Prototype */ -nanomatch.every = function(list, patterns, options) { - if (typeof list === 'string') { - list = [list]; - } +FragmentCache.prototype = { - for (var i = 0; i < list.length; i++) { - if (nanomatch(list[i], patterns, options).length !== 1) { - return false; - } - } + /** + * Get cache `name` from the `fragment.caches` object. Creates a new + * `MapCache` if it doesn't already exist. + * + * ```js + * var cache = fragment.cache('files'); + * console.log(fragment.caches.hasOwnProperty('files')); + * //=> true + * ``` + * @name .cache + * @param {String} `cacheName` + * @return {Object} Returns the [map-cache][] instance. + * @api public + */ - return true; -}; + cache: function(cacheName) { + return this.caches[cacheName] || (this.caches[cacheName] = new MapCache()); + }, -/** - * Returns true if **any** of the given glob `patterns` - * match the specified `string`. - * - * ```js - * var nm = require('nanomatch'); - * nm.any(string, patterns[, options]); - * - * console.log(nm.any('a.a', ['b.*', '*.a'])); - * //=> true - * console.log(nm.any('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) for changing how matches are performed - * @return {Boolean} Returns true if any patterns match `str` - * @api public - */ + /** + * Set a value for property `key` on cache `name` + * + * ```js + * fragment.set('files', 'somefile.js', new File({path: 'somefile.js'})); + * ``` + * @name .set + * @param {String} `name` + * @param {String} `key` Property name to set + * @param {any} `val` The value of `key` + * @return {Object} The cache instance for chaining + * @api public + */ -nanomatch.any = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } + set: function(cacheName, key, val) { + var cache = this.cache(cacheName); + cache.set(key, val); + return cache; + }, - if (utils.isEmptyString(str) || utils.isEmptyString(patterns)) { - return false; - } + /** + * Returns true if a non-undefined value is set for `key` on fragment cache `name`. + * + * ```js + * var cache = fragment.cache('files'); + * cache.set('somefile.js'); + * + * console.log(cache.has('somefile.js')); + * //=> true + * + * console.log(cache.has('some-other-file.js')); + * //=> false + * ``` + * @name .has + * @param {String} `name` Cache name + * @param {String} `key` Optionally specify a property to check for on cache `name` + * @return {Boolean} + * @api public + */ - if (typeof patterns === 'string') { - patterns = [patterns]; - } + has: function(cacheName, key) { + return typeof this.get(cacheName, key) !== 'undefined'; + }, - for (var i = 0; i < patterns.length; i++) { - if (nanomatch.isMatch(str, patterns[i], options)) { - return true; + /** + * Get `name`, or if specified, the value of `key`. Invokes the [cache]() method, + * so that cache `name` will be created it doesn't already exist. If `key` is not passed, + * the entire cache (`name`) is returned. + * + * ```js + * var Vinyl = require('vinyl'); + * var cache = fragment.cache('files'); + * cache.set('somefile.js', new Vinyl({path: 'somefile.js'})); + * console.log(cache.get('somefile.js')); + * //=> + * ``` + * @name .get + * @param {String} `name` + * @return {Object} Returns cache `name`, or the value of `key` if specified + * @api public + */ + + get: function(name, key) { + var cache = this.cache(name); + if (typeof key === 'string') { + return cache.get(key); } + return cache; } - return false; }; /** - * Returns true if **all** of the given `patterns` - * match the specified string. - * - * ```js - * var nm = require('nanomatch'); - * nm.all(string, patterns[, options]); - * - * console.log(nm.all('foo.js', ['foo.js'])); - * // true - * - * console.log(nm.all('foo.js', ['*.js', '!foo.js'])); - * // false - * - * console.log(nm.all('foo.js', ['*.js', 'foo.js'])); - * // true - * - * console.log(nm.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 + * Expose `FragmentCache` */ -nanomatch.all = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); - } +exports = module.exports = FragmentCache; - if (typeof patterns === 'string') { - patterns = [patterns]; - } - for (var i = 0; i < patterns.length; i++) { - if (!nanomatch.isMatch(str, patterns[i], options)) { - return false; - } - } - return true; -}; +/***/ }), +/* 845 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var utils = module.exports; +var path = __webpack_require__(16); /** - * Returns a list of strings that _**do not match any**_ of the given `patterns`. - * - * ```js - * var nm = require('nanomatch'); - * nm.not(list, patterns[, options]); - * - * console.log(nm.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 + * Module dependencies */ -nanomatch.not = function(list, patterns, options) { - var opts = extend({}, options); - var ignore = opts.ignore; - delete opts.ignore; +var isWindows = __webpack_require__(846)(); +var Snapdragon = __webpack_require__(762); +utils.define = __webpack_require__(847); +utils.diff = __webpack_require__(848); +utils.extend = __webpack_require__(837); +utils.pick = __webpack_require__(849); +utils.typeOf = __webpack_require__(850); +utils.unique = __webpack_require__(735); + +/** + * Returns true if the given value is effectively an empty string + */ + +utils.isEmptyString = function(val) { + return String(val) === '' || String(val) === './'; +}; + +/** + * Returns true if the platform is windows, or `path.sep` is `\\`. + * This is defined as a function to allow `path.sep` to be set in unit tests, + * or by the user, if there is a reason to do so. + * @return {Boolean} + */ - list = utils.arrayify(list); +utils.isWindows = function() { + return path.sep === '\\' || isWindows === true; +}; - var matches = utils.diff(list, nanomatch(list, patterns, opts)); - if (ignore) { - matches = utils.diff(matches, nanomatch(list, ignore)); - } +/** + * Return the last element from an array + */ - return opts.nodupes !== false ? utils.unique(matches) : matches; +utils.last = function(arr, n) { + return arr[arr.length - (n || 1)]; }; /** - * 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 nm = require('nanomatch'); - * nm.contains(string, pattern[, options]); - * - * console.log(nm.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(nm.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 + * Get the `Snapdragon` instance to use */ -nanomatch.contains = function(str, patterns, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string: "' + util.inspect(str) + '"'); +utils.instantiate = function(ast, options) { + var snapdragon; + // if an instance was created by `.parse`, use that instance + if (utils.typeOf(ast) === 'object' && ast.snapdragon) { + snapdragon = ast.snapdragon; + // if the user supplies an instance on options, use that instance + } else if (utils.typeOf(options) === 'object' && options.snapdragon) { + snapdragon = options.snapdragon; + // create a new instance + } else { + snapdragon = new Snapdragon(options); } - if (typeof patterns === 'string') { - if (utils.isEmptyString(str) || utils.isEmptyString(patterns)) { - return false; - } + utils.define(snapdragon, 'parse', function(str, options) { + var parsed = Snapdragon.prototype.parse.call(this, str, options); + parsed.input = str; - var equals = utils.equalsPattern(patterns, options); - if (equals(str)) { - return true; - } - var contains = utils.containsPattern(patterns, options); - if (contains(str)) { - return true; + // escape unmatched brace/bracket/parens + var last = this.parser.stack.pop(); + if (last && this.options.strictErrors !== true) { + var open = last.nodes[0]; + var inner = last.nodes[1]; + if (last.type === 'bracket') { + if (inner.val.charAt(0) === '[') { + inner.val = '\\' + inner.val; + } + + } else { + open.val = '\\' + open.val; + var sibling = open.parent.nodes[1]; + if (sibling.type === 'star') { + sibling.loose = true; + } + } } - } - var opts = extend({}, options, {contains: true}); - return nanomatch.any(str, patterns, opts); + // add non-enumerable parser reference + utils.define(parsed, 'parser', this.parser); + return parsed; + }); + + return snapdragon; }; /** - * Returns true if the given pattern and options should enable - * the `matchBase` option. - * @return {Boolean} - * @api private + * Create the key to use for memoization. The key is generated + * by iterating over the options and concatenating key-value pairs + * to the pattern string. */ -nanomatch.matchBase = function(pattern, options) { - if (pattern && pattern.indexOf('/') !== -1 || !options) return false; - return options.basename === true || options.matchBase === true; +utils.createKey = function(pattern, options) { + if (typeof options === 'undefined') { + return pattern; + } + var key = pattern; + for (var prop in options) { + if (options.hasOwnProperty(prop)) { + key += ';' + prop + '=' + String(options[prop]); + } + } + return key; }; /** - * 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 - * var nm = require('nanomatch'); - * nm.matchKeys(object, patterns[, options]); - * - * var obj = { aa: 'a', ab: 'b', ac: 'c' }; - * console.log(nm.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 + * Cast `val` to an array + * @return {Array} */ -nanomatch.matchKeys = function(obj, patterns, options) { - if (!utils.isObject(obj)) { - throw new TypeError('expected the first argument to be an object'); - } - var keys = nanomatch(Object.keys(obj), patterns, options); - return utils.pick(obj, keys); +utils.arrayify = function(val) { + if (typeof val === 'string') return [val]; + return val ? (Array.isArray(val) ? val : [val]) : []; }; /** - * Returns a memoized 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 - * var nm = require('nanomatch'); - * nm.matcher(pattern[, options]); - * - * var isMatch = nm.matcher('*.!(*a)'); - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.b')); - * //=> true - * ``` - * @param {String} `pattern` Glob pattern - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {Function} Returns a matcher function. - * @api public + * Return true if `val` is a non-empty string */ -nanomatch.matcher = function matcher(pattern, options) { - if (utils.isEmptyString(pattern)) { - return function() { - return false; - }; - } +utils.isString = function(val) { + return typeof val === 'string'; +}; - if (Array.isArray(pattern)) { - return compose(pattern, options, matcher); - } +/** + * Return true if `val` is a non-empty string + */ - // if pattern is a regex - if (pattern instanceof RegExp) { - return test(pattern); - } +utils.isRegex = function(val) { + return utils.typeOf(val) === 'regexp'; +}; - // if pattern is invalid - if (!utils.isString(pattern)) { - throw new TypeError('expected pattern to be an array, string or regex'); - } +/** + * Return true if `val` is a non-empty string + */ - // if pattern is a non-glob string - if (!utils.hasSpecialChars(pattern)) { - if (options && options.nocase === true) { - pattern = pattern.toLowerCase(); - } - return utils.matchPath(pattern, options); - } +utils.isObject = function(val) { + return utils.typeOf(val) === 'object'; +}; - // if pattern is a glob string - var re = nanomatch.makeRe(pattern, options); +/** + * Escape regex characters in the given string + */ - // if `options.matchBase` or `options.basename` is defined - if (nanomatch.matchBase(pattern, options)) { - return utils.matchBasename(re, options); - } +utils.escapeRegex = function(str) { + return str.replace(/[-[\]{}()^$|*+?.\\/\s]/g, '\\$&'); +}; - function test(regex) { - var equals = utils.equalsPattern(options); - var unixify = utils.unixify(options); +/** + * Combines duplicate characters in the provided `input` string. + * @param {String} `input` + * @returns {String} + */ - return function(str) { - if (equals(str)) { - return true; - } +utils.combineDupes = function(input, patterns) { + patterns = utils.arrayify(patterns).join('|').split('|'); + patterns = patterns.map(function(s) { + return s.replace(/\\?([+*\\/])/g, '\\$1'); + }); + var substr = patterns.join('|'); + var regex = new RegExp('(' + substr + ')(?=\\1)', 'g'); + return input.replace(regex, ''); +}; - if (regex.test(unixify(str))) { - return true; - } - return false; - }; - } +/** + * Returns true if the given `str` has special characters + */ - // create matcher function - var matcherFn = test(re); - // set result object from compiler on matcher function, - // as a non-enumerable property. useful for debugging - utils.define(matcherFn, 'result', re.result); - return matcherFn; +utils.hasSpecialChars = function(str) { + return /(?:(?:(^|\/)[!.])|[*?+()|[\]{}]|[+@]\()/.test(str); }; /** - * Returns an array of matches captured by `pattern` in `string, or - * `null` if the pattern did not match. - * - * ```js - * var nm = require('nanomatch'); - * nm.capture(pattern, string[, options]); + * Normalize slashes in the given filepath. * - * console.log(nm.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(nm.capture('test/*.js', 'foo/bar.css')); - * //=> null - * ``` - * @param {String} `pattern` Glob pattern to use for matching. - * @param {String} `string` 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 string matches the glob pattern, otherwise `null`. - * @api public + * @param {String} `filepath` + * @return {String} */ -nanomatch.capture = function(pattern, str, options) { - var re = nanomatch.makeRe(pattern, extend({capture: true}, options)); - var unixify = utils.unixify(options); - - function match() { - return function(string) { - var match = re.exec(unixify(string)); - if (!match) { - return null; - } +utils.toPosixPath = function(str) { + return str.replace(/\\+/g, '/'); +}; - return match.slice(1); - }; - } +/** + * Strip backslashes before special characters in a string. + * + * @param {String} `str` + * @return {String} + */ - var capture = memoize('capture', pattern, options, match); - return capture(str); +utils.unescape = function(str) { + return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); }; /** - * Create a regular expression from the given glob `pattern`. - * - * ```js - * var nm = require('nanomatch'); - * nm.makeRe(pattern[, options]); - * - * console.log(nm.makeRe('*.js')); - * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ - * ``` - * @param {String} `pattern` A glob pattern to convert to regex. - * @param {Object} `options` See available [options](#options) for changing how matches are performed. - * @return {RegExp} Returns a regex created from the given pattern. - * @api public + * Strip the drive letter from a windows filepath + * @param {String} `fp` + * @return {String} */ -nanomatch.makeRe = function(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } +utils.stripDrive = function(fp) { + return utils.isWindows() ? fp.replace(/^[a-z]:[\\/]+?/i, '/') : fp; +}; - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } +/** + * Strip the prefix from a filepath + * @param {String} `fp` + * @return {String} + */ - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); +utils.stripPrefix = function(str) { + if (str.charAt(0) === '.' && (str.charAt(1) === '/' || str.charAt(1) === '\\')) { + return str.slice(2); } + return str; +}; - function makeRe() { - var opts = utils.extend({wrap: false}, options); - var result = nanomatch.create(pattern, opts); - var regex = toRegex(result.output, opts); - utils.define(regex, 'result', result); - return regex; - } +/** + * Returns true if `str` is a common character that doesn't need + * to be processed to be used for matching. + * @param {String} `str` + * @return {Boolean} + */ - return memoize('makeRe', pattern, options, makeRe); +utils.isSimpleChar = function(str) { + return str.trim() === '' || str === '.'; }; /** - * Parses the given glob `pattern` and returns an object with the compiled `output` - * and optional source `map`. - * - * ```js - * var nm = require('nanomatch'); - * nm.create(pattern[, options]); - * - * console.log(nm.create('abc/*.js')); - * // { options: { source: 'string', sourcemap: true }, - * // state: {}, - * // compilers: - * // { ... }, - * // output: '(\\.[\\\\\\/])?abc\\/(?!\\.)(?=.)[^\\/]*?\\.js', - * // ast: - * // { type: 'root', - * // errors: [], - * // nodes: - * // [ ... ], - * // dot: false, - * // input: 'abc/*.js' }, - * // parsingErrors: [], - * // map: - * // { version: 3, - * // sources: [ 'string' ], - * // names: [], - * // mappings: 'AAAA,GAAG,EAAC,kBAAC,EAAC,EAAE', - * // sourcesContent: [ 'abc/*.js' ] }, - * // position: { line: 1, column: 28 }, - * // content: {}, - * // files: {}, - * // idx: 6 } - * ``` - * @param {String} `pattern` Glob pattern to parse and compile. - * @param {Object} `options` Any [options](#options) to change how parsing and compiling is performed. - * @return {Object} Returns an object with the parsed AST, compiled string and optional source map. - * @api public + * Returns true if the given str is an escaped or + * unescaped path character */ -nanomatch.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } - function create() { - return nanomatch.compile(nanomatch.parse(pattern, options), options); - } - return memoize('create', pattern, options, create); +utils.isSlash = function(str) { + return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; }; /** - * Parse the given `str` with the given `options`. - * - * ```js - * var nm = require('nanomatch'); - * nm.parse(pattern[, options]); + * Returns a function that returns true if the given + * pattern matches or contains a `filepath` * - * var ast = nm.parse('a/{b,c}/d'); - * console.log(ast); - * // { type: 'root', - * // errors: [], - * // input: 'a/{b,c}/d', - * // nodes: - * // [ { type: 'bos', val: '' }, - * // { type: 'text', val: 'a/' }, - * // { type: 'brace', - * // nodes: - * // [ { type: 'brace.open', val: '{' }, - * // { type: 'text', val: 'b,c' }, - * // { type: 'brace.close', val: '}' } ] }, - * // { type: 'text', val: '/d' }, - * // { type: 'eos', val: '' } ] } - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {Object} Returns an AST - * @api public + * @param {String} `pattern` + * @return {Function} */ -nanomatch.parse = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected a string'); - } +utils.matchPath = function(pattern, options) { + return (options && options.contains) + ? utils.containsPattern(pattern, options) + : utils.equalsPattern(pattern, options); +}; - function parse() { - var snapdragon = utils.instantiate(null, options); - parsers(snapdragon, options); +/** + * Returns true if the given (original) filepath or unixified path are equal + * to the given pattern. + */ - var ast = snapdragon.parse(pattern, options); - utils.define(ast, 'snapdragon', snapdragon); - ast.input = pattern; - return ast; - } +utils._equals = function(filepath, unixPath, pattern) { + return pattern === filepath || pattern === unixPath; +}; - return memoize('parse', pattern, options, parse); +/** + * Returns true if the given (original) filepath or unixified path contain + * the given pattern. + */ + +utils._contains = function(filepath, unixPath, pattern) { + return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; }; /** - * Compile the given `ast` or string with the given `options`. - * - * ```js - * var nm = require('nanomatch'); - * nm.compile(ast[, options]); + * Returns a function that returns true if the given + * pattern is the same as a given `filepath` * - * var ast = nm.parse('a/{b,c}/d'); - * console.log(nm.compile(ast)); - * // { options: { source: 'string' }, - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // brace: [Function], - * // 'brace.open': [Function], - * // text: [Function], - * // 'brace.close': [Function] }, - * // output: [ 'a/(b|c)/d' ], - * // ast: - * // { ... }, - * // parsingErrors: [] } - * ``` - * @param {Object|String} `ast` - * @param {Object} `options` - * @return {Object} Returns an object that has an `output` property with the compiled string. - * @api public + * @param {String} `pattern` + * @return {Function} */ -nanomatch.compile = function(ast, options) { - if (typeof ast === 'string') { - ast = nanomatch.parse(ast, options); - } +utils.equalsPattern = function(pattern, options) { + var unixify = utils.unixify(options); + options = options || {}; - function compile() { - var snapdragon = utils.instantiate(ast, options); - compilers(snapdragon, options); - return snapdragon.compile(ast, options); - } + return function fn(filepath) { + var equal = utils._equals(filepath, unixify(filepath), pattern); + if (equal === true || options.nocase !== true) { + return equal; + } + var lower = filepath.toLowerCase(); + return utils._equals(lower, unixify(lower), pattern); + }; +}; + +/** + * Returns a function that returns true if the given + * pattern contains a `filepath` + * + * @param {String} `pattern` + * @return {Function} + */ - return memoize('compile', ast.input, options, compile); +utils.containsPattern = function(pattern, options) { + var unixify = utils.unixify(options); + options = options || {}; + + return function(filepath) { + var contains = utils._contains(filepath, unixify(filepath), pattern); + if (contains === true || options.nocase !== true) { + return contains; + } + var lower = filepath.toLowerCase(); + return utils._contains(lower, unixify(lower), pattern); + }; }; /** - * Clear the regex cache. + * Returns a function that returns true if the given + * regex matches the `filename` of a file path. * - * ```js - * nm.clearCache(); - * ``` - * @api public + * @param {RegExp} `re` Matching regex + * @return {Function} */ -nanomatch.clearCache = function() { - nanomatch.cache.__data__ = {}; +utils.matchBasename = function(re) { + return function(filepath) { + return re.test(filepath) || re.test(path.basename(filepath)); + }; }; /** - * Compose a matcher function with the given patterns. - * This allows matcher functions to be compiled once and - * called multiple times. + * Returns the given value unchanced. + * @return {any} */ -function compose(patterns, options, matcher) { - var matchers; - - return memoize('compose', String(patterns), options, function() { - return function(file) { - // delay composition until it's invoked the first time, - // after that it won't be called again - if (!matchers) { - matchers = []; - for (var i = 0; i < patterns.length; i++) { - matchers.push(matcher(patterns[i], options)); - } - } - - var len = matchers.length; - while (len--) { - if (matchers[len](file) === true) { - return true; - } - } - return false; - }; - }); -} +utils.identity = function(val) { + return val; +}; /** - * Memoize a generated regex or function. A unique key is generated - * from the `type` (usually method name), the `pattern`, and - * user-defined options. + * Determines the filepath to return based on the provided options. + * @return {any} */ -function memoize(type, pattern, options, fn) { - var key = utils.createKey(type + '=' + pattern, options); - - if (options && options.cache === false) { - return fn(pattern, options); +utils.value = function(str, unixify, options) { + if (options && options.unixify === false) { + return str; } - - if (cache.has(type, key)) { - return cache.get(type, key); + if (options && typeof options.unixify === 'function') { + return options.unixify(str); } - - var val = fn(pattern, options); - cache.set(type, key, val); - return val; -} + return unixify(str); +}; /** - * Expose compiler, parser and cache on `nanomatch` + * Returns a function that normalizes slashes in a string to forward + * slashes, strips `./` from beginning of paths, and optionally unescapes + * special characters. + * @return {Function} */ -nanomatch.compilers = compilers; -nanomatch.parsers = parsers; -nanomatch.cache = cache; +utils.unixify = function(options) { + var opts = options || {}; + return function(filepath) { + if (opts.stripPrefix !== false) { + filepath = utils.stripPrefix(filepath); + } + if (opts.unescape === true) { + filepath = utils.unescape(filepath); + } + if (opts.unixify === true || utils.isWindows()) { + filepath = utils.toPosixPath(filepath); + } + return filepath; + }; +}; -/** - * Expose `nanomatch` - * @type {Function} + +/***/ }), +/* 846 */ +/***/ (function(module, exports, __webpack_require__) { + +var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! + * is-windows + * + * Copyright © 2015-2018, Jon Schlinkert. + * Released under the MIT License. */ -module.exports = nanomatch; +(function(factory) { + if (exports && typeof exports === 'object' && typeof module !== 'undefined') { + module.exports = factory(); + } else if (true) { + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else {} +})(function() { + 'use strict'; + return function isWindows() { + return process && (process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE)); + }; +}); /***/ }), -/* 842 */ +/* 847 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * define-property + * + * Copyright (c) 2015-2018, Jon Schlinkert. + * Released under the MIT License. + */ -var isExtendable = __webpack_require__(843); -var assignSymbols = __webpack_require__(748); -module.exports = Object.assign || function(obj/*, objects*/) { - if (obj === null || typeof obj === 'undefined') { - throw new TypeError('Cannot convert undefined or null to object'); - } - if (!isObject(obj)) { - obj = {}; - } - for (var i = 1; i < arguments.length; i++) { - var val = arguments[i]; - if (isString(val)) { - val = toObject(val); - } - if (isObject(val)) { - assign(obj, val); - assignSymbols(obj, val); - } - } - return obj; -}; +var isobject = __webpack_require__(742); +var isDescriptor = __webpack_require__(754); +var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) + ? Reflect.defineProperty + : Object.defineProperty; -function assign(a, b) { - for (var key in b) { - if (hasOwn(b, key)) { - a[key] = b[key]; - } +module.exports = function defineProperty(obj, key, val) { + if (!isobject(obj) && typeof obj !== 'function' && !Array.isArray(obj)) { + throw new TypeError('expected an object, function, or array'); } -} - -function isString(val) { - return (val && typeof val === 'string'); -} -function toObject(str) { - var obj = {}; - for (var i in str) { - obj[i] = str[i]; + if (typeof key !== 'string') { + throw new TypeError('expected "key" to be a string'); } - return obj; -} - -function isObject(val) { - return (val && typeof val === 'object') || isExtendable(val); -} -/** - * Returns true if the given `key` is an own property of `obj`. - */ + if (isDescriptor(val)) { + define(obj, key, val); + return obj; + } -function hasOwn(obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key); -} + define(obj, key, { + configurable: true, + enumerable: false, + writable: true, + value: val + }); -function isEnum(obj, key) { - return Object.prototype.propertyIsEnumerable.call(obj, key); -} + return obj; +}; /***/ }), -/* 843 */ +/* 848 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; /*! - * is-extendable + * arr-diff * - * Copyright (c) 2015-2017, Jon Schlinkert. + * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. */ -var isPlainObject = __webpack_require__(746); - -module.exports = function isExtendable(val) { - return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); +module.exports = function diff(arr/*, arrays*/) { + var len = arguments.length; + var idx = 0; + while (++idx < len) { + arr = diffArray(arr, arguments[idx]); + } + return arr; }; +function diffArray(one, two) { + if (!Array.isArray(two)) { + return one.slice(); + } -/***/ }), -/* 844 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; + var tlen = two.length + var olen = one.length; + var idx = -1; + var arr = []; + while (++idx < olen) { + var ele = one[idx]; -/** -* Nanomatch compilers -*/ + var hasEle = false; + for (var i = 0; i < tlen; i++) { + var val = two[i]; -module.exports = function(nanomatch, options) { - function slash() { - if (options && typeof options.slash === 'string') { - return options.slash; - } - if (options && typeof options.slash === 'function') { - return options.slash.call(nanomatch); + if (ele === val) { + hasEle = true; + break; + } } - return '\\\\/'; - } - function star() { - if (options && typeof options.star === 'string') { - return options.star; - } - if (options && typeof options.star === 'function') { - return options.star.call(nanomatch); + if (hasEle === false) { + arr.push(ele); } - return '[^' + slash() + ']*?'; } + return arr; +} - var ast = nanomatch.ast = nanomatch.parser.ast; - ast.state = nanomatch.parser.state; - nanomatch.compiler.state = ast.state; - nanomatch.compiler - - /** - * Negation / escaping - */ - - .set('not', function(node) { - var prev = this.prev(); - if (this.options.nonegate === true || prev.type !== 'bos') { - return this.emit('\\' + node.val, node); - } - return this.emit(node.val, node); - }) - .set('escape', function(node) { - if (this.options.unescape && /^[-\w_.]/.test(node.val)) { - return this.emit(node.val, node); - } - return this.emit('\\' + node.val, node); - }) - .set('quoted', function(node) { - return this.emit(node.val, node); - }) - - /** - * Regex - */ - - .set('dollar', function(node) { - if (node.parent.type === 'bracket') { - return this.emit(node.val, node); - } - return this.emit('\\' + node.val, node); - }) - - /** - * Dot: "." - */ - - .set('dot', function(node) { - if (node.dotfiles === true) this.dotfiles = true; - return this.emit('\\' + node.val, node); - }) - /** - * Slashes: "/" and "\" - */ +/***/ }), +/* 849 */ +/***/ (function(module, exports, __webpack_require__) { - .set('backslash', function(node) { - return this.emit(node.val, node); - }) - .set('slash', function(node, nodes, i) { - var val = '[' + slash() + ']'; - var parent = node.parent; - var prev = this.prev(); +"use strict"; +/*! + * object.pick + * + * Copyright (c) 2014-2015 Jon Schlinkert, contributors. + * Licensed under the MIT License + */ - // set "node.hasSlash" to true on all ancestor parens nodes - while (parent.type === 'paren' && !parent.hasSlash) { - parent.hasSlash = true; - parent = parent.parent; - } - if (prev.addQmark) { - val += '?'; - } - // word boundary - if (node.rest.slice(0, 2) === '\\b') { - return this.emit(val, node); - } +var isObject = __webpack_require__(742); - // globstars - if (node.parsed === '**' || node.parsed === './**') { - this.output = '(?:' + this.output; - return this.emit(val + ')?', node); - } +module.exports = function pick(obj, keys) { + if (!isObject(obj) && typeof obj !== 'function') { + return {}; + } - // negation - if (node.parsed === '!**' && this.options.nonegate !== true) { - return this.emit(val + '?\\b', node); - } - return this.emit(val, node); - }) + var res = {}; + if (typeof keys === 'string') { + if (keys in obj) { + res[keys] = obj[keys]; + } + return res; + } - /** - * Square brackets - */ + var len = keys.length; + var idx = -1; - .set('bracket', function(node) { - var close = node.close; - var open = !node.escaped ? '[' : '\\['; - var negated = node.negated; - var inner = node.inner; - var val = node.val; + while (++idx < len) { + var key = keys[idx]; + if (key in obj) { + res[key] = obj[key]; + } + } + return res; +}; - if (node.escaped === true) { - inner = inner.replace(/\\?(\W)/g, '\\$1'); - negated = ''; - } - if (inner === ']-') { - inner = '\\]\\-'; - } +/***/ }), +/* 850 */ +/***/ (function(module, exports) { - if (negated && inner.indexOf('.') === -1) { - inner += '.'; - } - if (negated && inner.indexOf('/') === -1) { - inner += '/'; - } +var toString = Object.prototype.toString; - val = open + negated + inner + close; - return this.emit(val, node); - }) +module.exports = function kindOf(val) { + if (val === void 0) return 'undefined'; + if (val === null) return 'null'; - /** - * Square: "[.]" (only matches a single character in brackets) - */ + var type = typeof val; + if (type === 'boolean') return 'boolean'; + if (type === 'string') return 'string'; + if (type === 'number') return 'number'; + if (type === 'symbol') return 'symbol'; + if (type === 'function') { + return isGeneratorFn(val) ? 'generatorfunction' : 'function'; + } - .set('square', function(node) { - var val = (/^\W/.test(node.val) ? '\\' : '') + node.val; - return this.emit(val, node); - }) + if (isArray(val)) return 'array'; + if (isBuffer(val)) return 'buffer'; + if (isArguments(val)) return 'arguments'; + if (isDate(val)) return 'date'; + if (isError(val)) return 'error'; + if (isRegexp(val)) return 'regexp'; - /** - * Question mark: "?" - */ + switch (ctorName(val)) { + case 'Symbol': return 'symbol'; + case 'Promise': return 'promise'; - .set('qmark', function(node) { - var prev = this.prev(); - // don't use "slash" variable so that we always avoid - // matching backslashes and slashes with a qmark - var val = '[^.\\\\/]'; - if (this.options.dot || (prev.type !== 'bos' && prev.type !== 'slash')) { - val = '[^\\\\/]'; - } + // Set, Map, WeakSet, WeakMap + case 'WeakMap': return 'weakmap'; + case 'WeakSet': return 'weakset'; + case 'Map': return 'map'; + case 'Set': return 'set'; - if (node.parsed.slice(-1) === '(') { - var ch = node.rest.charAt(0); - if (ch === '!' || ch === '=' || ch === ':') { - return this.emit(node.val, node); - } - } + // 8-bit typed arrays + case 'Int8Array': return 'int8array'; + case 'Uint8Array': return 'uint8array'; + case 'Uint8ClampedArray': return 'uint8clampedarray'; - if (node.val.length > 1) { - val += '{' + node.val.length + '}'; - } - return this.emit(val, node); - }) + // 16-bit typed arrays + case 'Int16Array': return 'int16array'; + case 'Uint16Array': return 'uint16array'; - /** - * Plus - */ + // 32-bit typed arrays + case 'Int32Array': return 'int32array'; + case 'Uint32Array': return 'uint32array'; + case 'Float32Array': return 'float32array'; + case 'Float64Array': return 'float64array'; + } - .set('plus', function(node) { - var prev = node.parsed.slice(-1); - if (prev === ']' || prev === ')') { - return this.emit(node.val, node); - } - if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) { - return this.emit('\\+', node); - } - var ch = this.output.slice(-1); - if (/\w/.test(ch) && !node.inside) { - return this.emit('+\\+?', node); - } - return this.emit('+', node); - }) + if (isGeneratorObj(val)) { + return 'generator'; + } - /** - * globstar: '**' - */ + // Non-plain objects + type = toString.call(val); + switch (type) { + case '[object Object]': return 'object'; + // iterators + case '[object Map Iterator]': return 'mapiterator'; + case '[object Set Iterator]': return 'setiterator'; + case '[object String Iterator]': return 'stringiterator'; + case '[object Array Iterator]': return 'arrayiterator'; + } - .set('globstar', function(node, nodes, i) { - if (!this.output) { - this.state.leadingGlobstar = true; - } + // other + return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); +}; - var prev = this.prev(); - var before = this.prev(2); - var next = this.next(); - var after = this.next(2); - var type = prev.type; - var val = node.val; +function ctorName(val) { + return val.constructor ? val.constructor.name : null; +} - if (prev.type === 'slash' && next.type === 'slash') { - if (before.type === 'text') { - this.output += '?'; +function isArray(val) { + if (Array.isArray) return Array.isArray(val); + return val instanceof Array; +} - if (after.type !== 'text') { - this.output += '\\b'; - } - } - } +function isError(val) { + return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); +} - var parsed = node.parsed; - if (parsed.charAt(0) === '!') { - parsed = parsed.slice(1); - } +function isDate(val) { + if (val instanceof Date) return true; + return typeof val.toDateString === 'function' + && typeof val.getDate === 'function' + && typeof val.setDate === 'function'; +} - var isInside = node.isInside.paren || node.isInside.brace; - if (parsed && type !== 'slash' && type !== 'bos' && !isInside) { - val = star(); - } else { - val = this.options.dot !== true - ? '(?:(?!(?:[' + slash() + ']|^)\\.).)*?' - : '(?:(?!(?:[' + slash() + ']|^)(?:\\.{1,2})($|[' + slash() + ']))(?!\\.{2}).)*?'; - } +function isRegexp(val) { + if (val instanceof RegExp) return true; + return typeof val.flags === 'string' + && typeof val.ignoreCase === 'boolean' + && typeof val.multiline === 'boolean' + && typeof val.global === 'boolean'; +} - if ((type === 'slash' || type === 'bos') && this.options.dot !== true) { - val = '(?!\\.)' + val; - } +function isGeneratorFn(name, val) { + return ctorName(name) === 'GeneratorFunction'; +} - if (prev.type === 'slash' && next.type === 'slash' && before.type !== 'text') { - if (after.type === 'text' || after.type === 'star') { - node.addQmark = true; - } - } +function isGeneratorObj(val) { + return typeof val.throw === 'function' + && typeof val.return === 'function' + && typeof val.next === 'function'; +} - if (this.options.capture) { - val = '(' + val + ')'; - } +function isArguments(val) { + try { + if (typeof val.length === 'number' && typeof val.callee === 'function') { + return true; + } + } catch (err) { + if (err.message.indexOf('callee') !== -1) { + return true; + } + } + return false; +} - return this.emit(val, node); - }) +/** + * If you need to support Safari 5-7 (8-10 yr-old browser), + * take a look at https://github.com/feross/is-buffer + */ - /** - * Star: "*" - */ +function isBuffer(val) { + if (val.constructor && typeof val.constructor.isBuffer === 'function') { + return val.constructor.isBuffer(val); + } + return false; +} - .set('star', function(node, nodes, i) { - var prior = nodes[i - 2] || {}; - var prev = this.prev(); - var next = this.next(); - var type = prev.type; - function isStart(n) { - return n.type === 'bos' || n.type === 'slash'; - } +/***/ }), +/* 851 */ +/***/ (function(module, exports, __webpack_require__) { - if (this.output === '' && this.options.contains !== true) { - this.output = '(?![' + slash() + '])'; - } +"use strict"; - if (type === 'bracket' && this.options.bash === false) { - var str = next && next.type === 'bracket' ? star() : '*?'; - if (!prev.nodes || prev.nodes[1].type !== 'posix') { - return this.emit(str, node); - } - } - var prefix = !this.dotfiles && type !== 'text' && type !== 'escape' - ? (this.options.dot ? '(?!(?:^|[' + slash() + '])\\.{1,2}(?:$|[' + slash() + ']))' : '(?!\\.)') - : ''; +/** + * Module dependencies + */ - if (isStart(prev) || (isStart(prior) && type === 'not')) { - if (prefix !== '(?!\\.)') { - prefix += '(?!(\\.{2}|\\.[' + slash() + ']))(?=.)'; - } else { - prefix += '(?=.)'; - } - } else if (prefix === '(?!\\.)') { - prefix = ''; - } +var extend = __webpack_require__(732); +var unique = __webpack_require__(735); +var toRegex = __webpack_require__(723); - if (prev.type === 'not' && prior.type === 'bos' && this.options.dot === true) { - this.output = '(?!\\.)' + this.output; - } +/** + * Local dependencies + */ - var output = prefix + star(); - if (this.options.capture) { - output = '(' + output + ')'; - } +var compilers = __webpack_require__(852); +var parsers = __webpack_require__(863); +var Extglob = __webpack_require__(866); +var utils = __webpack_require__(865); +var MAX_LENGTH = 1024 * 64; - return this.emit(output, node); - }) +/** + * Convert the given `extglob` pattern into a regex-compatible string. Returns + * an object with the compiled result and the parsed AST. + * + * ```js + * var extglob = require('extglob'); + * console.log(extglob('*.!(*a)')); + * //=> '(?!\\.)[^/]*?\\.(?!(?!\\.)[^/]*?a\\b).*?' + * ``` + * @param {String} `pattern` + * @param {Object} `options` + * @return {String} + * @api public + */ - /** - * Text - */ +function extglob(pattern, options) { + return extglob.create(pattern, options).output; +} - .set('text', function(node) { - return this.emit(node.val, node); - }) +/** + * Takes an array of strings and an extglob pattern and returns a new + * array that contains only the strings that match the pattern. + * + * ```js + * var extglob = require('extglob'); + * console.log(extglob.match(['a.a', 'a.b', 'a.c'], '*.!(*a)')); + * //=> ['a.b', 'a.c'] + * ``` + * @param {Array} `list` Array of strings to match + * @param {String} `pattern` Extglob pattern + * @param {Object} `options` + * @return {Array} Returns an array of matches + * @api public + */ - /** - * End-of-string - */ +extglob.match = function(list, pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected pattern to be a string'); + } - .set('eos', function(node) { - var prev = this.prev(); - var val = node.val; + list = utils.arrayify(list); + var isMatch = extglob.matcher(pattern, options); + var len = list.length; + var idx = -1; + var matches = []; - this.output = '(?:\\.[' + slash() + '](?=.))?' + this.output; - if (this.state.metachar && prev.type !== 'qmark' && prev.type !== 'slash') { - val += (this.options.contains ? '[' + slash() + ']?' : '(?:[' + slash() + ']|$)'); - } + while (++idx < len) { + var ele = list[idx]; - return this.emit(val, node); - }); + if (isMatch(ele)) { + matches.push(ele); + } + } - /** - * Allow custom compilers to be passed on options - */ + // if no options were passed, uniquify results and return + if (typeof options === 'undefined') { + return unique(matches); + } - if (options && typeof options.compilers === 'function') { - options.compilers(nanomatch.compiler); + if (matches.length === 0) { + if (options.failglob === true) { + throw new Error('no matches found for "' + pattern + '"'); + } + if (options.nonull === true || options.nullglob === true) { + return [pattern.split('\\').join('')]; + } } + + return options.nodupes !== false ? unique(matches) : matches; }; +/** + * Returns true if the specified `string` matches the given + * extglob `pattern`. + * + * ```js + * var extglob = require('extglob'); + * + * console.log(extglob.isMatch('a.a', '*.!(*a)')); + * //=> false + * console.log(extglob.isMatch('a.b', '*.!(*a)')); + * //=> true + * ``` + * @param {String} `string` String to match + * @param {String} `pattern` Extglob pattern + * @param {String} `options` + * @return {Boolean} + * @api public + */ +extglob.isMatch = function(str, pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected pattern to be a string'); + } -/***/ }), -/* 845 */ -/***/ (function(module, exports, __webpack_require__) { + if (typeof str !== 'string') { + throw new TypeError('expected a string'); + } -"use strict"; + if (pattern === str) { + return true; + } + if (pattern === '' || pattern === ' ' || pattern === '.') { + return pattern === str; + } -var regexNot = __webpack_require__(739); -var toRegex = __webpack_require__(728); -var isOdd = __webpack_require__(846); + var isMatch = utils.memoize('isMatch', pattern, options, extglob.matcher); + return isMatch(str); +}; /** - * Characters to use in negation regex (we want to "not" match - * characters that are matched by other parsers) + * Returns true if the given `string` contains the given pattern. Similar to `.isMatch` but + * the pattern can match any part of the string. + * + * ```js + * var extglob = require('extglob'); + * console.log(extglob.contains('aa/bb/cc', '*b')); + * //=> true + * console.log(extglob.contains('aa/bb/cc', '*d')); + * //=> false + * ``` + * @param {String} `str` The string to match. + * @param {String} `pattern` Glob pattern to use for matching. + * @param {Object} `options` + * @return {Boolean} Returns true if the patter matches any part of `str`. + * @api public */ -var cached; -var NOT_REGEX = '[\\[!*+?$^"\'.\\\\/]+'; -var not = createTextRegex(NOT_REGEX); +extglob.contains = function(str, pattern, options) { + if (typeof str !== 'string') { + throw new TypeError('expected a string'); + } + + if (pattern === '' || pattern === ' ' || pattern === '.') { + return pattern === str; + } + + var opts = extend({}, options, {contains: true}); + opts.strictClose = false; + opts.strictOpen = false; + return extglob.isMatch(str, pattern, opts); +}; /** - * Nanomatch parsers + * Takes an extglob pattern and returns a matcher function. The returned + * function takes the string to match as its only argument. + * + * ```js + * var extglob = require('extglob'); + * var isMatch = extglob.matcher('*.!(*a)'); + * + * console.log(isMatch('a.a')); + * //=> false + * console.log(isMatch('a.b')); + * //=> true + * ``` + * @param {String} `pattern` Extglob pattern + * @param {String} `options` + * @return {Boolean} + * @api public */ -module.exports = function(nanomatch, options) { - var parser = nanomatch.parser; - var opts = parser.options; - - parser.state = { - slashes: 0, - paths: [] - }; +extglob.matcher = function(pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected pattern to be a string'); + } - parser.ast.state = parser.state; - parser + function matcher() { + var re = extglob.makeRe(pattern, options); + return function(str) { + return re.test(str); + }; + } - /** - * Beginning-of-string - */ + return utils.memoize('matcher', pattern, options, matcher); +}; - .capture('prefix', function() { - if (this.parsed) return; - var m = this.match(/^\.[\\/]/); - if (!m) return; - this.state.strictOpen = !!this.options.strictOpen; - this.state.addPrefix = true; - }) +/** + * Convert the given `extglob` pattern into a regex-compatible string. Returns + * an object with the compiled result and the parsed AST. + * + * ```js + * var extglob = require('extglob'); + * console.log(extglob.create('*.!(*a)').output); + * //=> '(?!\\.)[^/]*?\\.(?!(?!\\.)[^/]*?a\\b).*?' + * ``` + * @param {String} `str` + * @param {Object} `options` + * @return {String} + * @api public + */ - /** - * Escape: "\\." - */ +extglob.create = function(pattern, options) { + if (typeof pattern !== 'string') { + throw new TypeError('expected pattern to be a string'); + } - .capture('escape', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^(?:\\(.)|([$^]))/); - if (!m) return; + function create() { + var ext = new Extglob(options); + var ast = ext.parse(pattern, options); + return ext.compile(ast, options); + } - return pos({ - type: 'escape', - val: m[2] || m[1] - }); - }) + return utils.memoize('create', pattern, options, create); +}; - /** - * Quoted strings - */ +/** + * Returns an array of matches captured by `pattern` in `string`, or `null` + * if the pattern did not match. + * + * ```js + * var extglob = require('extglob'); + * extglob.capture(pattern, string[, options]); + * + * console.log(extglob.capture('test/*.js', 'test/foo.js')); + * //=> ['foo'] + * console.log(extglob.capture('test/*.js', 'foo/bar.css')); + * //=> null + * ``` + * @param {String} `pattern` Glob pattern to use for matching. + * @param {String} `string` 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 string matches the glob pattern, otherwise `null`. + * @api public + */ - .capture('quoted', function() { - var pos = this.position(); - var m = this.match(/^["']/); - if (!m) return; +extglob.capture = function(pattern, str, options) { + var re = extglob.makeRe(pattern, extend({capture: true}, options)); - var quote = m[0]; - if (this.input.indexOf(quote) === -1) { - return pos({ - type: 'escape', - val: quote - }); + function match() { + return function(string) { + var match = re.exec(string); + if (!match) { + return null; } - var tok = advanceTo(this.input, quote); - this.consume(tok.len); + return match.slice(1); + }; + } - return pos({ - type: 'quoted', - val: tok.esc - }); - }) + var capture = utils.memoize('capture', pattern, options, match); + return capture(str); +}; - /** - * Negations: "!" - */ +/** + * Create a regular expression from the given `pattern` and `options`. + * + * ```js + * var extglob = require('extglob'); + * var re = extglob.makeRe('*.!(*a)'); + * console.log(re); + * //=> /^[^\/]*?\.(?![^\/]*?a)[^\/]*?$/ + * ``` + * @param {String} `pattern` The pattern to convert to regex. + * @param {Object} `options` + * @return {RegExp} + * @api public + */ - .capture('not', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(this.notRegex || /^!+/); - if (!m) return; - var val = m[0]; +extglob.makeRe = function(pattern, options) { + if (pattern instanceof RegExp) { + return pattern; + } - var isNegated = isOdd(val.length); - if (parsed === '' && !isNegated) { - val = ''; - } + if (typeof pattern !== 'string') { + throw new TypeError('expected pattern to be a string'); + } - // if nothing has been parsed, we know `!` is at the start, - // so we need to wrap the result in a negation regex - if (parsed === '' && isNegated && this.options.nonegate !== true) { - this.bos.val = '(?!^(?:'; - this.append = ')$).*'; - val = ''; - } - return pos({ - type: 'not', - val: val - }); - }) + if (pattern.length > MAX_LENGTH) { + throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); + } - /** - * Dot: "." - */ + function makeRe() { + var opts = extend({strictErrors: false}, options); + if (opts.strictErrors === true) opts.strict = true; + var res = extglob.create(pattern, opts); + return toRegex(res.output, opts); + } - .capture('dot', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\.+/); - if (!m) return; + var regex = utils.memoize('makeRe', pattern, options, makeRe); + if (regex.source.length > MAX_LENGTH) { + throw new SyntaxError('potentially malicious regex detected'); + } - var val = m[0]; - this.state.dot = val === '.' && (parsed === '' || parsed.slice(-1) === '/'); + return regex; +}; - return pos({ - type: 'dot', - dotfiles: this.state.dot, - val: val - }); - }) +/** + * Cache + */ - /** - * Plus: "+" - */ +extglob.cache = utils.cache; +extglob.clearCache = function() { + extglob.cache.__data__ = {}; +}; - .capture('plus', /^\+(?!\()/) +/** + * Expose `Extglob` constructor, parsers and compilers + */ - /** - * Question mark: "?" - */ +extglob.Extglob = Extglob; +extglob.compilers = compilers; +extglob.parsers = parsers; - .capture('qmark', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\?+(?!\()/); - if (!m) return; +/** + * Expose `extglob` + * @type {Function} + */ - this.state.metachar = true; - this.state.qmark = true; +module.exports = extglob; - return pos({ - type: 'qmark', - parsed: parsed, - val: m[0] - }); - }) - /** - * Globstar: "**" - */ +/***/ }), +/* 852 */ +/***/ (function(module, exports, __webpack_require__) { - .capture('globstar', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\*{2}(?![*(])(?=[,)/]|$)/); - if (!m) return; +"use strict"; - var type = opts.noglobstar !== true ? 'globstar' : 'star'; - var node = pos({type: type, parsed: parsed}); - this.state.metachar = true; - while (this.input.slice(0, 4) === '/**/') { - this.input = this.input.slice(3); - } +var brackets = __webpack_require__(853); - node.isInside = { - brace: this.isInside('brace'), - paren: this.isInside('paren') - }; +/** + * Extglob compilers + */ - if (type === 'globstar') { - this.state.globstar = true; - node.val = '**'; +module.exports = function(extglob) { + function star() { + if (typeof extglob.options.star === 'function') { + return extglob.options.star.apply(this, arguments); + } + if (typeof extglob.options.star === 'string') { + return extglob.options.star; + } + return '.*?'; + } - } else { - this.state.star = true; - node.val = '*'; - } + /** + * Use `expand-brackets` compilers + */ - return node; - }) + extglob.use(brackets.compilers); + extglob.compiler /** - * Star: "*" + * Escaped: "\\*" */ - .capture('star', function() { - var pos = this.position(); - var starRe = /^(?:\*(?![*(])|[*]{3,}(?!\()|[*]{2}(?![(/]|$)|\*(?=\*\())/; - var m = this.match(starRe); - if (!m) return; - - this.state.metachar = true; - this.state.star = true; - return pos({ - type: 'star', - val: m[0] - }); + .set('escape', function(node) { + return this.emit(node.val, node); }) /** - * Slash: "/" + * Dot: "." */ - .capture('slash', function() { - var pos = this.position(); - var m = this.match(/^\//); - if (!m) return; - - this.state.slashes++; - return pos({ - type: 'slash', - val: m[0] - }); + .set('dot', function(node) { + return this.emit('\\' + node.val, node); }) /** - * Backslash: "\\" + * Question mark: "?" */ - .capture('backslash', function() { - var pos = this.position(); - var m = this.match(/^\\(?![*+?(){}[\]'"])/); - if (!m) return; + .set('qmark', function(node) { + var val = '[^\\\\/.]'; + var prev = this.prev(); - var val = m[0]; + if (node.parsed.slice(-1) === '(') { + var ch = node.rest.charAt(0); + if (ch !== '!' && ch !== '=' && ch !== ':') { + return this.emit(val, node); + } + return this.emit(node.val, node); + } - if (this.isInside('bracket')) { - val = '\\'; - } else if (val.length > 1) { - val = '\\\\'; + if (prev.type === 'text' && prev.val) { + return this.emit(val, node); } - return pos({ - type: 'backslash', - val: val - }); + if (node.val.length > 1) { + val += '{' + node.val.length + '}'; + } + return this.emit(val, node); }) /** - * Square: "[.]" + * Plus: "+" */ - .capture('square', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^\[([^!^\\])\]/); - if (!m) return; + .set('plus', function(node) { + var prev = node.parsed.slice(-1); + if (prev === ']' || prev === ')') { + return this.emit(node.val, node); + } + var ch = this.output.slice(-1); + if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) { + return this.emit('\\+', node); + } + if (/\w/.test(ch) && !node.inside) { + return this.emit('+\\+?', node); + } + return this.emit('+', node); + }) - return pos({ - type: 'square', - val: m[1] - }); + /** + * Star: "*" + */ + + .set('star', function(node) { + var prev = this.prev(); + var prefix = prev.type !== 'text' && prev.type !== 'escape' + ? '(?!\\.)' + : ''; + + return this.emit(prefix + star.call(this, node), node); }) /** - * Brackets: "[...]" (basic, this can be overridden by other parsers) + * Parens */ - .capture('bracket', function() { - var pos = this.position(); - var m = this.match(/^(?:\[([!^]?)([^\]]+|\]-)(\]|[^*+?]+)|\[)/); - if (!m) return; + .set('paren', function(node) { + return this.mapVisit(node.nodes); + }) + .set('paren.open', function(node) { + var capture = this.options.capture ? '(' : ''; - var val = m[0]; - var negated = m[1] ? '^' : ''; - var inner = (m[2] || '').replace(/\\\\+/, '\\\\'); - var close = m[3] || ''; + switch (node.parent.prefix) { + case '!': + case '^': + return this.emit(capture + '(?:(?!(?:', node); + case '*': + case '+': + case '?': + case '@': + return this.emit(capture + '(?:', node); + default: { + var val = node.val; + if (this.options.bash === true) { + val = '\\' + val; + } else if (!this.options.capture && val === '(' && node.parent.rest[0] !== '?') { + val += '?:'; + } - if (m[2] && inner.length < m[2].length) { - val = val.replace(/\\\\+/, '\\\\'); + return this.emit(val, node); + } } + }) + .set('paren.close', function(node) { + var capture = this.options.capture ? ')' : ''; - var esc = this.input.slice(0, 2); - if (inner === '' && esc === '\\]') { - inner += esc; - this.consume(2); - - var str = this.input; - var idx = -1; - var ch; + switch (node.prefix) { + case '!': + case '^': + var prefix = /^(\)|$)/.test(node.rest) ? '$' : ''; + var str = star.call(this, node); - while ((ch = str[++idx])) { - this.consume(1); - if (ch === ']') { - close = ch; - break; + // if the extglob has a slash explicitly defined, we know the user wants + // to match slashes, so we need to ensure the "star" regex allows for it + if (node.parent.hasSlash && !this.options.star && this.options.slash !== false) { + str = '.*?'; } - inner += ch; + + return this.emit(prefix + ('))' + str + ')') + capture, node); + case '*': + case '+': + case '?': + return this.emit(')' + node.prefix + capture, node); + case '@': + return this.emit(')' + capture, node); + default: { + var val = (this.options.bash === true ? '\\' : '') + ')'; + return this.emit(val, node); } } - - return pos({ - type: 'bracket', - val: val, - escaped: close !== ']', - negated: negated, - inner: inner, - close: close - }); }) /** * Text */ - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; - - return pos({ - type: 'text', - val: m[0] - }); + .set('text', function(node) { + var val = node.val.replace(/[\[\]]/g, '\\$&'); + return this.emit(val, node); }); - - /** - * Allow custom parsers to be passed on options - */ - - if (options && typeof options.parsers === 'function') { - options.parsers(nanomatch.parser); - } }; -/** - * Advance to the next non-escaped character - */ - -function advanceTo(input, endChar) { - var ch = input.charAt(0); - var tok = { len: 1, val: '', esc: '' }; - var idx = 0; - - function advance() { - if (ch !== '\\') { - tok.esc += '\\' + ch; - tok.val += ch; - } - ch = input.charAt(++idx); - tok.len++; +/***/ }), +/* 853 */ +/***/ (function(module, exports, __webpack_require__) { - if (ch === '\\') { - advance(); - advance(); - } - } +"use strict"; - while (ch && ch !== endChar) { - advance(); - } - return tok; -} /** - * Create text regex + * Local dependencies */ -function createTextRegex(pattern) { - if (cached) return cached; - var opts = {contains: true, strictClose: false}; - var not = regexNot.create(pattern, opts); - var re = toRegex('^(?:[*]\\((?=.)|' + not + ')', opts); - return (cached = re); -} +var compilers = __webpack_require__(854); +var parsers = __webpack_require__(856); /** - * Expose negation string + * Module dependencies */ -module.exports.not = NOT_REGEX; +var debug = __webpack_require__(858)('expand-brackets'); +var extend = __webpack_require__(732); +var Snapdragon = __webpack_require__(762); +var toRegex = __webpack_require__(723); +/** + * Parses the given POSIX character class `pattern` and returns a + * string that can be used for creating regular expressions for matching. + * + * @param {String} `pattern` + * @param {Object} `options` + * @return {Object} + * @api public + */ -/***/ }), -/* 846 */ -/***/ (function(module, exports, __webpack_require__) { +function brackets(pattern, options) { + debug('initializing from <%s>', __filename); + var res = brackets.create(pattern, options); + return res.output; +} -"use strict"; -/*! - * is-odd +/** + * Takes an array of strings and a POSIX character class pattern, and returns a new + * array with only the strings that matched the pattern. * - * Copyright (c) 2015-2017, Jon Schlinkert. - * Released under the MIT License. + * ```js + * var brackets = require('expand-brackets'); + * console.log(brackets.match(['1', 'a', 'ab'], '[[:alpha:]]')); + * //=> ['a'] + * + * console.log(brackets.match(['1', 'a', 'ab'], '[[:alpha:]]+')); + * //=> ['a', 'ab'] + * ``` + * @param {Array} `arr` Array of strings to match + * @param {String} `pattern` POSIX character class pattern(s) + * @param {Object} `options` + * @return {Array} + * @api public */ +brackets.match = function(arr, pattern, options) { + arr = [].concat(arr); + var opts = extend({}, options); + var isMatch = brackets.matcher(pattern, opts); + var len = arr.length; + var idx = -1; + var res = []; + while (++idx < len) { + var ele = arr[idx]; + if (isMatch(ele)) { + res.push(ele); + } + } -var isNumber = __webpack_require__(847); + if (res.length === 0) { + if (opts.failglob === true) { + throw new Error('no matches found for "' + pattern + '"'); + } -module.exports = function isOdd(i) { - if (!isNumber(i)) { - throw new TypeError('is-odd expects a number.'); - } - if (Number(i) !== Math.floor(i)) { - throw new RangeError('is-odd expects an integer.'); + if (opts.nonull === true || opts.nullglob === true) { + return [pattern.split('\\').join('')]; + } } - return !!(~~i & 1); + return res; }; - -/***/ }), -/* 847 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/*! - * is-number +/** + * Returns true if the specified `string` matches the given + * brackets `pattern`. * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. + * ```js + * var brackets = require('expand-brackets'); + * + * console.log(brackets.isMatch('a.a', '[[:alpha:]].[[:alpha:]]')); + * //=> true + * console.log(brackets.isMatch('1.2', '[[:alpha:]].[[:alpha:]]')); + * //=> false + * ``` + * @param {String} `string` String to match + * @param {String} `pattern` Poxis pattern + * @param {String} `options` + * @return {Boolean} + * @api public */ - - -module.exports = function isNumber(num) { - var type = typeof num; - - if (type === 'string' || num instanceof String) { - // an empty string would be coerced to true with the below logic - if (!num.trim()) return false; - } else if (type !== 'number' && !(num instanceof Number)) { - return false; - } - - return (num - num + 1) >= 0; +brackets.isMatch = function(str, pattern, options) { + return brackets.matcher(pattern, options)(str); }; +/** + * Takes a POSIX character class pattern and returns a matcher function. The returned + * function takes the string to match as its only argument. + * + * ```js + * var brackets = require('expand-brackets'); + * var isMatch = brackets.matcher('[[:lower:]].[[:upper:]]'); + * + * console.log(isMatch('a.a')); + * //=> false + * console.log(isMatch('a.A')); + * //=> true + * ``` + * @param {String} `pattern` Poxis pattern + * @param {String} `options` + * @return {Boolean} + * @api public + */ -/***/ }), -/* 848 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = new (__webpack_require__(849))(); +brackets.matcher = function(pattern, options) { + var re = brackets.makeRe(pattern, options); + return function(str) { + return re.test(str); + }; +}; +/** + * Create a regular expression from the given `pattern`. + * + * ```js + * var brackets = require('expand-brackets'); + * var re = brackets.makeRe('[[:alpha:]]'); + * console.log(re); + * //=> /^(?:[a-zA-Z])$/ + * ``` + * @param {String} `pattern` The pattern to convert to regex. + * @param {Object} `options` + * @return {RegExp} + * @api public + */ -/***/ }), -/* 849 */ -/***/ (function(module, exports, __webpack_require__) { +brackets.makeRe = function(pattern, options) { + var res = brackets.create(pattern, options); + var opts = extend({strictErrors: false}, options); + return toRegex(res.output, opts); +}; -"use strict"; -/*! - * fragment-cache +/** + * Parses the given POSIX character class `pattern` and returns an object + * with the compiled `output` and optional source `map`. * - * Copyright (c) 2016-2017, Jon Schlinkert. - * Released under the MIT License. + * ```js + * var brackets = require('expand-brackets'); + * console.log(brackets('[[:alpha:]]')); + * // { options: { source: 'string' }, + * // input: '[[:alpha:]]', + * // state: {}, + * // compilers: + * // { eos: [Function], + * // noop: [Function], + * // bos: [Function], + * // not: [Function], + * // escape: [Function], + * // text: [Function], + * // posix: [Function], + * // bracket: [Function], + * // 'bracket.open': [Function], + * // 'bracket.inner': [Function], + * // 'bracket.literal': [Function], + * // 'bracket.close': [Function] }, + * // output: '[a-zA-Z]', + * // ast: + * // { type: 'root', + * // errors: [], + * // nodes: [ [Object], [Object], [Object] ] }, + * // parsingErrors: [] } + * ``` + * @param {String} `pattern` + * @param {Object} `options` + * @return {Object} + * @api public */ +brackets.create = function(pattern, options) { + var snapdragon = (options && options.snapdragon) || new Snapdragon(options); + compilers(snapdragon); + parsers(snapdragon); - -var MapCache = __webpack_require__(827); + var ast = snapdragon.parse(pattern, options); + ast.input = pattern; + var res = snapdragon.compile(ast, options); + res.input = pattern; + return res; +}; /** - * Create a new `FragmentCache` with an optional object to use for `caches`. - * - * ```js - * var fragment = new FragmentCache(); - * ``` - * @name FragmentCache - * @param {String} `cacheName` - * @return {Object} Returns the [map-cache][] instance. - * @api public + * Expose `brackets` constructor, parsers and compilers */ -function FragmentCache(caches) { - this.caches = caches || {}; -} +brackets.compilers = compilers; +brackets.parsers = parsers; /** - * Prototype + * Expose `brackets` + * @type {Function} */ -FragmentCache.prototype = { +module.exports = brackets; - /** - * Get cache `name` from the `fragment.caches` object. Creates a new - * `MapCache` if it doesn't already exist. - * - * ```js - * var cache = fragment.cache('files'); - * console.log(fragment.caches.hasOwnProperty('files')); - * //=> true - * ``` - * @name .cache - * @param {String} `cacheName` - * @return {Object} Returns the [map-cache][] instance. - * @api public - */ - cache: function(cacheName) { - return this.caches[cacheName] || (this.caches[cacheName] = new MapCache()); - }, +/***/ }), +/* 854 */ +/***/ (function(module, exports, __webpack_require__) { - /** - * Set a value for property `key` on cache `name` - * - * ```js - * fragment.set('files', 'somefile.js', new File({path: 'somefile.js'})); - * ``` - * @name .set - * @param {String} `name` - * @param {String} `key` Property name to set - * @param {any} `val` The value of `key` - * @return {Object} The cache instance for chaining - * @api public - */ +"use strict"; - set: function(cacheName, key, val) { - var cache = this.cache(cacheName); - cache.set(key, val); - return cache; - }, - /** - * Returns true if a non-undefined value is set for `key` on fragment cache `name`. - * - * ```js - * var cache = fragment.cache('files'); - * cache.set('somefile.js'); - * - * console.log(cache.has('somefile.js')); - * //=> true - * - * console.log(cache.has('some-other-file.js')); - * //=> false - * ``` - * @name .has - * @param {String} `name` Cache name - * @param {String} `key` Optionally specify a property to check for on cache `name` - * @return {Boolean} - * @api public - */ +var posix = __webpack_require__(855); - has: function(cacheName, key) { - return typeof this.get(cacheName, key) !== 'undefined'; - }, +module.exports = function(brackets) { + brackets.compiler - /** - * Get `name`, or if specified, the value of `key`. Invokes the [cache]() method, - * so that cache `name` will be created it doesn't already exist. If `key` is not passed, - * the entire cache (`name`) is returned. - * - * ```js - * var Vinyl = require('vinyl'); - * var cache = fragment.cache('files'); - * cache.set('somefile.js', new Vinyl({path: 'somefile.js'})); - * console.log(cache.get('somefile.js')); - * //=> - * ``` - * @name .get - * @param {String} `name` - * @return {Object} Returns cache `name`, or the value of `key` if specified - * @api public - */ + /** + * Escaped characters + */ - get: function(name, key) { - var cache = this.cache(name); - if (typeof key === 'string') { - return cache.get(key); - } - return cache; - } -}; + .set('escape', function(node) { + return this.emit('\\' + node.val.replace(/^\\/, ''), node); + }) -/** - * Expose `FragmentCache` - */ + /** + * Text + */ -exports = module.exports = FragmentCache; + .set('text', function(node) { + return this.emit(node.val.replace(/([{}])/g, '\\$1'), node); + }) + /** + * POSIX character classes + */ -/***/ }), -/* 850 */ -/***/ (function(module, exports, __webpack_require__) { + .set('posix', function(node) { + if (node.val === '[::]') { + return this.emit('\\[::\\]', node); + } -"use strict"; + var val = posix[node.inner]; + if (typeof val === 'undefined') { + val = '[' + node.inner + ']'; + } + return this.emit(val, node); + }) + /** + * Non-posix brackets + */ -var utils = module.exports; -var path = __webpack_require__(16); + .set('bracket', function(node) { + return this.mapVisit(node.nodes); + }) + .set('bracket.open', function(node) { + return this.emit(node.val, node); + }) + .set('bracket.inner', function(node) { + var inner = node.val; -/** - * Module dependencies - */ + if (inner === '[' || inner === ']') { + return this.emit('\\' + node.val, node); + } + if (inner === '^]') { + return this.emit('^\\]', node); + } + if (inner === '^') { + return this.emit('^', node); + } -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); + if (/-/.test(inner) && !/(\d-\d|\w-\w)/.test(inner)) { + inner = inner.split('-').join('\\-'); + } -/** - * Returns true if the given value is effectively an empty string - */ + var isNegated = inner.charAt(0) === '^'; + // add slashes to negated brackets, per spec + if (isNegated && inner.indexOf('/') === -1) { + inner += '/'; + } + if (isNegated && inner.indexOf('.') === -1) { + inner += '.'; + } -utils.isEmptyString = function(val) { - return String(val) === '' || String(val) === './'; + // don't unescape `0` (octal literal) + inner = inner.replace(/\\([1-9])/g, '$1'); + return this.emit(inner, node); + }) + .set('bracket.close', function(node) { + var val = node.val.replace(/^\\/, ''); + if (node.parent.escaped === true) { + return this.emit('\\' + val, node); + } + return this.emit(val, node); + }); }; -/** - * Returns true if the platform is windows, or `path.sep` is `\\`. - * This is defined as a function to allow `path.sep` to be set in unit tests, - * or by the user, if there is a reason to do so. - * @return {Boolean} - */ -utils.isWindows = function() { - return path.sep === '\\' || isWindows === true; -}; +/***/ }), +/* 855 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Return the last element from an array - */ +"use strict"; -utils.last = function(arr, n) { - return arr[arr.length - (n || 1)]; -}; /** - * Get the `Snapdragon` instance to use + * POSIX character classes */ -utils.instantiate = function(ast, options) { - var snapdragon; - // if an instance was created by `.parse`, use that instance - if (utils.typeOf(ast) === 'object' && ast.snapdragon) { - snapdragon = ast.snapdragon; - // if the user supplies an instance on options, use that instance - } else if (utils.typeOf(options) === 'object' && options.snapdragon) { - snapdragon = options.snapdragon; - // create a new instance - } else { - snapdragon = new Snapdragon(options); - } - - utils.define(snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.call(this, str, options); - parsed.input = str; - - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strictErrors !== true) { - var open = last.nodes[0]; - var inner = last.nodes[1]; - if (last.type === 'bracket') { - if (inner.val.charAt(0) === '[') { - inner.val = '\\' + inner.val; - } +module.exports = { + alnum: 'a-zA-Z0-9', + alpha: 'a-zA-Z', + ascii: '\\x00-\\x7F', + blank: ' \\t', + cntrl: '\\x00-\\x1F\\x7F', + digit: '0-9', + graph: '\\x21-\\x7E', + lower: 'a-z', + print: '\\x20-\\x7E ', + punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~', + space: ' \\t\\r\\n\\v\\f', + upper: 'A-Z', + word: 'A-Za-z0-9_', + xdigit: 'A-Fa-f0-9' +}; - } else { - open.val = '\\' + open.val; - var sibling = open.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } - } - } - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); +/***/ }), +/* 856 */ +/***/ (function(module, exports, __webpack_require__) { - return snapdragon; -}; +"use strict"; -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ -utils.createKey = function(pattern, options) { - if (typeof options === 'undefined') { - return pattern; - } - var key = pattern; - for (var prop in options) { - if (options.hasOwnProperty(prop)) { - key += ';' + prop + '=' + String(options[prop]); - } - } - return key; -}; +var utils = __webpack_require__(857); +var define = __webpack_require__(724); /** - * Cast `val` to an array - * @return {Array} + * Text regex */ -utils.arrayify = function(val) { - if (typeof val === 'string') return [val]; - return val ? (Array.isArray(val) ? val : [val]) : []; -}; +var TEXT_REGEX = '(\\[(?=.*\\])|\\])+'; +var not = utils.createRegex(TEXT_REGEX); /** - * Return true if `val` is a non-empty string + * Brackets parsers */ -utils.isString = function(val) { - return typeof val === 'string'; -}; - -/** - * Return true if `val` is a non-empty string - */ +function parsers(brackets) { + brackets.state = brackets.state || {}; + brackets.parser.sets.bracket = brackets.parser.sets.bracket || []; + brackets.parser -utils.isRegex = function(val) { - return utils.typeOf(val) === 'regexp'; -}; + .capture('escape', function() { + if (this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(/^\\(.)/); + if (!m) return; -/** - * Return true if `val` is a non-empty string - */ + return pos({ + type: 'escape', + val: m[0] + }); + }) -utils.isObject = function(val) { - return utils.typeOf(val) === 'object'; -}; + /** + * Text parser + */ -/** - * Escape regex characters in the given string - */ + .capture('text', function() { + if (this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(not); + if (!m || !m[0]) return; -utils.escapeRegex = function(str) { - return str.replace(/[-[\]{}()^$|*+?.\\/\s]/g, '\\$&'); -}; + return pos({ + type: 'text', + val: m[0] + }); + }) -/** - * Combines duplicate characters in the provided `input` string. - * @param {String} `input` - * @returns {String} - */ + /** + * POSIX character classes: "[[:alpha:][:digits:]]" + */ -utils.combineDupes = function(input, patterns) { - patterns = utils.arrayify(patterns).join('|').split('|'); - patterns = patterns.map(function(s) { - return s.replace(/\\?([+*\\/])/g, '\\$1'); - }); - var substr = patterns.join('|'); - var regex = new RegExp('(' + substr + ')(?=\\1)', 'g'); - return input.replace(regex, ''); -}; + .capture('posix', function() { + var pos = this.position(); + var m = this.match(/^\[:(.*?):\](?=.*\])/); + if (!m) return; -/** - * Returns true if the given `str` has special characters - */ + var inside = this.isInside('bracket'); + if (inside) { + brackets.posix++; + } -utils.hasSpecialChars = function(str) { - return /(?:(?:(^|\/)[!.])|[*?+()|[\]{}]|[+@]\()/.test(str); -}; + return pos({ + type: 'posix', + insideBracket: inside, + inner: m[1], + val: m[0] + }); + }) -/** - * Normalize slashes in the given filepath. - * - * @param {String} `filepath` - * @return {String} - */ + /** + * Bracket (noop) + */ -utils.toPosixPath = function(str) { - return str.replace(/\\+/g, '/'); -}; + .capture('bracket', function() {}) -/** - * Strip backslashes before special characters in a string. - * - * @param {String} `str` - * @return {String} - */ + /** + * Open: '[' + */ -utils.unescape = function(str) { - return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); -}; + .capture('bracket.open', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^\[(?=.*\])/); + if (!m) return; -/** - * Strip the drive letter from a windows filepath - * @param {String} `fp` - * @return {String} - */ + var prev = this.prev(); + var last = utils.last(prev.nodes); -utils.stripDrive = function(fp) { - return utils.isWindows() ? fp.replace(/^[a-z]:[\\/]+?/i, '/') : fp; -}; + if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { + last.val = last.val.slice(0, last.val.length - 1); + return pos({ + type: 'escape', + val: m[0] + }); + } -/** - * Strip the prefix from a filepath - * @param {String} `fp` - * @return {String} - */ + var open = pos({ + type: 'bracket.open', + val: m[0] + }); -utils.stripPrefix = function(str) { - if (str.charAt(0) === '.' && (str.charAt(1) === '/' || str.charAt(1) === '\\')) { - return str.slice(2); - } - return str; -}; + if (last.type === 'bracket.open' || this.isInside('bracket')) { + open.val = '\\' + open.val; + open.type = 'bracket.inner'; + open.escaped = true; + return open; + } -/** - * Returns true if `str` is a common character that doesn't need - * to be processed to be used for matching. - * @param {String} `str` - * @return {Boolean} - */ + var node = pos({ + type: 'bracket', + nodes: [open] + }); -utils.isSimpleChar = function(str) { - return str.trim() === '' || str === '.'; -}; + define(node, 'parent', prev); + define(open, 'parent', node); + this.push('bracket', node); + prev.nodes.push(node); + }) -/** - * Returns true if the given str is an escaped or - * unescaped path character - */ + /** + * Bracket text + */ -utils.isSlash = function(str) { - return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; -}; + .capture('bracket.inner', function() { + if (!this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(not); + if (!m || !m[0]) return; -/** - * Returns a function that returns true if the given - * pattern matches or contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ + var next = this.input.charAt(0); + var val = m[0]; -utils.matchPath = function(pattern, options) { - return (options && options.contains) - ? utils.containsPattern(pattern, options) - : utils.equalsPattern(pattern, options); -}; + var node = pos({ + type: 'bracket.inner', + val: val + }); -/** - * Returns true if the given (original) filepath or unixified path are equal - * to the given pattern. - */ + if (val === '\\\\') { + return node; + } -utils._equals = function(filepath, unixPath, pattern) { - return pattern === filepath || pattern === unixPath; -}; + var first = val.charAt(0); + var last = val.slice(-1); -/** - * Returns true if the given (original) filepath or unixified path contain - * the given pattern. - */ + if (first === '!') { + val = '^' + val.slice(1); + } -utils._contains = function(filepath, unixPath, pattern) { - return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; -}; + if (last === '\\' || (val === '^' && next === ']')) { + val += this.input[0]; + this.consume(1); + } -/** - * Returns a function that returns true if the given - * pattern is the same as a given `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ + node.val = val; + return node; + }) -utils.equalsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; + /** + * Close: ']' + */ - return function fn(filepath) { - var equal = utils._equals(filepath, unixify(filepath), pattern); - if (equal === true || options.nocase !== true) { - return equal; - } - var lower = filepath.toLowerCase(); - return utils._equals(lower, unixify(lower), pattern); - }; -}; + .capture('bracket.close', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^\]/); + if (!m) return; -/** - * Returns a function that returns true if the given - * pattern contains a `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ + var prev = this.prev(); + var last = utils.last(prev.nodes); -utils.containsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; + if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { + last.val = last.val.slice(0, last.val.length - 1); - return function(filepath) { - var contains = utils._contains(filepath, unixify(filepath), pattern); - if (contains === true || options.nocase !== true) { - return contains; - } - var lower = filepath.toLowerCase(); - return utils._contains(lower, unixify(lower), pattern); - }; -}; + return pos({ + type: 'escape', + val: m[0] + }); + } -/** - * Returns a function that returns true if the given - * regex matches the `filename` of a file path. - * - * @param {RegExp} `re` Matching regex - * @return {Function} - */ + var node = pos({ + type: 'bracket.close', + rest: this.input, + val: m[0] + }); -utils.matchBasename = function(re) { - return function(filepath) { - return re.test(filepath) || re.test(path.basename(filepath)); - }; -}; + if (last.type === 'bracket.open') { + node.type = 'bracket.inner'; + node.escaped = true; + return node; + } -/** - * Returns the given value unchanced. - * @return {any} - */ + var bracket = this.pop('bracket'); + if (!this.isType(bracket, 'bracket')) { + if (this.options.strict) { + throw new Error('missing opening "["'); + } + node.type = 'bracket.inner'; + node.escaped = true; + return node; + } -utils.identity = function(val) { - return val; -}; + bracket.nodes.push(node); + define(node, 'parent', bracket); + }); +} /** - * Determines the filepath to return based on the provided options. - * @return {any} + * Brackets parsers */ -utils.value = function(str, unixify, options) { - if (options && options.unixify === false) { - return str; - } - if (options && typeof options.unixify === 'function') { - return options.unixify(str); - } - return unixify(str); -}; +module.exports = parsers; /** - * Returns a function that normalizes slashes in a string to forward - * slashes, strips `./` from beginning of paths, and optionally unescapes - * special characters. - * @return {Function} + * Expose text regex */ -utils.unixify = function(options) { - var opts = options || {}; - return function(filepath) { - if (opts.stripPrefix !== false) { - filepath = utils.stripPrefix(filepath); - } - if (opts.unescape === true) { - filepath = utils.unescape(filepath); - } - if (opts.unixify === true || utils.isWindows()) { - filepath = utils.toPosixPath(filepath); - } - return filepath; - }; -}; +module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 851 */ +/* 857 */ /***/ (function(module, exports, __webpack_require__) { -var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! - * is-windows - * - * Copyright © 2015-2018, Jon Schlinkert. - * Released under the MIT License. - */ - -(function(factory) { - if (exports && typeof exports === 'object' && typeof module !== 'undefined') { - module.exports = factory(); - } else if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), - __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? - (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } else {} -})(function() { - 'use strict'; - return function isWindows() { - return process && (process.platform === 'win32' || /^(msys|cygwin)$/.test(process.env.OSTYPE)); - }; -}); +"use strict"; -/***/ }), -/* 852 */ -/***/ (function(module, exports, __webpack_require__) { +var toRegex = __webpack_require__(723); +var regexNot = __webpack_require__(734); +var cached; -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015-2018, Jon Schlinkert. - * Released under the MIT License. +/** + * Get the last element from `array` + * @param {Array} `array` + * @return {*} */ +exports.last = function(arr) { + return arr[arr.length - 1]; +}; +/** + * Create and cache regex to use for text nodes + */ -var isobject = __webpack_require__(747); -var isDescriptor = __webpack_require__(759); -var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) - ? Reflect.defineProperty - : Object.defineProperty; - -module.exports = function defineProperty(obj, key, val) { - if (!isobject(obj) && typeof obj !== 'function' && !Array.isArray(obj)) { - throw new TypeError('expected an object, function, or array'); - } - - if (typeof key !== 'string') { - throw new TypeError('expected "key" to be a string'); - } +exports.createRegex = function(pattern, include) { + if (cached) return cached; + var opts = {contains: true, strictClose: false}; + var not = regexNot.create(pattern, opts); + var re; - if (isDescriptor(val)) { - define(obj, key, val); - return obj; + if (typeof include === 'string') { + re = toRegex('^(?:' + include + '|' + not + ')', opts); + } else { + re = toRegex(not, opts); } - define(obj, key, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); - - return obj; + return (cached = re); }; /***/ }), -/* 853 */ +/* 858 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; -/*! - * arr-diff - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. +/** + * Detect Electron renderer process, which is node, but we should + * treat as a browser. */ - - -module.exports = function diff(arr/*, arrays*/) { - var len = arguments.length; - var idx = 0; - while (++idx < len) { - arr = diffArray(arr, arguments[idx]); - } - return arr; -}; - -function diffArray(one, two) { - if (!Array.isArray(two)) { - return one.slice(); - } - - var tlen = two.length - var olen = one.length; - var idx = -1; - var arr = []; - - while (++idx < olen) { - var ele = one[idx]; - - var hasEle = false; - for (var i = 0; i < tlen; i++) { - var val = two[i]; - - if (ele === val) { - hasEle = true; - break; - } - } - - if (hasEle === false) { - arr.push(ele); - } - } - return arr; +if (typeof process !== 'undefined' && process.type === 'renderer') { + module.exports = __webpack_require__(859); +} else { + module.exports = __webpack_require__(862); } /***/ }), -/* 854 */ +/* 859 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; -/*! - * object.pick +/** + * This is the web browser implementation of `debug()`. * - * Copyright (c) 2014-2015 Jon Schlinkert, contributors. - * Licensed under the MIT License + * Expose `debug()` as the module. */ +exports = module.exports = __webpack_require__(860); +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = 'undefined' != typeof chrome + && 'undefined' != typeof chrome.storage + ? chrome.storage.local + : localstorage(); +/** + * Colors. + */ -var isObject = __webpack_require__(747); - -module.exports = function pick(obj, keys) { - if (!isObject(obj) && typeof obj !== 'function') { - return {}; - } - - var res = {}; - if (typeof keys === 'string') { - if (keys in obj) { - res[keys] = obj[keys]; - } - return res; - } +exports.colors = [ + 'lightseagreen', + 'forestgreen', + 'goldenrod', + 'dodgerblue', + 'darkorchid', + 'crimson' +]; - var len = keys.length; - var idx = -1; +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ - while (++idx < len) { - var key = keys[idx]; - if (key in obj) { - res[key] = obj[key]; - } +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { + return true; } - return res; -}; + // is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || + // is firebug? http://stackoverflow.com/a/398120/376773 + (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || + // is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || + // double check webkit in userAgent just in case we are in a worker + (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); +} -/***/ }), -/* 855 */ -/***/ (function(module, exports) { - -var toString = Object.prototype.toString; - -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; +exports.formatters.j = function(v) { + try { + return JSON.stringify(v); + } catch (err) { + return '[UnexpectedJSONParseError]: ' + err.message; } +}; - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; - - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; - - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; +/** + * Colorize log arguments if enabled. + * + * @api public + */ - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } +function formatArgs(args) { + var useColors = this.useColors; - if (isGeneratorObj(val)) { - return 'generator'; - } + args[0] = (useColors ? '%c' : '') + + this.namespace + + (useColors ? ' %c' : ' ') + + args[0] + + (useColors ? '%c ' : ' ') + + '+' + exports.humanize(this.diff); - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } + if (!useColors) return; - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); -}; + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit') -function ctorName(val) { - return val.constructor ? val.constructor.name : null; -} + // the final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function(match) { + if ('%%' === match) return; + index++; + if ('%c' === match) { + // we only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; + } + }); -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; + args.splice(lastC, 0, c); } -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; +function log() { + // this hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return 'object' === typeof console + && console.log + && Function.prototype.apply.call(console.log, console, arguments); } -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; -} +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; +function save(namespaces) { + try { + if (null == namespaces) { + exports.storage.removeItem('debug'); + } else { + exports.storage.debug = namespaces; + } + } catch(e) {} } -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ -function isArguments(val) { +function load() { + var r; try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; - } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; - } + r = exports.storage.debug; + } catch(e) {} + + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; } - return false; + + return r; } /** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer + * Enable namespaces listed in `localStorage.debug` initially. */ -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; +exports.enable(load()); + +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + +function localstorage() { + try { + return window.localStorage; + } catch (e) {} } /***/ }), -/* 856 */ +/* 860 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - /** - * Module dependencies + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + * + * Expose `debug()` as the module. */ -var extend = __webpack_require__(737); -var unique = __webpack_require__(740); -var toRegex = __webpack_require__(728); +exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; +exports.coerce = coerce; +exports.disable = disable; +exports.enable = enable; +exports.enabled = enabled; +exports.humanize = __webpack_require__(861); /** - * Local dependencies + * The currently active debug mode names, and names to skip. */ -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; +exports.names = []; +exports.skips = []; /** - * Convert the given `extglob` pattern into a regex-compatible string. Returns - * an object with the compiled result and the parsed AST. + * Map of special "%n" handling functions, for the debug "format" argument. * - * ```js - * var extglob = require('extglob'); - * console.log(extglob('*.!(*a)')); - * //=> '(?!\\.)[^/]*?\\.(?!(?!\\.)[^/]*?a\\b).*?' - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {String} - * @api public + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". */ -function extglob(pattern, options) { - return extglob.create(pattern, options).output; +exports.formatters = {}; + +/** + * Previous log timestamp. + */ + +var prevTime; + +/** + * Select a color. + * @param {String} namespace + * @return {Number} + * @api private + */ + +function selectColor(namespace) { + var hash = 0, i; + + for (i in namespace) { + hash = ((hash << 5) - hash) + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return exports.colors[Math.abs(hash) % exports.colors.length]; } /** - * Takes an array of strings and an extglob pattern and returns a new - * array that contains only the strings that match the pattern. + * Create a debugger with the given `namespace`. * - * ```js - * var extglob = require('extglob'); - * console.log(extglob.match(['a.a', 'a.b', 'a.c'], '*.!(*a)')); - * //=> ['a.b', 'a.c'] - * ``` - * @param {Array} `list` Array of strings to match - * @param {String} `pattern` Extglob pattern - * @param {Object} `options` - * @return {Array} Returns an array of matches + * @param {String} namespace + * @return {Function} * @api public */ -extglob.match = function(list, pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } +function createDebug(namespace) { - list = utils.arrayify(list); - var isMatch = extglob.matcher(pattern, options); - var len = list.length; - var idx = -1; - var matches = []; + function debug() { + // disabled? + if (!debug.enabled) return; - while (++idx < len) { - var ele = list[idx]; + var self = debug; - if (isMatch(ele)) { - matches.push(ele); + // set `diff` timestamp + var curr = +new Date(); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + + // turn the `arguments` into a proper Array + var args = new Array(arguments.length); + for (var i = 0; i < args.length; i++) { + args[i] = arguments[i]; } - } - // if no options were passed, uniquify results and return - if (typeof options === 'undefined') { - return unique(matches); - } + args[0] = exports.coerce(args[0]); - if (matches.length === 0) { - if (options.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } - if (options.nonull === true || options.nullglob === true) { - return [pattern.split('\\').join('')]; + if ('string' !== typeof args[0]) { + // anything else let's inspect with %O + args.unshift('%O'); } - } - return options.nodupes !== false ? unique(matches) : matches; -}; + // apply any `formatters` transformations + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { + // if we encounter an escaped % then don't increase the array index + if (match === '%%') return match; + index++; + var formatter = exports.formatters[format]; + if ('function' === typeof formatter) { + var val = args[index]; + match = formatter.call(self, val); -/** - * Returns true if the specified `string` matches the given - * extglob `pattern`. - * - * ```js - * var extglob = require('extglob'); - * - * console.log(extglob.isMatch('a.a', '*.!(*a)')); - * //=> false - * console.log(extglob.isMatch('a.b', '*.!(*a)')); - * //=> true - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Extglob pattern - * @param {String} `options` - * @return {Boolean} - * @api public - */ + // now we need to remove `args[index]` since it's inlined in the `format` + args.splice(index, 1); + index--; + } + return match; + }); -extglob.isMatch = function(str, pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } + // apply env-specific formatting (colors, etc.) + exports.formatArgs.call(self, args); - if (typeof str !== 'string') { - throw new TypeError('expected a string'); + var logFn = debug.log || exports.log || console.log.bind(console); + logFn.apply(self, args); } - if (pattern === str) { - return true; - } + debug.namespace = namespace; + debug.enabled = exports.enabled(namespace); + debug.useColors = exports.useColors(); + debug.color = selectColor(namespace); - if (pattern === '' || pattern === ' ' || pattern === '.') { - return pattern === str; + // env-specific initialization logic for debug instances + if ('function' === typeof exports.init) { + exports.init(debug); } - var isMatch = utils.memoize('isMatch', pattern, options, extglob.matcher); - return isMatch(str); -}; + return debug; +} /** - * Returns true if the given `string` contains the given pattern. Similar to `.isMatch` but - * the pattern can match any part of the string. + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. * - * ```js - * var extglob = require('extglob'); - * console.log(extglob.contains('aa/bb/cc', '*b')); - * //=> true - * console.log(extglob.contains('aa/bb/cc', '*d')); - * //=> false - * ``` - * @param {String} `str` The string to match. - * @param {String} `pattern` Glob pattern to use for matching. - * @param {Object} `options` - * @return {Boolean} Returns true if the patter matches any part of `str`. + * @param {String} namespaces * @api public */ -extglob.contains = function(str, pattern, options) { - if (typeof str !== 'string') { - throw new TypeError('expected a string'); - } +function enable(namespaces) { + exports.save(namespaces); - if (pattern === '' || pattern === ' ' || pattern === '.') { - return pattern === str; - } + exports.names = []; + exports.skips = []; - var opts = extend({}, options, {contains: true}); - opts.strictClose = false; - opts.strictOpen = false; - return extglob.isMatch(str, pattern, opts); -}; + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; + + for (var i = 0; i < len; i++) { + if (!split[i]) continue; // ignore empty strings + namespaces = split[i].replace(/\*/g, '.*?'); + if (namespaces[0] === '-') { + exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + exports.names.push(new RegExp('^' + namespaces + '$')); + } + } +} /** - * Takes an extglob pattern and returns a matcher function. The returned - * function takes the string to match as its only argument. + * Disable debug output. * - * ```js - * var extglob = require('extglob'); - * var isMatch = extglob.matcher('*.!(*a)'); + * @api public + */ + +function disable() { + exports.enable(''); +} + +/** + * Returns true if the given mode name is enabled, false otherwise. * - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.b')); - * //=> true - * ``` - * @param {String} `pattern` Extglob pattern - * @param {String} `options` + * @param {String} name * @return {Boolean} * @api public */ -extglob.matcher = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); +function enabled(name) { + var i, len; + for (i = 0, len = exports.skips.length; i < len; i++) { + if (exports.skips[i].test(name)) { + return false; + } } - - function matcher() { - var re = extglob.makeRe(pattern, options); - return function(str) { - return re.test(str); - }; + for (i = 0, len = exports.names.length; i < len; i++) { + if (exports.names[i].test(name)) { + return true; + } } - - return utils.memoize('matcher', pattern, options, matcher); -}; + return false; +} /** - * Convert the given `extglob` pattern into a regex-compatible string. Returns - * an object with the compiled result and the parsed AST. + * Coerce `val`. * - * ```js - * var extglob = require('extglob'); - * console.log(extglob.create('*.!(*a)').output); - * //=> '(?!\\.)[^/]*?\\.(?!(?!\\.)[^/]*?a\\b).*?' - * ``` - * @param {String} `str` - * @param {Object} `options` - * @return {String} - * @api public + * @param {Mixed} val + * @return {Mixed} + * @api private */ -extglob.create = function(pattern, options) { - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); - } +function coerce(val) { + if (val instanceof Error) return val.stack || val.message; + return val; +} - function create() { - var ext = new Extglob(options); - var ast = ext.parse(pattern, options); - return ext.compile(ast, options); - } - return utils.memoize('create', pattern, options, create); -}; +/***/ }), +/* 861 */ +/***/ (function(module, exports) { /** - * Returns an array of matches captured by `pattern` in `string`, or `null` - * if the pattern did not match. + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. * - * ```js - * var extglob = require('extglob'); - * extglob.capture(pattern, string[, options]); + * Options: * - * console.log(extglob.capture('test/*.js', 'test/foo.js')); - * //=> ['foo'] - * console.log(extglob.capture('test/*.js', 'foo/bar.css')); - * //=> null - * ``` - * @param {String} `pattern` Glob pattern to use for matching. - * @param {String} `string` 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 string matches the glob pattern, otherwise `null`. + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} * @api public */ -extglob.capture = function(pattern, str, options) { - var re = extglob.makeRe(pattern, extend({capture: true}, options)); +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); +}; - function match() { - return function(string) { - var match = re.exec(string); - if (!match) { - return null; - } +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ - return match.slice(1); - }; +function parse(str) { + str = String(str); + if (str.length > 100) { + return; } - - var capture = utils.memoize('capture', pattern, options, match); - return capture(str); -}; + var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} /** - * Create a regular expression from the given `pattern` and `options`. + * Short format for `ms`. * - * ```js - * var extglob = require('extglob'); - * var re = extglob.makeRe('*.!(*a)'); - * console.log(re); - * //=> /^[^\/]*?\.(?![^\/]*?a)[^\/]*?$/ - * ``` - * @param {String} `pattern` The pattern to convert to regex. - * @param {Object} `options` - * @return {RegExp} - * @api public + * @param {Number} ms + * @return {String} + * @api private */ -extglob.makeRe = function(pattern, options) { - if (pattern instanceof RegExp) { - return pattern; - } - - if (typeof pattern !== 'string') { - throw new TypeError('expected pattern to be a string'); +function fmtShort(ms) { + if (ms >= d) { + return Math.round(ms / d) + 'd'; } - - if (pattern.length > MAX_LENGTH) { - throw new Error('expected pattern to be less than ' + MAX_LENGTH + ' characters'); + if (ms >= h) { + return Math.round(ms / h) + 'h'; } - - function makeRe() { - var opts = extend({strictErrors: false}, options); - if (opts.strictErrors === true) opts.strict = true; - var res = extglob.create(pattern, opts); - return toRegex(res.output, opts); + if (ms >= m) { + return Math.round(ms / m) + 'm'; } - - var regex = utils.memoize('makeRe', pattern, options, makeRe); - if (regex.source.length > MAX_LENGTH) { - throw new SyntaxError('potentially malicious regex detected'); + if (ms >= s) { + return Math.round(ms / s) + 's'; } - - return regex; -}; - -/** - * Cache - */ - -extglob.cache = utils.cache; -extglob.clearCache = function() { - extglob.cache.__data__ = {}; -}; + return ms + 'ms'; +} /** - * Expose `Extglob` constructor, parsers and compilers + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private */ -extglob.Extglob = Extglob; -extglob.compilers = compilers; -extglob.parsers = parsers; +function fmtLong(ms) { + return plural(ms, d, 'day') || + plural(ms, h, 'hour') || + plural(ms, m, 'minute') || + plural(ms, s, 'second') || + ms + ' ms'; +} /** - * Expose `extglob` - * @type {Function} + * Pluralization helper. */ -module.exports = extglob; +function plural(ms, n, name) { + if (ms < n) { + return; + } + if (ms < n * 1.5) { + return Math.floor(ms / n) + ' ' + name; + } + return Math.ceil(ms / n) + ' ' + name + 's'; +} /***/ }), -/* 857 */ +/* 862 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - - -var brackets = __webpack_require__(858); - /** - * Extglob compilers + * Module dependencies. */ -module.exports = function(extglob) { - function star() { - if (typeof extglob.options.star === 'function') { - return extglob.options.star.apply(this, arguments); - } - if (typeof extglob.options.star === 'string') { - return extglob.options.star; - } - return '.*?'; - } - - /** - * Use `expand-brackets` compilers - */ - - extglob.use(brackets.compilers); - extglob.compiler - - /** - * Escaped: "\\*" - */ - - .set('escape', function(node) { - return this.emit(node.val, node); - }) - - /** - * Dot: "." - */ - - .set('dot', function(node) { - return this.emit('\\' + node.val, node); - }) - - /** - * Question mark: "?" - */ - - .set('qmark', function(node) { - var val = '[^\\\\/.]'; - var prev = this.prev(); - - if (node.parsed.slice(-1) === '(') { - var ch = node.rest.charAt(0); - if (ch !== '!' && ch !== '=' && ch !== ':') { - return this.emit(val, node); - } - return this.emit(node.val, node); - } - - if (prev.type === 'text' && prev.val) { - return this.emit(val, node); - } - - if (node.val.length > 1) { - val += '{' + node.val.length + '}'; - } - return this.emit(val, node); - }) - - /** - * Plus: "+" - */ - - .set('plus', function(node) { - var prev = node.parsed.slice(-1); - if (prev === ']' || prev === ')') { - return this.emit(node.val, node); - } - var ch = this.output.slice(-1); - if (!this.output || (/[?*+]/.test(ch) && node.parent.type !== 'bracket')) { - return this.emit('\\+', node); - } - if (/\w/.test(ch) && !node.inside) { - return this.emit('+\\+?', node); - } - return this.emit('+', node); - }) - - /** - * Star: "*" - */ - - .set('star', function(node) { - var prev = this.prev(); - var prefix = prev.type !== 'text' && prev.type !== 'escape' - ? '(?!\\.)' - : ''; - - return this.emit(prefix + star.call(this, node), node); - }) - - /** - * Parens - */ +var tty = __webpack_require__(480); +var util = __webpack_require__(29); - .set('paren', function(node) { - return this.mapVisit(node.nodes); - }) - .set('paren.open', function(node) { - var capture = this.options.capture ? '(' : ''; +/** + * This is the Node.js implementation of `debug()`. + * + * Expose `debug()` as the module. + */ - switch (node.parent.prefix) { - case '!': - case '^': - return this.emit(capture + '(?:(?!(?:', node); - case '*': - case '+': - case '?': - case '@': - return this.emit(capture + '(?:', node); - default: { - var val = node.val; - if (this.options.bash === true) { - val = '\\' + val; - } else if (!this.options.capture && val === '(' && node.parent.rest[0] !== '?') { - val += '?:'; - } +exports = module.exports = __webpack_require__(860); +exports.init = init; +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; - return this.emit(val, node); - } - } - }) - .set('paren.close', function(node) { - var capture = this.options.capture ? ')' : ''; +/** + * Colors. + */ - switch (node.prefix) { - case '!': - case '^': - var prefix = /^(\)|$)/.test(node.rest) ? '$' : ''; - var str = star.call(this, node); +exports.colors = [6, 2, 3, 4, 5, 1]; - // if the extglob has a slash explicitly defined, we know the user wants - // to match slashes, so we need to ensure the "star" regex allows for it - if (node.parent.hasSlash && !this.options.star && this.options.slash !== false) { - str = '.*?'; - } +/** + * Build up the default `inspectOpts` object from the environment variables. + * + * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js + */ - return this.emit(prefix + ('))' + str + ')') + capture, node); - case '*': - case '+': - case '?': - return this.emit(')' + node.prefix + capture, node); - case '@': - return this.emit(')' + capture, node); - default: { - var val = (this.options.bash === true ? '\\' : '') + ')'; - return this.emit(val, node); - } - } - }) +exports.inspectOpts = Object.keys(process.env).filter(function (key) { + return /^debug_/i.test(key); +}).reduce(function (obj, key) { + // camel-case + var prop = key + .substring(6) + .toLowerCase() + .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); - /** - * Text - */ + // coerce string value into JS value + var val = process.env[key]; + if (/^(yes|on|true|enabled)$/i.test(val)) val = true; + else if (/^(no|off|false|disabled)$/i.test(val)) val = false; + else if (val === 'null') val = null; + else val = Number(val); - .set('text', function(node) { - var val = node.val.replace(/[\[\]]/g, '\\$&'); - return this.emit(val, node); - }); -}; + obj[prop] = val; + return obj; +}, {}); +/** + * The file descriptor to write the `debug()` calls to. + * Set the `DEBUG_FD` env variable to override with another value. i.e.: + * + * $ DEBUG_FD=3 node script.js 3>debug.log + */ -/***/ }), -/* 858 */ -/***/ (function(module, exports, __webpack_require__) { +var fd = parseInt(process.env.DEBUG_FD, 10) || 2; -"use strict"; +if (1 !== fd && 2 !== fd) { + util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')() +} +var stream = 1 === fd ? process.stdout : + 2 === fd ? process.stderr : + createWritableStdioStream(fd); /** - * Local dependencies + * Is stdout a TTY? Colored output is enabled when `true`. */ -var compilers = __webpack_require__(859); -var parsers = __webpack_require__(861); +function useColors() { + return 'colors' in exports.inspectOpts + ? Boolean(exports.inspectOpts.colors) + : tty.isatty(fd); +} /** - * Module dependencies + * Map %o to `util.inspect()`, all on a single line. */ -var debug = __webpack_require__(863)('expand-brackets'); -var extend = __webpack_require__(737); -var Snapdragon = __webpack_require__(767); -var toRegex = __webpack_require__(728); +exports.formatters.o = function(v) { + this.inspectOpts.colors = this.useColors; + return util.inspect(v, this.inspectOpts) + .split('\n').map(function(str) { + return str.trim() + }).join(' '); +}; /** - * Parses the given POSIX character class `pattern` and returns a - * string that can be used for creating regular expressions for matching. - * - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} - * @api public + * Map %o to `util.inspect()`, allowing multiple lines if needed. */ -function brackets(pattern, options) { - debug('initializing from <%s>', __filename); - var res = brackets.create(pattern, options); - return res.output; -} +exports.formatters.O = function(v) { + this.inspectOpts.colors = this.useColors; + return util.inspect(v, this.inspectOpts); +}; /** - * Takes an array of strings and a POSIX character class pattern, and returns a new - * array with only the strings that matched the pattern. - * - * ```js - * var brackets = require('expand-brackets'); - * console.log(brackets.match(['1', 'a', 'ab'], '[[:alpha:]]')); - * //=> ['a'] + * Adds ANSI color escape codes if enabled. * - * console.log(brackets.match(['1', 'a', 'ab'], '[[:alpha:]]+')); - * //=> ['a', 'ab'] - * ``` - * @param {Array} `arr` Array of strings to match - * @param {String} `pattern` POSIX character class pattern(s) - * @param {Object} `options` - * @return {Array} * @api public */ -brackets.match = function(arr, pattern, options) { - arr = [].concat(arr); - var opts = extend({}, options); - var isMatch = brackets.matcher(pattern, opts); - var len = arr.length; - var idx = -1; - var res = []; +function formatArgs(args) { + var name = this.namespace; + var useColors = this.useColors; - while (++idx < len) { - var ele = arr[idx]; - if (isMatch(ele)) { - res.push(ele); - } + if (useColors) { + var c = this.color; + var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; + + args[0] = prefix + args[0].split('\n').join('\n' + prefix); + args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); + } else { + args[0] = new Date().toUTCString() + + ' ' + name + ' ' + args[0]; } +} - if (res.length === 0) { - if (opts.failglob === true) { - throw new Error('no matches found for "' + pattern + '"'); - } +/** + * Invokes `util.format()` with the specified arguments and writes to `stream`. + */ - if (opts.nonull === true || opts.nullglob === true) { - return [pattern.split('\\').join('')]; - } - } - return res; -}; +function log() { + return stream.write(util.format.apply(util, arguments) + '\n'); +} /** - * Returns true if the specified `string` matches the given - * brackets `pattern`. - * - * ```js - * var brackets = require('expand-brackets'); + * Save `namespaces`. * - * console.log(brackets.isMatch('a.a', '[[:alpha:]].[[:alpha:]]')); - * //=> true - * console.log(brackets.isMatch('1.2', '[[:alpha:]].[[:alpha:]]')); - * //=> false - * ``` - * @param {String} `string` String to match - * @param {String} `pattern` Poxis pattern - * @param {String} `options` - * @return {Boolean} - * @api public + * @param {String} namespaces + * @api private */ -brackets.isMatch = function(str, pattern, options) { - return brackets.matcher(pattern, options)(str); -}; +function save(namespaces) { + if (null == namespaces) { + // If you set a process.env field to null or undefined, it gets cast to the + // string 'null' or 'undefined'. Just delete instead. + delete process.env.DEBUG; + } else { + process.env.DEBUG = namespaces; + } +} /** - * Takes a POSIX character class pattern and returns a matcher function. The returned - * function takes the string to match as its only argument. - * - * ```js - * var brackets = require('expand-brackets'); - * var isMatch = brackets.matcher('[[:lower:]].[[:upper:]]'); + * Load `namespaces`. * - * console.log(isMatch('a.a')); - * //=> false - * console.log(isMatch('a.A')); - * //=> true - * ``` - * @param {String} `pattern` Poxis pattern - * @param {String} `options` - * @return {Boolean} - * @api public + * @return {String} returns the previously persisted debug modes + * @api private */ -brackets.matcher = function(pattern, options) { - var re = brackets.makeRe(pattern, options); - return function(str) { - return re.test(str); - }; -}; +function load() { + return process.env.DEBUG; +} /** - * Create a regular expression from the given `pattern`. + * Copied from `node/src/node.js`. * - * ```js - * var brackets = require('expand-brackets'); - * var re = brackets.makeRe('[[:alpha:]]'); - * console.log(re); - * //=> /^(?:[a-zA-Z])$/ - * ``` - * @param {String} `pattern` The pattern to convert to regex. - * @param {Object} `options` - * @return {RegExp} - * @api public + * XXX: It's lame that node doesn't expose this API out-of-the-box. It also + * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. */ -brackets.makeRe = function(pattern, options) { - var res = brackets.create(pattern, options); - var opts = extend({strictErrors: false}, options); - return toRegex(res.output, opts); -}; +function createWritableStdioStream (fd) { + var stream; + var tty_wrap = process.binding('tty_wrap'); + + // Note stream._type is used for test-module-load-list.js + + switch (tty_wrap.guessHandleType(fd)) { + case 'TTY': + stream = new tty.WriteStream(fd); + stream._type = 'tty'; + + // Hack to have stream not keep the event loop alive. + // See https://github.com/joyent/node/issues/1726 + if (stream._handle && stream._handle.unref) { + stream._handle.unref(); + } + break; + + case 'FILE': + var fs = __webpack_require__(23); + stream = new fs.SyncWriteStream(fd, { autoClose: false }); + stream._type = 'fs'; + break; + + case 'PIPE': + case 'TCP': + var net = __webpack_require__(800); + stream = new net.Socket({ + fd: fd, + readable: false, + writable: true + }); + + // FIXME Should probably have an option in net.Socket to create a + // stream from an existing fd which is writable only. But for now + // we'll just add this hack and set the `readable` member to false. + // Test: ./node test/fixtures/echo.js < /etc/passwd + stream.readable = false; + stream.read = null; + stream._type = 'pipe'; + + // FIXME Hack to have stream not keep the event loop alive. + // See https://github.com/joyent/node/issues/1726 + if (stream._handle && stream._handle.unref) { + stream._handle.unref(); + } + break; -/** - * Parses the given POSIX character class `pattern` and returns an object - * with the compiled `output` and optional source `map`. - * - * ```js - * var brackets = require('expand-brackets'); - * console.log(brackets('[[:alpha:]]')); - * // { options: { source: 'string' }, - * // input: '[[:alpha:]]', - * // state: {}, - * // compilers: - * // { eos: [Function], - * // noop: [Function], - * // bos: [Function], - * // not: [Function], - * // escape: [Function], - * // text: [Function], - * // posix: [Function], - * // bracket: [Function], - * // 'bracket.open': [Function], - * // 'bracket.inner': [Function], - * // 'bracket.literal': [Function], - * // 'bracket.close': [Function] }, - * // output: '[a-zA-Z]', - * // ast: - * // { type: 'root', - * // errors: [], - * // nodes: [ [Object], [Object], [Object] ] }, - * // parsingErrors: [] } - * ``` - * @param {String} `pattern` - * @param {Object} `options` - * @return {Object} - * @api public - */ + default: + // Probably an error on in uv_guess_handle() + throw new Error('Implement me. Unknown stream file type!'); + } -brackets.create = function(pattern, options) { - var snapdragon = (options && options.snapdragon) || new Snapdragon(options); - compilers(snapdragon); - parsers(snapdragon); + // For supporting legacy API we put the FD here. + stream.fd = fd; - var ast = snapdragon.parse(pattern, options); - ast.input = pattern; - var res = snapdragon.compile(ast, options); - res.input = pattern; - return res; -}; + stream._isStdio = true; + + return stream; +} /** - * Expose `brackets` constructor, parsers and compilers + * Init logic for `debug` instances. + * + * Create a new `inspectOpts` object in case `useColors` is set + * differently for a particular `debug` instance. */ -brackets.compilers = compilers; -brackets.parsers = parsers; +function init (debug) { + debug.inspectOpts = {}; + + var keys = Object.keys(exports.inspectOpts); + for (var i = 0; i < keys.length; i++) { + debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; + } +} /** - * Expose `brackets` - * @type {Function} + * Enable namespaces listed in `process.env.DEBUG` initially. */ -module.exports = brackets; +exports.enable(load()); /***/ }), -/* 859 */ +/* 863 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(860); +var brackets = __webpack_require__(853); +var define = __webpack_require__(864); +var utils = __webpack_require__(865); -module.exports = function(brackets) { - brackets.compiler +/** + * Characters to use in text regex (we want to "not" match + * characters that are matched by other parsers) + */ - /** - * Escaped characters - */ +var TEXT_REGEX = '([!@*?+]?\\(|\\)|[*?.+\\\\]|\\[:?(?=.*\\])|:?\\])+'; +var not = utils.createRegex(TEXT_REGEX); - .set('escape', function(node) { - return this.emit('\\' + node.val.replace(/^\\/, ''), node); - }) +/** + * Extglob parsers + */ + +function parsers(extglob) { + extglob.state = extglob.state || {}; + + /** + * Use `expand-brackets` parsers + */ + + extglob.use(brackets.parsers); + extglob.parser.sets.paren = extglob.parser.sets.paren || []; + extglob.parser /** - * Text + * Extglob open: "*(" */ - .set('text', function(node) { - return this.emit(node.val.replace(/([{}])/g, '\\$1'), node); + .capture('paren.open', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^([!@*?+])?\(/); + if (!m) return; + + var prev = this.prev(); + var prefix = m[1]; + var val = m[0]; + + var open = pos({ + type: 'paren.open', + parsed: parsed, + val: val + }); + + var node = pos({ + type: 'paren', + prefix: prefix, + nodes: [open] + }); + + // if nested negation extglobs, just cancel them out to simplify + if (prefix === '!' && prev.type === 'paren' && prev.prefix === '!') { + prev.prefix = '@'; + node.prefix = '@'; + } + + define(node, 'rest', this.input); + define(node, 'parsed', parsed); + define(node, 'parent', prev); + define(open, 'parent', node); + + this.push('paren', node); + prev.nodes.push(node); }) /** - * POSIX character classes + * Extglob close: ")" */ - .set('posix', function(node) { - if (node.val === '[::]') { - return this.emit('\\[::\\]', node); - } + .capture('paren.close', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^\)/); + if (!m) return; - var val = posix[node.inner]; - if (typeof val === 'undefined') { - val = '[' + node.inner + ']'; + var parent = this.pop('paren'); + var node = pos({ + type: 'paren.close', + rest: this.input, + parsed: parsed, + val: m[0] + }); + + if (!this.isType(parent, 'paren')) { + if (this.options.strict) { + throw new Error('missing opening paren: "("'); + } + node.escaped = true; + return node; } - return this.emit(val, node); + + node.prefix = parent.prefix; + parent.nodes.push(node); + define(node, 'parent', parent); }) /** - * Non-posix brackets + * Escape: "\\." */ - .set('bracket', function(node) { - return this.mapVisit(node.nodes); - }) - .set('bracket.open', function(node) { - return this.emit(node.val, node); - }) - .set('bracket.inner', function(node) { - var inner = node.val; - - if (inner === '[' || inner === ']') { - return this.emit('\\' + node.val, node); - } - if (inner === '^]') { - return this.emit('^\\]', node); - } - if (inner === '^') { - return this.emit('^', node); - } + .capture('escape', function() { + var pos = this.position(); + var m = this.match(/^\\(.)/); + if (!m) return; - if (/-/.test(inner) && !/(\d-\d|\w-\w)/.test(inner)) { - inner = inner.split('-').join('\\-'); - } + return pos({ + type: 'escape', + val: m[0], + ch: m[1] + }); + }) - var isNegated = inner.charAt(0) === '^'; - // add slashes to negated brackets, per spec - if (isNegated && inner.indexOf('/') === -1) { - inner += '/'; - } - if (isNegated && inner.indexOf('.') === -1) { - inner += '.'; - } + /** + * Question marks: "?" + */ - // don't unescape `0` (octal literal) - inner = inner.replace(/\\([1-9])/g, '$1'); - return this.emit(inner, node); + .capture('qmark', function() { + var parsed = this.parsed; + var pos = this.position(); + var m = this.match(/^\?+(?!\()/); + if (!m) return; + extglob.state.metachar = true; + return pos({ + type: 'qmark', + rest: this.input, + parsed: parsed, + val: m[0] + }); }) - .set('bracket.close', function(node) { - var val = node.val.replace(/^\\/, ''); - if (node.parent.escaped === true) { - return this.emit('\\' + val, node); - } - return this.emit(val, node); - }); -}; + /** + * Character parsers + */ -/***/ }), -/* 860 */ -/***/ (function(module, exports, __webpack_require__) { + .capture('star', /^\*(?!\()/) + .capture('plus', /^\+(?!\()/) + .capture('dot', /^\./) + .capture('text', not); +}; -"use strict"; +/** + * Expose text regex string + */ +module.exports.TEXT_REGEX = TEXT_REGEX; /** - * POSIX character classes + * Extglob parsers */ -module.exports = { - alnum: 'a-zA-Z0-9', - alpha: 'a-zA-Z', - ascii: '\\x00-\\x7F', - blank: ' \\t', - cntrl: '\\x00-\\x1F\\x7F', - digit: '0-9', - graph: '\\x21-\\x7E', - lower: 'a-z', - print: '\\x20-\\x7E ', - punct: '\\-!"#$%&\'()\\*+,./:;<=>?@[\\]^_`{|}~', - space: ' \\t\\r\\n\\v\\f', - upper: 'A-Z', - word: 'A-Za-z0-9_', - xdigit: 'A-Fa-f0-9' -}; +module.exports = parsers; /***/ }), -/* 861 */ +/* 864 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +/*! + * define-property + * + * Copyright (c) 2015, 2017, Jon Schlinkert. + * Released under the MIT License. + */ -var utils = __webpack_require__(862); -var define = __webpack_require__(729); -/** - * Text regex - */ +var isDescriptor = __webpack_require__(754); -var TEXT_REGEX = '(\\[(?=.*\\])|\\])+'; -var not = utils.createRegex(TEXT_REGEX); +module.exports = function defineProperty(obj, prop, val) { + if (typeof obj !== 'object' && typeof obj !== 'function') { + throw new TypeError('expected an object or function.'); + } -/** - * Brackets parsers - */ + if (typeof prop !== 'string') { + throw new TypeError('expected `prop` to be a string.'); + } -function parsers(brackets) { - brackets.state = brackets.state || {}; - brackets.parser.sets.bracket = brackets.parser.sets.bracket || []; - brackets.parser + if (isDescriptor(val) && ('set' in val || 'get' in val)) { + return Object.defineProperty(obj, prop, val); + } - .capture('escape', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(/^\\(.)/); - if (!m) return; + return Object.defineProperty(obj, prop, { + configurable: true, + enumerable: false, + writable: true, + value: val + }); +}; - return pos({ - type: 'escape', - val: m[0] - }); - }) - /** - * Text parser - */ +/***/ }), +/* 865 */ +/***/ (function(module, exports, __webpack_require__) { - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; +"use strict"; - return pos({ - type: 'text', - val: m[0] - }); - }) - /** - * POSIX character classes: "[[:alpha:][:digits:]]" - */ +var regex = __webpack_require__(734); +var Cache = __webpack_require__(844); - .capture('posix', function() { - var pos = this.position(); - var m = this.match(/^\[:(.*?):\](?=.*\])/); - if (!m) return; +/** + * Utils + */ - var inside = this.isInside('bracket'); - if (inside) { - brackets.posix++; - } +var utils = module.exports; +var cache = utils.cache = new Cache(); - return pos({ - type: 'posix', - insideBracket: inside, - inner: m[1], - val: m[0] - }); - }) +/** + * Cast `val` to an array + * @return {Array} + */ - /** - * Bracket (noop) - */ +utils.arrayify = function(val) { + if (!Array.isArray(val)) { + return [val]; + } + return val; +}; - .capture('bracket', function() {}) +/** + * Memoize a generated regex or function + */ - /** - * Open: '[' - */ +utils.memoize = function(type, pattern, options, fn) { + var key = utils.createKey(type + pattern, options); - .capture('bracket.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\[(?=.*\])/); - if (!m) return; + if (cache.has(type, key)) { + return cache.get(type, key); + } - var prev = this.prev(); - var last = utils.last(prev.nodes); + var val = fn(pattern, options); + if (options && options.cache === false) { + return val; + } - if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { - last.val = last.val.slice(0, last.val.length - 1); - return pos({ - type: 'escape', - val: m[0] - }); - } + cache.set(type, key, val); + return val; +}; - var open = pos({ - type: 'bracket.open', - val: m[0] - }); +/** + * Create the key to use for memoization. The key is generated + * by iterating over the options and concatenating key-value pairs + * to the pattern string. + */ - if (last.type === 'bracket.open' || this.isInside('bracket')) { - open.val = '\\' + open.val; - open.type = 'bracket.inner'; - open.escaped = true; - return open; - } +utils.createKey = function(pattern, options) { + var key = pattern; + if (typeof options === 'undefined') { + return key; + } + for (var prop in options) { + key += ';' + prop + '=' + String(options[prop]); + } + return key; +}; - var node = pos({ - type: 'bracket', - nodes: [open] - }); +/** + * Create the regex to use for matching text + */ - define(node, 'parent', prev); - define(open, 'parent', node); - this.push('bracket', node); - prev.nodes.push(node); - }) +utils.createRegex = function(str) { + var opts = {contains: true, strictClose: false}; + return regex(str, opts); +}; - /** - * Bracket text - */ - .capture('bracket.inner', function() { - if (!this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(not); - if (!m || !m[0]) return; +/***/ }), +/* 866 */ +/***/ (function(module, exports, __webpack_require__) { - var next = this.input.charAt(0); - var val = m[0]; +"use strict"; - var node = pos({ - type: 'bracket.inner', - val: val - }); - if (val === '\\\\') { - return node; - } +/** + * Module dependencies + */ - var first = val.charAt(0); - var last = val.slice(-1); +var Snapdragon = __webpack_require__(762); +var define = __webpack_require__(864); +var extend = __webpack_require__(732); - if (first === '!') { - val = '^' + val.slice(1); - } +/** + * Local dependencies + */ - if (last === '\\' || (val === '^' && next === ']')) { - val += this.input[0]; - this.consume(1); - } +var compilers = __webpack_require__(852); +var parsers = __webpack_require__(863); - node.val = val; - return node; - }) +/** + * Customize Snapdragon parser and renderer + */ - /** - * Close: ']' - */ +function Extglob(options) { + this.options = extend({source: 'extglob'}, options); + this.snapdragon = this.options.snapdragon || new Snapdragon(this.options); + this.snapdragon.patterns = this.snapdragon.patterns || {}; + this.compiler = this.snapdragon.compiler; + this.parser = this.snapdragon.parser; - .capture('bracket.close', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\]/); - if (!m) return; + compilers(this.snapdragon); + parsers(this.snapdragon); - var prev = this.prev(); - var last = utils.last(prev.nodes); + /** + * Override Snapdragon `.parse` method + */ - if (parsed.slice(-1) === '\\' && !this.isInside('bracket')) { - last.val = last.val.slice(0, last.val.length - 1); + define(this.snapdragon, 'parse', function(str, options) { + var parsed = Snapdragon.prototype.parse.apply(this, arguments); + parsed.input = str; - return pos({ - type: 'escape', - val: m[0] - }); + // escape unmatched brace/bracket/parens + var last = this.parser.stack.pop(); + if (last && this.options.strict !== true) { + var node = last.nodes[0]; + node.val = '\\' + node.val; + var sibling = node.parent.nodes[1]; + if (sibling.type === 'star') { + sibling.loose = true; } + } - var node = pos({ - type: 'bracket.close', - rest: this.input, - val: m[0] - }); + // add non-enumerable parser reference + define(parsed, 'parser', this.parser); + return parsed; + }); - if (last.type === 'bracket.open') { - node.type = 'bracket.inner'; - node.escaped = true; - return node; - } + /** + * Decorate `.parse` method + */ - var bracket = this.pop('bracket'); - if (!this.isType(bracket, 'bracket')) { - if (this.options.strict) { - throw new Error('missing opening "["'); - } - node.type = 'bracket.inner'; - node.escaped = true; - return node; - } + define(this, 'parse', function(ast, options) { + return this.snapdragon.parse.apply(this.snapdragon, arguments); + }); - bracket.nodes.push(node); - define(node, 'parent', bracket); - }); -} + /** + * Decorate `.compile` method + */ -/** - * Brackets parsers - */ + define(this, 'compile', function(ast, options) { + return this.snapdragon.compile.apply(this.snapdragon, arguments); + }); -module.exports = parsers; +} /** - * Expose text regex + * Expose `Extglob` */ -module.exports.TEXT_REGEX = TEXT_REGEX; +module.exports = Extglob; /***/ }), -/* 862 */ +/* 867 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(728); -var regexNot = __webpack_require__(739); -var cached; +var extglob = __webpack_require__(851); +var nanomatch = __webpack_require__(836); +var regexNot = __webpack_require__(734); +var toRegex = __webpack_require__(824); +var not; /** - * Get the last element from `array` - * @param {Array} `array` - * @return {*} + * Characters to use in negation regex (we want to "not" match + * characters that are matched by other parsers) */ -exports.last = function(arr) { - return arr[arr.length - 1]; +var TEXT = '([!@*?+]?\\(|\\)|\\[:?(?=.*?:?\\])|:?\\]|[*+?!^$.\\\\/])+'; +var createNotRegex = function(opts) { + return not || (not = textRegex(TEXT)); }; /** - * Create and cache regex to use for text nodes + * Parsers */ -exports.createRegex = function(pattern, include) { - if (cached) return cached; - var opts = {contains: true, strictClose: false}; - var not = regexNot.create(pattern, opts); - var re; +module.exports = function(snapdragon) { + var parsers = snapdragon.parser.parsers; - if (typeof include === 'string') { - re = toRegex('^(?:' + include + '|' + not + ')', opts); - } else { - re = toRegex(not, opts); - } + // register nanomatch parsers + snapdragon.use(nanomatch.parsers); - return (cached = re); -}; + // get references to some specific nanomatch parsers before they + // are overridden by the extglob and/or parsers + var escape = parsers.escape; + var slash = parsers.slash; + var qmark = parsers.qmark; + var plus = parsers.plus; + var star = parsers.star; + var dot = parsers.dot; + // register extglob parsers + snapdragon.use(extglob.parsers); -/***/ }), -/* 863 */ -/***/ (function(module, exports, __webpack_require__) { + // custom micromatch parsers + snapdragon.parser + .use(function() { + // override "notRegex" created in nanomatch parser + this.notRegex = /^\!+(?!\()/; + }) + // reset the referenced parsers + .capture('escape', escape) + .capture('slash', slash) + .capture('qmark', qmark) + .capture('star', star) + .capture('plus', plus) + .capture('dot', dot) + + /** + * Override `text` parser + */ + + .capture('text', function() { + if (this.isInside('bracket')) return; + var pos = this.position(); + var m = this.match(createNotRegex(this.options)); + if (!m || !m[0]) return; + + // escape regex boundary characters and simple brackets + var val = m[0].replace(/([[\]^$])/g, '\\$1'); + + return pos({ + type: 'text', + val: val + }); + }); +}; /** - * Detect Electron renderer process, which is node, but we should - * treat as a browser. + * Create text regex */ -if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(864); -} else { - module.exports = __webpack_require__(867); +function textRegex(pattern) { + var notStr = regexNot.create(pattern, {contains: true, strictClose: false}); + var prefix = '(?:[\\^]|\\\\|'; + return toRegex(prefix + notStr + ')', {strictClose: false}); } /***/ }), -/* 864 */ +/* 868 */ +/***/ (function(module, exports, __webpack_require__) { + +module.exports = new (__webpack_require__(844))(); + + +/***/ }), +/* 869 */ /***/ (function(module, exports, __webpack_require__) { +"use strict"; + + +var utils = module.exports; +var path = __webpack_require__(16); + /** - * This is the web browser implementation of `debug()`. - * - * Expose `debug()` as the module. + * Module dependencies */ -exports = module.exports = __webpack_require__(865); -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; -exports.storage = 'undefined' != typeof chrome - && 'undefined' != typeof chrome.storage - ? chrome.storage.local - : localstorage(); +var Snapdragon = __webpack_require__(762); +utils.define = __webpack_require__(831); +utils.diff = __webpack_require__(848); +utils.extend = __webpack_require__(832); +utils.pick = __webpack_require__(849); +utils.typeOf = __webpack_require__(870); +utils.unique = __webpack_require__(735); /** - * Colors. + * Returns true if the platform is windows, or `path.sep` is `\\`. + * This is defined as a function to allow `path.sep` to be set in unit tests, + * or by the user, if there is a reason to do so. + * @return {Boolean} */ -exports.colors = [ - 'lightseagreen', - 'forestgreen', - 'goldenrod', - 'dodgerblue', - 'darkorchid', - 'crimson' -]; +utils.isWindows = function() { + return path.sep === '\\' || process.platform === 'win32'; +}; /** - * Currently only WebKit-based Web Inspectors, Firefox >= v31, - * and the Firebug extension (any Firefox version) are known - * to support "%c" CSS customizations. - * - * TODO: add a `localStorage` variable to explicitly enable/disable colors + * Get the `Snapdragon` instance to use */ -function useColors() { - // NB: In an Electron preload script, document will be defined but not fully - // initialized. Since we know we're in Chrome, we'll just detect this case - // explicitly - if (typeof window !== 'undefined' && window.process && window.process.type === 'renderer') { - return true; +utils.instantiate = function(ast, options) { + var snapdragon; + // if an instance was created by `.parse`, use that instance + if (utils.typeOf(ast) === 'object' && ast.snapdragon) { + snapdragon = ast.snapdragon; + // if the user supplies an instance on options, use that instance + } else if (utils.typeOf(options) === 'object' && options.snapdragon) { + snapdragon = options.snapdragon; + // create a new instance + } else { + snapdragon = new Snapdragon(options); } - // is webkit? http://stackoverflow.com/a/16459606/376773 - // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 - return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) || - // is firebug? http://stackoverflow.com/a/398120/376773 - (typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) || - // is firefox >= v31? - // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) || - // double check webkit in userAgent just in case we are in a worker - (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)); -} + utils.define(snapdragon, 'parse', function(str, options) { + var parsed = Snapdragon.prototype.parse.apply(this, arguments); + parsed.input = str; + + // escape unmatched brace/bracket/parens + var last = this.parser.stack.pop(); + if (last && this.options.strictErrors !== true) { + var open = last.nodes[0]; + var inner = last.nodes[1]; + if (last.type === 'bracket') { + if (inner.val.charAt(0) === '[') { + inner.val = '\\' + inner.val; + } + + } else { + open.val = '\\' + open.val; + var sibling = open.parent.nodes[1]; + if (sibling.type === 'star') { + sibling.loose = true; + } + } + } + + // add non-enumerable parser reference + utils.define(parsed, 'parser', this.parser); + return parsed; + }); + + return snapdragon; +}; /** - * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + * Create the key to use for memoization. The key is generated + * by iterating over the options and concatenating key-value pairs + * to the pattern string. */ -exports.formatters.j = function(v) { - try { - return JSON.stringify(v); - } catch (err) { - return '[UnexpectedJSONParseError]: ' + err.message; +utils.createKey = function(pattern, options) { + if (utils.typeOf(options) !== 'object') { + return pattern; + } + var val = pattern; + var keys = Object.keys(options); + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + val += ';' + key + '=' + String(options[key]); } + return val; }; - /** - * Colorize log arguments if enabled. - * - * @api public + * Cast `val` to an array + * @return {Array} */ -function formatArgs(args) { - var useColors = this.useColors; +utils.arrayify = function(val) { + if (typeof val === 'string') return [val]; + return val ? (Array.isArray(val) ? val : [val]) : []; +}; - args[0] = (useColors ? '%c' : '') - + this.namespace - + (useColors ? ' %c' : ' ') - + args[0] - + (useColors ? '%c ' : ' ') - + '+' + exports.humanize(this.diff); +/** + * Return true if `val` is a non-empty string + */ - if (!useColors) return; +utils.isString = function(val) { + return typeof val === 'string'; +}; - var c = 'color: ' + this.color; - args.splice(1, 0, c, 'color: inherit') +/** + * Return true if `val` is a non-empty string + */ - // the final "%c" is somewhat tricky, because there could be other - // arguments passed either before or after the %c, so we need to - // figure out the correct index to insert the CSS into - var index = 0; - var lastC = 0; - args[0].replace(/%[a-zA-Z%]/g, function(match) { - if ('%%' === match) return; - index++; - if ('%c' === match) { - // we only are interested in the *last* %c - // (the user may have provided their own) - lastC = index; - } - }); +utils.isObject = function(val) { + return utils.typeOf(val) === 'object'; +}; - args.splice(lastC, 0, c); -} +/** + * Returns true if the given `str` has special characters + */ + +utils.hasSpecialChars = function(str) { + return /(?:(?:(^|\/)[!.])|[*?+()|\[\]{}]|[+@]\()/.test(str); +}; /** - * Invokes `console.log()` when available. - * No-op when `console.log` is not a "function". - * - * @api public + * Escape regex characters in the given string */ -function log() { - // this hackery is required for IE8/9, where - // the `console.log` function doesn't have 'apply' - return 'object' === typeof console - && console.log - && Function.prototype.apply.call(console.log, console, arguments); -} +utils.escapeRegex = function(str) { + return str.replace(/[-[\]{}()^$|*+?.\\\/\s]/g, '\\$&'); +}; /** - * Save `namespaces`. + * Normalize slashes in the given filepath. * - * @param {String} namespaces - * @api private + * @param {String} `filepath` + * @return {String} */ -function save(namespaces) { - try { - if (null == namespaces) { - exports.storage.removeItem('debug'); - } else { - exports.storage.debug = namespaces; - } - } catch(e) {} -} +utils.toPosixPath = function(str) { + return str.replace(/\\+/g, '/'); +}; /** - * Load `namespaces`. + * Strip backslashes before special characters in a string. * - * @return {String} returns the previously persisted debug modes - * @api private + * @param {String} `str` + * @return {String} */ -function load() { - var r; - try { - r = exports.storage.debug; - } catch(e) {} +utils.unescape = function(str) { + return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); +}; - // If debug isn't set in LS, and we're in Electron, try to load $DEBUG - if (!r && typeof process !== 'undefined' && 'env' in process) { - r = process.env.DEBUG; - } +/** + * Strip the prefix from a filepath + * @param {String} `fp` + * @return {String} + */ - return r; -} +utils.stripPrefix = function(str) { + if (str.charAt(0) !== '.') { + return str; + } + var ch = str.charAt(1); + if (utils.isSlash(ch)) { + return str.slice(2); + } + return str; +}; /** - * Enable namespaces listed in `localStorage.debug` initially. + * Returns true if the given str is an escaped or + * unescaped path character */ -exports.enable(load()); +utils.isSlash = function(str) { + return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; +}; /** - * Localstorage attempts to return the localstorage. - * - * This is necessary because safari throws - * when a user disables cookies/localstorage - * and you attempt to access it. + * Returns a function that returns true if the given + * pattern matches or contains a `filepath` * - * @return {LocalStorage} - * @api private + * @param {String} `pattern` + * @return {Function} */ -function localstorage() { - try { - return window.localStorage; - } catch (e) {} -} - +utils.matchPath = function(pattern, options) { + return (options && options.contains) + ? utils.containsPattern(pattern, options) + : utils.equalsPattern(pattern, options); +}; -/***/ }), -/* 865 */ -/***/ (function(module, exports, __webpack_require__) { +/** + * Returns true if the given (original) filepath or unixified path are equal + * to the given pattern. + */ +utils._equals = function(filepath, unixPath, pattern) { + return pattern === filepath || pattern === unixPath; +}; /** - * This is the common logic for both the Node.js and web browser - * implementations of `debug()`. - * - * Expose `debug()` as the module. + * Returns true if the given (original) filepath or unixified path contain + * the given pattern. */ -exports = module.exports = createDebug.debug = createDebug['default'] = createDebug; -exports.coerce = coerce; -exports.disable = disable; -exports.enable = enable; -exports.enabled = enabled; -exports.humanize = __webpack_require__(866); +utils._contains = function(filepath, unixPath, pattern) { + return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; +}; /** - * The currently active debug mode names, and names to skip. + * Returns a function that returns true if the given + * pattern is the same as a given `filepath` + * + * @param {String} `pattern` + * @return {Function} */ -exports.names = []; -exports.skips = []; +utils.equalsPattern = function(pattern, options) { + var unixify = utils.unixify(options); + options = options || {}; + + return function fn(filepath) { + var equal = utils._equals(filepath, unixify(filepath), pattern); + if (equal === true || options.nocase !== true) { + return equal; + } + var lower = filepath.toLowerCase(); + return utils._equals(lower, unixify(lower), pattern); + }; +}; /** - * Map of special "%n" handling functions, for the debug "format" argument. + * Returns a function that returns true if the given + * pattern contains a `filepath` * - * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + * @param {String} `pattern` + * @return {Function} */ -exports.formatters = {}; +utils.containsPattern = function(pattern, options) { + var unixify = utils.unixify(options); + options = options || {}; + + return function(filepath) { + var contains = utils._contains(filepath, unixify(filepath), pattern); + if (contains === true || options.nocase !== true) { + return contains; + } + var lower = filepath.toLowerCase(); + return utils._contains(lower, unixify(lower), pattern); + }; +}; /** - * Previous log timestamp. + * Returns a function that returns true if the given + * regex matches the `filename` of a file path. + * + * @param {RegExp} `re` Matching regex + * @return {Function} */ -var prevTime; +utils.matchBasename = function(re) { + return function(filepath) { + return re.test(path.basename(filepath)); + }; +}; /** - * Select a color. - * @param {String} namespace - * @return {Number} - * @api private + * Determines the filepath to return based on the provided options. + * @return {any} */ -function selectColor(namespace) { - var hash = 0, i; - - for (i in namespace) { - hash = ((hash << 5) - hash) + namespace.charCodeAt(i); - hash |= 0; // Convert to 32bit integer +utils.value = function(str, unixify, options) { + if (options && options.unixify === false) { + return str; } - - return exports.colors[Math.abs(hash) % exports.colors.length]; -} + return unixify(str); +}; /** - * Create a debugger with the given `namespace`. - * - * @param {String} namespace + * Returns a function that normalizes slashes in a string to forward + * slashes, strips `./` from beginning of paths, and optionally unescapes + * special characters. * @return {Function} - * @api public */ -function createDebug(namespace) { +utils.unixify = function(options) { + options = options || {}; + return function(filepath) { + if (utils.isWindows() || options.unixify === true) { + filepath = utils.toPosixPath(filepath); + } + if (options.stripPrefix !== false) { + filepath = utils.stripPrefix(filepath); + } + if (options.unescape === true) { + filepath = utils.unescape(filepath); + } + return filepath; + }; +}; - function debug() { - // disabled? - if (!debug.enabled) return; - var self = debug; +/***/ }), +/* 870 */ +/***/ (function(module, exports) { - // set `diff` timestamp - var curr = +new Date(); - var ms = curr - (prevTime || curr); - self.diff = ms; - self.prev = prevTime; - self.curr = curr; - prevTime = curr; +var toString = Object.prototype.toString; - // turn the `arguments` into a proper Array - var args = new Array(arguments.length); - for (var i = 0; i < args.length; i++) { - args[i] = arguments[i]; - } +module.exports = function kindOf(val) { + if (val === void 0) return 'undefined'; + if (val === null) return 'null'; - args[0] = exports.coerce(args[0]); + var type = typeof val; + if (type === 'boolean') return 'boolean'; + if (type === 'string') return 'string'; + if (type === 'number') return 'number'; + if (type === 'symbol') return 'symbol'; + if (type === 'function') { + return isGeneratorFn(val) ? 'generatorfunction' : 'function'; + } - if ('string' !== typeof args[0]) { - // anything else let's inspect with %O - args.unshift('%O'); - } + if (isArray(val)) return 'array'; + if (isBuffer(val)) return 'buffer'; + if (isArguments(val)) return 'arguments'; + if (isDate(val)) return 'date'; + if (isError(val)) return 'error'; + if (isRegexp(val)) return 'regexp'; - // apply any `formatters` transformations - var index = 0; - args[0] = args[0].replace(/%([a-zA-Z%])/g, function(match, format) { - // if we encounter an escaped % then don't increase the array index - if (match === '%%') return match; - index++; - var formatter = exports.formatters[format]; - if ('function' === typeof formatter) { - var val = args[index]; - match = formatter.call(self, val); + switch (ctorName(val)) { + case 'Symbol': return 'symbol'; + case 'Promise': return 'promise'; - // now we need to remove `args[index]` since it's inlined in the `format` - args.splice(index, 1); - index--; - } - return match; - }); + // Set, Map, WeakSet, WeakMap + case 'WeakMap': return 'weakmap'; + case 'WeakSet': return 'weakset'; + case 'Map': return 'map'; + case 'Set': return 'set'; - // apply env-specific formatting (colors, etc.) - exports.formatArgs.call(self, args); + // 8-bit typed arrays + case 'Int8Array': return 'int8array'; + case 'Uint8Array': return 'uint8array'; + case 'Uint8ClampedArray': return 'uint8clampedarray'; - var logFn = debug.log || exports.log || console.log.bind(console); - logFn.apply(self, args); - } + // 16-bit typed arrays + case 'Int16Array': return 'int16array'; + case 'Uint16Array': return 'uint16array'; - debug.namespace = namespace; - debug.enabled = exports.enabled(namespace); - debug.useColors = exports.useColors(); - debug.color = selectColor(namespace); + // 32-bit typed arrays + case 'Int32Array': return 'int32array'; + case 'Uint32Array': return 'uint32array'; + case 'Float32Array': return 'float32array'; + case 'Float64Array': return 'float64array'; + } - // env-specific initialization logic for debug instances - if ('function' === typeof exports.init) { - exports.init(debug); + if (isGeneratorObj(val)) { + return 'generator'; } - return debug; -} + // Non-plain objects + type = toString.call(val); + switch (type) { + case '[object Object]': return 'object'; + // iterators + case '[object Map Iterator]': return 'mapiterator'; + case '[object Set Iterator]': return 'setiterator'; + case '[object String Iterator]': return 'stringiterator'; + case '[object Array Iterator]': return 'arrayiterator'; + } -/** - * Enables a debug mode by namespaces. This can include modes - * separated by a colon and wildcards. - * - * @param {String} namespaces - * @api public - */ + // other + return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); +}; -function enable(namespaces) { - exports.save(namespaces); +function ctorName(val) { + return val.constructor ? val.constructor.name : null; +} - exports.names = []; - exports.skips = []; +function isArray(val) { + if (Array.isArray) return Array.isArray(val); + return val instanceof Array; +} - var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); - var len = split.length; +function isError(val) { + return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); +} - for (var i = 0; i < len; i++) { - if (!split[i]) continue; // ignore empty strings - namespaces = split[i].replace(/\*/g, '.*?'); - if (namespaces[0] === '-') { - exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); - } else { - exports.names.push(new RegExp('^' + namespaces + '$')); - } - } +function isDate(val) { + if (val instanceof Date) return true; + return typeof val.toDateString === 'function' + && typeof val.getDate === 'function' + && typeof val.setDate === 'function'; } -/** - * Disable debug output. - * - * @api public - */ +function isRegexp(val) { + if (val instanceof RegExp) return true; + return typeof val.flags === 'string' + && typeof val.ignoreCase === 'boolean' + && typeof val.multiline === 'boolean' + && typeof val.global === 'boolean'; +} -function disable() { - exports.enable(''); +function isGeneratorFn(name, val) { + return ctorName(name) === 'GeneratorFunction'; } -/** - * Returns true if the given mode name is enabled, false otherwise. - * - * @param {String} name - * @return {Boolean} - * @api public - */ +function isGeneratorObj(val) { + return typeof val.throw === 'function' + && typeof val.return === 'function' + && typeof val.next === 'function'; +} -function enabled(name) { - var i, len; - for (i = 0, len = exports.skips.length; i < len; i++) { - if (exports.skips[i].test(name)) { - return false; +function isArguments(val) { + try { + if (typeof val.length === 'number' && typeof val.callee === 'function') { + return true; } - } - for (i = 0, len = exports.names.length; i < len; i++) { - if (exports.names[i].test(name)) { + } catch (err) { + if (err.message.indexOf('callee') !== -1) { return true; } } @@ -103493,1343 +102571,1857 @@ function enabled(name) { } /** - * Coerce `val`. - * - * @param {Mixed} val - * @return {Mixed} - * @api private + * If you need to support Safari 5-7 (8-10 yr-old browser), + * take a look at https://github.com/feross/is-buffer */ -function coerce(val) { - if (val instanceof Error) return val.stack || val.message; - return val; +function isBuffer(val) { + if (val.constructor && typeof val.constructor.isBuffer === 'function') { + return val.constructor.isBuffer(val); + } + return false; } /***/ }), -/* 866 */ -/***/ (function(module, exports) { +/* 871 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Helpers. - */ +"use strict"; + +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var readdir = __webpack_require__(872); +var reader_1 = __webpack_require__(885); +var fs_stream_1 = __webpack_require__(889); +var ReaderAsync = /** @class */ (function (_super) { + __extends(ReaderAsync, _super); + function ReaderAsync() { + return _super !== null && _super.apply(this, arguments) || this; + } + Object.defineProperty(ReaderAsync.prototype, "fsAdapter", { + /** + * Returns FileSystem adapter. + */ + get: function () { + return new fs_stream_1.default(this.options); + }, + enumerable: true, + configurable: true + }); + /** + * Use async API to read entries for Task. + */ + ReaderAsync.prototype.read = function (task) { + var _this = this; + var root = this.getRootDirectory(task); + var options = this.getReaderOptions(task); + var entries = []; + return new Promise(function (resolve, reject) { + var stream = _this.api(root, task, options); + stream.on('error', function (err) { + _this.isEnoentCodeError(err) ? resolve([]) : reject(err); + stream.pause(); + }); + stream.on('data', function (entry) { return entries.push(_this.transform(entry)); }); + stream.on('end', function () { return resolve(entries); }); + }); + }; + /** + * Returns founded paths. + */ + ReaderAsync.prototype.api = function (root, task, options) { + if (task.dynamic) { + return this.dynamicApi(root, options); + } + return this.staticApi(task, options); + }; + /** + * Api for dynamic tasks. + */ + ReaderAsync.prototype.dynamicApi = function (root, options) { + return readdir.readdirStreamStat(root, options); + }; + /** + * Api for static tasks. + */ + ReaderAsync.prototype.staticApi = function (task, options) { + return this.fsAdapter.read(task.patterns, options.filter); + }; + return ReaderAsync; +}(reader_1.default)); +exports.default = ReaderAsync; -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; + +/***/ }), +/* 872 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const readdirSync = __webpack_require__(873); +const readdirAsync = __webpack_require__(881); +const readdirStream = __webpack_require__(884); + +module.exports = exports = readdirAsyncPath; +exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; +exports.readdirAsyncStat = exports.async.stat = readdirAsyncStat; +exports.readdirStream = exports.stream = readdirStreamPath; +exports.readdirStreamStat = exports.stream.stat = readdirStreamStat; +exports.readdirSync = exports.sync = readdirSyncPath; +exports.readdirSyncStat = exports.sync.stat = readdirSyncStat; /** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] + * Synchronous readdir that returns an array of string paths. * - * @param {String|Number} val - * @param {Object} [options] - * @throws {Error} throw an error if val is not a non-empty string or a number - * @return {String|Number} - * @api public + * @param {string} dir + * @param {object} [options] + * @returns {string[]} */ +function readdirSyncPath (dir, options) { + return readdirSync(dir, options, {}); +} -module.exports = function(val, options) { - options = options || {}; - var type = typeof val; - if (type === 'string' && val.length > 0) { - return parse(val); - } else if (type === 'number' && isNaN(val) === false) { - return options.long ? fmtLong(val) : fmtShort(val); - } - throw new Error( - 'val is not a non-empty string or a valid number. val=' + - JSON.stringify(val) - ); -}; +/** + * Synchronous readdir that returns results as an array of {@link fs.Stats} objects + * + * @param {string} dir + * @param {object} [options] + * @returns {fs.Stats[]} + */ +function readdirSyncStat (dir, options) { + return readdirSync(dir, options, { stats: true }); +} /** - * Parse the given `str` and return milliseconds. + * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). + * Results are an array of path strings. * - * @param {String} str - * @return {Number} - * @api private + * @param {string} dir + * @param {object} [options] + * @param {function} [callback] + * @returns {Promise} */ +function readdirAsyncPath (dir, options, callback) { + return readdirAsync(dir, options, callback, {}); +} -function parse(str) { - str = String(str); - if (str.length > 100) { - return; - } - var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec( - str - ); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'yrs': - case 'yr': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'hrs': - case 'hr': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'mins': - case 'min': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 'secs': - case 'sec': - case 's': - return n * s; - case 'milliseconds': - case 'millisecond': - case 'msecs': - case 'msec': - case 'ms': - return n; - default: - return undefined; - } +/** + * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). + * Results are an array of {@link fs.Stats} objects. + * + * @param {string} dir + * @param {object} [options] + * @param {function} [callback] + * @returns {Promise} + */ +function readdirAsyncStat (dir, options, callback) { + return readdirAsync(dir, options, callback, { stats: true }); } /** - * Short format for `ms`. + * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}). + * All stream data events ("data", "file", "directory", "symlink") are passed a path string. * - * @param {Number} ms - * @return {String} - * @api private + * @param {string} dir + * @param {object} [options] + * @returns {stream.Readable} */ +function readdirStreamPath (dir, options) { + return readdirStream(dir, options, {}); +} -function fmtShort(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; +/** + * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}) + * All stream data events ("data", "file", "directory", "symlink") are passed an {@link fs.Stats} object. + * + * @param {string} dir + * @param {object} [options] + * @returns {stream.Readable} + */ +function readdirStreamStat (dir, options) { + return readdirStream(dir, options, { stats: true }); } + +/***/ }), +/* 873 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +module.exports = readdirSync; + +const DirectoryReader = __webpack_require__(874); + +let syncFacade = { + fs: __webpack_require__(879), + forEach: __webpack_require__(880), + sync: true +}; + /** - * Long format for `ms`. + * Returns the buffered output from a synchronous {@link DirectoryReader}. * - * @param {Number} ms - * @return {String} - * @api private + * @param {string} dir + * @param {object} [options] + * @param {object} internalOptions */ +function readdirSync (dir, options, internalOptions) { + internalOptions.facade = syncFacade; -function fmtLong(ms) { - return plural(ms, d, 'day') || - plural(ms, h, 'hour') || - plural(ms, m, 'minute') || - plural(ms, s, 'second') || - ms + ' ms'; -} - -/** - * Pluralization helper. - */ + let reader = new DirectoryReader(dir, options, internalOptions); + let stream = reader.stream; -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; + let results = []; + let data = stream.read(); + while (data !== null) { + results.push(data); + data = stream.read(); } - return Math.ceil(ms / n) + ' ' + name + 's'; + + return results; } /***/ }), -/* 867 */ +/* 874 */ /***/ (function(module, exports, __webpack_require__) { -/** - * Module dependencies. - */ +"use strict"; -var tty = __webpack_require__(480); -var util = __webpack_require__(29); + +const Readable = __webpack_require__(27).Readable; +const EventEmitter = __webpack_require__(379).EventEmitter; +const path = __webpack_require__(16); +const normalizeOptions = __webpack_require__(875); +const stat = __webpack_require__(877); +const call = __webpack_require__(878); /** - * This is the Node.js implementation of `debug()`. - * - * Expose `debug()` as the module. + * Asynchronously reads the contents of a directory and streams the results + * via a {@link stream.Readable}. */ +class DirectoryReader { + /** + * @param {string} dir - The absolute or relative directory path to read + * @param {object} [options] - User-specified options, if any (see {@link normalizeOptions}) + * @param {object} internalOptions - Internal options that aren't part of the public API + * @class + */ + constructor (dir, options, internalOptions) { + this.options = options = normalizeOptions(options, internalOptions); -exports = module.exports = __webpack_require__(865); -exports.init = init; -exports.log = log; -exports.formatArgs = formatArgs; -exports.save = save; -exports.load = load; -exports.useColors = useColors; + // Indicates whether we should keep reading + // This is set false if stream.Readable.push() returns false. + this.shouldRead = true; -/** - * Colors. - */ + // The directories to read + // (initialized with the top-level directory) + this.queue = [{ + path: dir, + basePath: options.basePath, + posixBasePath: options.posixBasePath, + depth: 0 + }]; -exports.colors = [6, 2, 3, 4, 5, 1]; + // The number of directories that are currently being processed + this.pending = 0; -/** - * Build up the default `inspectOpts` object from the environment variables. - * - * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js - */ + // The data that has been read, but not yet emitted + this.buffer = []; -exports.inspectOpts = Object.keys(process.env).filter(function (key) { - return /^debug_/i.test(key); -}).reduce(function (obj, key) { - // camel-case - var prop = key - .substring(6) - .toLowerCase() - .replace(/_([a-z])/g, function (_, k) { return k.toUpperCase() }); + this.stream = new Readable({ objectMode: true }); + this.stream._read = () => { + // Start (or resume) reading + this.shouldRead = true; - // coerce string value into JS value - var val = process.env[key]; - if (/^(yes|on|true|enabled)$/i.test(val)) val = true; - else if (/^(no|off|false|disabled)$/i.test(val)) val = false; - else if (val === 'null') val = null; - else val = Number(val); + // If we have data in the buffer, then send the next chunk + if (this.buffer.length > 0) { + this.pushFromBuffer(); + } - obj[prop] = val; - return obj; -}, {}); + // If we have directories queued, then start processing the next one + if (this.queue.length > 0) { + if (this.options.facade.sync) { + while (this.queue.length > 0) { + this.readNextDirectory(); + } + } + else { + this.readNextDirectory(); + } + } -/** - * The file descriptor to write the `debug()` calls to. - * Set the `DEBUG_FD` env variable to override with another value. i.e.: - * - * $ DEBUG_FD=3 node script.js 3>debug.log - */ + this.checkForEOF(); + }; + } -var fd = parseInt(process.env.DEBUG_FD, 10) || 2; + /** + * Reads the next directory in the queue + */ + readNextDirectory () { + let facade = this.options.facade; + let dir = this.queue.shift(); + this.pending++; -if (1 !== fd && 2 !== fd) { - util.deprecate(function(){}, 'except for stderr(2) and stdout(1), any other usage of DEBUG_FD is deprecated. Override debug.log if you want to use a different log function (https://git.io/debug_fd)')() -} + // Read the directory listing + call.safe(facade.fs.readdir, dir.path, (err, items) => { + if (err) { + // fs.readdir threw an error + this.emit('error', err); + return this.finishedReadingDirectory(); + } -var stream = 1 === fd ? process.stdout : - 2 === fd ? process.stderr : - createWritableStdioStream(fd); + try { + // Process each item in the directory (simultaneously, if async) + facade.forEach( + items, + this.processItem.bind(this, dir), + this.finishedReadingDirectory.bind(this, dir) + ); + } + catch (err2) { + // facade.forEach threw an error + // (probably because fs.readdir returned an invalid result) + this.emit('error', err2); + this.finishedReadingDirectory(); + } + }); + } -/** - * Is stdout a TTY? Colored output is enabled when `true`. - */ + /** + * This method is called after all items in a directory have been processed. + * + * NOTE: This does not necessarily mean that the reader is finished, since there may still + * be other directories queued or pending. + */ + finishedReadingDirectory () { + this.pending--; -function useColors() { - return 'colors' in exports.inspectOpts - ? Boolean(exports.inspectOpts.colors) - : tty.isatty(fd); -} + if (this.shouldRead) { + // If we have directories queued, then start processing the next one + if (this.queue.length > 0 && this.options.facade.async) { + this.readNextDirectory(); + } -/** - * Map %o to `util.inspect()`, all on a single line. - */ + this.checkForEOF(); + } + } -exports.formatters.o = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts) - .split('\n').map(function(str) { - return str.trim() - }).join(' '); -}; + /** + * Determines whether the reader has finished processing all items in all directories. + * If so, then the "end" event is fired (via {@Readable#push}) + */ + checkForEOF () { + if (this.buffer.length === 0 && // The stuff we've already read + this.pending === 0 && // The stuff we're currently reading + this.queue.length === 0) { // The stuff we haven't read yet + // There's no more stuff! + this.stream.push(null); + } + } -/** - * Map %o to `util.inspect()`, allowing multiple lines if needed. - */ + /** + * Processes a single item in a directory. + * + * If the item is a directory, and `option.deep` is enabled, then the item will be added + * to the directory queue. + * + * If the item meets the filter criteria, then it will be emitted to the reader's stream. + * + * @param {object} dir - A directory object from the queue + * @param {string} item - The name of the item (name only, no path) + * @param {function} done - A callback function that is called after the item has been processed + */ + processItem (dir, item, done) { + let stream = this.stream; + let options = this.options; -exports.formatters.O = function(v) { - this.inspectOpts.colors = this.useColors; - return util.inspect(v, this.inspectOpts); -}; + let itemPath = dir.basePath + item; + let posixPath = dir.posixBasePath + item; + let fullPath = path.join(dir.path, item); -/** - * Adds ANSI color escape codes if enabled. - * - * @api public - */ + // If `options.deep` is a number, and we've already recursed to the max depth, + // then there's no need to check fs.Stats to know if it's a directory. + // If `options.deep` is a function, then we'll need fs.Stats + let maxDepthReached = dir.depth >= options.recurseDepth; -function formatArgs(args) { - var name = this.namespace; - var useColors = this.useColors; + // Do we need to call `fs.stat`? + let needStats = + !maxDepthReached || // we need the fs.Stats to know if it's a directory + options.stats || // the user wants fs.Stats objects returned + options.recurseFn || // we need fs.Stats for the recurse function + options.filterFn || // we need fs.Stats for the filter function + EventEmitter.listenerCount(stream, 'file') || // we need the fs.Stats to know if it's a file + EventEmitter.listenerCount(stream, 'directory') || // we need the fs.Stats to know if it's a directory + EventEmitter.listenerCount(stream, 'symlink'); // we need the fs.Stats to know if it's a symlink - if (useColors) { - var c = this.color; - var prefix = ' \u001b[3' + c + ';1m' + name + ' ' + '\u001b[0m'; + // If we don't need stats, then exit early + if (!needStats) { + if (this.filter(itemPath, posixPath)) { + this.pushOrBuffer({ data: itemPath }); + } + return done(); + } - args[0] = prefix + args[0].split('\n').join('\n' + prefix); - args.push('\u001b[3' + c + 'm+' + exports.humanize(this.diff) + '\u001b[0m'); - } else { - args[0] = new Date().toUTCString() - + ' ' + name + ' ' + args[0]; - } -} + // Get the fs.Stats object for this path + stat(options.facade.fs, fullPath, (err, stats) => { + if (err) { + // fs.stat threw an error + this.emit('error', err); + return done(); + } -/** - * Invokes `util.format()` with the specified arguments and writes to `stream`. - */ + try { + // Add the item's path to the fs.Stats object + // The base of this path, and its separators are determined by the options + // (i.e. options.basePath and options.sep) + stats.path = itemPath; -function log() { - return stream.write(util.format.apply(util, arguments) + '\n'); -} + // Add depth of the path to the fs.Stats object for use this in the filter function + stats.depth = dir.depth; -/** - * Save `namespaces`. - * - * @param {String} namespaces - * @api private - */ + if (this.shouldRecurse(stats, posixPath, maxDepthReached)) { + // Add this subdirectory to the queue + this.queue.push({ + path: fullPath, + basePath: itemPath + options.sep, + posixBasePath: posixPath + '/', + depth: dir.depth + 1, + }); + } -function save(namespaces) { - if (null == namespaces) { - // If you set a process.env field to null or undefined, it gets cast to the - // string 'null' or 'undefined'. Just delete instead. - delete process.env.DEBUG; - } else { - process.env.DEBUG = namespaces; + // Determine whether this item matches the filter criteria + if (this.filter(stats, posixPath)) { + this.pushOrBuffer({ + data: options.stats ? stats : itemPath, + file: stats.isFile(), + directory: stats.isDirectory(), + symlink: stats.isSymbolicLink(), + }); + } + + done(); + } + catch (err2) { + // An error occurred while processing the item + // (probably during a user-specified function, such as options.deep, options.filter, etc.) + this.emit('error', err2); + done(); + } + }); } -} -/** - * Load `namespaces`. - * - * @return {String} returns the previously persisted debug modes - * @api private - */ + /** + * Pushes the given chunk of data to the stream, or adds it to the buffer, + * depending on the state of the stream. + * + * @param {object} chunk + */ + pushOrBuffer (chunk) { + // Add the chunk to the buffer + this.buffer.push(chunk); -function load() { - return process.env.DEBUG; -} + // If we're still reading, then immediately emit the next chunk in the buffer + // (which may or may not be the chunk that we just added) + if (this.shouldRead) { + this.pushFromBuffer(); + } + } -/** - * Copied from `node/src/node.js`. - * - * XXX: It's lame that node doesn't expose this API out-of-the-box. It also - * relies on the undocumented `tty_wrap.guessHandleType()` which is also lame. - */ + /** + * Immediately pushes the next chunk in the buffer to the reader's stream. + * The "data" event will always be fired (via {@link Readable#push}). + * In addition, the "file", "directory", and/or "symlink" events may be fired, + * depending on the type of properties of the chunk. + */ + pushFromBuffer () { + let stream = this.stream; + let chunk = this.buffer.shift(); -function createWritableStdioStream (fd) { - var stream; - var tty_wrap = process.binding('tty_wrap'); + // Stream the data + try { + this.shouldRead = stream.push(chunk.data); + } + catch (err) { + this.emit('error', err); + } - // Note stream._type is used for test-module-load-list.js + // Also emit specific events, based on the type of chunk + chunk.file && this.emit('file', chunk.data); + chunk.symlink && this.emit('symlink', chunk.data); + chunk.directory && this.emit('directory', chunk.data); + } - switch (tty_wrap.guessHandleType(fd)) { - case 'TTY': - stream = new tty.WriteStream(fd); - stream._type = 'tty'; + /** + * Determines whether the given directory meets the user-specified recursion criteria. + * If the user didn't specify recursion criteria, then this function will default to true. + * + * @param {fs.Stats} stats - The directory's {@link fs.Stats} object + * @param {string} posixPath - The item's POSIX path (used for glob matching) + * @param {boolean} maxDepthReached - Whether we've already crawled the user-specified depth + * @returns {boolean} + */ + shouldRecurse (stats, posixPath, maxDepthReached) { + let options = this.options; - // Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); + if (maxDepthReached) { + // We've already crawled to the maximum depth. So no more recursion. + return false; + } + else if (!stats.isDirectory()) { + // It's not a directory. So don't try to crawl it. + return false; + } + else if (options.recurseGlob) { + // Glob patterns are always tested against the POSIX path, even on Windows + // https://github.com/isaacs/node-glob#windows + return options.recurseGlob.test(posixPath); + } + else if (options.recurseRegExp) { + // Regular expressions are tested against the normal path + // (based on the OS or options.sep) + return options.recurseRegExp.test(stats.path); + } + else if (options.recurseFn) { + try { + // Run the user-specified recursion criteria + return options.recurseFn.call(null, stats); } - break; - - case 'FILE': - var fs = __webpack_require__(23); - stream = new fs.SyncWriteStream(fd, { autoClose: false }); - stream._type = 'fs'; - break; - - case 'PIPE': - case 'TCP': - var net = __webpack_require__(805); - stream = new net.Socket({ - fd: fd, - readable: false, - writable: true - }); + catch (err) { + // An error occurred in the user's code. + // In Sync and Async modes, this will return an error. + // In Streaming mode, we emit an "error" event, but continue processing + this.emit('error', err); + } + } + else { + // No recursion function was specified, and we're within the maximum depth. + // So crawl this directory. + return true; + } + } - // FIXME Should probably have an option in net.Socket to create a - // stream from an existing fd which is writable only. But for now - // we'll just add this hack and set the `readable` member to false. - // Test: ./node test/fixtures/echo.js < /etc/passwd - stream.readable = false; - stream.read = null; - stream._type = 'pipe'; + /** + * Determines whether the given item meets the user-specified filter criteria. + * If the user didn't specify a filter, then this function will always return true. + * + * @param {string|fs.Stats} value - Either the item's path, or the item's {@link fs.Stats} object + * @param {string} posixPath - The item's POSIX path (used for glob matching) + * @returns {boolean} + */ + filter (value, posixPath) { + let options = this.options; - // FIXME Hack to have stream not keep the event loop alive. - // See https://github.com/joyent/node/issues/1726 - if (stream._handle && stream._handle.unref) { - stream._handle.unref(); + if (options.filterGlob) { + // Glob patterns are always tested against the POSIX path, even on Windows + // https://github.com/isaacs/node-glob#windows + return options.filterGlob.test(posixPath); + } + else if (options.filterRegExp) { + // Regular expressions are tested against the normal path + // (based on the OS or options.sep) + return options.filterRegExp.test(value.path || value); + } + else if (options.filterFn) { + try { + // Run the user-specified filter function + return options.filterFn.call(null, value); + } + catch (err) { + // An error occurred in the user's code. + // In Sync and Async modes, this will return an error. + // In Streaming mode, we emit an "error" event, but continue processing + this.emit('error', err); } - break; - - default: - // Probably an error on in uv_guess_handle() - throw new Error('Implement me. Unknown stream file type!'); + } + else { + // No filter was specified, so match everything + return true; + } } - // For supporting legacy API we put the FD here. - stream.fd = fd; - - stream._isStdio = true; - - return stream; -} - -/** - * Init logic for `debug` instances. - * - * Create a new `inspectOpts` object in case `useColors` is set - * differently for a particular `debug` instance. - */ - -function init (debug) { - debug.inspectOpts = {}; + /** + * Emits an event. If one of the event listeners throws an error, + * then an "error" event is emitted. + * + * @param {string} eventName + * @param {*} data + */ + emit (eventName, data) { + let stream = this.stream; - var keys = Object.keys(exports.inspectOpts); - for (var i = 0; i < keys.length; i++) { - debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]]; + try { + stream.emit(eventName, data); + } + catch (err) { + if (eventName === 'error') { + // Don't recursively emit "error" events. + // If the first one fails, then just throw + throw err; + } + else { + stream.emit('error', err); + } + } } } -/** - * Enable namespaces listed in `process.env.DEBUG` initially. - */ - -exports.enable(load()); +module.exports = DirectoryReader; /***/ }), -/* 868 */ +/* 875 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(858); -var define = __webpack_require__(869); -var utils = __webpack_require__(870); +const path = __webpack_require__(16); +const globToRegExp = __webpack_require__(876); -/** - * Characters to use in text regex (we want to "not" match - * characters that are matched by other parsers) - */ +module.exports = normalizeOptions; -var TEXT_REGEX = '([!@*?+]?\\(|\\)|[*?.+\\\\]|\\[:?(?=.*\\])|:?\\])+'; -var not = utils.createRegex(TEXT_REGEX); +let isWindows = /^win/.test(process.platform); /** - * Extglob parsers + * @typedef {Object} FSFacade + * @property {fs.readdir} readdir + * @property {fs.stat} stat + * @property {fs.lstat} lstat */ -function parsers(extglob) { - extglob.state = extglob.state || {}; - - /** - * Use `expand-brackets` parsers - */ - - extglob.use(brackets.parsers); - extglob.parser.sets.paren = extglob.parser.sets.paren || []; - extglob.parser - - /** - * Extglob open: "*(" - */ - - .capture('paren.open', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^([!@*?+])?\(/); - if (!m) return; - - var prev = this.prev(); - var prefix = m[1]; - var val = m[0]; - - var open = pos({ - type: 'paren.open', - parsed: parsed, - val: val - }); - - var node = pos({ - type: 'paren', - prefix: prefix, - nodes: [open] - }); - - // if nested negation extglobs, just cancel them out to simplify - if (prefix === '!' && prev.type === 'paren' && prev.prefix === '!') { - prev.prefix = '@'; - node.prefix = '@'; - } - - define(node, 'rest', this.input); - define(node, 'parsed', parsed); - define(node, 'parent', prev); - define(open, 'parent', node); - - this.push('paren', node); - prev.nodes.push(node); - }) - - /** - * Extglob close: ")" - */ - - .capture('paren.close', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\)/); - if (!m) return; - - var parent = this.pop('paren'); - var node = pos({ - type: 'paren.close', - rest: this.input, - parsed: parsed, - val: m[0] - }); - - if (!this.isType(parent, 'paren')) { - if (this.options.strict) { - throw new Error('missing opening paren: "("'); - } - node.escaped = true; - return node; - } - - node.prefix = parent.prefix; - parent.nodes.push(node); - define(node, 'parent', parent); - }) - - /** - * Escape: "\\." - */ - - .capture('escape', function() { - var pos = this.position(); - var m = this.match(/^\\(.)/); - if (!m) return; - - return pos({ - type: 'escape', - val: m[0], - ch: m[1] - }); - }) - - /** - * Question marks: "?" - */ - - .capture('qmark', function() { - var parsed = this.parsed; - var pos = this.position(); - var m = this.match(/^\?+(?!\()/); - if (!m) return; - extglob.state.metachar = true; - return pos({ - type: 'qmark', - rest: this.input, - parsed: parsed, - val: m[0] - }); - }) - - /** - * Character parsers - */ - - .capture('star', /^\*(?!\()/) - .capture('plus', /^\+(?!\()/) - .capture('dot', /^\./) - .capture('text', not); -}; - /** - * Expose text regex string + * Validates and normalizes the options argument + * + * @param {object} [options] - User-specified options, if any + * @param {object} internalOptions - Internal options that aren't part of the public API + * + * @param {number|boolean|function} [options.deep] + * The number of directories to recursively traverse. Any falsy value or negative number will + * default to zero, so only the top-level contents will be returned. Set to `true` or `Infinity` + * to traverse all subdirectories. Or provide a function that accepts a {@link fs.Stats} object + * and returns a truthy value if the directory's contents should be crawled. + * + * @param {function|string|RegExp} [options.filter] + * A function that accepts a {@link fs.Stats} object and returns a truthy value if the data should + * be returned. Or a RegExp or glob string pattern, to filter by file name. + * + * @param {string} [options.sep] + * The path separator to use. By default, the OS-specific separator will be used, but this can be + * set to a specific value to ensure consistency across platforms. + * + * @param {string} [options.basePath] + * The base path to prepend to each result. If empty, then all results will be relative to `dir`. + * + * @param {FSFacade} [options.fs] + * Synchronous or asynchronous facades for Node.js File System module + * + * @param {object} [internalOptions.facade] + * Synchronous or asynchronous facades for various methods, including for the Node.js File System module + * + * @param {boolean} [internalOptions.emit] + * Indicates whether the reader should emit "file", "directory", and "symlink" events + * + * @param {boolean} [internalOptions.stats] + * Indicates whether the reader should emit {@link fs.Stats} objects instead of path strings + * + * @returns {object} */ +function normalizeOptions (options, internalOptions) { + if (options === null || options === undefined) { + options = {}; + } + else if (typeof options !== 'object') { + throw new TypeError('options must be an object'); + } -module.exports.TEXT_REGEX = TEXT_REGEX; - -/** - * Extglob parsers - */ + let recurseDepth, recurseFn, recurseRegExp, recurseGlob, deep = options.deep; + if (deep === null || deep === undefined) { + recurseDepth = 0; + } + else if (typeof deep === 'boolean') { + recurseDepth = deep ? Infinity : 0; + } + else if (typeof deep === 'number') { + if (deep < 0 || isNaN(deep)) { + throw new Error('options.deep must be a positive number'); + } + else if (Math.floor(deep) !== deep) { + throw new Error('options.deep must be an integer'); + } + else { + recurseDepth = deep; + } + } + else if (typeof deep === 'function') { + recurseDepth = Infinity; + recurseFn = deep; + } + else if (deep instanceof RegExp) { + recurseDepth = Infinity; + recurseRegExp = deep; + } + else if (typeof deep === 'string' && deep.length > 0) { + recurseDepth = Infinity; + recurseGlob = globToRegExp(deep, { extended: true, globstar: true }); + } + else { + throw new TypeError('options.deep must be a boolean, number, function, regular expression, or glob pattern'); + } -module.exports = parsers; + let filterFn, filterRegExp, filterGlob, filter = options.filter; + if (filter !== null && filter !== undefined) { + if (typeof filter === 'function') { + filterFn = filter; + } + else if (filter instanceof RegExp) { + filterRegExp = filter; + } + else if (typeof filter === 'string' && filter.length > 0) { + filterGlob = globToRegExp(filter, { extended: true, globstar: true }); + } + else { + throw new TypeError('options.filter must be a function, regular expression, or glob pattern'); + } + } + let sep = options.sep; + if (sep === null || sep === undefined) { + sep = path.sep; + } + else if (typeof sep !== 'string') { + throw new TypeError('options.sep must be a string'); + } -/***/ }), -/* 869 */ -/***/ (function(module, exports, __webpack_require__) { + let basePath = options.basePath; + if (basePath === null || basePath === undefined) { + basePath = ''; + } + else if (typeof basePath === 'string') { + // Append a path separator to the basePath, if necessary + if (basePath && basePath.substr(-1) !== sep) { + basePath += sep; + } + } + else { + throw new TypeError('options.basePath must be a string'); + } -"use strict"; -/*! - * define-property - * - * Copyright (c) 2015, 2017, Jon Schlinkert. - * Released under the MIT License. - */ + // Convert the basePath to POSIX (forward slashes) + // so that glob pattern matching works consistently, even on Windows + let posixBasePath = basePath; + if (posixBasePath && sep !== '/') { + posixBasePath = posixBasePath.replace(new RegExp('\\' + sep, 'g'), '/'); + /* istanbul ignore if */ + if (isWindows) { + // Convert Windows root paths (C:\) and UNCs (\\) to POSIX root paths + posixBasePath = posixBasePath.replace(/^([a-zA-Z]\:\/|\/\/)/, '/'); + } + } + // Determine which facade methods to use + let facade; + if (options.fs === null || options.fs === undefined) { + // The user didn't provide their own facades, so use our internal ones + facade = internalOptions.facade; + } + else if (typeof options.fs === 'object') { + // Merge the internal facade methods with the user-provided `fs` facades + facade = Object.assign({}, internalOptions.facade); + facade.fs = Object.assign({}, internalOptions.facade.fs, options.fs); + } + else { + throw new TypeError('options.fs must be an object'); + } -var isDescriptor = __webpack_require__(759); + return { + recurseDepth, + recurseFn, + recurseRegExp, + recurseGlob, + filterFn, + filterRegExp, + filterGlob, + sep, + basePath, + posixBasePath, + facade, + emit: !!internalOptions.emit, + stats: !!internalOptions.stats, + }; +} -module.exports = function defineProperty(obj, prop, val) { - if (typeof obj !== 'object' && typeof obj !== 'function') { - throw new TypeError('expected an object or function.'); - } - if (typeof prop !== 'string') { - throw new TypeError('expected `prop` to be a string.'); - } +/***/ }), +/* 876 */ +/***/ (function(module, exports) { - if (isDescriptor(val) && ('set' in val || 'get' in val)) { - return Object.defineProperty(obj, prop, val); +module.exports = function (glob, opts) { + if (typeof glob !== 'string') { + throw new TypeError('Expected a string'); } - return Object.defineProperty(obj, prop, { - configurable: true, - enumerable: false, - writable: true, - value: val - }); -}; + var str = String(glob); + // The regexp we are building, as a string. + var reStr = ""; -/***/ }), -/* 870 */ -/***/ (function(module, exports, __webpack_require__) { + // Whether we are matching so called "extended" globs (like bash) and should + // support single character matching, matching ranges of characters, group + // matching, etc. + var extended = opts ? !!opts.extended : false; -"use strict"; + // When globstar is _false_ (default), '/foo/*' is translated a regexp like + // '^\/foo\/.*$' which will match any string beginning with '/foo/' + // When globstar is _true_, '/foo/*' is translated to regexp like + // '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT + // which does not have a '/' to the right of it. + // E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but + // these will not '/foo/bar/baz', '/foo/bar/baz.txt' + // Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when + // globstar is _false_ + var globstar = opts ? !!opts.globstar : false; + // If we are doing extended matching, this boolean is true when we are inside + // a group (eg {*.html,*.js}), and false otherwise. + var inGroup = false; -var regex = __webpack_require__(739); -var Cache = __webpack_require__(849); + // RegExp flags (eg "i" ) to pass in to RegExp constructor. + var flags = opts && typeof( opts.flags ) === "string" ? opts.flags : ""; -/** - * Utils - */ + var c; + for (var i = 0, len = str.length; i < len; i++) { + c = str[i]; -var utils = module.exports; -var cache = utils.cache = new Cache(); + switch (c) { + case "\\": + case "/": + case "$": + case "^": + case "+": + case ".": + case "(": + case ")": + case "=": + case "!": + case "|": + reStr += "\\" + c; + break; -/** - * Cast `val` to an array - * @return {Array} - */ + case "?": + if (extended) { + reStr += "."; + break; + } -utils.arrayify = function(val) { - if (!Array.isArray(val)) { - return [val]; - } - return val; -}; + case "[": + case "]": + if (extended) { + reStr += c; + break; + } -/** - * Memoize a generated regex or function - */ + case "{": + if (extended) { + inGroup = true; + reStr += "("; + break; + } -utils.memoize = function(type, pattern, options, fn) { - var key = utils.createKey(type + pattern, options); + case "}": + if (extended) { + inGroup = false; + reStr += ")"; + break; + } - if (cache.has(type, key)) { - return cache.get(type, key); - } + case ",": + if (inGroup) { + reStr += "|"; + break; + } + reStr += "\\" + c; + break; - var val = fn(pattern, options); - if (options && options.cache === false) { - return val; - } + case "*": + // Move over all consecutive "*"'s. + // Also store the previous and next characters + var prevChar = str[i - 1]; + var starCount = 1; + while(str[i + 1] === "*") { + starCount++; + i++; + } + var nextChar = str[i + 1]; - cache.set(type, key, val); - return val; -}; + if (!globstar) { + // globstar is disabled, so treat any number of "*" as one + reStr += ".*"; + } else { + // globstar is enabled, so determine if this is a globstar segment + var isGlobstar = starCount > 1 // multiple "*"'s + && (prevChar === "/" || prevChar === undefined) // from the start of the segment + && (nextChar === "/" || nextChar === undefined) // to the end of the segment -/** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. - */ + if (isGlobstar) { + // it's a globstar, so match zero or more path segments + reStr += "(?:[^/]*(?:\/|$))*"; + i++; // move over the "/" + } else { + // it's not a globstar, so only match one path segment + reStr += "[^/]*"; + } + } + break; -utils.createKey = function(pattern, options) { - var key = pattern; - if (typeof options === 'undefined') { - return key; - } - for (var prop in options) { - key += ';' + prop + '=' + String(options[prop]); + default: + reStr += c; + } } - return key; -}; -/** - * Create the regex to use for matching text - */ + // When regexp 'g' flag is specified don't + // constrain the regular expression with ^ & $ + if (!flags || !~flags.indexOf('g')) { + reStr = "^" + reStr + "$"; + } -utils.createRegex = function(str) { - var opts = {contains: true, strictClose: false}; - return regex(str, opts); + return new RegExp(reStr, flags); }; /***/ }), -/* 871 */ +/* 877 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -/** - * Module dependencies - */ - -var Snapdragon = __webpack_require__(767); -var define = __webpack_require__(869); -var extend = __webpack_require__(737); - -/** - * Local dependencies - */ +const call = __webpack_require__(878); -var compilers = __webpack_require__(857); -var parsers = __webpack_require__(868); +module.exports = stat; /** - * Customize Snapdragon parser and renderer + * Retrieves the {@link fs.Stats} for the given path. If the path is a symbolic link, + * then the Stats of the symlink's target are returned instead. If the symlink is broken, + * then the Stats of the symlink itself are returned. + * + * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module + * @param {string} path - The path to return stats for + * @param {function} callback */ +function stat (fs, path, callback) { + let isSymLink = false; -function Extglob(options) { - this.options = extend({source: 'extglob'}, options); - this.snapdragon = this.options.snapdragon || new Snapdragon(this.options); - this.snapdragon.patterns = this.snapdragon.patterns || {}; - this.compiler = this.snapdragon.compiler; - this.parser = this.snapdragon.parser; - - compilers(this.snapdragon); - parsers(this.snapdragon); - - /** - * Override Snapdragon `.parse` method - */ - - define(this.snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - parsed.input = str; - - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strict !== true) { - var node = last.nodes[0]; - node.val = '\\' + node.val; - var sibling = node.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } + call.safe(fs.lstat, path, (err, lstats) => { + if (err) { + // fs.lstat threw an eror + return callback(err); } - // add non-enumerable parser reference - define(parsed, 'parser', this.parser); - return parsed; - }); - - /** - * Decorate `.parse` method - */ - - define(this, 'parse', function(ast, options) { - return this.snapdragon.parse.apply(this.snapdragon, arguments); - }); - - /** - * Decorate `.compile` method - */ + try { + isSymLink = lstats.isSymbolicLink(); + } + catch (err2) { + // lstats.isSymbolicLink() threw an error + // (probably because fs.lstat returned an invalid result) + return callback(err2); + } - define(this, 'compile', function(ast, options) { - return this.snapdragon.compile.apply(this.snapdragon, arguments); + if (isSymLink) { + // Try to resolve the symlink + symlinkStat(fs, path, lstats, callback); + } + else { + // It's not a symlink, so return the stats as-is + callback(null, lstats); + } }); - } /** - * Expose `Extglob` + * Retrieves the {@link fs.Stats} for the target of the given symlink. + * If the symlink is broken, then the Stats of the symlink itself are returned. + * + * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module + * @param {string} path - The path of the symlink to return stats for + * @param {object} lstats - The stats of the symlink + * @param {function} callback */ +function symlinkStat (fs, path, lstats, callback) { + call.safe(fs.stat, path, (err, stats) => { + if (err) { + // The symlink is broken, so return the stats for the link itself + return callback(null, lstats); + } -module.exports = Extglob; + try { + // Return the stats for the resolved symlink target, + // and override the `isSymbolicLink` method to indicate that it's a symlink + stats.isSymbolicLink = () => true; + } + catch (err2) { + // Setting stats.isSymbolicLink threw an error + // (probably because fs.stat returned an invalid result) + return callback(err2); + } + + callback(null, stats); + }); +} /***/ }), -/* 872 */ +/* 878 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(856); -var nanomatch = __webpack_require__(841); -var regexNot = __webpack_require__(739); -var toRegex = __webpack_require__(829); -var not; - -/** - * Characters to use in negation regex (we want to "not" match - * characters that are matched by other parsers) - */ - -var TEXT = '([!@*?+]?\\(|\\)|\\[:?(?=.*?:?\\])|:?\\]|[*+?!^$.\\\\/])+'; -var createNotRegex = function(opts) { - return not || (not = textRegex(TEXT)); +let call = module.exports = { + safe: safeCall, + once: callOnce, }; /** - * Parsers + * Calls a function with the given arguments, and ensures that the error-first callback is _always_ + * invoked exactly once, even if the function throws an error. + * + * @param {function} fn - The function to invoke + * @param {...*} args - The arguments to pass to the function. The final argument must be a callback function. */ +function safeCall (fn, args) { + // Get the function arguments as an array + args = Array.prototype.slice.call(arguments, 1); -module.exports = function(snapdragon) { - var parsers = snapdragon.parser.parsers; - - // register nanomatch parsers - snapdragon.use(nanomatch.parsers); - - // get references to some specific nanomatch parsers before they - // are overridden by the extglob and/or parsers - var escape = parsers.escape; - var slash = parsers.slash; - var qmark = parsers.qmark; - var plus = parsers.plus; - var star = parsers.star; - var dot = parsers.dot; - - // register extglob parsers - snapdragon.use(extglob.parsers); - - // custom micromatch parsers - snapdragon.parser - .use(function() { - // override "notRegex" created in nanomatch parser - this.notRegex = /^\!+(?!\()/; - }) - // reset the referenced parsers - .capture('escape', escape) - .capture('slash', slash) - .capture('qmark', qmark) - .capture('star', star) - .capture('plus', plus) - .capture('dot', dot) - - /** - * Override `text` parser - */ - - .capture('text', function() { - if (this.isInside('bracket')) return; - var pos = this.position(); - var m = this.match(createNotRegex(this.options)); - if (!m || !m[0]) return; - - // escape regex boundary characters and simple brackets - var val = m[0].replace(/([[\]^$])/g, '\\$1'); + // Replace the callback function with a wrapper that ensures it will only be called once + let callback = call.once(args.pop()); + args.push(callback); - return pos({ - type: 'text', - val: val - }); - }); -}; + try { + fn.apply(null, args); + } + catch (err) { + callback(err); + } +} /** - * Create text regex + * Returns a wrapper function that ensures the given callback function is only called once. + * Subsequent calls are ignored, unless the first argument is an Error, in which case the + * error is thrown. + * + * @param {function} fn - The function that should only be called once + * @returns {function} */ +function callOnce (fn) { + let fulfilled = false; -function textRegex(pattern) { - var notStr = regexNot.create(pattern, {contains: true, strictClose: false}); - var prefix = '(?:[\\^]|\\\\|'; - return toRegex(prefix + notStr + ')', {strictClose: false}); + return function onceWrapper (err) { + if (!fulfilled) { + fulfilled = true; + return fn.apply(this, arguments); + } + else if (err) { + // The callback has already been called, but now an error has occurred + // (most likely inside the callback function). So re-throw the error, + // so it gets handled further up the call stack + throw err; + } + }; } /***/ }), -/* 873 */ -/***/ (function(module, exports, __webpack_require__) { - -module.exports = new (__webpack_require__(849))(); - - -/***/ }), -/* 874 */ +/* 879 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = module.exports; -var path = __webpack_require__(16); +const fs = __webpack_require__(23); +const call = __webpack_require__(878); /** - * Module dependencies + * A facade around {@link fs.readdirSync} that allows it to be called + * the same way as {@link fs.readdir}. + * + * @param {string} dir + * @param {function} callback */ +exports.readdir = function (dir, callback) { + // Make sure the callback is only called once + callback = call.once(callback); -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); + try { + let items = fs.readdirSync(dir); + callback(null, items); + } + catch (err) { + callback(err); + } +}; /** - * Returns true if the platform is windows, or `path.sep` is `\\`. - * This is defined as a function to allow `path.sep` to be set in unit tests, - * or by the user, if there is a reason to do so. - * @return {Boolean} + * A facade around {@link fs.statSync} that allows it to be called + * the same way as {@link fs.stat}. + * + * @param {string} path + * @param {function} callback */ +exports.stat = function (path, callback) { + // Make sure the callback is only called once + callback = call.once(callback); -utils.isWindows = function() { - return path.sep === '\\' || process.platform === 'win32'; + try { + let stats = fs.statSync(path); + callback(null, stats); + } + catch (err) { + callback(err); + } }; /** - * Get the `Snapdragon` instance to use + * A facade around {@link fs.lstatSync} that allows it to be called + * the same way as {@link fs.lstat}. + * + * @param {string} path + * @param {function} callback */ +exports.lstat = function (path, callback) { + // Make sure the callback is only called once + callback = call.once(callback); -utils.instantiate = function(ast, options) { - var snapdragon; - // if an instance was created by `.parse`, use that instance - if (utils.typeOf(ast) === 'object' && ast.snapdragon) { - snapdragon = ast.snapdragon; - // if the user supplies an instance on options, use that instance - } else if (utils.typeOf(options) === 'object' && options.snapdragon) { - snapdragon = options.snapdragon; - // create a new instance - } else { - snapdragon = new Snapdragon(options); + try { + let stats = fs.lstatSync(path); + callback(null, stats); } + catch (err) { + callback(err); + } +}; - utils.define(snapdragon, 'parse', function(str, options) { - var parsed = Snapdragon.prototype.parse.apply(this, arguments); - parsed.input = str; - // escape unmatched brace/bracket/parens - var last = this.parser.stack.pop(); - if (last && this.options.strictErrors !== true) { - var open = last.nodes[0]; - var inner = last.nodes[1]; - if (last.type === 'bracket') { - if (inner.val.charAt(0) === '[') { - inner.val = '\\' + inner.val; - } +/***/ }), +/* 880 */ +/***/ (function(module, exports, __webpack_require__) { - } else { - open.val = '\\' + open.val; - var sibling = open.parent.nodes[1]; - if (sibling.type === 'star') { - sibling.loose = true; - } - } - } +"use strict"; - // add non-enumerable parser reference - utils.define(parsed, 'parser', this.parser); - return parsed; - }); - return snapdragon; -}; +module.exports = syncForEach; /** - * Create the key to use for memoization. The key is generated - * by iterating over the options and concatenating key-value pairs - * to the pattern string. + * A facade that allows {@link Array.forEach} to be called as though it were asynchronous. + * + * @param {array} array - The array to iterate over + * @param {function} iterator - The function to call for each item in the array + * @param {function} done - The function to call when all iterators have completed */ +function syncForEach (array, iterator, done) { + array.forEach(item => { + iterator(item, () => { + // Note: No error-handling here because this is currently only ever called + // by DirectoryReader, which never passes an `error` parameter to the callback. + // Instead, DirectoryReader emits an "error" event if an error occurs. + }); + }); -utils.createKey = function(pattern, options) { - if (utils.typeOf(options) !== 'object') { - return pattern; - } - var val = pattern; - var keys = Object.keys(options); - for (var i = 0; i < keys.length; i++) { - var key = keys[i]; - val += ';' + key + '=' + String(options[key]); - } - return val; -}; + done(); +} -/** - * Cast `val` to an array - * @return {Array} - */ -utils.arrayify = function(val) { - if (typeof val === 'string') return [val]; - return val ? (Array.isArray(val) ? val : [val]) : []; -}; +/***/ }), +/* 881 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Return true if `val` is a non-empty string - */ +"use strict"; -utils.isString = function(val) { - return typeof val === 'string'; -}; -/** - * Return true if `val` is a non-empty string - */ +module.exports = readdirAsync; -utils.isObject = function(val) { - return utils.typeOf(val) === 'object'; +const maybe = __webpack_require__(882); +const DirectoryReader = __webpack_require__(874); + +let asyncFacade = { + fs: __webpack_require__(23), + forEach: __webpack_require__(883), + async: true }; /** - * Returns true if the given `str` has special characters + * Returns the buffered output from an asynchronous {@link DirectoryReader}, + * via an error-first callback or a {@link Promise}. + * + * @param {string} dir + * @param {object} [options] + * @param {function} [callback] + * @param {object} internalOptions */ +function readdirAsync (dir, options, callback, internalOptions) { + if (typeof options === 'function') { + callback = options; + options = undefined; + } -utils.hasSpecialChars = function(str) { - return /(?:(?:(^|\/)[!.])|[*?+()|\[\]{}]|[+@]\()/.test(str); -}; + return maybe(callback, new Promise(((resolve, reject) => { + let results = []; -/** - * Escape regex characters in the given string - */ + internalOptions.facade = asyncFacade; -utils.escapeRegex = function(str) { - return str.replace(/[-[\]{}()^$|*+?.\\\/\s]/g, '\\$&'); -}; + let reader = new DirectoryReader(dir, options, internalOptions); + let stream = reader.stream; -/** - * Normalize slashes in the given filepath. - * - * @param {String} `filepath` - * @return {String} - */ + stream.on('error', err => { + reject(err); + stream.pause(); + }); + stream.on('data', result => { + results.push(result); + }); + stream.on('end', () => { + resolve(results); + }); + }))); +} -utils.toPosixPath = function(str) { - return str.replace(/\\+/g, '/'); -}; -/** - * Strip backslashes before special characters in a string. - * - * @param {String} `str` - * @return {String} - */ +/***/ }), +/* 882 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +var next = (global.process && process.nextTick) || global.setImmediate || function (f) { + setTimeout(f, 0) +} + +module.exports = function maybe (cb, promise) { + if (cb) { + promise + .then(function (result) { + next(function () { cb(null, result) }) + }, function (err) { + next(function () { cb(err) }) + }) + return undefined + } + else { + return promise + } +} -utils.unescape = function(str) { - return utils.toPosixPath(str.replace(/\\(?=[*+?!.])/g, '')); -}; -/** - * Strip the prefix from a filepath - * @param {String} `fp` - * @return {String} - */ +/***/ }), +/* 883 */ +/***/ (function(module, exports, __webpack_require__) { -utils.stripPrefix = function(str) { - if (str.charAt(0) !== '.') { - return str; - } - var ch = str.charAt(1); - if (utils.isSlash(ch)) { - return str.slice(2); - } - return str; -}; +"use strict"; -/** - * Returns true if the given str is an escaped or - * unescaped path character - */ -utils.isSlash = function(str) { - return str === '/' || str === '\\/' || str === '\\' || str === '\\\\'; -}; +module.exports = asyncForEach; /** - * Returns a function that returns true if the given - * pattern matches or contains a `filepath` + * Simultaneously processes all items in the given array. * - * @param {String} `pattern` - * @return {Function} + * @param {array} array - The array to iterate over + * @param {function} iterator - The function to call for each item in the array + * @param {function} done - The function to call when all iterators have completed */ +function asyncForEach (array, iterator, done) { + if (array.length === 0) { + // NOTE: Normally a bad idea to mix sync and async, but it's safe here because + // of the way that this method is currently used by DirectoryReader. + done(); + return; + } -utils.matchPath = function(pattern, options) { - return (options && options.contains) - ? utils.containsPattern(pattern, options) - : utils.equalsPattern(pattern, options); -}; + // Simultaneously process all items in the array. + let pending = array.length; + array.forEach(item => { + iterator(item, () => { + if (--pending === 0) { + done(); + } + }); + }); +} -/** - * Returns true if the given (original) filepath or unixified path are equal - * to the given pattern. - */ -utils._equals = function(filepath, unixPath, pattern) { - return pattern === filepath || pattern === unixPath; -}; +/***/ }), +/* 884 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Returns true if the given (original) filepath or unixified path contain - * the given pattern. - */ +"use strict"; -utils._contains = function(filepath, unixPath, pattern) { - return filepath.indexOf(pattern) !== -1 || unixPath.indexOf(pattern) !== -1; -}; -/** - * Returns a function that returns true if the given - * pattern is the same as a given `filepath` - * - * @param {String} `pattern` - * @return {Function} - */ +module.exports = readdirStream; -utils.equalsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; +const DirectoryReader = __webpack_require__(874); - return function fn(filepath) { - var equal = utils._equals(filepath, unixify(filepath), pattern); - if (equal === true || options.nocase !== true) { - return equal; - } - var lower = filepath.toLowerCase(); - return utils._equals(lower, unixify(lower), pattern); - }; +let streamFacade = { + fs: __webpack_require__(23), + forEach: __webpack_require__(883), + async: true }; /** - * Returns a function that returns true if the given - * pattern contains a `filepath` + * Returns the {@link stream.Readable} of an asynchronous {@link DirectoryReader}. * - * @param {String} `pattern` - * @return {Function} + * @param {string} dir + * @param {object} [options] + * @param {object} internalOptions */ +function readdirStream (dir, options, internalOptions) { + internalOptions.facade = streamFacade; -utils.containsPattern = function(pattern, options) { - var unixify = utils.unixify(options); - options = options || {}; - - return function(filepath) { - var contains = utils._contains(filepath, unixify(filepath), pattern); - if (contains === true || options.nocase !== true) { - return contains; - } - var lower = filepath.toLowerCase(); - return utils._contains(lower, unixify(lower), pattern); - }; -}; + let reader = new DirectoryReader(dir, options, internalOptions); + return reader.stream; +} -/** - * Returns a function that returns true if the given - * regex matches the `filename` of a file path. - * - * @param {RegExp} `re` Matching regex - * @return {Function} - */ -utils.matchBasename = function(re) { - return function(filepath) { - return re.test(path.basename(filepath)); - }; -}; +/***/ }), +/* 885 */ +/***/ (function(module, exports, __webpack_require__) { -/** - * Determines the filepath to return based on the provided options. - * @return {any} - */ +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var path = __webpack_require__(16); +var deep_1 = __webpack_require__(886); +var entry_1 = __webpack_require__(888); +var pathUtil = __webpack_require__(887); +var Reader = /** @class */ (function () { + function Reader(options) { + this.options = options; + this.micromatchOptions = this.getMicromatchOptions(); + this.entryFilter = new entry_1.default(options, this.micromatchOptions); + this.deepFilter = new deep_1.default(options, this.micromatchOptions); + } + /** + * Returns root path to scanner. + */ + Reader.prototype.getRootDirectory = function (task) { + return path.resolve(this.options.cwd, task.base); + }; + /** + * Returns options for reader. + */ + Reader.prototype.getReaderOptions = function (task) { + return { + basePath: task.base === '.' ? '' : task.base, + filter: this.entryFilter.getFilter(task.positive, task.negative), + deep: this.deepFilter.getFilter(task.positive, task.negative), + sep: '/' + }; + }; + /** + * Returns options for micromatch. + */ + Reader.prototype.getMicromatchOptions = function () { + return { + dot: this.options.dot, + nobrace: !this.options.brace, + noglobstar: !this.options.globstar, + noext: !this.options.extension, + nocase: !this.options.case, + matchBase: this.options.matchBase + }; + }; + /** + * Returns transformed entry. + */ + Reader.prototype.transform = function (entry) { + if (this.options.absolute) { + entry.path = pathUtil.makeAbsolute(this.options.cwd, entry.path); + } + if (this.options.markDirectories && entry.isDirectory()) { + entry.path += '/'; + } + var item = this.options.stats ? entry : entry.path; + if (this.options.transform === null) { + return item; + } + return this.options.transform(item); + }; + /** + * Returns true if error has ENOENT code. + */ + Reader.prototype.isEnoentCodeError = function (err) { + return err.code === 'ENOENT'; + }; + return Reader; +}()); +exports.default = Reader; -utils.value = function(str, unixify, options) { - if (options && options.unixify === false) { - return str; - } - return unixify(str); -}; -/** - * Returns a function that normalizes slashes in a string to forward - * slashes, strips `./` from beginning of paths, and optionally unescapes - * special characters. - * @return {Function} - */ +/***/ }), +/* 886 */ +/***/ (function(module, exports, __webpack_require__) { -utils.unixify = function(options) { - options = options || {}; - return function(filepath) { - if (utils.isWindows() || options.unixify === true) { - filepath = utils.toPosixPath(filepath); - } - if (options.stripPrefix !== false) { - filepath = utils.stripPrefix(filepath); - } - if (options.unescape === true) { - filepath = utils.unescape(filepath); - } - return filepath; - }; -}; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var pathUtils = __webpack_require__(887); +var patternUtils = __webpack_require__(716); +var DeepFilter = /** @class */ (function () { + function DeepFilter(options, micromatchOptions) { + this.options = options; + this.micromatchOptions = micromatchOptions; + } + /** + * Returns filter for directories. + */ + DeepFilter.prototype.getFilter = function (positive, negative) { + var _this = this; + var maxPatternDepth = this.getMaxPatternDepth(positive); + var negativeRe = this.getNegativePatternsRe(negative); + return function (entry) { return _this.filter(entry, negativeRe, maxPatternDepth); }; + }; + /** + * Returns max depth of the provided patterns. + */ + DeepFilter.prototype.getMaxPatternDepth = function (patterns) { + var globstar = patterns.some(patternUtils.hasGlobStar); + return globstar ? Infinity : patternUtils.getMaxNaivePatternsDepth(patterns); + }; + /** + * Returns RegExp's for patterns that can affect the depth of reading. + */ + DeepFilter.prototype.getNegativePatternsRe = function (patterns) { + var affectDepthOfReadingPatterns = patterns.filter(patternUtils.isAffectDepthOfReadingPattern); + return patternUtils.convertPatternsToRe(affectDepthOfReadingPatterns, this.micromatchOptions); + }; + /** + * Returns «true» for directory that should be read. + */ + DeepFilter.prototype.filter = function (entry, negativeRe, maxPatternDepth) { + if (this.isSkippedByDeepOption(entry.depth)) { + return false; + } + if (this.isSkippedByMaxPatternDepth(entry.depth, maxPatternDepth)) { + return false; + } + if (this.isSkippedSymlinkedDirectory(entry)) { + return false; + } + if (this.isSkippedDotDirectory(entry)) { + return false; + } + return this.isSkippedByNegativePatterns(entry, negativeRe); + }; + /** + * Returns «true» when the «deep» option is disabled or number and depth of the entry is greater that the option value. + */ + DeepFilter.prototype.isSkippedByDeepOption = function (entryDepth) { + return !this.options.deep || (typeof this.options.deep === 'number' && entryDepth >= this.options.deep); + }; + /** + * Returns «true» when depth parameter is not an Infinity and entry depth greater that the parameter value. + */ + DeepFilter.prototype.isSkippedByMaxPatternDepth = function (entryDepth, maxPatternDepth) { + return maxPatternDepth !== Infinity && entryDepth >= maxPatternDepth; + }; + /** + * Returns «true» for symlinked directory if the «followSymlinkedDirectories» option is disabled. + */ + DeepFilter.prototype.isSkippedSymlinkedDirectory = function (entry) { + return !this.options.followSymlinkedDirectories && entry.isSymbolicLink(); + }; + /** + * Returns «true» for a directory whose name starts with a period if «dot» option is disabled. + */ + DeepFilter.prototype.isSkippedDotDirectory = function (entry) { + return !this.options.dot && pathUtils.isDotDirectory(entry.path); + }; + /** + * Returns «true» for a directory whose path math to any negative pattern. + */ + DeepFilter.prototype.isSkippedByNegativePatterns = function (entry, negativeRe) { + return !patternUtils.matchAny(entry.path, negativeRe); + }; + return DeepFilter; +}()); +exports.default = DeepFilter; /***/ }), -/* 875 */ -/***/ (function(module, exports) { +/* 887 */ +/***/ (function(module, exports, __webpack_require__) { -var toString = Object.prototype.toString; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var path = __webpack_require__(16); +/** + * Returns «true» if the last partial of the path starting with a period. + */ +function isDotDirectory(filepath) { + return path.basename(filepath).startsWith('.'); +} +exports.isDotDirectory = isDotDirectory; +/** + * Convert a windows-like path to a unix-style path. + */ +function normalize(filepath) { + return filepath.replace(/\\/g, '/'); +} +exports.normalize = normalize; +/** + * Returns normalized absolute path of provided filepath. + */ +function makeAbsolute(cwd, filepath) { + return normalize(path.resolve(cwd, filepath)); +} +exports.makeAbsolute = makeAbsolute; -module.exports = function kindOf(val) { - if (val === void 0) return 'undefined'; - if (val === null) return 'null'; - var type = typeof val; - if (type === 'boolean') return 'boolean'; - if (type === 'string') return 'string'; - if (type === 'number') return 'number'; - if (type === 'symbol') return 'symbol'; - if (type === 'function') { - return isGeneratorFn(val) ? 'generatorfunction' : 'function'; - } +/***/ }), +/* 888 */ +/***/ (function(module, exports, __webpack_require__) { - if (isArray(val)) return 'array'; - if (isBuffer(val)) return 'buffer'; - if (isArguments(val)) return 'arguments'; - if (isDate(val)) return 'date'; - if (isError(val)) return 'error'; - if (isRegexp(val)) return 'regexp'; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var pathUtils = __webpack_require__(887); +var patternUtils = __webpack_require__(716); +var EntryFilter = /** @class */ (function () { + function EntryFilter(options, micromatchOptions) { + this.options = options; + this.micromatchOptions = micromatchOptions; + this.index = new Map(); + } + /** + * Returns filter for directories. + */ + EntryFilter.prototype.getFilter = function (positive, negative) { + var _this = this; + var positiveRe = patternUtils.convertPatternsToRe(positive, this.micromatchOptions); + var negativeRe = patternUtils.convertPatternsToRe(negative, this.micromatchOptions); + return function (entry) { return _this.filter(entry, positiveRe, negativeRe); }; + }; + /** + * Returns true if entry must be added to result. + */ + EntryFilter.prototype.filter = function (entry, positiveRe, negativeRe) { + // Exclude duplicate results + if (this.options.unique) { + if (this.isDuplicateEntry(entry)) { + return false; + } + this.createIndexRecord(entry); + } + // Filter files and directories by options + if (this.onlyFileFilter(entry) || this.onlyDirectoryFilter(entry)) { + return false; + } + if (this.isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { + return false; + } + return this.isMatchToPatterns(entry.path, positiveRe) && !this.isMatchToPatterns(entry.path, negativeRe); + }; + /** + * Return true if the entry already has in the cross reader index. + */ + EntryFilter.prototype.isDuplicateEntry = function (entry) { + return this.index.has(entry.path); + }; + /** + * Create record in the cross reader index. + */ + EntryFilter.prototype.createIndexRecord = function (entry) { + this.index.set(entry.path, undefined); + }; + /** + * Returns true for non-files if the «onlyFiles» option is enabled. + */ + EntryFilter.prototype.onlyFileFilter = function (entry) { + return this.options.onlyFiles && !entry.isFile(); + }; + /** + * Returns true for non-directories if the «onlyDirectories» option is enabled. + */ + EntryFilter.prototype.onlyDirectoryFilter = function (entry) { + return this.options.onlyDirectories && !entry.isDirectory(); + }; + /** + * Return true when `absolute` option is enabled and matched to the negative patterns. + */ + EntryFilter.prototype.isSkippedByAbsoluteNegativePatterns = function (entry, negativeRe) { + if (!this.options.absolute) { + return false; + } + var fullpath = pathUtils.makeAbsolute(this.options.cwd, entry.path); + return this.isMatchToPatterns(fullpath, negativeRe); + }; + /** + * Return true when entry match to provided patterns. + * + * First, just trying to apply patterns to the path. + * Second, trying to apply patterns to the path with final slash (need to micromatch to support «directory/**» patterns). + */ + EntryFilter.prototype.isMatchToPatterns = function (filepath, patternsRe) { + return patternUtils.matchAny(filepath, patternsRe) || patternUtils.matchAny(filepath + '/', patternsRe); + }; + return EntryFilter; +}()); +exports.default = EntryFilter; - switch (ctorName(val)) { - case 'Symbol': return 'symbol'; - case 'Promise': return 'promise'; - // Set, Map, WeakSet, WeakMap - case 'WeakMap': return 'weakmap'; - case 'WeakSet': return 'weakset'; - case 'Map': return 'map'; - case 'Set': return 'set'; +/***/ }), +/* 889 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var stream = __webpack_require__(27); +var fsStat = __webpack_require__(890); +var fs_1 = __webpack_require__(894); +var FileSystemStream = /** @class */ (function (_super) { + __extends(FileSystemStream, _super); + function FileSystemStream() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * Use stream API to read entries for Task. + */ + FileSystemStream.prototype.read = function (patterns, filter) { + var _this = this; + var filepaths = patterns.map(this.getFullEntryPath, this); + var transform = new stream.Transform({ objectMode: true }); + transform._transform = function (index, _enc, done) { + return _this.getEntry(filepaths[index], patterns[index]).then(function (entry) { + if (entry !== null && filter(entry)) { + transform.push(entry); + } + if (index === filepaths.length - 1) { + transform.end(); + } + done(); + }); + }; + for (var i = 0; i < filepaths.length; i++) { + transform.write(i); + } + return transform; + }; + /** + * Return entry for the provided path. + */ + FileSystemStream.prototype.getEntry = function (filepath, pattern) { + var _this = this; + return this.getStat(filepath) + .then(function (stat) { return _this.makeEntry(stat, pattern); }) + .catch(function () { return null; }); + }; + /** + * Return fs.Stats for the provided path. + */ + FileSystemStream.prototype.getStat = function (filepath) { + return fsStat.stat(filepath, { throwErrorOnBrokenSymlinks: false }); + }; + return FileSystemStream; +}(fs_1.default)); +exports.default = FileSystemStream; + - // 8-bit typed arrays - case 'Int8Array': return 'int8array'; - case 'Uint8Array': return 'uint8array'; - case 'Uint8ClampedArray': return 'uint8clampedarray'; +/***/ }), +/* 890 */ +/***/ (function(module, exports, __webpack_require__) { - // 16-bit typed arrays - case 'Int16Array': return 'int16array'; - case 'Uint16Array': return 'uint16array'; +"use strict"; - // 32-bit typed arrays - case 'Int32Array': return 'int32array'; - case 'Uint32Array': return 'uint32array'; - case 'Float32Array': return 'float32array'; - case 'Float64Array': return 'float64array'; - } +Object.defineProperty(exports, "__esModule", { value: true }); +const optionsManager = __webpack_require__(891); +const statProvider = __webpack_require__(893); +/** + * Asynchronous API. + */ +function stat(path, opts) { + return new Promise((resolve, reject) => { + statProvider.async(path, optionsManager.prepare(opts), (err, stats) => err ? reject(err) : resolve(stats)); + }); +} +exports.stat = stat; +function statCallback(path, optsOrCallback, callback) { + if (typeof optsOrCallback === 'function') { + callback = optsOrCallback; /* tslint:disable-line: no-parameter-reassignment */ + optsOrCallback = undefined; /* tslint:disable-line: no-parameter-reassignment */ + } + if (typeof callback === 'undefined') { + throw new TypeError('The "callback" argument must be of type Function.'); + } + statProvider.async(path, optionsManager.prepare(optsOrCallback), callback); +} +exports.statCallback = statCallback; +/** + * Synchronous API. + */ +function statSync(path, opts) { + return statProvider.sync(path, optionsManager.prepare(opts)); +} +exports.statSync = statSync; - if (isGeneratorObj(val)) { - return 'generator'; - } - // Non-plain objects - type = toString.call(val); - switch (type) { - case '[object Object]': return 'object'; - // iterators - case '[object Map Iterator]': return 'mapiterator'; - case '[object Set Iterator]': return 'setiterator'; - case '[object String Iterator]': return 'stringiterator'; - case '[object Array Iterator]': return 'arrayiterator'; - } +/***/ }), +/* 891 */ +/***/ (function(module, exports, __webpack_require__) { - // other - return type.slice(8, -1).toLowerCase().replace(/\s/g, ''); -}; +"use strict"; -function ctorName(val) { - return val.constructor ? val.constructor.name : null; +Object.defineProperty(exports, "__esModule", { value: true }); +const fsAdapter = __webpack_require__(892); +function prepare(opts) { + const options = Object.assign({ + fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), + throwErrorOnBrokenSymlinks: true, + followSymlinks: true + }, opts); + return options; } +exports.prepare = prepare; -function isArray(val) { - if (Array.isArray) return Array.isArray(val); - return val instanceof Array; -} -function isError(val) { - return val instanceof Error || (typeof val.message === 'string' && val.constructor && typeof val.constructor.stackTraceLimit === 'number'); -} +/***/ }), +/* 892 */ +/***/ (function(module, exports, __webpack_require__) { -function isDate(val) { - if (val instanceof Date) return true; - return typeof val.toDateString === 'function' - && typeof val.getDate === 'function' - && typeof val.setDate === 'function'; -} +"use strict"; -function isRegexp(val) { - if (val instanceof RegExp) return true; - return typeof val.flags === 'string' - && typeof val.ignoreCase === 'boolean' - && typeof val.multiline === 'boolean' - && typeof val.global === 'boolean'; +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 getFileSystemAdapter(fsMethods) { + if (!fsMethods) { + return exports.FILE_SYSTEM_ADAPTER; + } + return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); } +exports.getFileSystemAdapter = getFileSystemAdapter; -function isGeneratorFn(name, val) { - return ctorName(name) === 'GeneratorFunction'; -} -function isGeneratorObj(val) { - return typeof val.throw === 'function' - && typeof val.return === 'function' - && typeof val.next === 'function'; -} +/***/ }), +/* 893 */ +/***/ (function(module, exports, __webpack_require__) { -function isArguments(val) { - try { - if (typeof val.length === 'number' && typeof val.callee === 'function') { - return true; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function sync(path, options) { + const lstat = options.fs.lstatSync(path); + if (!isFollowedSymlink(lstat, options)) { + return lstat; } - } catch (err) { - if (err.message.indexOf('callee') !== -1) { - return true; + try { + const stat = options.fs.statSync(path); + stat.isSymbolicLink = () => true; + return stat; + } + catch (err) { + if (!options.throwErrorOnBrokenSymlinks) { + return lstat; + } + throw err; } - } - return false; } - +exports.sync = sync; +function async(path, options, callback) { + options.fs.lstat(path, (err0, lstat) => { + if (err0) { + return callback(err0, undefined); + } + if (!isFollowedSymlink(lstat, options)) { + return callback(null, lstat); + } + options.fs.stat(path, (err1, stat) => { + if (err1) { + return options.throwErrorOnBrokenSymlinks ? callback(err1) : callback(null, lstat); + } + stat.isSymbolicLink = () => true; + callback(null, stat); + }); + }); +} +exports.async = async; /** - * If you need to support Safari 5-7 (8-10 yr-old browser), - * take a look at https://github.com/feross/is-buffer + * Returns `true` for followed symlink. */ - -function isBuffer(val) { - if (val.constructor && typeof val.constructor.isBuffer === 'function') { - return val.constructor.isBuffer(val); - } - return false; +function isFollowedSymlink(stat, options) { + return stat.isSymbolicLink() && options.followSymlinks; } +exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 876 */ +/* 894 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var path = __webpack_require__(16); +var FileSystem = /** @class */ (function () { + function FileSystem(options) { + this.options = options; + } + /** + * Return full path to entry. + */ + FileSystem.prototype.getFullEntryPath = function (filepath) { + return path.resolve(this.options.cwd, filepath); + }; + /** + * Return an implementation of the Entry interface. + */ + FileSystem.prototype.makeEntry = function (stat, pattern) { + stat.path = pattern; + stat.depth = pattern.split('/').length; + return stat; + }; + return FileSystem; +}()); +exports.default = FileSystem; + + +/***/ }), +/* 895 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104848,15 +104440,28 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -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() { +var stream = __webpack_require__(27); +var readdir = __webpack_require__(872); +var reader_1 = __webpack_require__(885); +var fs_stream_1 = __webpack_require__(889); +var TransformStream = /** @class */ (function (_super) { + __extends(TransformStream, _super); + function TransformStream(reader) { + var _this = _super.call(this, { objectMode: true }) || this; + _this.reader = reader; + return _this; + } + TransformStream.prototype._transform = function (entry, _encoding, callback) { + callback(null, this.reader.transform(entry)); + }; + return TransformStream; +}(stream.Transform)); +var ReaderStream = /** @class */ (function (_super) { + __extends(ReaderStream, _super); + function ReaderStream() { return _super !== null && _super.apply(this, arguments) || this; } - Object.defineProperty(ReaderAsync.prototype, "fsAdapter", { + Object.defineProperty(ReaderStream.prototype, "fsAdapter", { /** * Returns FileSystem adapter. */ @@ -104867,27 +104472,22 @@ var ReaderAsync = /** @class */ (function (_super) { configurable: true }); /** - * Use async API to read entries for Task. + * Use stream API to read entries for Task. */ - ReaderAsync.prototype.read = function (task) { + ReaderStream.prototype.read = function (task) { var _this = this; var root = this.getRootDirectory(task); var options = this.getReaderOptions(task); - var entries = []; - return new Promise(function (resolve, reject) { - var stream = _this.api(root, task, options); - stream.on('error', function (err) { - _this.isEnoentCodeError(err) ? resolve([]) : reject(err); - stream.pause(); - }); - stream.on('data', function (entry) { return entries.push(_this.transform(entry)); }); - stream.on('end', function () { return resolve(entries); }); - }); + var transform = new TransformStream(this); + var readable = this.api(root, task, options); + return readable + .on('error', function (err) { return _this.isEnoentCodeError(err) ? null : transform.emit('error', err); }) + .pipe(transform); }; /** * Returns founded paths. */ - ReaderAsync.prototype.api = function (root, task, options) { + ReaderStream.prototype.api = function (root, task, options) { if (task.dynamic) { return this.dynamicApi(root, options); } @@ -104896,3508 +104496,3475 @@ var ReaderAsync = /** @class */ (function (_super) { /** * Api for dynamic tasks. */ - ReaderAsync.prototype.dynamicApi = function (root, options) { + ReaderStream.prototype.dynamicApi = function (root, options) { return readdir.readdirStreamStat(root, options); }; /** * Api for static tasks. */ - ReaderAsync.prototype.staticApi = function (task, options) { + ReaderStream.prototype.staticApi = function (task, options) { return this.fsAdapter.read(task.patterns, options.filter); }; - return ReaderAsync; + return ReaderStream; }(reader_1.default)); -exports.default = ReaderAsync; +exports.default = ReaderStream; + + +/***/ }), +/* 896 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var readdir = __webpack_require__(872); +var reader_1 = __webpack_require__(885); +var fs_sync_1 = __webpack_require__(897); +var ReaderSync = /** @class */ (function (_super) { + __extends(ReaderSync, _super); + function ReaderSync() { + return _super !== null && _super.apply(this, arguments) || this; + } + Object.defineProperty(ReaderSync.prototype, "fsAdapter", { + /** + * Returns FileSystem adapter. + */ + get: function () { + return new fs_sync_1.default(this.options); + }, + enumerable: true, + configurable: true + }); + /** + * Use sync API to read entries for Task. + */ + ReaderSync.prototype.read = function (task) { + var root = this.getRootDirectory(task); + var options = this.getReaderOptions(task); + try { + var entries = this.api(root, task, options); + return entries.map(this.transform, this); + } + catch (err) { + if (this.isEnoentCodeError(err)) { + return []; + } + throw err; + } + }; + /** + * Returns founded paths. + */ + ReaderSync.prototype.api = function (root, task, options) { + if (task.dynamic) { + return this.dynamicApi(root, options); + } + return this.staticApi(task, options); + }; + /** + * Api for dynamic tasks. + */ + ReaderSync.prototype.dynamicApi = function (root, options) { + return readdir.readdirSyncStat(root, options); + }; + /** + * Api for static tasks. + */ + ReaderSync.prototype.staticApi = function (task, options) { + return this.fsAdapter.read(task.patterns, options.filter); + }; + return ReaderSync; +}(reader_1.default)); +exports.default = ReaderSync; + + +/***/ }), +/* 897 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +var fsStat = __webpack_require__(890); +var fs_1 = __webpack_require__(894); +var FileSystemSync = /** @class */ (function (_super) { + __extends(FileSystemSync, _super); + function FileSystemSync() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * Use sync API to read entries for Task. + */ + FileSystemSync.prototype.read = function (patterns, filter) { + var _this = this; + var entries = []; + patterns.forEach(function (pattern) { + var filepath = _this.getFullEntryPath(pattern); + var entry = _this.getEntry(filepath, pattern); + if (entry === null || !filter(entry)) { + return; + } + entries.push(entry); + }); + return entries; + }; + /** + * Return entry for the provided path. + */ + FileSystemSync.prototype.getEntry = function (filepath, pattern) { + try { + var stat = this.getStat(filepath); + return this.makeEntry(stat, pattern); + } + catch (err) { + return null; + } + }; + /** + * Return fs.Stats for the provided path. + */ + FileSystemSync.prototype.getStat = function (filepath) { + return fsStat.statSync(filepath, { throwErrorOnBrokenSymlinks: false }); + }; + return FileSystemSync; +}(fs_1.default)); +exports.default = FileSystemSync; + + +/***/ }), +/* 898 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +/** + * Flatten nested arrays (max depth is 2) into a non-nested array of non-array items. + */ +function flatten(items) { + return items.reduce(function (collection, item) { return [].concat(collection, item); }, []); +} +exports.flatten = flatten; + + +/***/ }), +/* 899 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +var merge2 = __webpack_require__(591); +/** + * Merge multiple streams and propagate their errors into one stream in parallel. + */ +function merge(streams) { + var mergedStream = merge2(streams); + streams.forEach(function (stream) { + stream.on('error', function (err) { return mergedStream.emit('error', err); }); + }); + return mergedStream; +} +exports.merge = merge; + + +/***/ }), +/* 900 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const path = __webpack_require__(16); +const pathType = __webpack_require__(901); + +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 = (dir, opts) => { + if (opts.files && !Array.isArray(opts.files)) { + throw new TypeError(`Expected \`files\` to be of type \`Array\` but received type \`${typeof opts.files}\``); + } + + if (opts.extensions && !Array.isArray(opts.extensions)) { + throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof opts.extensions}\``); + } + + if (opts.files && opts.extensions) { + return opts.files.map(x => path.join(dir, addExtensions(x, opts.extensions))); + } + + if (opts.files) { + return opts.files.map(x => path.join(dir, `**/${x}`)); + } + + if (opts.extensions) { + return [path.join(dir, `**/*.${getExtensions(opts.extensions)}`)]; + } + + return [path.join(dir, '**')]; +}; + +module.exports = (input, opts) => { + opts = Object.assign({cwd: process.cwd()}, opts); + + if (typeof opts.cwd !== 'string') { + return Promise.reject(new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``)); + } + + return Promise.all([].concat(input).map(x => pathType.dir(getPath(x, opts.cwd)) + .then(isDir => isDir ? getGlob(x, opts) : x))) + .then(globs => [].concat.apply([], globs)); +}; + +module.exports.sync = (input, opts) => { + opts = Object.assign({cwd: process.cwd()}, opts); + + if (typeof opts.cwd !== 'string') { + throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``); + } + + const globs = [].concat(input).map(x => pathType.dirSync(getPath(x, opts.cwd)) ? getGlob(x, opts) : x); + return [].concat.apply([], globs); +}; /***/ }), -/* 877 */ +/* 901 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +const fs = __webpack_require__(23); +const pify = __webpack_require__(902); -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; -exports.readdirAsyncStat = exports.async.stat = readdirAsyncStat; -exports.readdirStream = exports.stream = readdirStreamPath; -exports.readdirStreamStat = exports.stream.stat = readdirStreamStat; -exports.readdirSync = exports.sync = readdirSyncPath; -exports.readdirSyncStat = exports.sync.stat = readdirSyncStat; +function type(fn, fn2, fp) { + if (typeof fp !== 'string') { + return Promise.reject(new TypeError(`Expected a string, got ${typeof fp}`)); + } -/** - * Synchronous readdir that returns an array of string paths. - * - * @param {string} dir - * @param {object} [options] - * @returns {string[]} - */ -function readdirSyncPath (dir, options) { - return readdirSync(dir, options, {}); -} + return pify(fs[fn])(fp) + .then(stats => stats[fn2]()) + .catch(err => { + if (err.code === 'ENOENT') { + return false; + } -/** - * Synchronous readdir that returns results as an array of {@link fs.Stats} objects - * - * @param {string} dir - * @param {object} [options] - * @returns {fs.Stats[]} - */ -function readdirSyncStat (dir, options) { - return readdirSync(dir, options, { stats: true }); + throw err; + }); } -/** - * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). - * Results are an array of path strings. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @returns {Promise} - */ -function readdirAsyncPath (dir, options, callback) { - return readdirAsync(dir, options, callback, {}); -} +function typeSync(fn, fn2, fp) { + if (typeof fp !== 'string') { + throw new TypeError(`Expected a string, got ${typeof fp}`); + } -/** - * Aynchronous readdir (accepts an error-first callback or returns a {@link Promise}). - * Results are an array of {@link fs.Stats} objects. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @returns {Promise} - */ -function readdirAsyncStat (dir, options, callback) { - return readdirAsync(dir, options, callback, { stats: true }); -} + try { + return fs[fn](fp)[fn2](); + } catch (err) { + if (err.code === 'ENOENT') { + return false; + } -/** - * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}). - * All stream data events ("data", "file", "directory", "symlink") are passed a path string. - * - * @param {string} dir - * @param {object} [options] - * @returns {stream.Readable} - */ -function readdirStreamPath (dir, options) { - return readdirStream(dir, options, {}); + throw err; + } } -/** - * Aynchronous readdir that returns a {@link stream.Readable} (which is also an {@link EventEmitter}) - * All stream data events ("data", "file", "directory", "symlink") are passed an {@link fs.Stats} object. - * - * @param {string} dir - * @param {object} [options] - * @returns {stream.Readable} - */ -function readdirStreamStat (dir, options) { - return readdirStream(dir, options, { stats: true }); -} +exports.file = type.bind(null, 'stat', 'isFile'); +exports.dir = type.bind(null, 'stat', 'isDirectory'); +exports.symlink = type.bind(null, 'lstat', 'isSymbolicLink'); +exports.fileSync = typeSync.bind(null, 'statSync', 'isFile'); +exports.dirSync = typeSync.bind(null, 'statSync', 'isDirectory'); +exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 878 */ +/* 902 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = readdirSync; +const processFn = (fn, opts) => function () { + const P = opts.promiseModule; + const args = new Array(arguments.length); -const DirectoryReader = __webpack_require__(879); + for (let i = 0; i < arguments.length; i++) { + args[i] = arguments[i]; + } -let syncFacade = { - fs: __webpack_require__(884), - forEach: __webpack_require__(885), - sync: true + return new P((resolve, reject) => { + if (opts.errorFirst) { + args.push(function (err, result) { + if (opts.multiArgs) { + const results = new Array(arguments.length - 1); + + for (let i = 1; i < arguments.length; i++) { + results[i - 1] = arguments[i]; + } + + if (err) { + results.unshift(err); + reject(results); + } else { + resolve(results); + } + } else if (err) { + reject(err); + } else { + resolve(result); + } + }); + } else { + args.push(function (result) { + if (opts.multiArgs) { + const results = new Array(arguments.length - 1); + + for (let i = 0; i < arguments.length; i++) { + results[i] = arguments[i]; + } + + resolve(results); + } else { + resolve(result); + } + }); + } + + fn.apply(this, args); + }); }; -/** - * Returns the buffered output from a synchronous {@link DirectoryReader}. - * - * @param {string} dir - * @param {object} [options] - * @param {object} internalOptions - */ -function readdirSync (dir, options, internalOptions) { - internalOptions.facade = syncFacade; +module.exports = (obj, opts) => { + opts = Object.assign({ + exclude: [/.+(Sync|Stream)$/], + errorFirst: true, + promiseModule: Promise + }, opts); - let reader = new DirectoryReader(dir, options, internalOptions); - let stream = reader.stream; + const filter = key => { + const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); + return opts.include ? opts.include.some(match) : !opts.exclude.some(match); + }; - let results = []; - let data = stream.read(); - while (data !== null) { - results.push(data); - data = stream.read(); - } + let ret; + if (typeof obj === 'function') { + ret = function () { + if (opts.excludeMain) { + return obj.apply(this, arguments); + } - return results; -} + return processFn(obj, opts).apply(this, arguments); + }; + } else { + ret = Object.create(Object.getPrototypeOf(obj)); + } + + for (const key in obj) { // eslint-disable-line guard-for-in + const x = obj[key]; + ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; + } + + return ret; +}; /***/ }), -/* 879 */ +/* 903 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -const Readable = __webpack_require__(27).Readable; -const EventEmitter = __webpack_require__(379).EventEmitter; +const fs = __webpack_require__(23); const path = __webpack_require__(16); -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 - * via a {@link stream.Readable}. - */ -class DirectoryReader { - /** - * @param {string} dir - The absolute or relative directory path to read - * @param {object} [options] - User-specified options, if any (see {@link normalizeOptions}) - * @param {object} internalOptions - Internal options that aren't part of the public API - * @class - */ - constructor (dir, options, internalOptions) { - this.options = options = normalizeOptions(options, internalOptions); - - // Indicates whether we should keep reading - // This is set false if stream.Readable.push() returns false. - this.shouldRead = true; - - // The directories to read - // (initialized with the top-level directory) - this.queue = [{ - path: dir, - basePath: options.basePath, - posixBasePath: options.posixBasePath, - depth: 0 - }]; +const fastGlob = __webpack_require__(712); +const gitIgnore = __webpack_require__(904); +const pify = __webpack_require__(905); +const slash = __webpack_require__(906); - // The number of directories that are currently being processed - this.pending = 0; +const DEFAULT_IGNORE = [ + '**/node_modules/**', + '**/bower_components/**', + '**/flow-typed/**', + '**/coverage/**', + '**/.git' +]; - // The data that has been read, but not yet emitted - this.buffer = []; +const readFileP = pify(fs.readFile); - this.stream = new Readable({ objectMode: true }); - this.stream._read = () => { - // Start (or resume) reading - this.shouldRead = true; +const mapGitIgnorePatternTo = base => ignore => { + if (ignore.startsWith('!')) { + return '!' + path.posix.join(base, ignore.slice(1)); + } - // If we have data in the buffer, then send the next chunk - if (this.buffer.length > 0) { - this.pushFromBuffer(); - } + return path.posix.join(base, ignore); +}; - // If we have directories queued, then start processing the next one - if (this.queue.length > 0) { - if (this.options.facade.sync) { - while (this.queue.length > 0) { - this.readNextDirectory(); - } - } - else { - this.readNextDirectory(); - } - } +const parseGitIgnore = (content, options) => { + const base = slash(path.relative(options.cwd, path.dirname(options.fileName))); - this.checkForEOF(); - }; - } + return content + .split(/\r?\n/) + .filter(Boolean) + .filter(line => line.charAt(0) !== '#') + .map(mapGitIgnorePatternTo(base)); +}; - /** - * Reads the next directory in the queue - */ - readNextDirectory () { - let facade = this.options.facade; - let dir = this.queue.shift(); - this.pending++; +const reduceIgnore = files => { + return files.reduce((ignores, file) => { + ignores.add(parseGitIgnore(file.content, { + cwd: file.cwd, + fileName: file.filePath + })); + return ignores; + }, gitIgnore()); +}; - // Read the directory listing - call.safe(facade.fs.readdir, dir.path, (err, items) => { - if (err) { - // fs.readdir threw an error - this.emit('error', err); - return this.finishedReadingDirectory(); - } +const getIsIgnoredPredecate = (ignores, cwd) => { + return p => ignores.ignores(slash(path.relative(cwd, p))); +}; - try { - // Process each item in the directory (simultaneously, if async) - facade.forEach( - items, - this.processItem.bind(this, dir), - this.finishedReadingDirectory.bind(this, dir) - ); - } - catch (err2) { - // facade.forEach threw an error - // (probably because fs.readdir returned an invalid result) - this.emit('error', err2); - this.finishedReadingDirectory(); - } - }); - } +const getFile = (file, cwd) => { + const filePath = path.join(cwd, file); + return readFileP(filePath, 'utf8') + .then(content => ({ + content, + cwd, + filePath + })); +}; - /** - * This method is called after all items in a directory have been processed. - * - * NOTE: This does not necessarily mean that the reader is finished, since there may still - * be other directories queued or pending. - */ - finishedReadingDirectory () { - this.pending--; +const getFileSync = (file, cwd) => { + const filePath = path.join(cwd, file); + const content = fs.readFileSync(filePath, 'utf8'); - if (this.shouldRead) { - // If we have directories queued, then start processing the next one - if (this.queue.length > 0 && this.options.facade.async) { - this.readNextDirectory(); - } + return { + content, + cwd, + filePath + }; +}; - this.checkForEOF(); - } - } +const normalizeOptions = (options = {}) => { + const ignore = options.ignore || []; + const cwd = options.cwd || process.cwd(); + return {ignore, cwd}; +}; - /** - * Determines whether the reader has finished processing all items in all directories. - * If so, then the "end" event is fired (via {@Readable#push}) - */ - checkForEOF () { - if (this.buffer.length === 0 && // The stuff we've already read - this.pending === 0 && // The stuff we're currently reading - this.queue.length === 0) { // The stuff we haven't read yet - // There's no more stuff! - this.stream.push(null); - } - } +module.exports = options => { + options = normalizeOptions(options); - /** - * Processes a single item in a directory. - * - * If the item is a directory, and `option.deep` is enabled, then the item will be added - * to the directory queue. - * - * If the item meets the filter criteria, then it will be emitted to the reader's stream. - * - * @param {object} dir - A directory object from the queue - * @param {string} item - The name of the item (name only, no path) - * @param {function} done - A callback function that is called after the item has been processed - */ - processItem (dir, item, done) { - let stream = this.stream; - let options = this.options; + return fastGlob('**/.gitignore', { + ignore: DEFAULT_IGNORE.concat(options.ignore), + cwd: options.cwd + }) + .then(paths => Promise.all(paths.map(file => getFile(file, options.cwd)))) + .then(files => reduceIgnore(files)) + .then(ignores => getIsIgnoredPredecate(ignores, options.cwd)); +}; - let itemPath = dir.basePath + item; - let posixPath = dir.posixBasePath + item; - let fullPath = path.join(dir.path, item); +module.exports.sync = options => { + options = normalizeOptions(options); - // If `options.deep` is a number, and we've already recursed to the max depth, - // then there's no need to check fs.Stats to know if it's a directory. - // If `options.deep` is a function, then we'll need fs.Stats - let maxDepthReached = dir.depth >= options.recurseDepth; + 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); - // Do we need to call `fs.stat`? - let needStats = - !maxDepthReached || // we need the fs.Stats to know if it's a directory - options.stats || // the user wants fs.Stats objects returned - options.recurseFn || // we need fs.Stats for the recurse function - options.filterFn || // we need fs.Stats for the filter function - EventEmitter.listenerCount(stream, 'file') || // we need the fs.Stats to know if it's a file - EventEmitter.listenerCount(stream, 'directory') || // we need the fs.Stats to know if it's a directory - EventEmitter.listenerCount(stream, 'symlink'); // we need the fs.Stats to know if it's a symlink + return getIsIgnoredPredecate(ignores, options.cwd); +}; - // If we don't need stats, then exit early - if (!needStats) { - if (this.filter(itemPath, posixPath)) { - this.pushOrBuffer({ data: itemPath }); - } - return done(); - } - // Get the fs.Stats object for this path - stat(options.facade.fs, fullPath, (err, stats) => { - if (err) { - // fs.stat threw an error - this.emit('error', err); - return done(); - } +/***/ }), +/* 904 */ +/***/ (function(module, exports) { - try { - // Add the item's path to the fs.Stats object - // The base of this path, and its separators are determined by the options - // (i.e. options.basePath and options.sep) - stats.path = itemPath; +// A simple implementation of make-array +function make_array (subject) { + return Array.isArray(subject) + ? subject + : [subject] +} - // Add depth of the path to the fs.Stats object for use this in the filter function - stats.depth = dir.depth; +const REGEX_BLANK_LINE = /^\s+$/ +const REGEX_LEADING_EXCAPED_EXCLAMATION = /^\\!/ +const REGEX_LEADING_EXCAPED_HASH = /^\\#/ +const SLASH = '/' +const KEY_IGNORE = typeof Symbol !== 'undefined' + ? Symbol.for('node-ignore') + /* istanbul ignore next */ + : 'node-ignore' - if (this.shouldRecurse(stats, posixPath, maxDepthReached)) { - // Add this subdirectory to the queue - this.queue.push({ - path: fullPath, - basePath: itemPath + options.sep, - posixBasePath: posixPath + '/', - depth: dir.depth + 1, - }); - } +const define = (object, key, value) => + Object.defineProperty(object, key, {value}) - // Determine whether this item matches the filter criteria - if (this.filter(stats, posixPath)) { - this.pushOrBuffer({ - data: options.stats ? stats : itemPath, - file: stats.isFile(), - directory: stats.isDirectory(), - symlink: stats.isSymbolicLink(), - }); - } +const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g - done(); - } - catch (err2) { - // An error occurred while processing the item - // (probably during a user-specified function, such as options.deep, options.filter, etc.) - this.emit('error', err2); - done(); - } - }); - } +// 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. + : '' +) - /** - * Pushes the given chunk of data to the stream, or adds it to the buffer, - * depending on the state of the stream. - * - * @param {object} chunk - */ - pushOrBuffer (chunk) { - // Add the chunk to the buffer - this.buffer.push(chunk); +// > 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` - // If we're still reading, then immediately emit the next chunk in the buffer - // (which may or may not be the chunk that we just added) - if (this.shouldRead) { - this.pushFromBuffer(); - } - } +// '`foo/`' should not continue with the '`..`' +const DEFAULT_REPLACER_PREFIX = [ - /** - * Immediately pushes the next chunk in the buffer to the reader's stream. - * The "data" event will always be fired (via {@link Readable#push}). - * In addition, the "file", "directory", and/or "symlink" events may be fired, - * depending on the type of properties of the chunk. - */ - pushFromBuffer () { - let stream = this.stream; - let chunk = this.buffer.shift(); + // > Trailing spaces are ignored unless they are quoted with backslash ("\") + [ + // (a\ ) -> (a ) + // (a ) -> (a) + // (a \ ) -> (a ) + /\\?\s+$/, + match => match.indexOf('\\') === 0 + ? ' ' + : '' + ], - // Stream the data - try { - this.shouldRead = stream.push(chunk.data); - } - catch (err) { - this.emit('error', err); - } + // replace (\ ) with ' ' + [ + /\\\s/g, + () => ' ' + ], - // Also emit specific events, based on the type of chunk - chunk.file && this.emit('file', chunk.data); - chunk.symlink && this.emit('symlink', chunk.data); - chunk.directory && this.emit('directory', chunk.data); - } + // Escape metacharacters + // which is written down by users but means special for regular expressions. - /** - * Determines whether the given directory meets the user-specified recursion criteria. - * If the user didn't specify recursion criteria, then this function will default to true. - * - * @param {fs.Stats} stats - The directory's {@link fs.Stats} object - * @param {string} posixPath - The item's POSIX path (used for glob matching) - * @param {boolean} maxDepthReached - Whether we've already crawled the user-specified depth - * @returns {boolean} - */ - shouldRecurse (stats, posixPath, maxDepthReached) { - let options = this.options; + // > 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 (maxDepthReached) { - // We've already crawled to the maximum depth. So no more recursion. - return false; - } - else if (!stats.isDirectory()) { - // It's not a directory. So don't try to crawl it. - return false; - } - else if (options.recurseGlob) { - // Glob patterns are always tested against the POSIX path, even on Windows - // https://github.com/isaacs/node-glob#windows - return options.recurseGlob.test(posixPath); - } - else if (options.recurseRegExp) { - // Regular expressions are tested against the normal path - // (based on the OS or options.sep) - return options.recurseRegExp.test(stats.path); - } - else if (options.recurseFn) { - try { - // Run the user-specified recursion criteria - return options.recurseFn.call(null, stats); - } - catch (err) { - // An error occurred in the user's code. - // In Sync and Async modes, this will return an error. - // In Streaming mode, we emit an "error" event, but continue processing - this.emit('error', err); - } - } - else { - // No recursion function was specified, and we're within the maximum depth. - // So crawl this directory. - return true; - } - } + [ + // > [abc] matches any character inside the brackets + // > (in this case a, b, or c); + /\[([^\]/]*)($|\])/g, + (match, p1, p2) => p2 === ']' + ? `[${sanitizeRange(p1)}]` + : `\\${match}` + ], - /** - * Determines whether the given item meets the user-specified filter criteria. - * If the user didn't specify a filter, then this function will always return true. - * - * @param {string|fs.Stats} value - Either the item's path, or the item's {@link fs.Stats} object - * @param {string} posixPath - The item's POSIX path (used for glob matching) - * @returns {boolean} - */ - filter (value, posixPath) { - let options = this.options; + [ + // > a question mark (?) matches a single character + /(?!\\)\?/g, + () => '[^/]' + ], - if (options.filterGlob) { - // Glob patterns are always tested against the POSIX path, even on Windows - // https://github.com/isaacs/node-glob#windows - return options.filterGlob.test(posixPath); - } - else if (options.filterRegExp) { - // Regular expressions are tested against the normal path - // (based on the OS or options.sep) - return options.filterRegExp.test(value.path || value); - } - else if (options.filterFn) { - try { - // Run the user-specified filter function - return options.filterFn.call(null, value); - } - catch (err) { - // An error occurred in the user's code. - // In Sync and Async modes, this will return an error. - // In Streaming mode, we emit an "error" event, but continue processing - this.emit('error', err); - } - } - else { - // No filter was specified, so match everything - return true; - } - } + // leading slash + [ - /** - * Emits an event. If one of the event listeners throws an error, - * then an "error" event is emitted. - * - * @param {string} eventName - * @param {*} data - */ - emit (eventName, data) { - let stream = this.stream; + // > 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 + /^\//, + () => '^' + ], - try { - stream.emit(eventName, data); - } - catch (err) { - if (eventName === 'error') { - // Don't recursively emit "error" events. - // If the first one fails, then just throw - throw err; - } - else { - stream.emit('error', err); - } - } - } -} + // replace special metacharacter slash after the leading slash + [ + /\//g, + () => '\\/' + ], -module.exports = DirectoryReader; + [ + // > 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' + () => '^(?:.*\\/)?' + ] +] -/***/ }), -/* 880 */ -/***/ (function(module, exports, __webpack_require__) { +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 + ? '(?:^|\\/)' -"use strict"; + // > 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, -const path = __webpack_require__(16); -const globToRegExp = __webpack_require__(881); + // Zero, one or several directories + // should not use '*', or it will be replaced by the next replacer -module.exports = normalizeOptions; + // Check if it is not the last `'/**'` + (match, index, str) => index + 6 < str.length -let isWindows = /^win/.test(process.platform); + // 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. + // '/**/' + ? '(?:\\/[^\\/]+)*' -/** - * @typedef {Object} FSFacade - * @property {fs.readdir} readdir - * @property {fs.stat} stat - * @property {fs.lstat} lstat - */ + // case: /** + // > A trailing `"/**"` matches everything inside. -/** - * Validates and normalizes the options argument - * - * @param {object} [options] - User-specified options, if any - * @param {object} internalOptions - Internal options that aren't part of the public API - * - * @param {number|boolean|function} [options.deep] - * The number of directories to recursively traverse. Any falsy value or negative number will - * default to zero, so only the top-level contents will be returned. Set to `true` or `Infinity` - * to traverse all subdirectories. Or provide a function that accepts a {@link fs.Stats} object - * and returns a truthy value if the directory's contents should be crawled. - * - * @param {function|string|RegExp} [options.filter] - * A function that accepts a {@link fs.Stats} object and returns a truthy value if the data should - * be returned. Or a RegExp or glob string pattern, to filter by file name. - * - * @param {string} [options.sep] - * The path separator to use. By default, the OS-specific separator will be used, but this can be - * set to a specific value to ensure consistency across platforms. - * - * @param {string} [options.basePath] - * The base path to prepend to each result. If empty, then all results will be relative to `dir`. - * - * @param {FSFacade} [options.fs] - * Synchronous or asynchronous facades for Node.js File System module - * - * @param {object} [internalOptions.facade] - * Synchronous or asynchronous facades for various methods, including for the Node.js File System module - * - * @param {boolean} [internalOptions.emit] - * Indicates whether the reader should emit "file", "directory", and "symlink" events - * - * @param {boolean} [internalOptions.stats] - * Indicates whether the reader should emit {@link fs.Stats} objects instead of path strings - * - * @returns {object} - */ -function normalizeOptions (options, internalOptions) { - if (options === null || options === undefined) { - options = {}; - } - else if (typeof options !== 'object') { - throw new TypeError('options must be an object'); - } + // #21: everything inside but it should not include the current folder + : '\\/.+' + ], - let recurseDepth, recurseFn, recurseRegExp, recurseGlob, deep = options.deep; - if (deep === null || deep === undefined) { - recurseDepth = 0; - } - else if (typeof deep === 'boolean') { - recurseDepth = deep ? Infinity : 0; - } - else if (typeof deep === 'number') { - if (deep < 0 || isNaN(deep)) { - throw new Error('options.deep must be a positive number'); - } - else if (Math.floor(deep) !== deep) { - throw new Error('options.deep must be an integer'); - } - else { - recurseDepth = deep; - } - } - else if (typeof deep === 'function') { - recurseDepth = Infinity; - recurseFn = deep; - } - else if (deep instanceof RegExp) { - recurseDepth = Infinity; - recurseRegExp = deep; - } - else if (typeof deep === 'string' && deep.length > 0) { - recurseDepth = Infinity; - recurseGlob = globToRegExp(deep, { extended: true, globstar: true }); - } - else { - throw new TypeError('options.deep must be a boolean, number, function, regular expression, or glob pattern'); - } + // intermediate wildcards + [ + // Never replace escaped '*' + // ignore rule '\*' will match the path '*' - let filterFn, filterRegExp, filterGlob, filter = options.filter; - if (filter !== null && filter !== undefined) { - if (typeof filter === 'function') { - filterFn = filter; - } - else if (filter instanceof RegExp) { - filterRegExp = filter; - } - else if (typeof filter === 'string' && filter.length > 0) { - filterGlob = globToRegExp(filter, { extended: true, globstar: true }); - } - else { - throw new TypeError('options.filter must be a function, regular expression, or glob pattern'); - } - } + // 'abc.*/' -> go + // 'abc.*' -> skip this rule + /(^|[^\\]+)\\\*(?=.+)/g, - let sep = options.sep; - if (sep === null || sep === undefined) { - sep = path.sep; - } - else if (typeof sep !== 'string') { - throw new TypeError('options.sep must be a string'); - } + // '*.js' matches '.js' + // '*.js' doesn't match 'abc' + (match, p1) => `${p1}[^\\/]*` + ], - let basePath = options.basePath; - if (basePath === null || basePath === undefined) { - basePath = ''; - } - else if (typeof basePath === 'string') { - // Append a path separator to the basePath, if necessary - if (basePath && basePath.substr(-1) !== sep) { - basePath += sep; - } - } - else { - throw new TypeError('options.basePath must be a string'); - } + // trailing wildcard + [ + /(\^|\\\/)?\\\*$/, + (match, p1) => { + const prefix = p1 + // '\^': + // '/*' does not match '' + // '/*' does not match everything - // Convert the basePath to POSIX (forward slashes) - // so that glob pattern matching works consistently, even on Windows - let posixBasePath = basePath; - if (posixBasePath && sep !== '/') { - posixBasePath = posixBasePath.replace(new RegExp('\\' + sep, 'g'), '/'); + // '\\\/': + // 'abc/*' does not match 'abc/' + ? `${p1}[^/]+` - /* istanbul ignore if */ - if (isWindows) { - // Convert Windows root paths (C:\) and UNCs (\\) to POSIX root paths - posixBasePath = posixBasePath.replace(/^([a-zA-Z]\:\/|\/\/)/, '/'); - } - } + // 'a*' matches 'a' + // 'a*' matches 'aa' + : '[^/]*' - // Determine which facade methods to use - let facade; - if (options.fs === null || options.fs === undefined) { - // The user didn't provide their own facades, so use our internal ones - facade = internalOptions.facade; - } - else if (typeof options.fs === 'object') { - // Merge the internal facade methods with the user-provided `fs` facades - facade = Object.assign({}, internalOptions.facade); - facade.fs = Object.assign({}, internalOptions.facade.fs, options.fs); - } - else { - throw new TypeError('options.fs must be an object'); - } + return `${prefix}(?=$|\\/$)` + } + ], - return { - recurseDepth, - recurseFn, - recurseRegExp, - recurseGlob, - filterFn, - filterRegExp, - filterGlob, - sep, - basePath, - posixBasePath, - facade, - emit: !!internalOptions.emit, - stats: !!internalOptions.stats, - }; -} + [ + // unescape + /\\\\\\/g, + () => '\\' + ] +] +const POSITIVE_REPLACERS = [ + ...DEFAULT_REPLACER_PREFIX, -/***/ }), -/* 881 */ -/***/ (function(module, exports) { + // 'f' + // matches + // - /f(end) + // - /f/ + // - (start)f(end) + // - (start)f/ + // doesn't match + // - oof + // - foo + // pseudo: + // -> (^|/)f(/|$) -module.exports = function (glob, opts) { - if (typeof glob !== 'string') { - throw new TypeError('Expected a string'); - } + // ending + [ + // 'js' will not match 'js.' + // 'ab' will not match 'abc' + /(?:[^*/])$/, - var str = String(glob); + // 'js*' will not match 'a.js' + // 'js/' will not match 'a.js' + // 'js' will match 'a.js' and 'a.js/' + match => `${match}(?=$|\\/)` + ], - // The regexp we are building, as a string. - var reStr = ""; + ...DEFAULT_REPLACER_SUFFIX +] - // Whether we are matching so called "extended" globs (like bash) and should - // support single character matching, matching ranges of characters, group - // matching, etc. - var extended = opts ? !!opts.extended : false; +const NEGATIVE_REPLACERS = [ + ...DEFAULT_REPLACER_PREFIX, - // When globstar is _false_ (default), '/foo/*' is translated a regexp like - // '^\/foo\/.*$' which will match any string beginning with '/foo/' - // When globstar is _true_, '/foo/*' is translated to regexp like - // '^\/foo\/[^/]*$' which will match any string beginning with '/foo/' BUT - // which does not have a '/' to the right of it. - // E.g. with '/foo/*' these will match: '/foo/bar', '/foo/bar.txt' but - // these will not '/foo/bar/baz', '/foo/bar/baz.txt' - // Lastely, when globstar is _true_, '/foo/**' is equivelant to '/foo/*' when - // globstar is _false_ - var globstar = opts ? !!opts.globstar : false; + // #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 we are doing extended matching, this boolean is true when we are inside - // a group (eg {*.html,*.js}), and false otherwise. - var inGroup = false; + // eg: + // ['node_modules/*', '!node_modules'] + // should ignore `node_modules/a.js` + [ + /(?:[^*])$/, + match => `${match}(?=$|\\/$)` + ], - // RegExp flags (eg "i" ) to pass in to RegExp constructor. - var flags = opts && typeof( opts.flags ) === "string" ? opts.flags : ""; + ...DEFAULT_REPLACER_SUFFIX +] - var c; - for (var i = 0, len = str.length; i < len; i++) { - c = str[i]; +// A simple cache, because an ignore rule only has only one certain meaning +const cache = Object.create(null) - switch (c) { - case "\\": - case "/": - case "$": - case "^": - case "+": - case ".": - case "(": - case ")": - case "=": - case "!": - case "|": - reStr += "\\" + c; - break; +// @param {pattern} +const make_regex = (pattern, negative, ignorecase) => { + const r = cache[pattern] + if (r) { + return r + } - case "?": - if (extended) { - reStr += "."; - break; - } + const replacers = negative + ? NEGATIVE_REPLACERS + : POSITIVE_REPLACERS - case "[": - case "]": - if (extended) { - reStr += c; - break; - } + const source = replacers.reduce( + (prev, current) => prev.replace(current[0], current[1].bind(pattern)), + pattern + ) - case "{": - if (extended) { - inGroup = true; - reStr += "("; - break; - } + return cache[pattern] = ignorecase + ? new RegExp(source, 'i') + : new RegExp(source) +} - case "}": - if (extended) { - inGroup = false; - reStr += ")"; - break; - } +// > A blank line matches no files, so it can serve as a separator for readability. +const checkPattern = pattern => pattern + && typeof pattern === 'string' + && !REGEX_BLANK_LINE.test(pattern) - case ",": - if (inGroup) { - reStr += "|"; - break; - } - reStr += "\\" + c; - break; + // > A line starting with # serves as a comment. + && pattern.indexOf('#') !== 0 - case "*": - // Move over all consecutive "*"'s. - // Also store the previous and next characters - var prevChar = str[i - 1]; - var starCount = 1; - while(str[i + 1] === "*") { - starCount++; - i++; - } - var nextChar = str[i + 1]; +const createRule = (pattern, ignorecase) => { + const origin = pattern + let negative = false - if (!globstar) { - // globstar is disabled, so treat any number of "*" as one - reStr += ".*"; - } else { - // globstar is enabled, so determine if this is a globstar segment - var isGlobstar = starCount > 1 // multiple "*"'s - && (prevChar === "/" || prevChar === undefined) // from the start of the segment - && (nextChar === "/" || nextChar === undefined) // to the end of the segment + // > An optional prefix "!" which negates the pattern; + if (pattern.indexOf('!') === 0) { + negative = true + pattern = pattern.substr(1) + } - if (isGlobstar) { - // it's a globstar, so match zero or more path segments - reStr += "(?:[^/]*(?:\/|$))*"; - i++; // move over the "/" - } else { - // it's not a globstar, so only match one path segment - reStr += "[^/]*"; - } - } - break; + pattern = pattern + // > Put a backslash ("\") in front of the first "!" for patterns that + // > begin with a literal "!", for example, `"\!important!.txt"`. + .replace(REGEX_LEADING_EXCAPED_EXCLAMATION, '!') + // > Put a backslash ("\") in front of the first hash for patterns that + // > begin with a hash. + .replace(REGEX_LEADING_EXCAPED_HASH, '#') - default: - reStr += c; - } - } + const regex = make_regex(pattern, negative, ignorecase) - // When regexp 'g' flag is specified don't - // constrain the regular expression with ^ & $ - if (!flags || !~flags.indexOf('g')) { - reStr = "^" + reStr + "$"; + return { + origin, + pattern, + negative, + regex } +} - return new RegExp(reStr, flags); -}; +class IgnoreBase { + constructor ({ + ignorecase = true + } = {}) { + this._rules = [] + this._ignorecase = ignorecase + define(this, KEY_IGNORE, true) + this._initCache() + } + _initCache () { + this._cache = Object.create(null) + } -/***/ }), -/* 882 */ -/***/ (function(module, exports, __webpack_require__) { + // @param {Array.|string|Ignore} pattern + add (pattern) { + this._added = false -"use strict"; + if (typeof pattern === 'string') { + pattern = pattern.split(/\r?\n/g) + } + make_array(pattern).forEach(this._addPattern, this) -const call = __webpack_require__(883); + // Some rules have just added to the ignore, + // making the behavior changed. + if (this._added) { + this._initCache() + } -module.exports = stat; + return this + } -/** - * Retrieves the {@link fs.Stats} for the given path. If the path is a symbolic link, - * then the Stats of the symlink's target are returned instead. If the symlink is broken, - * then the Stats of the symlink itself are returned. - * - * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module - * @param {string} path - The path to return stats for - * @param {function} callback - */ -function stat (fs, path, callback) { - let isSymLink = false; + // legacy + addPattern (pattern) { + return this.add(pattern) + } - call.safe(fs.lstat, path, (err, lstats) => { - if (err) { - // fs.lstat threw an eror - return callback(err); + _addPattern (pattern) { + // #32 + if (pattern && pattern[KEY_IGNORE]) { + this._rules = this._rules.concat(pattern._rules) + this._added = true + return } - try { - isSymLink = lstats.isSymbolicLink(); - } - catch (err2) { - // lstats.isSymbolicLink() threw an error - // (probably because fs.lstat returned an invalid result) - return callback(err2); + if (checkPattern(pattern)) { + const rule = createRule(pattern, this._ignorecase) + this._added = true + this._rules.push(rule) } + } - if (isSymLink) { - // Try to resolve the symlink - symlinkStat(fs, path, lstats, callback); - } - else { - // It's not a symlink, so return the stats as-is - callback(null, lstats); - } - }); -} + filter (paths) { + return make_array(paths).filter(path => this._filter(path)) + } -/** - * Retrieves the {@link fs.Stats} for the target of the given symlink. - * If the symlink is broken, then the Stats of the symlink itself are returned. - * - * @param {object} fs - Synchronous or Asynchronouse facade for the "fs" module - * @param {string} path - The path of the symlink to return stats for - * @param {object} lstats - The stats of the symlink - * @param {function} callback - */ -function symlinkStat (fs, path, lstats, callback) { - call.safe(fs.stat, path, (err, stats) => { - if (err) { - // The symlink is broken, so return the stats for the link itself - return callback(null, lstats); + createFilter () { + return path => this._filter(path) + } + + ignores (path) { + return !this._filter(path) + } + + // @returns `Boolean` true if the `path` is NOT ignored + _filter (path, slices) { + if (!path) { + return false } - try { - // Return the stats for the resolved symlink target, - // and override the `isSymbolicLink` method to indicate that it's a symlink - stats.isSymbolicLink = () => true; + if (path in this._cache) { + return this._cache[path] } - catch (err2) { - // Setting stats.isSymbolicLink threw an error - // (probably because fs.stat returned an invalid result) - return callback(err2); + + if (!slices) { + // path/to/a.js + // ['path', 'to', 'a.js'] + slices = path.split(SLASH) } - callback(null, stats); - }); -} + slices.pop() + return this._cache[path] = slices.length + // > It is not possible to re-include a file if a parent directory of + // > that file is excluded. + // If the path contains a parent directory, check the parent first + ? this._filter(slices.join(SLASH) + SLASH, slices) + && this._test(path) -/***/ }), -/* 883 */ -/***/ (function(module, exports, __webpack_require__) { + // Or only test the path + : this._test(path) + } -"use strict"; + // @returns {Boolean} true if a file is NOT ignored + _test (path) { + // Explicitly define variable type by setting matched to `0` + let matched = 0 + this._rules.forEach(rule => { + // if matched = true, then we only test negative rules + // if matched = false, then we test non-negative rules + if (!(matched ^ rule.negative)) { + matched = rule.negative ^ rule.regex.test(path) + } + }) -let call = module.exports = { - safe: safeCall, - once: callOnce, -}; + return !matched + } +} -/** - * Calls a function with the given arguments, and ensures that the error-first callback is _always_ - * invoked exactly once, even if the function throws an error. - * - * @param {function} fn - The function to invoke - * @param {...*} args - The arguments to pass to the function. The final argument must be a callback function. - */ -function safeCall (fn, args) { - // Get the function arguments as an array - args = Array.prototype.slice.call(arguments, 1); +// 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' + ) +) { + const filter = IgnoreBase.prototype._filter - // Replace the callback function with a wrapper that ensures it will only be called once - let callback = call.once(args.pop()); - args.push(callback); + /* eslint no-control-regex: "off" */ + const make_posix = str => /^\\\\\?\\/.test(str) + || /[^\x00-\x80]+/.test(str) + ? str + : str.replace(/\\/g, '/') - try { - fn.apply(null, args); - } - catch (err) { - callback(err); + IgnoreBase.prototype._filter = function filterWin32 (path, slices) { + path = make_posix(path) + return filter.call(this, path, slices) } } -/** - * Returns a wrapper function that ensures the given callback function is only called once. - * Subsequent calls are ignored, unless the first argument is an Error, in which case the - * error is thrown. - * - * @param {function} fn - The function that should only be called once - * @returns {function} - */ -function callOnce (fn) { - let fulfilled = false; - - return function onceWrapper (err) { - if (!fulfilled) { - fulfilled = true; - return fn.apply(this, arguments); - } - else if (err) { - // The callback has already been called, but now an error has occurred - // (most likely inside the callback function). So re-throw the error, - // so it gets handled further up the call stack - throw err; - } - }; -} +module.exports = options => new IgnoreBase(options) /***/ }), -/* 884 */ +/* 905 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const fs = __webpack_require__(23); -const call = __webpack_require__(883); +const processFn = (fn, options) => function (...args) { + const P = options.promiseModule; -/** - * A facade around {@link fs.readdirSync} that allows it to be called - * the same way as {@link fs.readdir}. - * - * @param {string} dir - * @param {function} callback - */ -exports.readdir = function (dir, callback) { - // Make sure the callback is only called once - callback = call.once(callback); + return new P((resolve, reject) => { + if (options.multiArgs) { + args.push((...result) => { + if (options.errorFirst) { + if (result[0]) { + reject(result); + } else { + result.shift(); + resolve(result); + } + } else { + resolve(result); + } + }); + } else if (options.errorFirst) { + args.push((error, result) => { + if (error) { + reject(error); + } else { + resolve(result); + } + }); + } else { + args.push(resolve); + } - try { - let items = fs.readdirSync(dir); - callback(null, items); - } - catch (err) { - callback(err); - } + fn.apply(this, args); + }); }; -/** - * A facade around {@link fs.statSync} that allows it to be called - * the same way as {@link fs.stat}. - * - * @param {string} path - * @param {function} callback - */ -exports.stat = function (path, callback) { - // Make sure the callback is only called once - callback = call.once(callback); +module.exports = (input, options) => { + options = Object.assign({ + exclude: [/.+(Sync|Stream)$/], + errorFirst: true, + promiseModule: Promise + }, options); - try { - let stats = fs.statSync(path); - callback(null, stats); - } - catch (err) { - callback(err); - } + const objType = typeof input; + if (!(input !== null && (objType === 'object' || objType === 'function'))) { + throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objType}\``); + } + + const filter = key => { + const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); + return options.include ? options.include.some(match) : !options.exclude.some(match); + }; + + let ret; + if (objType === 'function') { + ret = function (...args) { + return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args); + }; + } else { + ret = Object.create(Object.getPrototypeOf(input)); + } + + for (const key in input) { // eslint-disable-line guard-for-in + const property = input[key]; + ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property; + } + + return ret; }; -/** - * A facade around {@link fs.lstatSync} that allows it to be called - * the same way as {@link fs.lstat}. - * - * @param {string} path - * @param {function} callback - */ -exports.lstat = function (path, callback) { - // Make sure the callback is only called once - callback = call.once(callback); - try { - let stats = fs.lstatSync(path); - callback(null, stats); - } - catch (err) { - callback(err); - } +/***/ }), +/* 906 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +module.exports = input => { + const isExtendedLengthPath = /^\\\\\?\\/.test(input); + const hasNonAscii = /[^\u0000-\u0080]+/.test(input); // eslint-disable-line no-control-regex + + if (isExtendedLengthPath || hasNonAscii) { + return input; + } + + return input.replace(/\\/g, '/'); }; /***/ }), -/* 885 */ +/* 907 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +const path = __webpack_require__(16); +const {constants: fsConstants} = __webpack_require__(23); +const pEvent = __webpack_require__(908); +const CpFileError = __webpack_require__(911); +const fs = __webpack_require__(913); +const ProgressEmitter = __webpack_require__(916); + +const cpFileAsync = async (source, destination, options, progressEmitter) => { + let readError; + const stat = await fs.stat(source); + progressEmitter.size = stat.size; + + const read = await fs.createReadStream(source); + await fs.makeDir(path.dirname(destination)); + const write = fs.createWriteStream(destination, {flags: options.overwrite ? 'w' : 'wx'}); + read.on('data', () => { + progressEmitter.written = write.bytesWritten; + }); + read.once('error', error => { + readError = new CpFileError(`Cannot read from \`${source}\`: ${error.message}`, error); + write.end(); + }); -module.exports = syncForEach; + let updateStats = false; + try { + const writePromise = pEvent(write, 'close'); + read.pipe(write); + await writePromise; + progressEmitter.written = progressEmitter.size; + updateStats = true; + } catch (error) { + if (options.overwrite || error.code !== 'EEXIST') { + throw new CpFileError(`Cannot write to \`${destination}\`: ${error.message}`, error); + } + } -/** - * A facade that allows {@link Array.forEach} to be called as though it were asynchronous. - * - * @param {array} array - The array to iterate over - * @param {function} iterator - The function to call for each item in the array - * @param {function} done - The function to call when all iterators have completed - */ -function syncForEach (array, iterator, done) { - array.forEach(item => { - iterator(item, () => { - // Note: No error-handling here because this is currently only ever called - // by DirectoryReader, which never passes an `error` parameter to the callback. - // Instead, DirectoryReader emits an "error" event if an error occurs. - }); - }); + if (readError) { + throw readError; + } - done(); -} + if (updateStats) { + const stats = await fs.lstat(source); + return Promise.all([ + fs.utimes(destination, stats.atime, stats.mtime), + fs.chmod(destination, stats.mode), + fs.chown(destination, stats.uid, stats.gid) + ]); + } +}; -/***/ }), -/* 886 */ -/***/ (function(module, exports, __webpack_require__) { +const cpFile = (source, destination, options) => { + if (!source || !destination) { + return Promise.reject(new CpFileError('`source` and `destination` required')); + } -"use strict"; + options = { + overwrite: true, + ...options + }; + const progressEmitter = new ProgressEmitter(path.resolve(source), path.resolve(destination)); + const promise = cpFileAsync(source, destination, options, progressEmitter); + promise.on = (...args) => { + progressEmitter.on(...args); + return promise; + }; -module.exports = readdirAsync; + return promise; +}; -const maybe = __webpack_require__(887); -const DirectoryReader = __webpack_require__(879); +module.exports = cpFile; -let asyncFacade = { - fs: __webpack_require__(23), - forEach: __webpack_require__(888), - async: true +const checkSourceIsFile = (stat, source) => { + if (stat.isDirectory()) { + throw Object.assign(new CpFileError(`EISDIR: illegal operation on a directory '${source}'`), { + errno: -21, + code: 'EISDIR', + source + }); + } }; -/** - * Returns the buffered output from an asynchronous {@link DirectoryReader}, - * via an error-first callback or a {@link Promise}. - * - * @param {string} dir - * @param {object} [options] - * @param {function} [callback] - * @param {object} internalOptions - */ -function readdirAsync (dir, options, callback, internalOptions) { - if (typeof options === 'function') { - callback = options; - options = undefined; - } +const fixupAttributes = (destination, stat) => { + fs.chmodSync(destination, stat.mode); + fs.chownSync(destination, stat.uid, stat.gid); +}; - return maybe(callback, new Promise(((resolve, reject) => { - let results = []; +module.exports.sync = (source, destination, options) => { + if (!source || !destination) { + throw new CpFileError('`source` and `destination` required'); + } - internalOptions.facade = asyncFacade; + options = { + overwrite: true, + ...options + }; - let reader = new DirectoryReader(dir, options, internalOptions); - let stream = reader.stream; + const stat = fs.statSync(source); + checkSourceIsFile(stat, source); + fs.makeDirSync(path.dirname(destination)); - stream.on('error', err => { - reject(err); - stream.pause(); - }); - stream.on('data', result => { - results.push(result); - }); - stream.on('end', () => { - resolve(results); - }); - }))); -} + const flags = options.overwrite ? null : fsConstants.COPYFILE_EXCL; + try { + fs.copyFileSync(source, destination, flags); + } catch (error) { + if (!options.overwrite && error.code === 'EEXIST') { + return; + } + + throw error; + } + + fs.utimesSync(destination, stat.atime, stat.mtime); + fixupAttributes(destination, stat); +}; /***/ }), -/* 887 */ +/* 908 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; +const pTimeout = __webpack_require__(909); -var next = (global.process && process.nextTick) || global.setImmediate || function (f) { - setTimeout(f, 0) -} +const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; -module.exports = function maybe (cb, promise) { - if (cb) { - promise - .then(function (result) { - next(function () { cb(null, result) }) - }, function (err) { - next(function () { cb(err) }) - }) - return undefined - } - else { - return promise - } -} +const normalizeEmitter = emitter => { + const addListener = emitter.on || emitter.addListener || emitter.addEventListener; + const removeListener = emitter.off || emitter.removeListener || emitter.removeEventListener; + if (!addListener || !removeListener) { + throw new TypeError('Emitter is not compatible'); + } -/***/ }), -/* 888 */ -/***/ (function(module, exports, __webpack_require__) { + return { + addListener: addListener.bind(emitter), + removeListener: removeListener.bind(emitter) + }; +}; -"use strict"; +const normalizeEvents = event => Array.isArray(event) ? event : [event]; +const multiple = (emitter, event, options) => { + let cancel; + const ret = new Promise((resolve, reject) => { + options = { + rejectionEvents: ['error'], + multiArgs: false, + resolveImmediately: false, + ...options + }; -module.exports = asyncForEach; + if (!(options.count >= 0 && (options.count === Infinity || Number.isInteger(options.count)))) { + throw new TypeError('The `count` option should be at least 0 or more'); + } -/** - * Simultaneously processes all items in the given array. - * - * @param {array} array - The array to iterate over - * @param {function} iterator - The function to call for each item in the array - * @param {function} done - The function to call when all iterators have completed - */ -function asyncForEach (array, iterator, done) { - if (array.length === 0) { - // NOTE: Normally a bad idea to mix sync and async, but it's safe here because - // of the way that this method is currently used by DirectoryReader. - done(); - return; - } + // Allow multiple events + const events = normalizeEvents(event); - // Simultaneously process all items in the array. - let pending = array.length; - array.forEach(item => { - iterator(item, () => { - if (--pending === 0) { - done(); - } - }); - }); -} + const items = []; + const {addListener, removeListener} = normalizeEmitter(emitter); + const onItem = (...args) => { + const value = options.multiArgs ? args : args[0]; -/***/ }), -/* 889 */ -/***/ (function(module, exports, __webpack_require__) { + if (options.filter && !options.filter(value)) { + return; + } -"use strict"; + items.push(value); + if (options.count === items.length) { + cancel(); + resolve(items); + } + }; -module.exports = readdirStream; + const rejectHandler = error => { + cancel(); + reject(error); + }; -const DirectoryReader = __webpack_require__(879); + cancel = () => { + for (const event of events) { + removeListener(event, onItem); + } -let streamFacade = { - fs: __webpack_require__(23), - forEach: __webpack_require__(888), - async: true -}; + for (const rejectionEvent of options.rejectionEvents) { + removeListener(rejectionEvent, rejectHandler); + } + }; -/** - * Returns the {@link stream.Readable} of an asynchronous {@link DirectoryReader}. - * - * @param {string} dir - * @param {object} [options] - * @param {object} internalOptions - */ -function readdirStream (dir, options, internalOptions) { - internalOptions.facade = streamFacade; + for (const event of events) { + addListener(event, onItem); + } - let reader = new DirectoryReader(dir, options, internalOptions); - return reader.stream; -} + for (const rejectionEvent of options.rejectionEvents) { + addListener(rejectionEvent, rejectHandler); + } + if (options.resolveImmediately) { + resolve(items); + } + }); -/***/ }), -/* 890 */ -/***/ (function(module, exports, __webpack_require__) { + ret.cancel = cancel; -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(16); -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; - this.micromatchOptions = this.getMicromatchOptions(); - this.entryFilter = new entry_1.default(options, this.micromatchOptions); - this.deepFilter = new deep_1.default(options, this.micromatchOptions); - } - /** - * Returns root path to scanner. - */ - Reader.prototype.getRootDirectory = function (task) { - return path.resolve(this.options.cwd, task.base); - }; - /** - * Returns options for reader. - */ - Reader.prototype.getReaderOptions = function (task) { - return { - basePath: task.base === '.' ? '' : task.base, - filter: this.entryFilter.getFilter(task.positive, task.negative), - deep: this.deepFilter.getFilter(task.positive, task.negative), - sep: '/' - }; - }; - /** - * Returns options for micromatch. - */ - Reader.prototype.getMicromatchOptions = function () { - return { - dot: this.options.dot, - nobrace: !this.options.brace, - noglobstar: !this.options.globstar, - noext: !this.options.extension, - nocase: !this.options.case, - matchBase: this.options.matchBase - }; - }; - /** - * Returns transformed entry. - */ - Reader.prototype.transform = function (entry) { - if (this.options.absolute) { - entry.path = pathUtil.makeAbsolute(this.options.cwd, entry.path); - } - if (this.options.markDirectories && entry.isDirectory()) { - entry.path += '/'; - } - var item = this.options.stats ? entry : entry.path; - if (this.options.transform === null) { - return item; - } - return this.options.transform(item); - }; - /** - * Returns true if error has ENOENT code. - */ - Reader.prototype.isEnoentCodeError = function (err) { - return err.code === 'ENOENT'; - }; - return Reader; -}()); -exports.default = Reader; + if (typeof options.timeout === 'number') { + const timeout = pTimeout(ret, options.timeout); + timeout.cancel = cancel; + return timeout; + } + return ret; +}; -/***/ }), -/* 891 */ -/***/ (function(module, exports, __webpack_require__) { +const pEvent = (emitter, event, options) => { + if (typeof options === 'function') { + options = {filter: options}; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(892); -var patternUtils = __webpack_require__(721); -var DeepFilter = /** @class */ (function () { - function DeepFilter(options, micromatchOptions) { - this.options = options; - this.micromatchOptions = micromatchOptions; - } - /** - * Returns filter for directories. - */ - DeepFilter.prototype.getFilter = function (positive, negative) { - var _this = this; - var maxPatternDepth = this.getMaxPatternDepth(positive); - var negativeRe = this.getNegativePatternsRe(negative); - return function (entry) { return _this.filter(entry, negativeRe, maxPatternDepth); }; - }; - /** - * Returns max depth of the provided patterns. - */ - DeepFilter.prototype.getMaxPatternDepth = function (patterns) { - var globstar = patterns.some(patternUtils.hasGlobStar); - return globstar ? Infinity : patternUtils.getMaxNaivePatternsDepth(patterns); - }; - /** - * Returns RegExp's for patterns that can affect the depth of reading. - */ - DeepFilter.prototype.getNegativePatternsRe = function (patterns) { - var affectDepthOfReadingPatterns = patterns.filter(patternUtils.isAffectDepthOfReadingPattern); - return patternUtils.convertPatternsToRe(affectDepthOfReadingPatterns, this.micromatchOptions); - }; - /** - * Returns «true» for directory that should be read. - */ - DeepFilter.prototype.filter = function (entry, negativeRe, maxPatternDepth) { - if (this.isSkippedByDeepOption(entry.depth)) { - return false; - } - if (this.isSkippedByMaxPatternDepth(entry.depth, maxPatternDepth)) { - return false; - } - if (this.isSkippedSymlinkedDirectory(entry)) { - return false; - } - if (this.isSkippedDotDirectory(entry)) { - return false; - } - return this.isSkippedByNegativePatterns(entry, negativeRe); - }; - /** - * Returns «true» when the «deep» option is disabled or number and depth of the entry is greater that the option value. - */ - DeepFilter.prototype.isSkippedByDeepOption = function (entryDepth) { - return !this.options.deep || (typeof this.options.deep === 'number' && entryDepth >= this.options.deep); - }; - /** - * Returns «true» when depth parameter is not an Infinity and entry depth greater that the parameter value. - */ - DeepFilter.prototype.isSkippedByMaxPatternDepth = function (entryDepth, maxPatternDepth) { - return maxPatternDepth !== Infinity && entryDepth >= maxPatternDepth; - }; - /** - * Returns «true» for symlinked directory if the «followSymlinkedDirectories» option is disabled. - */ - DeepFilter.prototype.isSkippedSymlinkedDirectory = function (entry) { - return !this.options.followSymlinkedDirectories && entry.isSymbolicLink(); - }; - /** - * Returns «true» for a directory whose name starts with a period if «dot» option is disabled. - */ - DeepFilter.prototype.isSkippedDotDirectory = function (entry) { - return !this.options.dot && pathUtils.isDotDirectory(entry.path); - }; - /** - * Returns «true» for a directory whose path math to any negative pattern. - */ - DeepFilter.prototype.isSkippedByNegativePatterns = function (entry, negativeRe) { - return !patternUtils.matchAny(entry.path, negativeRe); - }; - return DeepFilter; -}()); -exports.default = DeepFilter; + options = { + ...options, + count: 1, + resolveImmediately: false + }; + const arrayPromise = multiple(emitter, event, options); + const promise = arrayPromise.then(array => array[0]); // eslint-disable-line promise/prefer-await-to-then + promise.cancel = arrayPromise.cancel; -/***/ }), -/* 892 */ -/***/ (function(module, exports, __webpack_require__) { + return promise; +}; -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(16); -/** - * Returns «true» if the last partial of the path starting with a period. - */ -function isDotDirectory(filepath) { - return path.basename(filepath).startsWith('.'); -} -exports.isDotDirectory = isDotDirectory; -/** - * Convert a windows-like path to a unix-style path. - */ -function normalize(filepath) { - return filepath.replace(/\\/g, '/'); -} -exports.normalize = normalize; -/** - * Returns normalized absolute path of provided filepath. - */ -function makeAbsolute(cwd, filepath) { - return normalize(path.resolve(cwd, filepath)); -} -exports.makeAbsolute = makeAbsolute; +module.exports = pEvent; +// TODO: Remove this for the next major release +module.exports.default = pEvent; +module.exports.multiple = multiple; -/***/ }), -/* 893 */ -/***/ (function(module, exports, __webpack_require__) { +module.exports.iterator = (emitter, event, options) => { + if (typeof options === 'function') { + options = {filter: options}; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(892); -var patternUtils = __webpack_require__(721); -var EntryFilter = /** @class */ (function () { - function EntryFilter(options, micromatchOptions) { - this.options = options; - this.micromatchOptions = micromatchOptions; - this.index = new Map(); - } - /** - * Returns filter for directories. - */ - EntryFilter.prototype.getFilter = function (positive, negative) { - var _this = this; - var positiveRe = patternUtils.convertPatternsToRe(positive, this.micromatchOptions); - var negativeRe = patternUtils.convertPatternsToRe(negative, this.micromatchOptions); - return function (entry) { return _this.filter(entry, positiveRe, negativeRe); }; - }; - /** - * Returns true if entry must be added to result. - */ - EntryFilter.prototype.filter = function (entry, positiveRe, negativeRe) { - // Exclude duplicate results - if (this.options.unique) { - if (this.isDuplicateEntry(entry)) { - return false; - } - this.createIndexRecord(entry); - } - // Filter files and directories by options - if (this.onlyFileFilter(entry) || this.onlyDirectoryFilter(entry)) { - return false; - } - if (this.isSkippedByAbsoluteNegativePatterns(entry, negativeRe)) { - return false; - } - return this.isMatchToPatterns(entry.path, positiveRe) && !this.isMatchToPatterns(entry.path, negativeRe); - }; - /** - * Return true if the entry already has in the cross reader index. - */ - EntryFilter.prototype.isDuplicateEntry = function (entry) { - return this.index.has(entry.path); - }; - /** - * Create record in the cross reader index. - */ - EntryFilter.prototype.createIndexRecord = function (entry) { - this.index.set(entry.path, undefined); - }; - /** - * Returns true for non-files if the «onlyFiles» option is enabled. - */ - EntryFilter.prototype.onlyFileFilter = function (entry) { - return this.options.onlyFiles && !entry.isFile(); - }; - /** - * Returns true for non-directories if the «onlyDirectories» option is enabled. - */ - EntryFilter.prototype.onlyDirectoryFilter = function (entry) { - return this.options.onlyDirectories && !entry.isDirectory(); - }; - /** - * Return true when `absolute` option is enabled and matched to the negative patterns. - */ - EntryFilter.prototype.isSkippedByAbsoluteNegativePatterns = function (entry, negativeRe) { - if (!this.options.absolute) { - return false; - } - var fullpath = pathUtils.makeAbsolute(this.options.cwd, entry.path); - return this.isMatchToPatterns(fullpath, negativeRe); - }; - /** - * Return true when entry match to provided patterns. - * - * First, just trying to apply patterns to the path. - * Second, trying to apply patterns to the path with final slash (need to micromatch to support «directory/**» patterns). - */ - EntryFilter.prototype.isMatchToPatterns = function (filepath, patternsRe) { - return patternUtils.matchAny(filepath, patternsRe) || patternUtils.matchAny(filepath + '/', patternsRe); - }; - return EntryFilter; -}()); -exports.default = EntryFilter; + // Allow multiple events + const events = normalizeEvents(event); + + options = { + rejectionEvents: ['error'], + resolutionEvents: [], + limit: Infinity, + multiArgs: false, + ...options + }; + + const {limit} = options; + const isValidLimit = limit >= 0 && (limit === Infinity || Number.isInteger(limit)); + if (!isValidLimit) { + throw new TypeError('The `limit` option should be a non-negative integer or Infinity'); + } + if (limit === 0) { + // Return an empty async iterator to avoid any further cost + return { + [Symbol.asyncIterator]() { + return this; + }, + async next() { + return { + done: true, + value: undefined + }; + } + }; + } -/***/ }), -/* 894 */ -/***/ (function(module, exports, __webpack_require__) { + const {addListener, removeListener} = normalizeEmitter(emitter); -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var stream = __webpack_require__(27); -var fsStat = __webpack_require__(895); -var fs_1 = __webpack_require__(899); -var FileSystemStream = /** @class */ (function (_super) { - __extends(FileSystemStream, _super); - function FileSystemStream() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - * Use stream API to read entries for Task. - */ - FileSystemStream.prototype.read = function (patterns, filter) { - var _this = this; - var filepaths = patterns.map(this.getFullEntryPath, this); - var transform = new stream.Transform({ objectMode: true }); - transform._transform = function (index, _enc, done) { - return _this.getEntry(filepaths[index], patterns[index]).then(function (entry) { - if (entry !== null && filter(entry)) { - transform.push(entry); - } - if (index === filepaths.length - 1) { - transform.end(); - } - done(); - }); - }; - for (var i = 0; i < filepaths.length; i++) { - transform.write(i); - } - return transform; - }; - /** - * Return entry for the provided path. - */ - FileSystemStream.prototype.getEntry = function (filepath, pattern) { - var _this = this; - return this.getStat(filepath) - .then(function (stat) { return _this.makeEntry(stat, pattern); }) - .catch(function () { return null; }); - }; - /** - * Return fs.Stats for the provided path. - */ - FileSystemStream.prototype.getStat = function (filepath) { - return fsStat.stat(filepath, { throwErrorOnBrokenSymlinks: false }); - }; - return FileSystemStream; -}(fs_1.default)); -exports.default = FileSystemStream; + let isDone = false; + let error; + let hasPendingError = false; + const nextQueue = []; + const valueQueue = []; + let eventCount = 0; + let isLimitReached = false; + const valueHandler = (...args) => { + eventCount++; + isLimitReached = eventCount === limit; -/***/ }), -/* 895 */ -/***/ (function(module, exports, __webpack_require__) { + const value = options.multiArgs ? args : args[0]; -"use strict"; + if (nextQueue.length > 0) { + const {resolve} = nextQueue.shift(); -Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(896); -const statProvider = __webpack_require__(898); -/** - * Asynchronous API. - */ -function stat(path, opts) { - return new Promise((resolve, reject) => { - statProvider.async(path, optionsManager.prepare(opts), (err, stats) => err ? reject(err) : resolve(stats)); - }); -} -exports.stat = stat; -function statCallback(path, optsOrCallback, callback) { - if (typeof optsOrCallback === 'function') { - callback = optsOrCallback; /* tslint:disable-line: no-parameter-reassignment */ - optsOrCallback = undefined; /* tslint:disable-line: no-parameter-reassignment */ - } - if (typeof callback === 'undefined') { - throw new TypeError('The "callback" argument must be of type Function.'); - } - statProvider.async(path, optionsManager.prepare(optsOrCallback), callback); -} -exports.statCallback = statCallback; -/** - * Synchronous API. - */ -function statSync(path, opts) { - return statProvider.sync(path, optionsManager.prepare(opts)); -} -exports.statSync = statSync; + resolve({done: false, value}); + if (isLimitReached) { + cancel(); + } -/***/ }), -/* 896 */ -/***/ (function(module, exports, __webpack_require__) { + return; + } -"use strict"; + valueQueue.push(value); -Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(897); -function prepare(opts) { - const options = Object.assign({ - fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), - throwErrorOnBrokenSymlinks: true, - followSymlinks: true - }, opts); - return options; -} -exports.prepare = prepare; + if (isLimitReached) { + cancel(); + } + }; + const cancel = () => { + isDone = true; + for (const event of events) { + removeListener(event, valueHandler); + } -/***/ }), -/* 897 */ -/***/ (function(module, exports, __webpack_require__) { + for (const rejectionEvent of options.rejectionEvents) { + removeListener(rejectionEvent, rejectHandler); + } -"use strict"; + for (const resolutionEvent of options.resolutionEvents) { + removeListener(resolutionEvent, resolveHandler); + } -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 + while (nextQueue.length > 0) { + const {resolve} = nextQueue.shift(); + resolve({done: true, value: undefined}); + } + }; + + const rejectHandler = (...args) => { + error = options.multiArgs ? args : args[0]; + + if (nextQueue.length > 0) { + const {reject} = nextQueue.shift(); + reject(error); + } else { + hasPendingError = true; + } + + cancel(); + }; + + const resolveHandler = (...args) => { + const value = options.multiArgs ? args : args[0]; + + if (options.filter && !options.filter(value)) { + return; + } + + if (nextQueue.length > 0) { + const {resolve} = nextQueue.shift(); + resolve({done: true, value}); + } else { + valueQueue.push(value); + } + + cancel(); + }; + + for (const event of events) { + addListener(event, valueHandler); + } + + for (const rejectionEvent of options.rejectionEvents) { + addListener(rejectionEvent, rejectHandler); + } + + for (const resolutionEvent of options.resolutionEvents) { + addListener(resolutionEvent, resolveHandler); + } + + return { + [symbolAsyncIterator]() { + return this; + }, + async next() { + if (valueQueue.length > 0) { + const value = valueQueue.shift(); + return { + done: isDone && valueQueue.length === 0 && !isLimitReached, + value + }; + } + + if (hasPendingError) { + hasPendingError = false; + throw error; + } + + if (isDone) { + return { + done: true, + value: undefined + }; + } + + return new Promise((resolve, reject) => nextQueue.push({resolve, reject})); + }, + async return(value) { + cancel(); + return { + done: isDone, + value + }; + } + }; }; -function getFileSystemAdapter(fsMethods) { - if (!fsMethods) { - return exports.FILE_SYSTEM_ADAPTER; - } - return Object.assign({}, exports.FILE_SYSTEM_ADAPTER, fsMethods); -} -exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 898 */ +/* 909 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -function sync(path, options) { - const lstat = options.fs.lstatSync(path); - if (!isFollowedSymlink(lstat, options)) { - return lstat; - } - try { - const stat = options.fs.statSync(path); - stat.isSymbolicLink = () => true; - return stat; - } - catch (err) { - if (!options.throwErrorOnBrokenSymlinks) { - return lstat; - } - throw err; - } -} -exports.sync = sync; -function async(path, options, callback) { - options.fs.lstat(path, (err0, lstat) => { - if (err0) { - return callback(err0, undefined); - } - if (!isFollowedSymlink(lstat, options)) { - return callback(null, lstat); - } - options.fs.stat(path, (err1, stat) => { - if (err1) { - return options.throwErrorOnBrokenSymlinks ? callback(err1) : callback(null, lstat); - } - stat.isSymbolicLink = () => true; - callback(null, stat); - }); - }); -} -exports.async = async; -/** - * Returns `true` for followed symlink. - */ -function isFollowedSymlink(stat, options) { - return stat.isSymbolicLink() && options.followSymlinks; +const pFinally = __webpack_require__(910); + +class TimeoutError extends Error { + constructor(message) { + super(message); + this.name = 'TimeoutError'; + } } -exports.isFollowedSymlink = isFollowedSymlink; +module.exports = (promise, ms, fallback) => new Promise((resolve, reject) => { + if (typeof ms !== 'number' || ms < 0) { + throw new TypeError('Expected `ms` to be a positive number'); + } -/***/ }), -/* 899 */ -/***/ (function(module, exports, __webpack_require__) { + const timer = setTimeout(() => { + if (typeof fallback === 'function') { + try { + resolve(fallback()); + } catch (err) { + reject(err); + } + return; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var path = __webpack_require__(16); -var FileSystem = /** @class */ (function () { - function FileSystem(options) { - this.options = options; - } - /** - * Return full path to entry. - */ - FileSystem.prototype.getFullEntryPath = function (filepath) { - return path.resolve(this.options.cwd, filepath); - }; - /** - * Return an implementation of the Entry interface. - */ - FileSystem.prototype.makeEntry = function (stat, pattern) { - stat.path = pattern; - stat.depth = pattern.split('/').length; - return stat; - }; - return FileSystem; -}()); -exports.default = FileSystem; + const message = typeof fallback === 'string' ? fallback : `Promise timed out after ${ms} milliseconds`; + const err = fallback instanceof Error ? fallback : new TimeoutError(message); + + if (typeof promise.cancel === 'function') { + promise.cancel(); + } + + reject(err); + }, ms); + + pFinally( + promise.then(resolve, reject), + () => { + clearTimeout(timer); + } + ); +}); + +module.exports.TimeoutError = TimeoutError; /***/ }), -/* 900 */ +/* 910 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var stream = __webpack_require__(27); -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) { - var _this = _super.call(this, { objectMode: true }) || this; - _this.reader = reader; - return _this; - } - TransformStream.prototype._transform = function (entry, _encoding, callback) { - callback(null, this.reader.transform(entry)); - }; - return TransformStream; -}(stream.Transform)); -var ReaderStream = /** @class */ (function (_super) { - __extends(ReaderStream, _super); - function ReaderStream() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderStream.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_stream_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use stream API to read entries for Task. - */ - ReaderStream.prototype.read = function (task) { - var _this = this; - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - var transform = new TransformStream(this); - var readable = this.api(root, task, options); - return readable - .on('error', function (err) { return _this.isEnoentCodeError(err) ? null : transform.emit('error', err); }) - .pipe(transform); - }; - /** - * Returns founded paths. - */ - ReaderStream.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderStream.prototype.dynamicApi = function (root, options) { - return readdir.readdirStreamStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderStream.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderStream; -}(reader_1.default)); -exports.default = ReaderStream; + +module.exports = (promise, onFinally) => { + onFinally = onFinally || (() => {}); + + return promise.then( + val => new Promise(resolve => { + resolve(onFinally()); + }).then(() => val), + err => new Promise(resolve => { + resolve(onFinally()); + }).then(() => { + throw err; + }) + ); +}; /***/ }), -/* 901 */ +/* 911 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -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() { - return _super !== null && _super.apply(this, arguments) || this; - } - Object.defineProperty(ReaderSync.prototype, "fsAdapter", { - /** - * Returns FileSystem adapter. - */ - get: function () { - return new fs_sync_1.default(this.options); - }, - enumerable: true, - configurable: true - }); - /** - * Use sync API to read entries for Task. - */ - ReaderSync.prototype.read = function (task) { - var root = this.getRootDirectory(task); - var options = this.getReaderOptions(task); - try { - var entries = this.api(root, task, options); - return entries.map(this.transform, this); - } - catch (err) { - if (this.isEnoentCodeError(err)) { - return []; - } - throw err; - } - }; - /** - * Returns founded paths. - */ - ReaderSync.prototype.api = function (root, task, options) { - if (task.dynamic) { - return this.dynamicApi(root, options); - } - return this.staticApi(task, options); - }; - /** - * Api for dynamic tasks. - */ - ReaderSync.prototype.dynamicApi = function (root, options) { - return readdir.readdirSyncStat(root, options); - }; - /** - * Api for static tasks. - */ - ReaderSync.prototype.staticApi = function (task, options) { - return this.fsAdapter.read(task.patterns, options.filter); - }; - return ReaderSync; -}(reader_1.default)); -exports.default = ReaderSync; + +const NestedError = __webpack_require__(912); + +class CpFileError extends NestedError { + constructor(message, nested) { + super(message, nested); + Object.assign(this, nested); + this.name = 'CpFileError'; + } +} + +module.exports = CpFileError; /***/ }), -/* 902 */ +/* 912 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - -var __extends = (this && this.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(895); -var fs_1 = __webpack_require__(899); -var FileSystemSync = /** @class */ (function (_super) { - __extends(FileSystemSync, _super); - function FileSystemSync() { - return _super !== null && _super.apply(this, arguments) || this; - } - /** - * Use sync API to read entries for Task. - */ - FileSystemSync.prototype.read = function (patterns, filter) { - var _this = this; - var entries = []; - patterns.forEach(function (pattern) { - var filepath = _this.getFullEntryPath(pattern); - var entry = _this.getEntry(filepath, pattern); - if (entry === null || !filter(entry)) { - return; - } - entries.push(entry); - }); - return entries; - }; - /** - * Return entry for the provided path. - */ - FileSystemSync.prototype.getEntry = function (filepath, pattern) { - try { - var stat = this.getStat(filepath); - return this.makeEntry(stat, pattern); - } - catch (err) { - return null; - } - }; - /** - * Return fs.Stats for the provided path. - */ - FileSystemSync.prototype.getStat = function (filepath) { - return fsStat.statSync(filepath, { throwErrorOnBrokenSymlinks: false }); - }; - return FileSystemSync; -}(fs_1.default)); -exports.default = FileSystemSync; +var inherits = __webpack_require__(509); + +var NestedError = function (message, nested) { + this.nested = nested; + + if (typeof message !== 'undefined') { + Object.defineProperty(this, 'message', { + value: message, + writable: true, + enumerable: false, + configurable: true + }); + } + Error.captureStackTrace(this, this.constructor); + var oldStackDescriptor = Object.getOwnPropertyDescriptor(this, 'stack'); + var stackDescriptor = buildStackDescriptor(oldStackDescriptor, nested); + Object.defineProperty(this, 'stack', stackDescriptor); +}; -/***/ }), -/* 903 */ -/***/ (function(module, exports, __webpack_require__) { +function buildStackDescriptor(oldStackDescriptor, nested) { + if (oldStackDescriptor.get) { + return { + get: function () { + var stack = oldStackDescriptor.get.call(this); + return buildCombinedStacks(stack, this.nested); + } + }; + } else { + var stack = oldStackDescriptor.value; + return { + value: buildCombinedStacks(stack, nested) + }; + } +} -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -/** - * Flatten nested arrays (max depth is 2) into a non-nested array of non-array items. - */ -function flatten(items) { - return items.reduce(function (collection, item) { return [].concat(collection, item); }, []); -} -exports.flatten = flatten; +function buildCombinedStacks(stack, nested) { + if (nested) { + stack += '\nCaused By: ' + nested.stack; + } + return stack; +} +inherits(NestedError, Error); +NestedError.prototype.name = 'NestedError'; -/***/ }), -/* 904 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var merge2 = __webpack_require__(591); -/** - * Merge multiple streams and propagate their errors into one stream in parallel. - */ -function merge(streams) { - var mergedStream = merge2(streams); - streams.forEach(function (stream) { - stream.on('error', function (err) { return mergedStream.emit('error', err); }); - }); - return mergedStream; -} -exports.merge = merge; +module.exports = NestedError; /***/ }), -/* 905 */ +/* 913 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const path = __webpack_require__(16); -const pathType = __webpack_require__(906); +const {promisify} = __webpack_require__(29); +const fs = __webpack_require__(22); +const makeDir = __webpack_require__(914); +const pEvent = __webpack_require__(908); +const CpFileError = __webpack_require__(911); -const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; +const stat = promisify(fs.stat); +const lstat = promisify(fs.lstat); +const utimes = promisify(fs.utimes); +const chmod = promisify(fs.chmod); +const chown = promisify(fs.chown); -const getPath = (filepath, cwd) => { - const pth = filepath[0] === '!' ? filepath.slice(1) : filepath; - return path.isAbsolute(pth) ? pth : path.join(cwd, pth); -}; +exports.closeSync = fs.closeSync.bind(fs); +exports.createWriteStream = fs.createWriteStream.bind(fs); -const addExtensions = (file, extensions) => { - if (path.extname(file)) { - return `**/${file}`; +exports.createReadStream = async (path, options) => { + const read = fs.createReadStream(path, options); + + try { + await pEvent(read, ['readable', 'end']); + } catch (error) { + throw new CpFileError(`Cannot read from \`${path}\`: ${error.message}`, error); } - return `**/${file}.${getExtensions(extensions)}`; + return read; }; -const getGlob = (dir, opts) => { - if (opts.files && !Array.isArray(opts.files)) { - throw new TypeError(`Expected \`files\` to be of type \`Array\` but received type \`${typeof opts.files}\``); - } +exports.stat = path => stat(path).catch(error => { + throw new CpFileError(`Cannot stat path \`${path}\`: ${error.message}`, error); +}); - if (opts.extensions && !Array.isArray(opts.extensions)) { - throw new TypeError(`Expected \`extensions\` to be of type \`Array\` but received type \`${typeof opts.extensions}\``); - } +exports.lstat = path => lstat(path).catch(error => { + throw new CpFileError(`lstat \`${path}\` failed: ${error.message}`, error); +}); - if (opts.files && opts.extensions) { - return opts.files.map(x => path.join(dir, addExtensions(x, opts.extensions))); - } +exports.utimes = (path, atime, mtime) => utimes(path, atime, mtime).catch(error => { + throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); +}); - if (opts.files) { - return opts.files.map(x => path.join(dir, `**/${x}`)); - } +exports.chmod = (path, mode) => chmod(path, mode).catch(error => { + throw new CpFileError(`chmod \`${path}\` failed: ${error.message}`, error); +}); - if (opts.extensions) { - return [path.join(dir, `**/*.${getExtensions(opts.extensions)}`)]; - } +exports.chown = (path, uid, gid) => chown(path, uid, gid).catch(error => { + throw new CpFileError(`chown \`${path}\` failed: ${error.message}`, error); +}); - return [path.join(dir, '**')]; +exports.statSync = path => { + try { + return fs.statSync(path); + } catch (error) { + throw new CpFileError(`stat \`${path}\` failed: ${error.message}`, error); + } }; -module.exports = (input, opts) => { - opts = Object.assign({cwd: process.cwd()}, opts); +exports.utimesSync = (path, atime, mtime) => { + try { + return fs.utimesSync(path, atime, mtime); + } catch (error) { + throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); + } +}; - if (typeof opts.cwd !== 'string') { - return Promise.reject(new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``)); +exports.chmodSync = (path, mode) => { + try { + return fs.chmodSync(path, mode); + } catch (error) { + throw new CpFileError(`chmod \`${path}\` failed: ${error.message}`, error); } +}; - return Promise.all([].concat(input).map(x => pathType.dir(getPath(x, opts.cwd)) - .then(isDir => isDir ? getGlob(x, opts) : x))) - .then(globs => [].concat.apply([], globs)); +exports.chownSync = (path, uid, gid) => { + try { + return fs.chownSync(path, uid, gid); + } catch (error) { + throw new CpFileError(`chown \`${path}\` failed: ${error.message}`, error); + } }; -module.exports.sync = (input, opts) => { - opts = Object.assign({cwd: process.cwd()}, opts); +exports.makeDir = path => makeDir(path, {fs}).catch(error => { + throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); +}); - if (typeof opts.cwd !== 'string') { - throw new TypeError(`Expected \`cwd\` to be of type \`string\` but received type \`${typeof opts.cwd}\``); +exports.makeDirSync = path => { + try { + makeDir.sync(path, {fs}); + } catch (error) { + throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); } +}; - const globs = [].concat(input).map(x => pathType.dirSync(getPath(x, opts.cwd)) ? getGlob(x, opts) : x); - return [].concat.apply([], globs); +exports.copyFileSync = (source, destination, flags) => { + try { + fs.copyFileSync(source, destination, flags); + } catch (error) { + throw new CpFileError(`Cannot copy from \`${source}\` to \`${destination}\`: ${error.message}`, error); + } }; /***/ }), -/* 906 */ +/* 914 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const pify = __webpack_require__(907); - -function type(fn, fn2, fp) { - if (typeof fp !== 'string') { - return Promise.reject(new TypeError(`Expected a string, got ${typeof fp}`)); - } +const path = __webpack_require__(16); +const {promisify} = __webpack_require__(29); +const semver = __webpack_require__(915); - return pify(fs[fn])(fp) - .then(stats => stats[fn2]()) - .catch(err => { - if (err.code === 'ENOENT') { - return false; - } +const defaults = { + mode: 0o777 & (~process.umask()), + fs +}; - throw err; - }); -} +const useNativeRecursiveOption = semver.satisfies(process.version, '>=10.12.0'); -function typeSync(fn, fn2, fp) { - if (typeof fp !== 'string') { - throw new TypeError(`Expected a string, got ${typeof fp}`); - } +// https://github.com/nodejs/node/issues/8987 +// https://github.com/libuv/libuv/pull/1088 +const checkPath = pth => { + if (process.platform === 'win32') { + const pathHasInvalidWinCharacters = /[<>:"|?*]/.test(pth.replace(path.parse(pth).root, '')); - try { - return fs[fn](fp)[fn2](); - } catch (err) { - if (err.code === 'ENOENT') { - return false; + if (pathHasInvalidWinCharacters) { + const error = new Error(`Path contains invalid characters: ${pth}`); + error.code = 'EINVAL'; + throw error; } - - throw err; } -} - -exports.file = type.bind(null, 'stat', 'isFile'); -exports.dir = type.bind(null, 'stat', 'isDirectory'); -exports.symlink = type.bind(null, 'lstat', 'isSymbolicLink'); -exports.fileSync = typeSync.bind(null, 'statSync', 'isFile'); -exports.dirSync = typeSync.bind(null, 'statSync', 'isDirectory'); -exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); +}; +const permissionError = pth => { + // This replicates the exception of `fs.mkdir` with native the + // `recusive` option when run on an invalid drive under Windows. + const error = new Error(`operation not permitted, mkdir '${pth}'`); + error.code = 'EPERM'; + error.errno = -4048; + error.path = pth; + error.syscall = 'mkdir'; + return error; +}; -/***/ }), -/* 907 */ -/***/ (function(module, exports, __webpack_require__) { +const makeDir = async (input, options) => { + checkPath(input); + options = { + ...defaults, + ...options + }; -"use strict"; + const mkdir = promisify(options.fs.mkdir); + const stat = promisify(options.fs.stat); + if (useNativeRecursiveOption && options.fs.mkdir === fs.mkdir) { + const pth = path.resolve(input); -const processFn = (fn, opts) => function () { - const P = opts.promiseModule; - const args = new Array(arguments.length); + await mkdir(pth, { + mode: options.mode, + recursive: true + }); - for (let i = 0; i < arguments.length; i++) { - args[i] = arguments[i]; + return pth; } - return new P((resolve, reject) => { - if (opts.errorFirst) { - args.push(function (err, result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); + const make = async pth => { + try { + await mkdir(pth, options.mode); - for (let i = 1; i < arguments.length; i++) { - results[i - 1] = arguments[i]; - } + return pth; + } catch (error) { + if (error.code === 'EPERM') { + throw error; + } - if (err) { - results.unshift(err); - reject(results); - } else { - resolve(results); - } - } else if (err) { - reject(err); - } else { - resolve(result); + if (error.code === 'ENOENT') { + if (path.dirname(pth) === pth) { + throw permissionError(pth); } - }); - } else { - args.push(function (result) { - if (opts.multiArgs) { - const results = new Array(arguments.length - 1); - - for (let i = 0; i < arguments.length; i++) { - results[i] = arguments[i]; - } - resolve(results); - } else { - resolve(result); + if (error.message.includes('null bytes')) { + throw error; } - }); + + await make(path.dirname(pth)); + + return make(pth); + } + + const stats = await stat(pth); + if (!stats.isDirectory()) { + throw error; + } + + return pth; } + }; - fn.apply(this, args); - }); + return make(path.resolve(input)); }; -module.exports = (obj, opts) => { - opts = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, opts); +module.exports = makeDir; - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return opts.include ? opts.include.some(match) : !opts.exclude.some(match); +module.exports.sync = (input, options) => { + checkPath(input); + options = { + ...defaults, + ...options }; - let ret; - if (typeof obj === 'function') { - ret = function () { - if (opts.excludeMain) { - return obj.apply(this, arguments); - } + if (useNativeRecursiveOption && options.fs.mkdirSync === fs.mkdirSync) { + const pth = path.resolve(input); - return processFn(obj, opts).apply(this, arguments); - }; - } else { - ret = Object.create(Object.getPrototypeOf(obj)); - } + fs.mkdirSync(pth, { + mode: options.mode, + recursive: true + }); - for (const key in obj) { // eslint-disable-line guard-for-in - const x = obj[key]; - ret[key] = typeof x === 'function' && filter(key) ? processFn(x, opts) : x; + return pth; } - return ret; -}; - - -/***/ }), -/* 908 */ -/***/ (function(module, exports, __webpack_require__) { + const make = pth => { + try { + options.fs.mkdirSync(pth, options.mode); + } catch (error) { + if (error.code === 'EPERM') { + throw error; + } -"use strict"; + if (error.code === 'ENOENT') { + if (path.dirname(pth) === pth) { + throw permissionError(pth); + } -const fs = __webpack_require__(23); -const path = __webpack_require__(16); -const fastGlob = __webpack_require__(717); -const gitIgnore = __webpack_require__(909); -const pify = __webpack_require__(910); -const slash = __webpack_require__(911); + if (error.message.includes('null bytes')) { + throw error; + } -const DEFAULT_IGNORE = [ - '**/node_modules/**', - '**/bower_components/**', - '**/flow-typed/**', - '**/coverage/**', - '**/.git' -]; + make(path.dirname(pth)); + return make(pth); + } -const readFileP = pify(fs.readFile); + try { + if (!options.fs.statSync(pth).isDirectory()) { + throw new Error('The path is not a directory'); + } + } catch (_) { + throw error; + } + } -const mapGitIgnorePatternTo = base => ignore => { - if (ignore.startsWith('!')) { - return '!' + path.posix.join(base, ignore.slice(1)); - } + return pth; + }; - return path.posix.join(base, ignore); + return make(path.resolve(input)); }; -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.charAt(0) !== '#') - .map(mapGitIgnorePatternTo(base)); -}; +/***/ }), +/* 915 */ +/***/ (function(module, exports) { -const reduceIgnore = files => { - return files.reduce((ignores, file) => { - ignores.add(parseGitIgnore(file.content, { - cwd: file.cwd, - fileName: file.filePath - })); - return ignores; - }, gitIgnore()); -}; +exports = module.exports = SemVer -const getIsIgnoredPredecate = (ignores, cwd) => { - return p => ignores.ignores(slash(path.relative(cwd, p))); -}; +var debug +/* istanbul ignore next */ +if (typeof process === 'object' && + process.env && + process.env.NODE_DEBUG && + /\bsemver\b/i.test(process.env.NODE_DEBUG)) { + debug = function () { + var args = Array.prototype.slice.call(arguments, 0) + args.unshift('SEMVER') + console.log.apply(console, args) + } +} else { + debug = function () {} +} -const getFile = (file, cwd) => { - const filePath = path.join(cwd, file); - return readFileP(filePath, 'utf8') - .then(content => ({ - content, - cwd, - filePath - })); -}; +// Note: this is the semver.org version of the spec that it implements +// Not necessarily the package version of this code. +exports.SEMVER_SPEC_VERSION = '2.0.0' -const getFileSync = (file, cwd) => { - const filePath = path.join(cwd, file); - const content = fs.readFileSync(filePath, 'utf8'); +var MAX_LENGTH = 256 +var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || + /* istanbul ignore next */ 9007199254740991 - return { - content, - cwd, - filePath - }; -}; +// Max safe segment length for coercion. +var MAX_SAFE_COMPONENT_LENGTH = 16 -const normalizeOptions = (options = {}) => { - const ignore = options.ignore || []; - const cwd = options.cwd || process.cwd(); - return {ignore, cwd}; -}; +// The actual regexps go on exports.re +var re = exports.re = [] +var src = exports.src = [] +var R = 0 -module.exports = options => { - options = normalizeOptions(options); +// The following Regular Expressions can be used for tokenizing, +// validating, and parsing SemVer version strings. - return fastGlob('**/.gitignore', { - ignore: DEFAULT_IGNORE.concat(options.ignore), - cwd: options.cwd - }) - .then(paths => Promise.all(paths.map(file => getFile(file, options.cwd)))) - .then(files => reduceIgnore(files)) - .then(ignores => getIsIgnoredPredecate(ignores, options.cwd)); -}; +// ## Numeric Identifier +// A single `0`, or a non-zero digit followed by zero or more digits. -module.exports.sync = options => { - options = normalizeOptions(options); +var NUMERICIDENTIFIER = R++ +src[NUMERICIDENTIFIER] = '0|[1-9]\\d*' +var NUMERICIDENTIFIERLOOSE = R++ +src[NUMERICIDENTIFIERLOOSE] = '[0-9]+' - 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); +// ## Non-numeric Identifier +// Zero or more digits, followed by a letter or hyphen, and then zero or +// more letters, digits, or hyphens. - return getIsIgnoredPredecate(ignores, options.cwd); -}; +var NONNUMERICIDENTIFIER = R++ +src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*' +// ## Main Version +// Three dot-separated numeric identifiers. -/***/ }), -/* 909 */ -/***/ (function(module, exports) { +var MAINVERSION = R++ +src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')\\.' + + '(' + src[NUMERICIDENTIFIER] + ')' -// A simple implementation of make-array -function make_array (subject) { - return Array.isArray(subject) - ? subject - : [subject] -} +var MAINVERSIONLOOSE = R++ +src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[NUMERICIDENTIFIERLOOSE] + ')' + +// ## Pre-release Version Identifier +// A numeric identifier, or a non-numeric identifier. -const REGEX_BLANK_LINE = /^\s+$/ -const REGEX_LEADING_EXCAPED_EXCLAMATION = /^\\!/ -const REGEX_LEADING_EXCAPED_HASH = /^\\#/ -const SLASH = '/' -const KEY_IGNORE = typeof Symbol !== 'undefined' - ? Symbol.for('node-ignore') - /* istanbul ignore next */ - : 'node-ignore' +var PRERELEASEIDENTIFIER = R++ +src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + + '|' + src[NONNUMERICIDENTIFIER] + ')' -const define = (object, key, value) => - Object.defineProperty(object, key, {value}) +var PRERELEASEIDENTIFIERLOOSE = R++ +src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + + '|' + src[NONNUMERICIDENTIFIER] + ')' -const REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g +// ## Pre-release Version +// Hyphen, followed by one or more dot-separated pre-release version +// identifiers. -// 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. - : '' -) +var PRERELEASE = R++ +src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + + '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))' -// > 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` +var PRERELEASELOOSE = R++ +src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + + '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))' -// '`foo/`' should not continue with the '`..`' -const DEFAULT_REPLACER_PREFIX = [ +// ## Build Metadata Identifier +// Any combination of digits, letters, or hyphens. - // > Trailing spaces are ignored unless they are quoted with backslash ("\") - [ - // (a\ ) -> (a ) - // (a ) -> (a) - // (a \ ) -> (a ) - /\\?\s+$/, - match => match.indexOf('\\') === 0 - ? ' ' - : '' - ], +var BUILDIDENTIFIER = R++ +src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+' - // replace (\ ) with ' ' - [ - /\\\s/g, - () => ' ' - ], +// ## Build Metadata +// Plus sign, followed by one or more period-separated build metadata +// identifiers. - // Escape metacharacters - // which is written down by users but means special for regular expressions. +var BUILD = R++ +src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + + '(?:\\.' + src[BUILDIDENTIFIER] + ')*))' - // > 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}` - ], +// ## Full Version String +// A main version, followed optionally by a pre-release version and +// build metadata. - [ - // > [abc] matches any character inside the brackets - // > (in this case a, b, or c); - /\[([^\]/]*)($|\])/g, - (match, p1, p2) => p2 === ']' - ? `[${sanitizeRange(p1)}]` - : `\\${match}` - ], +// Note that the only major, minor, patch, and pre-release sections of +// the version string are capturing groups. The build metadata is not a +// capturing group, because it should not ever be used in version +// comparison. - [ - // > a question mark (?) matches a single character - /(?!\\)\?/g, - () => '[^/]' - ], +var FULL = R++ +var FULLPLAIN = 'v?' + src[MAINVERSION] + + src[PRERELEASE] + '?' + + src[BUILD] + '?' - // leading slash - [ +src[FULL] = '^' + FULLPLAIN + '$' - // > 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 - /^\//, - () => '^' - ], +// like full, but allows v1.2.3 and =1.2.3, which people do sometimes. +// also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty +// common in the npm registry. +var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + + src[PRERELEASELOOSE] + '?' + + src[BUILD] + '?' - // replace special metacharacter slash after the leading slash - [ - /\//g, - () => '\\/' - ], +var LOOSE = R++ +src[LOOSE] = '^' + LOOSEPLAIN + '$' - [ - // > 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 '\\*' - /^\^*\\\*\\\*\\\//, +var GTLT = R++ +src[GTLT] = '((?:<|>)?=?)' - // '**/foo' <-> 'foo' - () => '^(?:.*\\/)?' - ] -] +// Something like "2.*" or "1.2.x". +// Note that "x.x" is a valid xRange identifer, meaning "any version" +// Only the first item is strictly required. +var XRANGEIDENTIFIERLOOSE = R++ +src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*' +var XRANGEIDENTIFIER = R++ +src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*' -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 - ? '(?:^|\\/)' +var XRANGEPLAIN = R++ +src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + + '(?:' + src[PRERELEASE] + ')?' + + src[BUILD] + '?' + + ')?)?' - // > Otherwise, Git treats the pattern as a shell glob suitable for - // > consumption by fnmatch(3) - : '^' - } - ], +var XRANGEPLAINLOOSE = R++ +src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + + '(?:' + src[PRERELEASELOOSE] + ')?' + + src[BUILD] + '?' + + ')?)?' - // two globstars - [ - // Use lookahead assertions so that we could match more than one `'/**'` - /\\\/\\\*\\\*(?=\\\/|$)/g, +var XRANGE = R++ +src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$' +var XRANGELOOSE = R++ +src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$' - // Zero, one or several directories - // should not use '*', or it will be replaced by the next replacer +// Coercion. +// Extract anything that could conceivably be a part of a valid semver +var COERCE = R++ +src[COERCE] = '(?:^|[^\\d])' + + '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + + '(?:$|[^\\d])' - // Check if it is not the last `'/**'` - (match, index, str) => index + 6 < str.length +// Tilde ranges. +// Meaning is "reasonably at or greater than" +var LONETILDE = R++ +src[LONETILDE] = '(?:~>?)' - // 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. - // '/**/' - ? '(?:\\/[^\\/]+)*' +var TILDETRIM = R++ +src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+' +re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g') +var tildeTrimReplace = '$1~' - // case: /** - // > A trailing `"/**"` matches everything inside. +var TILDE = R++ +src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$' +var TILDELOOSE = R++ +src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$' - // #21: everything inside but it should not include the current folder - : '\\/.+' - ], +// Caret ranges. +// Meaning is "at least and backwards compatible with" +var LONECARET = R++ +src[LONECARET] = '(?:\\^)' - // intermediate wildcards - [ - // Never replace escaped '*' - // ignore rule '\*' will match the path '*' +var CARETTRIM = R++ +src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+' +re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g') +var caretTrimReplace = '$1^' - // 'abc.*/' -> go - // 'abc.*' -> skip this rule - /(^|[^\\]+)\\\*(?=.+)/g, +var CARET = R++ +src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$' +var CARETLOOSE = R++ +src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$' - // '*.js' matches '.js' - // '*.js' doesn't match 'abc' - (match, p1) => `${p1}[^\\/]*` - ], +// A simple gt/lt/eq thing, or just "" to indicate "any version" +var COMPARATORLOOSE = R++ +src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$' +var COMPARATOR = R++ +src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$' - // trailing wildcard - [ - /(\^|\\\/)?\\\*$/, - (match, p1) => { - const prefix = p1 - // '\^': - // '/*' does not match '' - // '/*' does not match everything +// An expression to strip any whitespace between the gtlt and the thing +// it modifies, so that `> 1.2.3` ==> `>1.2.3` +var COMPARATORTRIM = R++ +src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + + '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')' - // '\\\/': - // 'abc/*' does not match 'abc/' - ? `${p1}[^/]+` +// this one has to use the /g flag +re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g') +var comparatorTrimReplace = '$1$2$3' - // 'a*' matches 'a' - // 'a*' matches 'aa' - : '[^/]*' +// Something like `1.2.3 - 1.2.4` +// Note that these all use the loose form, because they'll be +// checked against either the strict or loose comparator form +// later. +var HYPHENRANGE = R++ +src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAIN] + ')' + + '\\s*$' - return `${prefix}(?=$|\\/$)` - } - ], +var HYPHENRANGELOOSE = R++ +src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s+-\\s+' + + '(' + src[XRANGEPLAINLOOSE] + ')' + + '\\s*$' - [ - // unescape - /\\\\\\/g, - () => '\\' - ] -] +// Star ranges basically just allow anything at all. +var STAR = R++ +src[STAR] = '(<|>)?=?\\s*\\*' -const POSITIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, +// Compile to actual regexp objects. +// All are flag-free, unless they were created above with a flag. +for (var i = 0; i < R; i++) { + debug(i, src[i]) + if (!re[i]) { + re[i] = new RegExp(src[i]) + } +} - // 'f' - // matches - // - /f(end) - // - /f/ - // - (start)f(end) - // - (start)f/ - // doesn't match - // - oof - // - foo - // pseudo: - // -> (^|/)f(/|$) +exports.parse = parse +function parse (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } - // ending - [ - // 'js' will not match 'js.' - // 'ab' will not match 'abc' - /(?:[^*/])$/, + if (version instanceof SemVer) { + return version + } - // 'js*' will not match 'a.js' - // 'js/' will not match 'a.js' - // 'js' will match 'a.js' and 'a.js/' - match => `${match}(?=$|\\/)` - ], + if (typeof version !== 'string') { + return null + } - ...DEFAULT_REPLACER_SUFFIX -] + if (version.length > MAX_LENGTH) { + return null + } -const NEGATIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, + var r = options.loose ? re[LOOSE] : re[FULL] + if (!r.test(version)) { + return null + } - // #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. + try { + return new SemVer(version, options) + } catch (er) { + return null + } +} - // eg: - // ['node_modules/*', '!node_modules'] - // should ignore `node_modules/a.js` - [ - /(?:[^*])$/, - match => `${match}(?=$|\\/$)` - ], +exports.valid = valid +function valid (version, options) { + var v = parse(version, options) + return v ? v.version : null +} - ...DEFAULT_REPLACER_SUFFIX -] +exports.clean = clean +function clean (version, options) { + var s = parse(version.trim().replace(/^[=v]+/, ''), options) + return s ? s.version : null +} -// A simple cache, because an ignore rule only has only one certain meaning -const cache = Object.create(null) +exports.SemVer = SemVer -// @param {pattern} -const make_regex = (pattern, negative, ignorecase) => { - const r = cache[pattern] - if (r) { - return r +function SemVer (version, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + if (version instanceof SemVer) { + if (version.loose === options.loose) { + return version + } else { + version = version.version + } + } else if (typeof version !== 'string') { + throw new TypeError('Invalid Version: ' + version) } - const replacers = negative - ? NEGATIVE_REPLACERS - : POSITIVE_REPLACERS + if (version.length > MAX_LENGTH) { + throw new TypeError('version is longer than ' + MAX_LENGTH + ' characters') + } - const source = replacers.reduce( - (prev, current) => prev.replace(current[0], current[1].bind(pattern)), - pattern - ) + if (!(this instanceof SemVer)) { + return new SemVer(version, options) + } - return cache[pattern] = ignorecase - ? new RegExp(source, 'i') - : new RegExp(source) -} + debug('SemVer', version, options) + this.options = options + this.loose = !!options.loose -// > A blank line matches no files, so it can serve as a separator for readability. -const checkPattern = pattern => pattern - && typeof pattern === 'string' - && !REGEX_BLANK_LINE.test(pattern) + var m = version.trim().match(options.loose ? re[LOOSE] : re[FULL]) - // > A line starting with # serves as a comment. - && pattern.indexOf('#') !== 0 + if (!m) { + throw new TypeError('Invalid Version: ' + version) + } -const createRule = (pattern, ignorecase) => { - const origin = pattern - let negative = false + this.raw = version - // > An optional prefix "!" which negates the pattern; - if (pattern.indexOf('!') === 0) { - negative = true - pattern = pattern.substr(1) + // these are actually numbers + this.major = +m[1] + this.minor = +m[2] + this.patch = +m[3] + + if (this.major > MAX_SAFE_INTEGER || this.major < 0) { + throw new TypeError('Invalid major version') } - pattern = pattern - // > Put a backslash ("\") in front of the first "!" for patterns that - // > begin with a literal "!", for example, `"\!important!.txt"`. - .replace(REGEX_LEADING_EXCAPED_EXCLAMATION, '!') - // > Put a backslash ("\") in front of the first hash for patterns that - // > begin with a hash. - .replace(REGEX_LEADING_EXCAPED_HASH, '#') + if (this.minor > MAX_SAFE_INTEGER || this.minor < 0) { + throw new TypeError('Invalid minor version') + } - const regex = make_regex(pattern, negative, ignorecase) + if (this.patch > MAX_SAFE_INTEGER || this.patch < 0) { + throw new TypeError('Invalid patch version') + } - return { - origin, - pattern, - negative, - regex + // numberify any prerelease numeric ids + if (!m[4]) { + this.prerelease = [] + } else { + this.prerelease = m[4].split('.').map(function (id) { + if (/^[0-9]+$/.test(id)) { + var num = +id + if (num >= 0 && num < MAX_SAFE_INTEGER) { + return num + } + } + return id + }) } + + this.build = m[5] ? m[5].split('.') : [] + this.format() } -class IgnoreBase { - constructor ({ - ignorecase = true - } = {}) { - this._rules = [] - this._ignorecase = ignorecase - define(this, KEY_IGNORE, true) - this._initCache() +SemVer.prototype.format = function () { + this.version = this.major + '.' + this.minor + '.' + this.patch + if (this.prerelease.length) { + this.version += '-' + this.prerelease.join('.') } + return this.version +} - _initCache () { - this._cache = Object.create(null) - } +SemVer.prototype.toString = function () { + return this.version +} - // @param {Array.|string|Ignore} pattern - add (pattern) { - this._added = false +SemVer.prototype.compare = function (other) { + debug('SemVer.compare', this.version, this.options, other) + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } - if (typeof pattern === 'string') { - pattern = pattern.split(/\r?\n/g) - } + return this.compareMain(other) || this.comparePre(other) +} - make_array(pattern).forEach(this._addPattern, this) +SemVer.prototype.compareMain = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) + } - // Some rules have just added to the ignore, - // making the behavior changed. - if (this._added) { - this._initCache() - } + return compareIdentifiers(this.major, other.major) || + compareIdentifiers(this.minor, other.minor) || + compareIdentifiers(this.patch, other.patch) +} - return this +SemVer.prototype.comparePre = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) } - // legacy - addPattern (pattern) { - return this.add(pattern) + // NOT having a prerelease is > having one + if (this.prerelease.length && !other.prerelease.length) { + return -1 + } else if (!this.prerelease.length && other.prerelease.length) { + return 1 + } else if (!this.prerelease.length && !other.prerelease.length) { + return 0 } - _addPattern (pattern) { - // #32 - if (pattern && pattern[KEY_IGNORE]) { - this._rules = this._rules.concat(pattern._rules) - this._added = true - return + var i = 0 + do { + var a = this.prerelease[i] + var b = other.prerelease[i] + debug('prerelease compare', i, a, b) + if (a === undefined && b === undefined) { + return 0 + } else if (b === undefined) { + return 1 + } else if (a === undefined) { + return -1 + } else if (a === b) { + continue + } else { + return compareIdentifiers(a, b) } + } while (++i) +} - if (checkPattern(pattern)) { - const rule = createRule(pattern, this._ignorecase) - this._added = true - this._rules.push(rule) - } +SemVer.prototype.compareBuild = function (other) { + if (!(other instanceof SemVer)) { + other = new SemVer(other, this.options) } - filter (paths) { - return make_array(paths).filter(path => this._filter(path)) - } + var i = 0 + do { + var a = this.build[i] + var b = other.build[i] + debug('prerelease compare', i, a, b) + if (a === undefined && b === undefined) { + return 0 + } else if (b === undefined) { + return 1 + } else if (a === undefined) { + return -1 + } else if (a === b) { + continue + } else { + return compareIdentifiers(a, b) + } + } while (++i) +} - createFilter () { - return path => this._filter(path) +// preminor will bump the version up to the next minor release, and immediately +// down to pre-release. premajor and prepatch work the same way. +SemVer.prototype.inc = function (release, identifier) { + switch (release) { + case 'premajor': + this.prerelease.length = 0 + this.patch = 0 + this.minor = 0 + this.major++ + this.inc('pre', identifier) + break + case 'preminor': + this.prerelease.length = 0 + this.patch = 0 + this.minor++ + this.inc('pre', identifier) + break + case 'prepatch': + // If this is already a prerelease, it will bump to the next version + // drop any prereleases that might already exist, since they are not + // relevant at this point. + this.prerelease.length = 0 + this.inc('patch', identifier) + this.inc('pre', identifier) + break + // If the input is a non-prerelease version, this acts the same as + // prepatch. + case 'prerelease': + if (this.prerelease.length === 0) { + this.inc('patch', identifier) + } + this.inc('pre', identifier) + break + + case 'major': + // If this is a pre-major version, bump up to the same major version. + // Otherwise increment major. + // 1.0.0-5 bumps to 1.0.0 + // 1.1.0 bumps to 2.0.0 + if (this.minor !== 0 || + this.patch !== 0 || + this.prerelease.length === 0) { + this.major++ + } + this.minor = 0 + this.patch = 0 + this.prerelease = [] + break + case 'minor': + // If this is a pre-minor version, bump up to the same minor version. + // Otherwise increment minor. + // 1.2.0-5 bumps to 1.2.0 + // 1.2.1 bumps to 1.3.0 + if (this.patch !== 0 || this.prerelease.length === 0) { + this.minor++ + } + this.patch = 0 + this.prerelease = [] + break + case 'patch': + // If this is not a pre-release version, it will increment the patch. + // If it is a pre-release it will bump up to the same patch version. + // 1.2.0-5 patches to 1.2.0 + // 1.2.0 patches to 1.2.1 + if (this.prerelease.length === 0) { + this.patch++ + } + this.prerelease = [] + break + // This probably shouldn't be used publicly. + // 1.0.0 "pre" would become 1.0.0-0 which is the wrong direction. + case 'pre': + if (this.prerelease.length === 0) { + this.prerelease = [0] + } else { + var i = this.prerelease.length + while (--i >= 0) { + if (typeof this.prerelease[i] === 'number') { + this.prerelease[i]++ + i = -2 + } + } + if (i === -1) { + // didn't increment anything + this.prerelease.push(0) + } + } + if (identifier) { + // 1.2.0-beta.1 bumps to 1.2.0-beta.2, + // 1.2.0-beta.fooblz or 1.2.0-beta bumps to 1.2.0-beta.0 + if (this.prerelease[0] === identifier) { + if (isNaN(this.prerelease[1])) { + this.prerelease = [identifier, 0] + } + } else { + this.prerelease = [identifier, 0] + } + } + break + + default: + throw new Error('invalid increment argument: ' + release) } + this.format() + this.raw = this.version + return this +} - ignores (path) { - return !this._filter(path) +exports.inc = inc +function inc (version, release, loose, identifier) { + if (typeof (loose) === 'string') { + identifier = loose + loose = undefined } - // @returns `Boolean` true if the `path` is NOT ignored - _filter (path, slices) { - if (!path) { - return false - } + try { + return new SemVer(version, loose).inc(release, identifier).version + } catch (er) { + return null + } +} - if (path in this._cache) { - return this._cache[path] +exports.diff = diff +function diff (version1, version2) { + if (eq(version1, version2)) { + return null + } else { + var v1 = parse(version1) + var v2 = parse(version2) + var prefix = '' + if (v1.prerelease.length || v2.prerelease.length) { + prefix = 'pre' + var defaultResult = 'prerelease' } - - if (!slices) { - // path/to/a.js - // ['path', 'to', 'a.js'] - slices = path.split(SLASH) + for (var key in v1) { + if (key === 'major' || key === 'minor' || key === 'patch') { + if (v1[key] !== v2[key]) { + return prefix + key + } + } } + return defaultResult // may be undefined + } +} - slices.pop() +exports.compareIdentifiers = compareIdentifiers - return this._cache[path] = slices.length - // > It is not possible to re-include a file if a parent directory of - // > that file is excluded. - // If the path contains a parent directory, check the parent first - ? this._filter(slices.join(SLASH) + SLASH, slices) - && this._test(path) +var numeric = /^[0-9]+$/ +function compareIdentifiers (a, b) { + var anum = numeric.test(a) + var bnum = numeric.test(b) - // Or only test the path - : this._test(path) + if (anum && bnum) { + a = +a + b = +b } - // @returns {Boolean} true if a file is NOT ignored - _test (path) { - // Explicitly define variable type by setting matched to `0` - let matched = 0 + return a === b ? 0 + : (anum && !bnum) ? -1 + : (bnum && !anum) ? 1 + : a < b ? -1 + : 1 +} - this._rules.forEach(rule => { - // if matched = true, then we only test negative rules - // if matched = false, then we test non-negative rules - if (!(matched ^ rule.negative)) { - matched = rule.negative ^ rule.regex.test(path) - } - }) +exports.rcompareIdentifiers = rcompareIdentifiers +function rcompareIdentifiers (a, b) { + return compareIdentifiers(b, a) +} - return !matched - } +exports.major = major +function major (a, loose) { + return new SemVer(a, loose).major } -// 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' - ) -) { - const filter = IgnoreBase.prototype._filter +exports.minor = minor +function minor (a, loose) { + return new SemVer(a, loose).minor +} - /* eslint no-control-regex: "off" */ - const make_posix = str => /^\\\\\?\\/.test(str) - || /[^\x00-\x80]+/.test(str) - ? str - : str.replace(/\\/g, '/') +exports.patch = patch +function patch (a, loose) { + return new SemVer(a, loose).patch +} - IgnoreBase.prototype._filter = function filterWin32 (path, slices) { - path = make_posix(path) - return filter.call(this, path, slices) - } +exports.compare = compare +function compare (a, b, loose) { + return new SemVer(a, loose).compare(new SemVer(b, loose)) } -module.exports = options => new IgnoreBase(options) +exports.compareLoose = compareLoose +function compareLoose (a, b) { + return compare(a, b, true) +} +exports.compareBuild = compareBuild +function compareBuild (a, b, loose) { + var versionA = new SemVer(a, loose) + var versionB = new SemVer(b, loose) + return versionA.compare(versionB) || versionA.compareBuild(versionB) +} -/***/ }), -/* 910 */ -/***/ (function(module, exports, __webpack_require__) { +exports.rcompare = rcompare +function rcompare (a, b, loose) { + return compare(b, a, loose) +} -"use strict"; +exports.sort = sort +function sort (list, loose) { + return list.sort(function (a, b) { + return exports.compareBuild(a, b, loose) + }) +} +exports.rsort = rsort +function rsort (list, loose) { + return list.sort(function (a, b) { + return exports.compareBuild(b, a, loose) + }) +} -const processFn = (fn, options) => function (...args) { - const P = options.promiseModule; +exports.gt = gt +function gt (a, b, loose) { + return compare(a, b, loose) > 0 +} - return new P((resolve, reject) => { - if (options.multiArgs) { - args.push((...result) => { - if (options.errorFirst) { - if (result[0]) { - reject(result); - } else { - result.shift(); - resolve(result); - } - } else { - resolve(result); - } - }); - } else if (options.errorFirst) { - args.push((error, result) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); - } else { - args.push(resolve); - } +exports.lt = lt +function lt (a, b, loose) { + return compare(a, b, loose) < 0 +} - fn.apply(this, args); - }); -}; +exports.eq = eq +function eq (a, b, loose) { + return compare(a, b, loose) === 0 +} -module.exports = (input, options) => { - options = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, options); +exports.neq = neq +function neq (a, b, loose) { + return compare(a, b, loose) !== 0 +} - const objType = typeof input; - if (!(input !== null && (objType === 'object' || objType === 'function'))) { - throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objType}\``); - } +exports.gte = gte +function gte (a, b, loose) { + return compare(a, b, loose) >= 0 +} - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return options.include ? options.include.some(match) : !options.exclude.some(match); - }; +exports.lte = lte +function lte (a, b, loose) { + return compare(a, b, loose) <= 0 +} - let ret; - if (objType === 'function') { - ret = function (...args) { - return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args); - }; - } else { - ret = Object.create(Object.getPrototypeOf(input)); - } +exports.cmp = cmp +function cmp (a, op, b, loose) { + switch (op) { + case '===': + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a === b - for (const key in input) { // eslint-disable-line guard-for-in - const property = input[key]; - ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property; - } + case '!==': + if (typeof a === 'object') + a = a.version + if (typeof b === 'object') + b = b.version + return a !== b - return ret; -}; + case '': + case '=': + case '==': + return eq(a, b, loose) + case '!=': + return neq(a, b, loose) -/***/ }), -/* 911 */ -/***/ (function(module, exports, __webpack_require__) { + case '>': + return gt(a, b, loose) -"use strict"; + case '>=': + return gte(a, b, loose) -module.exports = input => { - const isExtendedLengthPath = /^\\\\\?\\/.test(input); - const hasNonAscii = /[^\u0000-\u0080]+/.test(input); // eslint-disable-line no-control-regex + case '<': + return lt(a, b, loose) - if (isExtendedLengthPath || hasNonAscii) { - return input; - } + case '<=': + return lte(a, b, loose) - return input.replace(/\\/g, '/'); -}; + default: + throw new TypeError('Invalid operator: ' + op) + } +} + +exports.Comparator = Comparator +function Comparator (comp, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } + if (comp instanceof Comparator) { + if (comp.loose === !!options.loose) { + return comp + } else { + comp = comp.value + } + } -/***/ }), -/* 912 */ -/***/ (function(module, exports, __webpack_require__) { + if (!(this instanceof Comparator)) { + return new Comparator(comp, options) + } -"use strict"; + debug('comparator', comp, options) + this.options = options + this.loose = !!options.loose + this.parse(comp) -const path = __webpack_require__(16); -const {constants: fsConstants} = __webpack_require__(23); -const {Buffer} = __webpack_require__(913); -const CpFileError = __webpack_require__(914); -const fs = __webpack_require__(918); -const ProgressEmitter = __webpack_require__(920); + if (this.semver === ANY) { + this.value = '' + } else { + this.value = this.operator + this.semver.version + } -const cpFile = (source, destination, options) => { - if (!source || !destination) { - return Promise.reject(new CpFileError('`source` and `destination` required')); - } + debug('comp', this) +} - options = Object.assign({overwrite: true}, options); +var ANY = {} +Comparator.prototype.parse = function (comp) { + var r = this.options.loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var m = comp.match(r) - const progressEmitter = new ProgressEmitter(path.resolve(source), path.resolve(destination)); + if (!m) { + throw new TypeError('Invalid comparator: ' + comp) + } - const promise = fs - .stat(source) - .then(stat => { - progressEmitter.size = stat.size; - }) - .then(() => fs.createReadStream(source)) - .then(read => fs.makeDir(path.dirname(destination)).then(() => read)) - .then(read => new Promise((resolve, reject) => { - const write = fs.createWriteStream(destination, {flags: options.overwrite ? 'w' : 'wx'}); + this.operator = m[1] !== undefined ? m[1] : '' + if (this.operator === '=') { + this.operator = '' + } - read.on('data', () => { - progressEmitter.written = write.bytesWritten; - }); + // if it literally is just '>' or '' then allow anything. + if (!m[2]) { + this.semver = ANY + } else { + this.semver = new SemVer(m[2], this.options.loose) + } +} - write.on('error', error => { - if (!options.overwrite && error.code === 'EEXIST') { - resolve(false); - return; - } +Comparator.prototype.toString = function () { + return this.value +} - reject(new CpFileError(`Cannot write to \`${destination}\`: ${error.message}`, error)); - }); +Comparator.prototype.test = function (version) { + debug('Comparator.test', version, this.options.loose) - write.on('close', () => { - progressEmitter.written = progressEmitter.size; - resolve(true); - }); + if (this.semver === ANY || version === ANY) { + return true + } - read.pipe(write); - })) - .then(updateStats => { - if (updateStats) { - return fs.lstat(source).then(stats => Promise.all([ - fs.utimes(destination, stats.atime, stats.mtime), - fs.chmod(destination, stats.mode), - fs.chown(destination, stats.uid, stats.gid) - ])); - } - }); + if (typeof version === 'string') { + try { + version = new SemVer(version, this.options) + } catch (er) { + return false + } + } - promise.on = (...args) => { - progressEmitter.on(...args); - return promise; - }; + return cmp(version, this.operator, this.semver, this.options) +} - return promise; -}; +Comparator.prototype.intersects = function (comp, options) { + if (!(comp instanceof Comparator)) { + throw new TypeError('a Comparator is required') + } -module.exports = cpFile; -// TODO: Remove this for the next major release -module.exports.default = cpFile; + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } -const checkSourceIsFile = (stat, source) => { - if (stat.isDirectory()) { - throw Object.assign(new CpFileError(`EISDIR: illegal operation on a directory '${source}'`), { - errno: -21, - code: 'EISDIR', - source - }); - } -}; + var rangeTmp -const fixupAttributes = (destination, stat) => { - fs.chmodSync(destination, stat.mode); - fs.chownSync(destination, stat.uid, stat.gid); -}; + if (this.operator === '') { + if (this.value === '') { + return true + } + rangeTmp = new Range(comp.value, options) + return satisfies(this.value, rangeTmp, options) + } else if (comp.operator === '') { + if (comp.value === '') { + return true + } + rangeTmp = new Range(this.value, options) + return satisfies(comp.semver, rangeTmp, options) + } -const copySyncNative = (source, destination, options) => { - const stat = fs.statSync(source); - checkSourceIsFile(stat, source); - fs.makeDirSync(path.dirname(destination)); + var sameDirectionIncreasing = + (this.operator === '>=' || this.operator === '>') && + (comp.operator === '>=' || comp.operator === '>') + var sameDirectionDecreasing = + (this.operator === '<=' || this.operator === '<') && + (comp.operator === '<=' || comp.operator === '<') + var sameSemVer = this.semver.version === comp.semver.version + var differentDirectionsInclusive = + (this.operator === '>=' || this.operator === '<=') && + (comp.operator === '>=' || comp.operator === '<=') + var oppositeDirectionsLessThan = + cmp(this.semver, '<', comp.semver, options) && + ((this.operator === '>=' || this.operator === '>') && + (comp.operator === '<=' || comp.operator === '<')) + var oppositeDirectionsGreaterThan = + cmp(this.semver, '>', comp.semver, options) && + ((this.operator === '<=' || this.operator === '<') && + (comp.operator === '>=' || comp.operator === '>')) - const flags = options.overwrite ? null : fsConstants.COPYFILE_EXCL; - try { - fs.copyFileSync(source, destination, flags); - } catch (error) { - if (!options.overwrite && error.code === 'EEXIST') { - return; - } + return sameDirectionIncreasing || sameDirectionDecreasing || + (sameSemVer && differentDirectionsInclusive) || + oppositeDirectionsLessThan || oppositeDirectionsGreaterThan +} - throw error; - } +exports.Range = Range +function Range (range, options) { + if (!options || typeof options !== 'object') { + options = { + loose: !!options, + includePrerelease: false + } + } - fs.utimesSync(destination, stat.atime, stat.mtime); - fixupAttributes(destination, stat); -}; + if (range instanceof Range) { + if (range.loose === !!options.loose && + range.includePrerelease === !!options.includePrerelease) { + return range + } else { + return new Range(range.raw, options) + } + } -const copySyncFallback = (source, destination, options) => { - let bytesRead; - let position; - let read; // eslint-disable-line prefer-const - let write; - const BUF_LENGTH = 100 * 1024; - const buffer = Buffer.alloc(BUF_LENGTH); - const readSync = position => fs.readSync(read, buffer, 0, BUF_LENGTH, position, source); - const writeSync = () => fs.writeSync(write, buffer, 0, bytesRead, undefined, destination); + if (range instanceof Comparator) { + return new Range(range.value, options) + } - read = fs.openSync(source, 'r'); - bytesRead = readSync(0); - position = bytesRead; - fs.makeDirSync(path.dirname(destination)); + if (!(this instanceof Range)) { + return new Range(range, options) + } - try { - write = fs.openSync(destination, options.overwrite ? 'w' : 'wx'); - } catch (error) { - if (!options.overwrite && error.code === 'EEXIST') { - return; - } + this.options = options + this.loose = !!options.loose + this.includePrerelease = !!options.includePrerelease - throw error; - } + // First, split based on boolean or || + this.raw = range + this.set = range.split(/\s*\|\|\s*/).map(function (range) { + return this.parseRange(range.trim()) + }, this).filter(function (c) { + // throw out any that are not relevant for whatever reason + return c.length + }) - writeSync(); + if (!this.set.length) { + throw new TypeError('Invalid SemVer Range: ' + range) + } - while (bytesRead === BUF_LENGTH) { - bytesRead = readSync(position); - writeSync(); - position += bytesRead; - } + this.format() +} - const stat = fs.fstatSync(read, source); - fs.futimesSync(write, stat.atime, stat.mtime, destination); - fs.closeSync(read); - fs.closeSync(write); - fixupAttributes(destination, stat); -}; +Range.prototype.format = function () { + this.range = this.set.map(function (comps) { + return comps.join(' ').trim() + }).join('||').trim() + return this.range +} -module.exports.sync = (source, destination, options) => { - if (!source || !destination) { - throw new CpFileError('`source` and `destination` required'); - } +Range.prototype.toString = function () { + return this.range +} - options = Object.assign({overwrite: true}, options); +Range.prototype.parseRange = function (range) { + var loose = this.options.loose + range = range.trim() + // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` + var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE] + range = range.replace(hr, hyphenReplace) + debug('hyphen replace', range) + // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` + range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace) + debug('comparator trim', range, re[COMPARATORTRIM]) - if (fs.copyFileSync) { - copySyncNative(source, destination, options); - } else { - copySyncFallback(source, destination, options); - } -}; + // `~ 1.2.3` => `~1.2.3` + range = range.replace(re[TILDETRIM], tildeTrimReplace) + // `^ 1.2.3` => `^1.2.3` + range = range.replace(re[CARETTRIM], caretTrimReplace) -/***/ }), -/* 913 */ -/***/ (function(module, exports, __webpack_require__) { + // normalize spaces + range = range.split(/\s+/).join(' ') -/* eslint-disable node/no-deprecated-api */ -var buffer = __webpack_require__(585) -var Buffer = buffer.Buffer + // At this point, the range is completely trimmed and + // ready to be split into comparators. -// alternative to using Object.keys for old browsers -function copyProps (src, dst) { - for (var key in src) { - dst[key] = src[key] + var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var set = range.split(' ').map(function (comp) { + return parseComparator(comp, this.options) + }, this).join(' ').split(/\s+/) + if (this.options.loose) { + // in loose mode, throw out any that are not valid comparators + set = set.filter(function (comp) { + return !!comp.match(compRe) + }) } -} -if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { - module.exports = buffer -} else { - // Copy properties from require('buffer') - copyProps(buffer, exports) - exports.Buffer = SafeBuffer + set = set.map(function (comp) { + return new Comparator(comp, this.options) + }, this) + + return set } -function SafeBuffer (arg, encodingOrOffset, length) { - return Buffer(arg, encodingOrOffset, length) +Range.prototype.intersects = function (range, options) { + if (!(range instanceof Range)) { + throw new TypeError('a Range is required') + } + + return this.set.some(function (thisComparators) { + return ( + isSatisfiable(thisComparators, options) && + range.set.some(function (rangeComparators) { + return ( + isSatisfiable(rangeComparators, options) && + thisComparators.every(function (thisComparator) { + return rangeComparators.every(function (rangeComparator) { + return thisComparator.intersects(rangeComparator, options) + }) + }) + ) + }) + ) + }) } -// Copy static methods from Buffer -copyProps(Buffer, SafeBuffer) +// take a set of comparators and determine whether there +// exists a version which can satisfy it +function isSatisfiable (comparators, options) { + var result = true + var remainingComparators = comparators.slice() + var testComparator = remainingComparators.pop() -SafeBuffer.from = function (arg, encodingOrOffset, length) { - if (typeof arg === 'number') { - throw new TypeError('Argument must not be a number') + while (result && remainingComparators.length) { + result = remainingComparators.every(function (otherComparator) { + return testComparator.intersects(otherComparator, options) + }) + + testComparator = remainingComparators.pop() } - return Buffer(arg, encodingOrOffset, length) + + return result } -SafeBuffer.alloc = function (size, fill, encoding) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - var buf = Buffer(size) - if (fill !== undefined) { - if (typeof encoding === 'string') { - buf.fill(fill, encoding) - } else { - buf.fill(fill) - } - } else { - buf.fill(0) - } - return buf +// Mostly just for testing and legacy API reasons +exports.toComparators = toComparators +function toComparators (range, options) { + return new Range(range, options).set.map(function (comp) { + return comp.map(function (c) { + return c.value + }).join(' ').trim().split(' ') + }) } -SafeBuffer.allocUnsafe = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return Buffer(size) +// comprised of xranges, tildes, stars, and gtlt's at this point. +// already replaced the hyphen ranges +// turn into a set of JUST comparators. +function parseComparator (comp, options) { + debug('comp', comp, options) + comp = replaceCarets(comp, options) + debug('caret', comp) + comp = replaceTildes(comp, options) + debug('tildes', comp) + comp = replaceXRanges(comp, options) + debug('xrange', comp) + comp = replaceStars(comp, options) + debug('stars', comp) + return comp } -SafeBuffer.allocUnsafeSlow = function (size) { - if (typeof size !== 'number') { - throw new TypeError('Argument must be a number') - } - return buffer.SlowBuffer(size) +function isX (id) { + return !id || id.toLowerCase() === 'x' || id === '*' } +// ~, ~> --> * (any, kinda silly) +// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0 <3.0.0 +// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0 <2.1.0 +// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0 <1.3.0 +// ~1.2.3, ~>1.2.3 --> >=1.2.3 <1.3.0 +// ~1.2.0, ~>1.2.0 --> >=1.2.0 <1.3.0 +function replaceTildes (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceTilde(comp, options) + }).join(' ') +} -/***/ }), -/* 914 */ -/***/ (function(module, exports, __webpack_require__) { +function replaceTilde (comp, options) { + var r = options.loose ? re[TILDELOOSE] : re[TILDE] + return comp.replace(r, function (_, M, m, p, pr) { + debug('tilde', comp, _, M, m, p, pr) + var ret -"use strict"; + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { + // ~1.2 == >=1.2.0 <1.3.0 + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else if (pr) { + debug('replaceTilde pr', pr) + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } else { + // ~1.2.3 == >=1.2.3 <1.3.0 + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0' + } -const NestedError = __webpack_require__(915); + debug('tilde return', ret) + return ret + }) +} -class CpFileError extends NestedError { - constructor(message, nested) { - super(message, nested); - Object.assign(this, nested); - this.name = 'CpFileError'; - } +// ^ --> * (any, kinda silly) +// ^2, ^2.x, ^2.x.x --> >=2.0.0 <3.0.0 +// ^2.0, ^2.0.x --> >=2.0.0 <3.0.0 +// ^1.2, ^1.2.x --> >=1.2.0 <2.0.0 +// ^1.2.3 --> >=1.2.3 <2.0.0 +// ^1.2.0 --> >=1.2.0 <2.0.0 +function replaceCarets (comp, options) { + return comp.trim().split(/\s+/).map(function (comp) { + return replaceCaret(comp, options) + }).join(' ') } -module.exports = CpFileError; +function replaceCaret (comp, options) { + debug('caret', comp, options) + var r = options.loose ? re[CARETLOOSE] : re[CARET] + return comp.replace(r, function (_, M, m, p, pr) { + debug('caret', comp, _, M, m, p, pr) + var ret + if (isX(M)) { + ret = '' + } else if (isX(m)) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (isX(p)) { + if (M === '0') { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + } else { + ret = '>=' + M + '.' + m + '.0 <' + (+M + 1) + '.0.0' + } + } else if (pr) { + debug('replaceCaret pr', pr) + if (M === '0') { + if (m === '0') { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + m + '.' + (+p + 1) + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { + ret = '>=' + M + '.' + m + '.' + p + '-' + pr + + ' <' + (+M + 1) + '.0.0' + } + } else { + debug('no pr') + if (M === '0') { + if (m === '0') { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + m + '.' + (+p + 1) + } else { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + M + '.' + (+m + 1) + '.0' + } + } else { + ret = '>=' + M + '.' + m + '.' + p + + ' <' + (+M + 1) + '.0.0' + } + } -/***/ }), -/* 915 */ -/***/ (function(module, exports, __webpack_require__) { + debug('caret return', ret) + return ret + }) +} -var inherits = __webpack_require__(916); +function replaceXRanges (comp, options) { + debug('replaceXRanges', comp, options) + return comp.split(/\s+/).map(function (comp) { + return replaceXRange(comp, options) + }).join(' ') +} -var NestedError = function (message, nested) { - this.nested = nested; +function replaceXRange (comp, options) { + comp = comp.trim() + var r = options.loose ? re[XRANGELOOSE] : re[XRANGE] + return comp.replace(r, function (ret, gtlt, M, m, p, pr) { + debug('xRange', comp, ret, gtlt, M, m, p, pr) + var xM = isX(M) + var xm = xM || isX(m) + var xp = xm || isX(p) + var anyX = xp - if (typeof message !== 'undefined') { - Object.defineProperty(this, 'message', { - value: message, - writable: true, - enumerable: false, - configurable: true - }); + if (gtlt === '=' && anyX) { + gtlt = '' } - Error.captureStackTrace(this, this.constructor); - var oldStackDescriptor = Object.getOwnPropertyDescriptor(this, 'stack'); - var stackDescriptor = buildStackDescriptor(oldStackDescriptor, nested); - Object.defineProperty(this, 'stack', stackDescriptor); -}; + if (xM) { + if (gtlt === '>' || gtlt === '<') { + // nothing is allowed + ret = '<0.0.0' + } else { + // nothing is forbidden + ret = '*' + } + } else if (gtlt && anyX) { + // we know patch is an x, because we have any x at all. + // replace X with 0 + if (xm) { + m = 0 + } + p = 0 -function buildStackDescriptor(oldStackDescriptor, nested) { - if (oldStackDescriptor.get) { - return { - get: function () { - var stack = oldStackDescriptor.get.call(this); - return buildCombinedStacks(stack, this.nested); - } - }; - } else { - var stack = oldStackDescriptor.value; - return { - value: buildCombinedStacks(stack, nested) - }; - } -} + if (gtlt === '>') { + // >1 => >=2.0.0 + // >1.2 => >=1.3.0 + // >1.2.3 => >= 1.2.4 + gtlt = '>=' + if (xm) { + M = +M + 1 + m = 0 + p = 0 + } else { + m = +m + 1 + p = 0 + } + } else if (gtlt === '<=') { + // <=0.7.x is actually <0.8.0, since any 0.7.x should + // pass. Similarly, <=7.x is actually <8.0.0, etc. + gtlt = '<' + if (xm) { + M = +M + 1 + } else { + m = +m + 1 + } + } -function buildCombinedStacks(stack, nested) { - if (nested) { - stack += '\nCaused By: ' + nested.stack; + ret = gtlt + M + '.' + m + '.' + p + } else if (xm) { + ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + } else if (xp) { + ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' } - return stack; -} -inherits(NestedError, Error); -NestedError.prototype.name = 'NestedError'; + debug('xRange return', ret) + return ret + }) +} -module.exports = NestedError; +// Because * is AND-ed with everything else in the comparator, +// and '' means "any version", just remove the *s entirely. +function replaceStars (comp, options) { + debug('replaceStars', comp, options) + // Looseness is ignored here. star is always as loose as it gets! + return comp.trim().replace(re[STAR], '') +} +// This function is passed to string.replace(re[HYPHENRANGE]) +// M, m, patch, prerelease, build +// 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 +// 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do +// 1.2 - 3.4 => >=1.2.0 <3.5.0 +function hyphenReplace ($0, + from, fM, fm, fp, fpr, fb, + to, tM, tm, tp, tpr, tb) { + if (isX(fM)) { + from = '' + } else if (isX(fm)) { + from = '>=' + fM + '.0.0' + } else if (isX(fp)) { + from = '>=' + fM + '.' + fm + '.0' + } else { + from = '>=' + from + } -/***/ }), -/* 916 */ -/***/ (function(module, exports, __webpack_require__) { + if (isX(tM)) { + to = '' + } else if (isX(tm)) { + to = '<' + (+tM + 1) + '.0.0' + } else if (isX(tp)) { + to = '<' + tM + '.' + (+tm + 1) + '.0' + } else if (tpr) { + to = '<=' + tM + '.' + tm + '.' + tp + '-' + tpr + } else { + to = '<=' + to + } -try { - var util = __webpack_require__(29); - if (typeof util.inherits !== 'function') throw ''; - module.exports = util.inherits; -} catch (e) { - module.exports = __webpack_require__(917); + return (from + ' ' + to).trim() } +// if ANY of the sets match ALL of its comparators, then pass +Range.prototype.test = function (version) { + if (!version) { + return false + } -/***/ }), -/* 917 */ -/***/ (function(module, exports) { + if (typeof version === 'string') { + try { + version = new SemVer(version, this.options) + } catch (er) { + return false + } + } -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 + for (var i = 0; i < this.set.length; i++) { + if (testSet(this.set[i], version, this.options)) { + return true + } } + return false } +function testSet (set, version, options) { + for (var i = 0; i < set.length; i++) { + if (!set[i].test(version)) { + return false + } + } -/***/ }), -/* 918 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; + if (version.prerelease.length && !options.includePrerelease) { + // Find the set of versions that are allowed to have prereleases + // For example, ^1.2.3-pr.1 desugars to >=1.2.3-pr.1 <2.0.0 + // That should allow `1.2.3-pr.2` to pass. + // However, `1.2.4-alpha.notready` should NOT be allowed, + // even though it's within the range set by the comparators. + for (i = 0; i < set.length; i++) { + debug(set[i].semver) + if (set[i].semver === ANY) { + continue + } -const fs = __webpack_require__(22); -const makeDir = __webpack_require__(559); -const pify = __webpack_require__(919); -const CpFileError = __webpack_require__(914); + if (set[i].semver.prerelease.length > 0) { + var allowed = set[i].semver + if (allowed.major === version.major && + allowed.minor === version.minor && + allowed.patch === version.patch) { + return true + } + } + } -const fsP = pify(fs); + // Version has a -pre, but it's not one of the ones we like. + return false + } -exports.closeSync = fs.closeSync.bind(fs); -exports.createWriteStream = fs.createWriteStream.bind(fs); + return true +} -exports.createReadStream = (path, options) => new Promise((resolve, reject) => { - const read = fs.createReadStream(path, options); +exports.satisfies = satisfies +function satisfies (version, range, options) { + try { + range = new Range(range, options) + } catch (er) { + return false + } + return range.test(version) +} - read.once('error', error => { - reject(new CpFileError(`Cannot read from \`${path}\`: ${error.message}`, error)); - }); +exports.maxSatisfying = maxSatisfying +function maxSatisfying (versions, range, options) { + var max = null + var maxSV = null + try { + var rangeObj = new Range(range, options) + } catch (er) { + return null + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!max || maxSV.compare(v) === -1) { + // compare(max, v, true) + max = v + maxSV = new SemVer(max, options) + } + } + }) + return max +} - read.once('readable', () => { - resolve(read); - }); +exports.minSatisfying = minSatisfying +function minSatisfying (versions, range, options) { + var min = null + var minSV = null + try { + var rangeObj = new Range(range, options) + } catch (er) { + return null + } + versions.forEach(function (v) { + if (rangeObj.test(v)) { + // satisfies(v, range, options) + if (!min || minSV.compare(v) === 1) { + // compare(min, v, true) + min = v + minSV = new SemVer(min, options) + } + } + }) + return min +} - read.once('end', () => { - resolve(read); - }); -}); +exports.minVersion = minVersion +function minVersion (range, loose) { + range = new Range(range, loose) -exports.stat = path => fsP.stat(path).catch(error => { - throw new CpFileError(`Cannot stat path \`${path}\`: ${error.message}`, error); -}); + var minver = new SemVer('0.0.0') + if (range.test(minver)) { + return minver + } -exports.lstat = path => fsP.lstat(path).catch(error => { - throw new CpFileError(`lstat \`${path}\` failed: ${error.message}`, error); -}); + minver = new SemVer('0.0.0-0') + if (range.test(minver)) { + return minver + } -exports.utimes = (path, atime, mtime) => fsP.utimes(path, atime, mtime).catch(error => { - throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); -}); + minver = null + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i] -exports.chmod = (path, mode) => fsP.chmod(path, mode).catch(error => { - throw new CpFileError(`chmod \`${path}\` failed: ${error.message}`, error); -}); + comparators.forEach(function (comparator) { + // Clone to avoid manipulating the comparator's semver object. + var compver = new SemVer(comparator.semver.version) + switch (comparator.operator) { + case '>': + if (compver.prerelease.length === 0) { + compver.patch++ + } else { + compver.prerelease.push(0) + } + compver.raw = compver.format() + /* fallthrough */ + case '': + case '>=': + if (!minver || gt(minver, compver)) { + minver = compver + } + break + case '<': + case '<=': + /* Ignore maximum versions */ + break + /* istanbul ignore next */ + default: + throw new Error('Unexpected operation: ' + comparator.operator) + } + }) + } -exports.chown = (path, uid, gid) => fsP.chown(path, uid, gid).catch(error => { - throw new CpFileError(`chown \`${path}\` failed: ${error.message}`, error); -}); + if (minver && range.test(minver)) { + return minver + } -exports.openSync = (path, flags, mode) => { - try { - return fs.openSync(path, flags, mode); - } catch (error) { - if (flags.includes('w')) { - throw new CpFileError(`Cannot write to \`${path}\`: ${error.message}`, error); - } + return null +} - throw new CpFileError(`Cannot open \`${path}\`: ${error.message}`, error); - } -}; +exports.validRange = validRange +function validRange (range, options) { + try { + // Return '*' instead of '' so that truthiness works. + // This will throw if it's invalid anyway + return new Range(range, options).range || '*' + } catch (er) { + return null + } +} -// eslint-disable-next-line max-params -exports.readSync = (fileDescriptor, buffer, offset, length, position, path) => { - try { - return fs.readSync(fileDescriptor, buffer, offset, length, position); - } catch (error) { - throw new CpFileError(`Cannot read from \`${path}\`: ${error.message}`, error); - } -}; +// Determine if version is less than all the versions possible in the range +exports.ltr = ltr +function ltr (version, range, options) { + return outside(version, range, '<', options) +} -// eslint-disable-next-line max-params -exports.writeSync = (fileDescriptor, buffer, offset, length, position, path) => { - try { - return fs.writeSync(fileDescriptor, buffer, offset, length, position); - } catch (error) { - throw new CpFileError(`Cannot write to \`${path}\`: ${error.message}`, error); - } -}; +// Determine if version is greater than all the versions possible in the range. +exports.gtr = gtr +function gtr (version, range, options) { + return outside(version, range, '>', options) +} -exports.statSync = path => { - try { - return fs.statSync(path); - } catch (error) { - throw new CpFileError(`stat \`${path}\` failed: ${error.message}`, error); - } -}; +exports.outside = outside +function outside (version, range, hilo, options) { + version = new SemVer(version, options) + range = new Range(range, options) -exports.fstatSync = (fileDescriptor, path) => { - try { - return fs.fstatSync(fileDescriptor); - } catch (error) { - throw new CpFileError(`fstat \`${path}\` failed: ${error.message}`, error); - } -}; + var gtfn, ltefn, ltfn, comp, ecomp + switch (hilo) { + case '>': + gtfn = gt + ltefn = lte + ltfn = lt + comp = '>' + ecomp = '>=' + break + case '<': + gtfn = lt + ltefn = gte + ltfn = gt + comp = '<' + ecomp = '<=' + break + default: + throw new TypeError('Must provide a hilo val of "<" or ">"') + } -exports.futimesSync = (fileDescriptor, atime, mtime, path) => { - try { - return fs.futimesSync(fileDescriptor, atime, mtime, path); - } catch (error) { - throw new CpFileError(`futimes \`${path}\` failed: ${error.message}`, error); - } -}; + // If it satisifes the range it is not outside + if (satisfies(version, range, options)) { + return false + } -exports.utimesSync = (path, atime, mtime) => { - try { - return fs.utimesSync(path, atime, mtime); - } catch (error) { - throw new CpFileError(`utimes \`${path}\` failed: ${error.message}`, error); - } -}; + // From now on, variable terms are as if we're in "gtr" mode. + // but note that everything is flipped for the "ltr" function. -exports.chmodSync = (path, mode) => { - try { - return fs.chmodSync(path, mode); - } catch (error) { - throw new CpFileError(`chmod \`${path}\` failed: ${error.message}`, error); - } -}; + for (var i = 0; i < range.set.length; ++i) { + var comparators = range.set[i] -exports.chownSync = (path, uid, gid) => { - try { - return fs.chownSync(path, uid, gid); - } catch (error) { - throw new CpFileError(`chown \`${path}\` failed: ${error.message}`, error); - } -}; + var high = null + var low = null -exports.makeDir = path => makeDir(path, {fs}).catch(error => { - throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); -}); + comparators.forEach(function (comparator) { + if (comparator.semver === ANY) { + comparator = new Comparator('>=0.0.0') + } + high = high || comparator + low = low || comparator + if (gtfn(comparator.semver, high.semver, options)) { + high = comparator + } else if (ltfn(comparator.semver, low.semver, options)) { + low = comparator + } + }) -exports.makeDirSync = path => { - try { - makeDir.sync(path, {fs}); - } catch (error) { - throw new CpFileError(`Cannot create directory \`${path}\`: ${error.message}`, error); - } -}; + // If the edge version comparator has a operator then our version + // isn't outside it + if (high.operator === comp || high.operator === ecomp) { + return false + } -if (fs.copyFileSync) { - exports.copyFileSync = (source, destination, flags) => { - try { - fs.copyFileSync(source, destination, flags); - } catch (error) { - throw new CpFileError(`Cannot copy from \`${source}\` to \`${destination}\`: ${error.message}`, error); - } - }; + // If the lowest version comparator has an operator and our version + // is less than it then it isn't higher than the range + if ((!low.operator || low.operator === comp) && + ltefn(version, low.semver)) { + return false + } else if (low.operator === ecomp && ltfn(version, low.semver)) { + return false + } + } + return true } +exports.prerelease = prerelease +function prerelease (version, options) { + var parsed = parse(version, options) + return (parsed && parsed.prerelease.length) ? parsed.prerelease : null +} -/***/ }), -/* 919 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const processFn = (fn, options) => function (...args) { - const P = options.promiseModule; - - return new P((resolve, reject) => { - if (options.multiArgs) { - args.push((...result) => { - if (options.errorFirst) { - if (result[0]) { - reject(result); - } else { - result.shift(); - resolve(result); - } - } else { - resolve(result); - } - }); - } else if (options.errorFirst) { - args.push((error, result) => { - if (error) { - reject(error); - } else { - resolve(result); - } - }); - } else { - args.push(resolve); - } - - fn.apply(this, args); - }); -}; - -module.exports = (input, options) => { - options = Object.assign({ - exclude: [/.+(Sync|Stream)$/], - errorFirst: true, - promiseModule: Promise - }, options); +exports.intersects = intersects +function intersects (r1, r2, options) { + r1 = new Range(r1, options) + r2 = new Range(r2, options) + return r1.intersects(r2) +} - const objType = typeof input; - if (!(input !== null && (objType === 'object' || objType === 'function'))) { - throw new TypeError(`Expected \`input\` to be a \`Function\` or \`Object\`, got \`${input === null ? 'null' : objType}\``); - } +exports.coerce = coerce +function coerce (version, options) { + if (version instanceof SemVer) { + return version + } - const filter = key => { - const match = pattern => typeof pattern === 'string' ? key === pattern : pattern.test(key); - return options.include ? options.include.some(match) : !options.exclude.some(match); - }; + if (typeof version !== 'string') { + return null + } - let ret; - if (objType === 'function') { - ret = function (...args) { - return options.excludeMain ? input(...args) : processFn(input, options).apply(this, args); - }; - } else { - ret = Object.create(Object.getPrototypeOf(input)); - } + var match = version.match(re[COERCE]) - for (const key in input) { // eslint-disable-line guard-for-in - const property = input[key]; - ret[key] = typeof property === 'function' && filter(key) ? processFn(property, options) : property; - } + if (match == null) { + return null + } - return ret; -}; + return parse(match[1] + + '.' + (match[2] || '0') + + '.' + (match[3] || '0'), options) +} /***/ }), -/* 920 */ +/* 916 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -108438,12 +108005,58 @@ module.exports = ProgressEmitter; /***/ }), -/* 921 */ +/* 917 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +const blacklist = [ + // # All + '^npm-debug\\.log$', // Error log for npm + '^\\..*\\.swp$', // Swap file for vim state + + // # macOS + '^\\.DS_Store$', // Stores custom folder attributes + '^\\.AppleDouble$', // Stores additional file resources + '^\\.LSOverride$', // Contains the absolute path to the app to be used + '^Icon\\r$', // Custom Finder icon: http://superuser.com/questions/298785/icon-file-on-os-x-desktop + '^\\._.*', // Thumbnail + '^\\.Spotlight-V100(?:$|\\/)', // Directory that might appear on external disk + '\\.Trashes', // File that might appear on external disk + '^__MACOSX$', // Resource fork + + // # Linux + '~$', // Backup file + + // # Windows + '^Thumbs\\.db$', // Image file cache + '^ehthumbs\\.db$', // Folder config file + '^Desktop\\.ini$', // Stores custom folder attributes + '@eaDir$' // Synology Diskstation "hidden" folder where the server stores thumbnails +]; + +exports.re = () => { + throw new Error('`junk.re` was renamed to `junk.regex`'); +}; + +exports.regex = new RegExp(blacklist.join('|')); + +exports.is = filename => exports.regex.test(filename); + +exports.not = filename => !exports.is(filename); + +// TODO: Remove this for the next major release +exports.default = module.exports; + + +/***/ }), +/* 918 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(922); +const NestedError = __webpack_require__(919); class CpyError extends NestedError { constructor(message, nested) { @@ -108457,7 +108070,7 @@ module.exports = CpyError; /***/ }), -/* 922 */ +/* 919 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(29).inherits; @@ -108513,7 +108126,7 @@ module.exports = NestedError; /***/ }), -/* 923 */ +/* 920 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; From 784df983e9b1d72fc0310574a811a07d39034fef Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 15:22:13 -0700 Subject: [PATCH 14/83] implement bundle caching/reuse --- packages/kbn-optimizer/package.json | 2 + .../mock_repo/plugins/bar/public/index.ts | 2 + .../src/assign_bundles_to_workers.test.ts | 143 ++---- .../src/assign_bundles_to_workers.ts | 97 ++-- packages/kbn-optimizer/src/cli.ts | 6 +- .../src/common/array_helpers.test.ts | 118 +++++ .../kbn-optimizer/src/common/array_helpers.ts | 80 ++++ packages/kbn-optimizer/src/common/bundle.ts | 140 ++++++ .../bundle_cache.ts} | 69 +-- .../src/common/compiler_messages.ts | 12 +- packages/kbn-optimizer/src/common/index.ts | 6 +- ...undle_definition.ts => promise_helpers.ts} | 33 +- .../kbn-optimizer/src/common/rxjs_helpers.ts | 50 +- .../src/{log.ts => common/ts_helpers.ts} | 12 +- .../kbn-optimizer/src/common/worker_config.ts | 81 ++-- .../src/common/worker_messages.ts | 6 +- ...efinitions.test.ts => get_bundles.test.ts} | 6 +- ...t_bundle_definitions.ts => get_bundles.ts} | 21 +- .../kbn-optimizer/src/get_changes.test.ts | 63 +++ packages/kbn-optimizer/src/get_changes.ts | 89 ++++ packages/kbn-optimizer/src/get_mtimes.test.ts | 47 ++ packages/kbn-optimizer/src/get_mtimes.ts | 49 ++ .../src/get_optimizer_version.ts | 60 +++ .../basic_optimization.test.ts.snap | 435 ++---------------- .../basic_optimization.test.ts | 19 +- .../src/log_optimizer_state.test.ts | 127 ----- .../kbn-optimizer/src/log_optimizer_state.ts | 63 ++- packages/kbn-optimizer/src/observe_worker.ts | 33 +- packages/kbn-optimizer/src/optimizer.ts | 304 +++++++++--- .../src/optimizer_config.test.ts | 134 +----- .../kbn-optimizer/src/optimizer_config.ts | 75 ++- packages/kbn-optimizer/src/watcher.ts | 128 ++++++ .../src/worker/block_legacy_code_plugin.ts | 55 --- .../kbn-optimizer/src/worker/run_worker.ts | 116 ++++- .../src/worker/webpack.config.ts | 28 +- .../src/worker/webpack_helpers.ts | 53 +++ src/cli/cluster/cluster_manager.ts | 2 +- .../build/tasks/build_new_platform_plugins.js | 2 +- .../data/public/{_index.scss => index.scss} | 0 src/plugins/data/public/index.ts | 2 +- yarn.lock | 16 + 41 files changed, 1612 insertions(+), 1172 deletions(-) create mode 100644 packages/kbn-optimizer/src/common/array_helpers.test.ts create mode 100644 packages/kbn-optimizer/src/common/array_helpers.ts create mode 100644 packages/kbn-optimizer/src/common/bundle.ts rename packages/kbn-optimizer/src/{optimizer_cache.ts => common/bundle_cache.ts} (61%) rename packages/kbn-optimizer/src/common/{bundle_definition.ts => promise_helpers.ts} (56%) rename packages/kbn-optimizer/src/{log.ts => common/ts_helpers.ts} (80%) rename packages/kbn-optimizer/src/{get_bundle_definitions.test.ts => get_bundles.test.ts} (95%) rename packages/kbn-optimizer/src/{get_bundle_definitions.ts => get_bundles.ts} (71%) create mode 100644 packages/kbn-optimizer/src/get_changes.test.ts create mode 100644 packages/kbn-optimizer/src/get_changes.ts create mode 100644 packages/kbn-optimizer/src/get_mtimes.test.ts create mode 100644 packages/kbn-optimizer/src/get_mtimes.ts create mode 100644 packages/kbn-optimizer/src/get_optimizer_version.ts delete mode 100644 packages/kbn-optimizer/src/log_optimizer_state.test.ts create mode 100644 packages/kbn-optimizer/src/watcher.ts delete mode 100644 packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts rename src/plugins/data/public/{_index.scss => index.scss} (100%) diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json index 30b9af2e1475e..ab08172553265 100644 --- a/packages/kbn-optimizer/package.json +++ b/packages/kbn-optimizer/package.json @@ -15,6 +15,7 @@ "@kbn/dev-utils": "1.0.0", "@kbn/ui-shared-deps": "1.0.0", "@types/loader-utils": "^1.1.3", + "@types/watchpack": "^1.1.5", "@types/webpack": "^4.41.3", "autoprefixer": "^9.7.4", "babel-loader": "^8.0.6", @@ -38,6 +39,7 @@ "tinymath": "1.2.1", "url-loader": "^2.2.0", "val-loader": "^1.1.1", + "watchpack": "^1.6.0", "webpack": "^4.41.5", "webpack-merge": "^4.2.2" } diff --git a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts index 12e580bbb76b3..66fa55479f3b9 100644 --- a/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts +++ b/packages/kbn-optimizer/src/__fixtures__/mock_repo/plugins/bar/public/index.ts @@ -17,4 +17,6 @@ * under the License. */ +import { fooLibFn } from '../../foo/public/index'; export * from './lib'; +export { fooLibFn }; diff --git a/packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts b/packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts index 54c4e7cfd77a1..0d272e9ce6bf0 100644 --- a/packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts +++ b/packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts @@ -17,10 +17,9 @@ * under the License. */ -import { getBundleDefinitions } from './get_bundle_definitions'; -import { OptimizerCache } from './optimizer_cache'; -import { assignBundlesToWorkers, Worker, Options } from './assign_bundles_to_workers'; -import { BundleDefinition } from './common'; +import { getBundles } from './get_bundles'; +import { assignBundlesToWorkers, Assignments } from './assign_bundles_to_workers'; +import { Bundle } from './common'; const REPO = '/repo'; const BIG_BUNDLES = 'dqv'.split(''); @@ -43,19 +42,15 @@ const pluginsWithoutCounts = (n: number) => isUiPlugin: true, })); -const cache = new OptimizerCache(false); -jest - .spyOn(cache, 'getBundleModuleCount') - .mockImplementation(id => - ALPHABET.includes(id) - ? (ALPHABET.indexOf(id) + 1) * (BIG_BUNDLES.includes(id) ? 10 : 1) - : undefined - ); +jest.spyOn(Bundle.prototype, 'getModuleCount').mockImplementation(function(this: Bundle) { + return ALPHABET.includes(this.id) + ? (ALPHABET.indexOf(this.id) + 1) * (BIG_BUNDLES.includes(this.id) ? 10 : 1) + : undefined; +}); -const moduleCount = (b: BundleDefinition) => cache.getBundleModuleCount(b.id); -const hasModuleCount = (b: BundleDefinition) => moduleCount(b) !== undefined; -const noModuleCount = (b: BundleDefinition) => moduleCount(b) === undefined; -const summarizeBundles = (w: Worker) => +const hasModuleCount = (b: Bundle) => b.getModuleCount() !== undefined; +const noModuleCount = (b: Bundle) => b.getModuleCount() === undefined; +const summarizeBundles = (w: Assignments) => [ w.moduleCount ? `${w.moduleCount} known modules` : '', w.newBundles ? `${w.newBundles} new bundles` : '', @@ -63,48 +58,29 @@ const summarizeBundles = (w: Worker) => .filter(Boolean) .join(', '); -const readConfigs = (workers: Worker[]) => +const readConfigs = (workers: Assignments[]) => workers.map( - (w, i) => `worker ${i} (${summarizeBundles(w)}) => ${w.config.bundles.map(b => b.id).join(',')}` + (w, i) => `worker ${i} (${summarizeBundles(w)}) => ${w.bundles.map(b => b.id).join(',')}` ); -const assertReturnVal = (workers: Worker[]) => { +const assertReturnVal = (workers: Assignments[]) => { expect(workers).toBeInstanceOf(Array); for (const worker of workers) { expect(worker).toEqual({ moduleCount: expect.any(Number), newBundles: expect.any(Number), - config: { - repoRoot: REPO, - watch: expect.any(Boolean), - dist: expect.any(Boolean), - profileWebpack: expect.any(Boolean), - bundles: expect.any(Array), - }, + bundles: expect.any(Array), }); - expect(worker.config.bundles.filter(noModuleCount).length).toBe(worker.newBundles); + expect(worker.bundles.filter(noModuleCount).length).toBe(worker.newBundles); expect( - worker.config.bundles.filter(hasModuleCount).reduce((sum, b) => sum + moduleCount(b)!, 0) + worker.bundles.filter(hasModuleCount).reduce((sum, b) => sum + b.getModuleCount()!, 0) ).toBe(worker.moduleCount); } }; -const defaultOptions: Omit = { - maxWorkerCount: 4, - watch: false, - dist: false, - cache, - repoRoot: REPO, - profileWebpack: false, -}; - it('creates less workers if maxWorkersCount is larger than bundle count', () => { - const workers = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions(pluginsWithCounts(2), REPO), - maxWorkerCount: 10, - }); + const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(2), REPO), 10); assertReturnVal(workers); expect(workers.length).toBe(2); @@ -117,14 +93,10 @@ it('creates less workers if maxWorkersCount is larger than bundle count', () => }); it('assigns unknown plugin counts as evenly as possible', () => { - const configs = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions(pluginsWithoutCounts(10), REPO), - maxWorkerCount: 3, - }); + const workers = assignBundlesToWorkers(getBundles(pluginsWithoutCounts(10), REPO), 3); - assertReturnVal(configs); - expect(readConfigs(configs)).toMatchInlineSnapshot(` + assertReturnVal(workers); + expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ "worker 0 (4 new bundles) => foo9,foo6,foo3,foo1", "worker 1 (3 new bundles) => foo8,foo5,foo2", @@ -134,13 +106,11 @@ it('assigns unknown plugin counts as evenly as possible', () => { }); it('distributes bundles without module counts evenly after assigning modules with known counts evenly', () => { - const configs = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions([...pluginsWithCounts(16), ...pluginsWithoutCounts(10)], REPO), - }); + const bundles = getBundles([...pluginsWithCounts(16), ...pluginsWithoutCounts(10)], REPO); + const workers = assignBundlesToWorkers(bundles, 4); - assertReturnVal(configs); - expect(readConfigs(configs)).toMatchInlineSnapshot(` + assertReturnVal(workers); + expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ "worker 0 (42 known modules, 3 new bundles) => n,m,h,g,foo9,foo5,foo10", "worker 1 (43 known modules, 3 new bundles) => o,l,i,f,a,foo8,foo4,foo1", @@ -151,13 +121,10 @@ it('distributes bundles without module counts evenly after assigning modules wit }); it('distributes 2 bundles to workers evenly', () => { - const configs = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions(pluginsWithCounts(2), REPO), - }); + const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(2), REPO), 4); - assertReturnVal(configs); - expect(readConfigs(configs)).toMatchInlineSnapshot(` + assertReturnVal(workers); + expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ "worker 0 (1 known modules) => a", "worker 1 (2 known modules) => b", @@ -166,13 +133,10 @@ it('distributes 2 bundles to workers evenly', () => { }); it('distributes 5 bundles to workers evenly', () => { - const configs = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions(pluginsWithCounts(5), REPO), - }); + const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(5), REPO), 4); - assertReturnVal(configs); - expect(readConfigs(configs)).toMatchInlineSnapshot(` + assertReturnVal(workers); + expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ "worker 0 (3 known modules) => b,a", "worker 1 (3 known modules) => c", @@ -183,13 +147,10 @@ it('distributes 5 bundles to workers evenly', () => { }); it('distributes 10 bundles to workers evenly', () => { - const configs = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions(pluginsWithCounts(10), REPO), - }); + const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(10), REPO), 4); - assertReturnVal(configs); - expect(readConfigs(configs)).toMatchInlineSnapshot(` + assertReturnVal(workers); + expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ "worker 0 (16 known modules) => h,g,a", "worker 1 (17 known modules) => i,f,b", @@ -200,13 +161,10 @@ it('distributes 10 bundles to workers evenly', () => { }); it('distributes 15 bundles to workers evenly', () => { - const configs = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions(pluginsWithCounts(15), REPO), - }); + const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(15), REPO), 4); - assertReturnVal(configs); - expect(readConfigs(configs)).toMatchInlineSnapshot(` + assertReturnVal(workers); + expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ "worker 0 (38 known modules) => m,l,g,f", "worker 1 (39 known modules) => n,k,h,e,a", @@ -217,13 +175,10 @@ it('distributes 15 bundles to workers evenly', () => { }); it('distributes 20 bundles to workers evenly', () => { - const configs = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions(pluginsWithCounts(20), REPO), - }); + const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(20), REPO), 4); - assertReturnVal(configs); - expect(readConfigs(configs)).toMatchInlineSnapshot(` + assertReturnVal(workers); + expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ "worker 0 (76 known modules) => d,m,j,h,e", "worker 1 (76 known modules) => s,r,n,l,g,f", @@ -234,13 +189,10 @@ it('distributes 20 bundles to workers evenly', () => { }); it('distributes 25 bundles to workers evenly', () => { - const configs = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions(pluginsWithCounts(25), REPO), - }); + const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(25), REPO), 4); - assertReturnVal(configs); - expect(readConfigs(configs)).toMatchInlineSnapshot(` + assertReturnVal(workers); + expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ "worker 0 (161 known modules) => d,w,t,r,o,m,k,i,f,e,a", "worker 1 (161 known modules) => y,x,u,s,p,n,l,j,h,g,c,b", @@ -251,13 +203,10 @@ it('distributes 25 bundles to workers evenly', () => { }); it('distributes 30 bundles to workers evenly', () => { - const configs = assignBundlesToWorkers({ - ...defaultOptions, - bundles: getBundleDefinitions(pluginsWithCounts(30), REPO), - }); + const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(30), REPO), 4); - assertReturnVal(configs); - expect(readConfigs(configs)).toMatchInlineSnapshot(` + assertReturnVal(workers); + expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ "worker 0 (172 known modules) => z,y,w,t,r,o,m,k,i,g,e", "worker 1 (173 known modules) => q,b,a", diff --git a/packages/kbn-optimizer/src/assign_bundles_to_workers.ts b/packages/kbn-optimizer/src/assign_bundles_to_workers.ts index 5961a148ce67b..a6c88dd2377a3 100644 --- a/packages/kbn-optimizer/src/assign_bundles_to_workers.ts +++ b/packages/kbn-optimizer/src/assign_bundles_to_workers.ts @@ -17,59 +17,29 @@ * under the License. */ -import { BundleDefinition, WorkerConfig } from './common'; -import { OptimizerCache } from './optimizer_cache'; +import { Bundle, descending, ascending } from './common'; // helper types used inside getWorkerConfigs so we don't have // to calculate moduleCounts over and over -export interface Worker extends HasModuleCount { - newBundles: number; - config: WorkerConfig; -} - -interface WrappedBundleWithCount extends HasModuleCount { - def: BundleDefinition; -} - -interface WrappedBundleWithoutCount { - moduleCount: undefined; - def: BundleDefinition; -} - -interface HasModuleCount { +export interface Assignments { moduleCount: number; + newBundles: number; + bundles: Bundle[]; } -type WrappedBundle = WrappedBundleWithCount | WrappedBundleWithoutCount; - /** assign a wrapped bundle to a worker */ -const assignBundle = (worker: Worker, { moduleCount, def }: WrappedBundle) => { +const assignBundle = (worker: Assignments, bundle: Bundle) => { + const moduleCount = bundle.getModuleCount(); if (moduleCount !== undefined) { worker.moduleCount += moduleCount; } else { worker.newBundles += 1; } - worker.config.bundles.push(def); + worker.bundles.push(bundle); }; -/** compare items with module counts */ -const byModuleCount = (a: HasModuleCount, b: HasModuleCount) => a.moduleCount - b.moduleCount; - -/** compare items with module counts in descending order */ -const byModuleCountDesc = (a: HasModuleCount, b: HasModuleCount) => byModuleCount(b, a); - -export interface Options { - bundles: BundleDefinition[]; - cache: OptimizerCache; - maxWorkerCount: number; - repoRoot: string; - watch: boolean; - dist: boolean; - profileWebpack: boolean; -} - /** * Create WorkerConfig objects for each worker we will use to build the bundles. * @@ -84,45 +54,32 @@ export interface Options { * assign them to workers round-robin, starting with the workers which have * the smallest number of modules to build. */ -export function assignBundlesToWorkers(options: Options) { - const workerCount = Math.min(options.bundles.length, options.maxWorkerCount); - const workers: Worker[] = []; +export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number) { + const workerCount = Math.min(bundles.length, maxWorkerCount); + const workers: Assignments[] = []; for (let i = 0; i < workerCount; i++) { workers.push({ moduleCount: 0, newBundles: 0, - config: { - repoRoot: options.repoRoot, - watch: options.watch, - dist: options.dist, - profileWebpack: options.profileWebpack, - bundles: [], - }, + bundles: [], }); } /** - * wrap all bundles with their module count and sort them by id - * descending so that subsequent sorting will be deterministic - * even if we're sorting by module count, which may be the same - * for two bundles + * separate the bundles which do and don't have module + * counts and sort them by [moduleCount, id] */ - const wrappedBundled = options.bundles - .map(b => ({ - moduleCount: options.cache.getBundleModuleCount(b.id), - def: b, - })) - .sort((a, b) => b.def.id.localeCompare(a.def.id)); - - /** - * separate the bundles which do and don't have module counts - */ - const bundlesWithCountsDesc = wrappedBundled - .filter((b): b is WrappedBundleWithCount => b.moduleCount !== undefined) - .sort(byModuleCountDesc); - const bundlesWithoutModuleCounts = wrappedBundled.filter( - (b): b is WrappedBundleWithoutCount => b.moduleCount === undefined - ); + const bundlesWithCountsDesc = bundles + .filter(b => b.getModuleCount() !== undefined) + .sort( + descending( + b => b.getModuleCount(), + b => b.id + ) + ); + const bundlesWithoutModuleCounts = bundles + .filter(b => b.getModuleCount() === undefined) + .sort(descending(b => b.id)); /** * assign largest bundles to the smallest worker until it is @@ -130,7 +87,7 @@ export function assignBundlesToWorkers(options: Options) { * with module counts are assigned */ while (bundlesWithCountsDesc.length) { - const [smallestWorker, nextSmallestWorker] = workers.sort(byModuleCount); + const [smallestWorker, nextSmallestWorker] = workers.sort(ascending(w => w.moduleCount)); while (!nextSmallestWorker || smallestWorker.moduleCount <= nextSmallestWorker.moduleCount) { const bundle = bundlesWithCountsDesc.shift(); @@ -147,13 +104,15 @@ export function assignBundlesToWorkers(options: Options) { * assign bundles without module counts to workers round-robin * starting with the smallest workers */ - workers.sort(byModuleCount); + workers.sort(ascending(w => w.moduleCount)); while (bundlesWithoutModuleCounts.length) { for (const worker of workers) { const bundle = bundlesWithoutModuleCounts.shift(); + if (!bundle) { break; } + assignBundle(worker, bundle); } } diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts index 87efd7dc63ff3..ff896ee621748 100644 --- a/packages/kbn-optimizer/src/cli.ts +++ b/packages/kbn-optimizer/src/cli.ts @@ -83,10 +83,8 @@ run( inspectWorkers, }); - await new Optimizer(config) - .run() - .pipe(logOptimizerState(log, config)) - .toPromise(); + const state$ = await new Optimizer(config).run(); + await state$.pipe(logOptimizerState(log, config)).toPromise(); }, { flags: { diff --git a/packages/kbn-optimizer/src/common/array_helpers.test.ts b/packages/kbn-optimizer/src/common/array_helpers.test.ts new file mode 100644 index 0000000000000..13e0c254ccdaa --- /dev/null +++ b/packages/kbn-optimizer/src/common/array_helpers.test.ts @@ -0,0 +1,118 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ascending, descending, invert } from './array_helpers'; + +describe('ascending/descending', () => { + interface Item { + a: number; + b: number | string; + c?: number; + } + + const a = (x: Item) => x.a; + const b = (x: Item) => x.b; + const c = (x: Item) => x.c; + const print = (x: Item) => `${x.a}/${x.b}/${x.c}`; + const values: Item[] = [ + { a: 1, b: 2, c: 3 }, + { a: 3, b: 2, c: 1 }, + { a: 9, b: 9, c: 9 }, + { a: 8, b: 5, c: 8 }, + { a: 8, b: 5 }, + { a: 8, b: 4 }, + { a: 8, b: 3, c: 8 }, + { a: 8, b: 2 }, + { a: 8, b: 1, c: 8 }, + { a: 8, b: 1 }, + { a: 8, b: 0 }, + { a: 8, b: -1, c: 8 }, + { a: 8, b: -2 }, + { a: 8, b: -3, c: 8 }, + { a: 8, b: -4 }, + { a: 8, b: 'foo', c: 8 }, + { a: 8, b: 'foo' }, + { a: 8, b: 'bar', c: 8 }, + { a: 8, b: 'bar' }, + ].sort(() => 0.5 - Math.random()); + + it('sorts items using getters', () => { + expect( + Array.from(values) + .sort(ascending(a, b, c)) + .map(print) + ).toMatchInlineSnapshot(` + Array [ + "1/2/3", + "3/2/1", + "8/-4/undefined", + "8/-3/8", + "8/-2/undefined", + "8/-1/8", + "8/0/undefined", + "8/1/undefined", + "8/1/8", + "8/2/undefined", + "8/3/8", + "8/4/undefined", + "8/5/undefined", + "8/5/8", + "8/bar/undefined", + "8/bar/8", + "8/foo/undefined", + "8/foo/8", + "9/9/9", + ] + `); + + expect( + Array.from(values) + .sort(descending(a, b, c)) + .map(print) + ).toMatchInlineSnapshot(` + Array [ + "9/9/9", + "8/foo/8", + "8/foo/undefined", + "8/bar/8", + "8/bar/undefined", + "8/5/8", + "8/5/undefined", + "8/4/undefined", + "8/3/8", + "8/2/undefined", + "8/1/8", + "8/1/undefined", + "8/0/undefined", + "8/-1/8", + "8/-2/undefined", + "8/-3/8", + "8/-4/undefined", + "3/2/1", + "1/2/3", + ] + `); + }); +}); + +describe('invert', () => { + it('inverts a filter function', () => { + expect([1, 2, '3', 4].filter(invert((i): i is number => typeof i === 'number'))).toEqual(['3']); + }); +}); diff --git a/packages/kbn-optimizer/src/common/array_helpers.ts b/packages/kbn-optimizer/src/common/array_helpers.ts new file mode 100644 index 0000000000000..4a236591e2769 --- /dev/null +++ b/packages/kbn-optimizer/src/common/array_helpers.ts @@ -0,0 +1,80 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +type SortPropGetter = (x: T) => number | string | undefined; +type Comparator = (a: T, b: T) => number; + +/** + * create a sort comparator that sorts objects in ascending + * order based on the ...getters. getters are called for each + * item and return the value to compare against the other items. + * + * - if a getter returns undefined the item will be sorted + * before all other items + * - if a getter returns a string it will be compared using + * `String#localeCompare` + * - otherwise comparison is done using subtraction + * - If the values for a getter are equal the next getter is + * used to compare the items. + */ +export const ascending = (...getters: Array>): Comparator => (a, b) => { + for (const getter of getters) { + const valA = getter(a); + const valB = getter(b); + + if (valA === valB) { + continue; + } + if (valA === undefined) { + return -1; + } + if (valB === undefined) { + return 1; + } + + return typeof valA === 'string' || typeof valB === 'string' + ? String(valA).localeCompare(String(valB)) + : valA - valB; + } + + return 0; +}; + +/** + * create a sort comparator that sorts values in descending + * order based on the ...getters + * + * See docs for ascending() + */ +export const descending = (...getters: Array>): Comparator => { + const sorter = ascending(...getters); + return (a, b) => sorter(b, a); +}; + +/** + * Invert a filter function that has a defined type guard with + * typescript support + */ +export const invert = (fn: (x: T) => x is T2) => (x: T): x is Exclude => + !fn(x); + +/** + * Alternate Array#includes() implementation with sane types, functions as a type guard + */ +export const includes = (array: T[], value: any): value is T => array.includes(value); diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts new file mode 100644 index 0000000000000..c39af73bd7206 --- /dev/null +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -0,0 +1,140 @@ +/* + * 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 Path from 'path'; + +import { BundleCache } from './bundle_cache'; +import { UnknownVals } from './ts_helpers'; +import { includes } from './array_helpers'; + +export const VALID_BUNDLE_TYPES = ['plugin' as const]; + +export interface BundleSpec { + readonly type: typeof VALID_BUNDLE_TYPES[0]; + /** Unique id for this bundle */ + readonly id: string; + /** Webpack entry request for this plugin, relative to the contextDir */ + readonly entry: string; + /** Absolute path to the plugin source directory */ + readonly contextDir: string; + /** Absolute path to the root of the repository */ + readonly sourceRoot: string; + /** Absolute path to the directory where output should be written */ + readonly outputDir: string; +} + +export class Bundle { + public readonly type: BundleSpec['type']; + public readonly id: BundleSpec['id']; + public readonly entry: BundleSpec['entry']; + public readonly contextDir: BundleSpec['contextDir']; + public readonly sourceRoot: BundleSpec['sourceRoot']; + public readonly outputDir: BundleSpec['outputDir']; + + public readonly cache: BundleCache; + + public static parseSpec(spec: UnknownVals) { + if (!(spec && typeof spec === 'object')) { + throw new Error('`bundles[]` must be an object'); + } + + const { type } = spec; + if (!includes(VALID_BUNDLE_TYPES, type)) { + throw new Error('`bundles[]` must have a valid `type`'); + } + + const { id } = spec; + if (!(typeof id === 'string')) { + throw new Error('`bundles[]` must have a string `id` property'); + } + + const { entry } = spec; + if (!(typeof entry === 'string')) { + throw new Error('`bundles[]` must have a string `entry` property'); + } + + const { contextDir } = spec; + if (!(typeof contextDir === 'string' && Path.isAbsolute(contextDir))) { + throw new Error('`bundles[]` must have a string `contextDir` property'); + } + + const { sourceRoot } = spec; + if (!(typeof sourceRoot === 'string' && Path.isAbsolute(sourceRoot))) { + throw new Error('`bundles[]` must have a string `sourceRoot` property'); + } + + const { outputDir } = spec; + if (typeof outputDir !== 'string') { + throw new Error('`bundles[]` must have a string `outputDir` property'); + } + + return new Bundle({ + type, + id, + entry, + contextDir, + sourceRoot, + outputDir, + }); + } + + constructor(spec: BundleSpec) { + this.type = spec.type; + this.id = spec.id; + this.entry = spec.entry; + this.contextDir = spec.contextDir; + this.sourceRoot = spec.sourceRoot; + this.outputDir = spec.outputDir; + + this.cache = new BundleCache(Path.resolve(this.outputDir, '.kbn-optimizer-cache')); + } + + public getModuleCount() { + return this.cache.getModuleCount(); + } + + toSpec(): BundleSpec { + return { + type: this.type, + id: this.id, + entry: this.entry, + contextDir: this.contextDir, + sourceRoot: this.sourceRoot, + outputDir: this.outputDir, + }; + } +} + +export function parseBundles(json: string) { + try { + if (typeof json !== 'string') { + throw new Error('must be a JSON string'); + } + + const specs: Array> = JSON.parse(json); + + if (!Array.isArray(specs)) { + throw new Error('must be an array'); + } + + return specs.map(spec => Bundle.parseSpec(spec)); + } catch (error) { + throw new Error(`unable to parse bundles: ${error.message}`); + } +} diff --git a/packages/kbn-optimizer/src/optimizer_cache.ts b/packages/kbn-optimizer/src/common/bundle_cache.ts similarity index 61% rename from packages/kbn-optimizer/src/optimizer_cache.ts rename to packages/kbn-optimizer/src/common/bundle_cache.ts index eb3c2ff42b6e0..bfb690365c39a 100644 --- a/packages/kbn-optimizer/src/optimizer_cache.ts +++ b/packages/kbn-optimizer/src/common/bundle_cache.ts @@ -20,12 +20,16 @@ import Fs from 'fs'; import Path from 'path'; -const DEFAULT_STATE = JSON.stringify({}); - interface State { - moduleCounts: { [key: string]: number | undefined }; + optimizerVersion?: string; + key?: string; + moduleCount?: number; + files?: string[]; } +const DEFAULT_STATE: State = {}; +const DEFAULT_STATE_JSON = JSON.stringify(DEFAULT_STATE); + /** * Helper to read and update metadata for bundles. * @@ -33,11 +37,15 @@ interface State { * us to assign bundles to workers in a way that ensures an even * distribution of modules to be built */ -export class OptimizerCache { +export class BundleCache { private state: State | undefined = undefined; constructor(private readonly path: string | false) {} - private getState() { + refresh() { + this.state = undefined; + } + + get() { if (!this.state) { let json; try { @@ -52,49 +60,46 @@ export class OptimizerCache { let partialCache: Partial; try { - partialCache = JSON.parse(json || DEFAULT_STATE); + partialCache = JSON.parse(json || DEFAULT_STATE_JSON); } catch (error) { partialCache = {}; } this.state = { - moduleCounts: partialCache.moduleCounts || {}, + ...DEFAULT_STATE, + ...partialCache, }; } return this.state; } - getBundleModuleCount(bundleId: string) { - const state = this.getState(); - return state.moduleCounts[bundleId]; + update(updater: (state: State) => State) { + this.set(updater(this.get())); + } + + set(updated: State) { + this.state = updated; + if (this.path) { + const directory = Path.dirname(this.path); + Fs.mkdirSync(directory, { recursive: true }); + Fs.writeFileSync(this.path, JSON.stringify(this.state, null, 2)); + } } - saveBundleModuleCount(bundleId: string, count: number) { - const current = this.getState(); + public getModuleCount() { + return this.get().moduleCount; + } - this.setState({ - ...current, - moduleCounts: { - ...current.moduleCounts, - [bundleId]: count, - }, - }); + public getReferencedFiles() { + return this.get().files; } - private scheduledWrite = false; - private setState(updated: State) { - this.state = updated; + public getKey() { + return this.get().key; + } - if (!this.scheduledWrite && this.path) { - const path = this.path; - const directory = Path.dirname(path); - this.scheduledWrite = true; - process.nextTick(() => { - this.scheduledWrite = false; - Fs.mkdirSync(directory, { recursive: true }); - Fs.writeFileSync(path, JSON.stringify(this.state, null, 2)); - }); - } + public getOptimizerVersion() { + return this.get().optimizerVersion; } } diff --git a/packages/kbn-optimizer/src/common/compiler_messages.ts b/packages/kbn-optimizer/src/common/compiler_messages.ts index 0b384c2a7f9ed..8308f49751030 100644 --- a/packages/kbn-optimizer/src/common/compiler_messages.ts +++ b/packages/kbn-optimizer/src/common/compiler_messages.ts @@ -34,7 +34,7 @@ export interface CompilerErrorMessage { */ export interface CompilerRunningMessage { type: 'running'; - id: string; + bundleId: string; } /** @@ -45,7 +45,7 @@ export interface CompilerRunningMessage { */ export interface CompilerIssueMessage { type: 'compiler issue'; - id: string; + bundleId: string; failure: string; } @@ -55,7 +55,7 @@ export interface CompilerIssueMessage { */ export interface CompilerSuccessMessage { type: 'compiler success'; - id: string; + bundleId: string; moduleCount: number; } @@ -66,14 +66,14 @@ export class CompilerMessages { running(): CompilerRunningMessage { return { - id: this.bundle, + bundleId: this.bundle, type: 'running', }; } compilerFailure(options: { failure: string }): CompilerIssueMessage { return { - id: this.bundle, + bundleId: this.bundle, type: 'compiler issue', failure: options.failure, }; @@ -81,7 +81,7 @@ export class CompilerMessages { compilerSuccess(options: { moduleCount: number }): CompilerSuccessMessage { return { - id: this.bundle, + bundleId: this.bundle, type: 'compiler success', moduleCount: options.moduleCount, }; diff --git a/packages/kbn-optimizer/src/common/index.ts b/packages/kbn-optimizer/src/common/index.ts index 9a9ae739dcde1..02dd8c3c004ce 100644 --- a/packages/kbn-optimizer/src/common/index.ts +++ b/packages/kbn-optimizer/src/common/index.ts @@ -17,8 +17,12 @@ * under the License. */ -export * from './bundle_definition'; +export * from './bundle'; +export * from './bundle_cache'; export * from './worker_config'; export * from './worker_messages'; export * from './compiler_messages'; +export * from './ts_helpers'; export * from './rxjs_helpers'; +export * from './promise_helpers'; +export * from './array_helpers'; diff --git a/packages/kbn-optimizer/src/common/bundle_definition.ts b/packages/kbn-optimizer/src/common/promise_helpers.ts similarity index 56% rename from packages/kbn-optimizer/src/common/bundle_definition.ts rename to packages/kbn-optimizer/src/common/promise_helpers.ts index c89b8a9bcfd86..d0ce3f2762bbe 100644 --- a/packages/kbn-optimizer/src/common/bundle_definition.ts +++ b/packages/kbn-optimizer/src/common/promise_helpers.ts @@ -17,18 +17,23 @@ * under the License. */ -export const VALID_BUNDLE_TYPES = ['plugin' as const]; +import * as Rx from 'rxjs'; +import { mergeMap, toArray } from 'rxjs/operators'; +import { maybe } from './rxjs_helpers'; -export interface BundleDefinition { - readonly type: typeof VALID_BUNDLE_TYPES[0]; - /** Unique id for this bundle */ - readonly id: string; - /** Webpack entry request for this plugin, relative to the contextDir */ - readonly entry: string; - /** Absolute path to the plugin source directory */ - readonly contextDir: string; - /** Absolute path to the root of the repository */ - readonly sourceRoot: string; - /** Absolute path to the directory where output should be written */ - readonly outputDir: string; -} +/** + * Concurrently iterate over an array of items, resolving the promises returned from each call to fn, + * limit concurrency, items are sorted in resolution order so be sure to sort after the fact. + */ +export const concurrentMap = async ( + array: Iterable, + fn: (item: T1) => Promise, + concurrency = 100 +) => + await Rx.from(array) + .pipe( + mergeMap(async item => await fn(item), concurrency), + maybe(), + toArray() + ) + .toPromise(); diff --git a/packages/kbn-optimizer/src/common/rxjs_helpers.ts b/packages/kbn-optimizer/src/common/rxjs_helpers.ts index 0430b507ae15f..a7af91a5971d5 100644 --- a/packages/kbn-optimizer/src/common/rxjs_helpers.ts +++ b/packages/kbn-optimizer/src/common/rxjs_helpers.ts @@ -18,7 +18,7 @@ */ import * as Rx from 'rxjs'; -import { mergeMap } from 'rxjs/operators'; +import { mergeMap, tap, debounceTime, map } from 'rxjs/operators'; type Operator = (source: Rx.Observable) => Rx.Observable; type MapFn = (item: T1, index: number) => T2; @@ -41,6 +41,14 @@ export const pipeClosure = (fn: Operator): Operator => { }; }; +/** + * An operator that filters out undefined values from the stream while + * supporting TypeScript + */ +export const maybe = (): Operator => { + return mergeMap(item => (item === undefined ? Rx.EMPTY : [item])); +}; + /** * An operator like map(), but undefined values are filered out automatically * with TypeScript support. For some reason TS doesn't have great support for @@ -50,6 +58,44 @@ export const pipeClosure = (fn: Operator): Operator => { export const maybeMap = (fn: MapFn): Operator => { return mergeMap((item, index) => { const result = fn(item, index); - return result === undefined ? [] : [result]; + return result === undefined ? Rx.EMPTY : [result]; + }); +}; + +/** + * Debounce received notifications and write them to a buffer. Once the source + * has been silent for `ms` milliseconds the buffer is flushed as a single array + * to the destination stream + */ +export const debounceTimeBuffer = (ms: number) => + pipeClosure((source$: Rx.Observable) => { + const buffer = new Set(); + return source$.pipe( + tap(item => buffer.add(item)), + debounceTime(ms), + map(() => { + const items = Array.from(buffer); + buffer.clear(); + return items; + }) + ); + }); + +/** + * Basically the same as the `scan()` function from RxJS but with the seed + * argument first and the types working properly. + */ +export const scanBetter = ( + seed: T1, + fn: (acc: T1 | T3, item: T2) => T3 +): Operator => { + return pipeClosure(source$ => { + let acc: T1 | T3 = seed; + return source$.pipe( + map(item => { + acc = fn(acc, item); + return acc; + }) + ); }); }; diff --git a/packages/kbn-optimizer/src/log.ts b/packages/kbn-optimizer/src/common/ts_helpers.ts similarity index 80% rename from packages/kbn-optimizer/src/log.ts rename to packages/kbn-optimizer/src/common/ts_helpers.ts index 79093605115f6..8c0b857d212ac 100644 --- a/packages/kbn-optimizer/src/log.ts +++ b/packages/kbn-optimizer/src/common/ts_helpers.ts @@ -17,8 +17,10 @@ * under the License. */ -export interface Log { - info(tmpl: string, ...args: any[]): void; - success(tmpl: string, ...args: any[]): void; - error(error: string | Error): void; -} +/** + * Convert an object type into an object with the same keys + * but with each value type replaced with `unknown` + */ +export type UnknownVals = { + [k in keyof T]: unknown; +}; diff --git a/packages/kbn-optimizer/src/common/worker_config.ts b/packages/kbn-optimizer/src/common/worker_config.ts index dffc6e6f29b52..f5aa5da794e7f 100644 --- a/packages/kbn-optimizer/src/common/worker_config.ts +++ b/packages/kbn-optimizer/src/common/worker_config.ts @@ -19,83 +19,68 @@ import Path from 'path'; -import { BundleDefinition, VALID_BUNDLE_TYPES } from './bundle_definition'; +import { UnknownVals } from './ts_helpers'; export interface WorkerConfig { readonly repoRoot: string; readonly watch: boolean; readonly dist: boolean; - readonly bundles: BundleDefinition[]; + readonly cache: boolean; readonly profileWebpack: boolean; + readonly optimizerVersion: string; } -type UnknownVals = { - [k in keyof T]: unknown; -}; - -export function parseWorkerConfig(json: string) { +export function parseWorkerConfig(json: string): WorkerConfig { try { if (typeof json !== 'string') { - throw new Error('expected config to be a JSON string'); + throw new Error('expected worker config to be a JSON string'); } const parsed: UnknownVals = JSON.parse(json); - if (!(parsed && typeof parsed === 'object')) { + + if (!(typeof parsed === 'object' && parsed)) { throw new Error('config must be an object'); } - if (!(parsed.watch === undefined || typeof parsed.watch === 'boolean')) { - throw new Error('`watch` config must be a boolean when defined'); + const repoRoot = parsed.repoRoot; + if (typeof repoRoot !== 'string' || !Path.isAbsolute(repoRoot)) { + throw new Error('`repoRoot` config must be an absolute path'); } - if (!(parsed.dist === undefined || typeof parsed.dist === 'boolean')) { - throw new Error('`dist` config must be a boolean when defined'); + const cache = parsed.cache; + if (typeof cache !== 'boolean') { + throw new Error('`cache` config must be a boolean'); } - if (typeof parsed.profileWebpack !== 'boolean') { - throw new Error('`profileWebpack` must be a boolean'); + const watch = parsed.watch; + if (typeof watch !== 'boolean') { + throw new Error('`watch` config must be a boolean'); } - if (!Array.isArray(parsed.bundles)) { - throw new Error('config.bundles must be an array'); + const dist = parsed.dist; + if (typeof dist !== 'boolean') { + throw new Error('`dist` config must be a boolean'); } - for (const parsedBundle of parsed.bundles as Array>) { - if (!(parsedBundle && typeof parsedBundle === 'object')) { - throw new Error('config.bundles[] must be an object'); - } - - if (!VALID_BUNDLE_TYPES.includes(parsedBundle.type as any)) { - throw new Error('config.bundles[] must have a valid `type`'); - } - - if (!(typeof parsedBundle.id === 'string')) { - throw new Error('config.bundles[] must have a string `id` property'); - } - - if (!(typeof parsedBundle.entry === 'string')) { - throw new Error('config.bundles[] must have a string `entry` property'); - } - - if (typeof parsedBundle.outputDir !== 'string') { - throw new Error('`outputDir` config must be a string'); - } + const profileWebpack = parsed.profileWebpack; + if (typeof profileWebpack !== 'boolean') { + throw new Error('`profileWebpack` must be a boolean'); + } - if ( - !(typeof parsedBundle.contextDir === 'string' && Path.isAbsolute(parsedBundle.contextDir)) - ) { - throw new Error('config.bundles[] must have a string `contextDir` property'); - } + const optimizerVersion = parsed.optimizerVersion; + if (typeof optimizerVersion !== 'string') { + throw new Error('`optimizerVersion` must be a string'); } return { - error: undefined, - workerConfig: parsed as WorkerConfig, + repoRoot, + cache, + watch, + dist, + profileWebpack, + optimizerVersion, }; } catch (error) { - return { - error: new Error(`unable to parse worker config: ${error.message}`), - workerConfig: undefined, - }; + throw new Error(`unable to parse worker config: ${error.message}`); } } diff --git a/packages/kbn-optimizer/src/common/worker_messages.ts b/packages/kbn-optimizer/src/common/worker_messages.ts index 5df09af315bbf..323904b598fe7 100644 --- a/packages/kbn-optimizer/src/common/worker_messages.ts +++ b/packages/kbn-optimizer/src/common/worker_messages.ts @@ -42,12 +42,12 @@ export interface WorkerErrorMessage { errorStack?: string; } -const WORKER_STATE_TYPES: Array = [ +const WORKER_STATE_TYPES: ReadonlyArray = [ 'running', - 'compiler success', 'compiler issue', - 'worker error', + 'compiler success', 'compiler error', + 'worker error', ]; export const isWorkerMessage = (value: any): value is WorkerMessage => diff --git a/packages/kbn-optimizer/src/get_bundle_definitions.test.ts b/packages/kbn-optimizer/src/get_bundles.test.ts similarity index 95% rename from packages/kbn-optimizer/src/get_bundle_definitions.test.ts rename to packages/kbn-optimizer/src/get_bundles.test.ts index d6c5212941207..9d95d883d605c 100644 --- a/packages/kbn-optimizer/src/get_bundle_definitions.test.ts +++ b/packages/kbn-optimizer/src/get_bundles.test.ts @@ -19,13 +19,13 @@ import { createAbsolutePathSerializer } from '@kbn/dev-utils'; -import { getBundleDefinitions } from './get_bundle_definitions'; +import { getBundles } from './get_bundles'; expect.addSnapshotSerializer(createAbsolutePathSerializer('/repo')); it('returns a bundle for each plugin', () => { expect( - getBundleDefinitions( + getBundles( [ { directory: '/repo/plugins/foo', @@ -44,7 +44,7 @@ it('returns a bundle for each plugin', () => { }, ], '/repo' - ) + ).map(b => b.toSpec()) ).toMatchInlineSnapshot(` Array [ Object { diff --git a/packages/kbn-optimizer/src/get_bundle_definitions.ts b/packages/kbn-optimizer/src/get_bundles.ts similarity index 71% rename from packages/kbn-optimizer/src/get_bundle_definitions.ts rename to packages/kbn-optimizer/src/get_bundles.ts index 4e9874d145b60..a8c919d3daeaa 100644 --- a/packages/kbn-optimizer/src/get_bundle_definitions.ts +++ b/packages/kbn-optimizer/src/get_bundles.ts @@ -20,19 +20,20 @@ import Path from 'path'; import { NewPlatformPlugin } from './new_platform_plugins'; -import { BundleDefinition } from './common'; +import { Bundle } from './common'; -export function getBundleDefinitions(plugins: NewPlatformPlugin[], repoRoot: string) { +export function getBundles(plugins: NewPlatformPlugin[], repoRoot: string) { return plugins .filter(p => p.isUiPlugin) .map( - (p): BundleDefinition => ({ - type: 'plugin', - id: p.id, - entry: './public/index', - sourceRoot: repoRoot, - contextDir: p.directory, - outputDir: Path.resolve(p.directory, 'target/public'), - }) + p => + new Bundle({ + type: 'plugin', + id: p.id, + entry: './public/index', + sourceRoot: repoRoot, + contextDir: p.directory, + outputDir: Path.resolve(p.directory, 'target/public'), + }) ); } diff --git a/packages/kbn-optimizer/src/get_changes.test.ts b/packages/kbn-optimizer/src/get_changes.test.ts new file mode 100644 index 0000000000000..65b4205ba6386 --- /dev/null +++ b/packages/kbn-optimizer/src/get_changes.test.ts @@ -0,0 +1,63 @@ +/* + * 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. + */ + +jest.mock('execa'); + +import { getChanges } from './get_changes'; + +const execa: jest.Mock = jest.requireMock('execa'); + +it('parses git ls-files output', async () => { + expect.assertions(4); + + execa.mockImplementation((cmd, args, options) => { + expect(cmd).toBe('git'); + expect(args).toEqual(['ls-files', '-dmt', '--', '/foo/bar/x', '/foo/bar/y']); + expect(options).toEqual({ + cwd: '/foo/bar', + }); + + return { + stdout: [ + 'C x/kbn-optimizer/package.json', + 'C x/kbn-optimizer/src/common/bundle.ts', + 'R x/kbn-optimizer/src/common/bundles.ts', + 'C x/kbn-optimizer/src/common/bundles.ts', + 'R x/kbn-optimizer/src/get_bundle_definitions.test.ts', + 'C x/kbn-optimizer/src/get_bundle_definitions.test.ts', + 'C y/src/plugins/data/public/index.ts', + ].join('\n'), + }; + }); + + await expect(getChanges('/foo/bar', ['/foo/bar/x', '/foo/bar/y'])).resolves + .toMatchInlineSnapshot(` + Map { + "/foo/bar/x" => Map { + "/foo/bar/x/kbn-optimizer/package.json" => "modified", + "/foo/bar/x/kbn-optimizer/src/common/bundle.ts" => "modified", + "/foo/bar/x/kbn-optimizer/src/common/bundles.ts" => "deleted", + "/foo/bar/x/kbn-optimizer/src/get_bundle_definitions.test.ts" => "deleted", + }, + "/foo/bar/y" => Map { + "/foo/bar/y/src/plugins/data/public/index.ts" => "modified", + }, + } + `); +}); diff --git a/packages/kbn-optimizer/src/get_changes.ts b/packages/kbn-optimizer/src/get_changes.ts new file mode 100644 index 0000000000000..c1526e6114ae2 --- /dev/null +++ b/packages/kbn-optimizer/src/get_changes.ts @@ -0,0 +1,89 @@ +/* + * 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 Path from 'path'; + +import execa from 'execa'; +import isPathInside from 'is-path-inside'; + +import { descending } from './common'; + +export type Changes = Map; + +/** + * get the changes in all the context directories (plugin public paths) + */ +export async function getChanges(repoRoot: string, dirs: string[]) { + const { stdout } = await execa('git', ['ls-files', '-dmt', '--', ...dirs], { + cwd: repoRoot, + }); + + const output = stdout.trim(); + const unassignedChanges: Changes = new Map(); + + if (output) { + for (const line of output.split('\n')) { + const [tag, ...pathParts] = line.trim().split(' '); + const path = Path.resolve(repoRoot, pathParts.join(' ')); + switch (tag) { + case 'M': + case 'C': + // for some reason ls-files returns deleted files as both deleted + // and modified, so make sure not to overwrite changes already + // tracked as "deleted" + if (unassignedChanges.get(path) !== 'deleted') { + unassignedChanges.set(path, 'modified'); + } + break; + + case 'R': + unassignedChanges.set(path, 'deleted'); + break; + + default: + throw new Error(`unexpected path status ${tag} for path ${path}`); + } + } + } + + const changesByDir = new Map(); + const dirsBySpecificity = Array.from(dirs).sort(descending(dir => dir.length)); + + for (const dir of dirsBySpecificity) { + const ownChanges: Changes = new Map(); + for (const [path, type] of unassignedChanges) { + if (isPathInside(path, dir)) { + ownChanges.set(path, type); + unassignedChanges.delete(path); + } + } + + changesByDir.set(dir, ownChanges); + } + + if (unassignedChanges.size) { + throw new Error( + `unable to assign all change paths to a project: ${JSON.stringify( + Array.from(unassignedChanges.entries()) + )}` + ); + } + + return changesByDir; +} diff --git a/packages/kbn-optimizer/src/get_mtimes.test.ts b/packages/kbn-optimizer/src/get_mtimes.test.ts new file mode 100644 index 0000000000000..68b412c15628d --- /dev/null +++ b/packages/kbn-optimizer/src/get_mtimes.test.ts @@ -0,0 +1,47 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +jest.mock('fs'); + +import { getMtimes } from './get_mtimes'; + +const { stat }: { stat: jest.Mock } = jest.requireMock('fs'); + +it('returns mtimes Map', async () => { + stat.mockImplementation((path, cb) => { + if (path.includes('missing')) { + const error = new Error('file not found'); + (error as any).code = 'ENOENT'; + cb(error); + } else { + cb(null, { + mtimeMs: 1234, + }); + } + }); + + await expect(getMtimes(['/foo/bar', '/foo/missing', '/foo/baz', '/foo/bar'])).resolves + .toMatchInlineSnapshot(` + Map { + "/foo/bar" => 1234, + "/foo/missing" => undefined, + "/foo/baz" => 1234, + } + `); +}); diff --git a/packages/kbn-optimizer/src/get_mtimes.ts b/packages/kbn-optimizer/src/get_mtimes.ts new file mode 100644 index 0000000000000..1993a799cff7b --- /dev/null +++ b/packages/kbn-optimizer/src/get_mtimes.ts @@ -0,0 +1,49 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Fs from 'fs'; +import { promisify } from 'util'; + +import { concurrentMap } from './common'; + +const statAsync = promisify(Fs.stat); + +/** + * get mtimes of referenced paths concurrently, limit concurrency to 100 + */ +export async function getMtimes(paths: Iterable) { + return new Map( + await concurrentMap( + paths, + async path => { + try { + const stat = await statAsync(path); + return [path, stat.mtimeMs] as const; + } catch (error) { + if (error?.code === 'ENOENT') { + return [path, undefined] as const; + } + + throw error; + } + }, + 100 + ) + ); +} diff --git a/packages/kbn-optimizer/src/get_optimizer_version.ts b/packages/kbn-optimizer/src/get_optimizer_version.ts new file mode 100644 index 0000000000000..8c095bec7421c --- /dev/null +++ b/packages/kbn-optimizer/src/get_optimizer_version.ts @@ -0,0 +1,60 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import Path from 'path'; +import { createHash } from 'crypto'; + +import execa from 'execa'; +import { REPO_ROOT } from '@kbn/dev-utils'; +import { getMtimes } from './get_mtimes'; +import { getChanges } from './get_changes'; +import { ascending } from './common'; + +const OPTIMIZER_DIR = Path.dirname(require.resolve('../package.json')); +const RELATIVE_DIR = Path.relative(REPO_ROOT, OPTIMIZER_DIR); + +async function getLastCommit() { + const { stdout } = await execa( + 'git', + ['log', '-n', '1', '--pretty=format:%H', '--', RELATIVE_DIR], + { + cwd: REPO_ROOT, + } + ); + + return stdout.trim() || undefined; +} + +export async function getOptimizerVersion() { + const cacheLines: string[] = []; + + cacheLines.push(`lastCommit:${await getLastCommit()}`); + + const changes = (await getChanges(REPO_ROOT, [OPTIMIZER_DIR])).get(OPTIMIZER_DIR); + if (changes) { + const mtimes = await getMtimes(changes.keys()); + for (const [path, mtime] of mtimes) { + cacheLines.push(`mtime:${path}:${mtime}`); + } + } + + return createHash('sha1') + .update(cacheLines.sort((a, b) => a.localeCompare(b)).join('\n')) + .digest('hex'); +} diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap index 52ff5f25f556d..a978851334f8d 100644 --- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap +++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap @@ -3,7 +3,11 @@ exports[`builds expected bundles, saves bundle counts to metadata: OptimizerConfig 1`] = ` OptimizerConfig { "bundles": Array [ - Object { + Bundle { + "cache": BundleCache { + "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public/.kbn-optimizer-cache, + "state": undefined, + }, "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, "entry": "./public/index", "id": "bar", @@ -11,7 +15,11 @@ OptimizerConfig { "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, "type": "plugin", }, - Object { + Bundle { + "cache": BundleCache { + "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public/.kbn-optimizer-cache, + "state": undefined, + }, "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, "entry": "./public/index", "id": "foo", @@ -20,412 +28,29 @@ OptimizerConfig { "type": "plugin", }, ], - "cache": OptimizerCache { - "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/data/.kbn-optimizer-cache.json, - "scheduledWrite": false, - "state": Object { - "moduleCounts": Object {}, - }, - }, + "cache": true, + "dist": false, "inspectWorkers": false, - "watch": false, - "workers": Array [ + "maxWorkerCount": 1, + "plugins": Array [ + Object { + "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, + "id": "bar", + "isUiPlugin": true, + }, Object { - "bundles": Array [ - Object { - "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, - "entry": "./public/index", - "id": "foo", - "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public, - "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, - "type": "plugin", - }, - Object { - "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, - "entry": "./public/index", - "id": "bar", - "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public, - "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, - "type": "plugin", - }, - ], - "dist": false, - "profileWebpack": false, - "repoRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, - "watch": false, + "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/baz, + "id": "baz", + "isUiPlugin": false, + }, + Object { + "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, + "id": "foo", + "isUiPlugin": true, }, ], + "profileWebpack": false, + "repoRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, + "watch": false, } `; - -exports[`builds expected bundles, saves bundle counts to metadata: bar bundle 1`] = ` -"var __kbnBundles__ = typeof __kbnBundles__ === \\"object\\" ? __kbnBundles__ : {}; __kbnBundles__[\\"plugin/bar\\"] = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = \\"__REPLACE_WITH_PUBLIC_PATH__\\"; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = \\"./public/index.ts\\"); -/******/ }) -/************************************************************************/ -/******/ ({ - -/***/ \\"./public/index.ts\\": -/*!*************************!*\\\\ - !*** ./public/index.ts ***! - \\\\*************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -\\"use strict\\"; - - -Object.defineProperty(exports, \\"__esModule\\", { - value: true -}); - -var _lib = __webpack_require__(/*! ./lib */ \\"./public/lib.ts\\"); - -Object.keys(_lib).forEach(function (key) { - if (key === \\"default\\" || key === \\"__esModule\\") return; - Object.defineProperty(exports, key, { - enumerable: true, - get: function () { - return _lib[key]; - } - }); -}); - -/***/ }), - -/***/ \\"./public/lib.ts\\": -/*!***********************!*\\\\ - !*** ./public/lib.ts ***! - \\\\***********************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -\\"use strict\\"; - - -Object.defineProperty(exports, \\"__esModule\\", { - value: true -}); -exports.barLibFn = barLibFn; - -/* - * 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 barLibFn() { - return 'bar'; -} - -/***/ }) - -/******/ })[\\"plugin\\"]; -//# sourceMappingURL=bar.plugin.js.map" -`; - -exports[`builds expected bundles, saves bundle counts to metadata: foo bundle 1`] = ` -"var __kbnBundles__ = typeof __kbnBundles__ === \\"object\\" ? __kbnBundles__ : {}; __kbnBundles__[\\"plugin/foo\\"] = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); -/******/ } -/******/ }; -/******/ -/******/ // define __esModule on exports -/******/ __webpack_require__.r = function(exports) { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ -/******/ // create a fake namespace object -/******/ // mode & 1: value is a module id, require it -/******/ // mode & 2: merge all properties of value into the ns -/******/ // mode & 4: return value when already ns object -/******/ // mode & 8|1: behave like require -/******/ __webpack_require__.t = function(value, mode) { -/******/ if(mode & 1) value = __webpack_require__(value); -/******/ if(mode & 8) return value; -/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; -/******/ var ns = Object.create(null); -/******/ __webpack_require__.r(ns); -/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); -/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); -/******/ return ns; -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = \\"__REPLACE_WITH_PUBLIC_PATH__\\"; -/******/ -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = \\"./public/index.ts\\"); -/******/ }) -/************************************************************************/ -/******/ ({ - -/***/ \\"./public/ext.ts\\": -/*!***********************!*\\\\ - !*** ./public/ext.ts ***! - \\\\***********************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -\\"use strict\\"; - - -Object.defineProperty(exports, \\"__esModule\\", { - value: true -}); -exports.ext = void 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. - */ -const ext = 'TRUE'; -exports.ext = ext; - -/***/ }), - -/***/ \\"./public/index.ts\\": -/*!*************************!*\\\\ - !*** ./public/index.ts ***! - \\\\*************************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -\\"use strict\\"; - - -Object.defineProperty(exports, \\"__esModule\\", { - value: true -}); - -var _lib = __webpack_require__(/*! ./lib */ \\"./public/lib.ts\\"); - -Object.keys(_lib).forEach(function (key) { - if (key === \\"default\\" || key === \\"__esModule\\") return; - Object.defineProperty(exports, key, { - enumerable: true, - get: function () { - return _lib[key]; - } - }); -}); - -var _ext = __webpack_require__(/*! ./ext */ \\"./public/ext.ts\\"); - -Object.keys(_ext).forEach(function (key) { - if (key === \\"default\\" || key === \\"__esModule\\") return; - Object.defineProperty(exports, key, { - enumerable: true, - get: function () { - return _ext[key]; - } - }); -}); - -/***/ }), - -/***/ \\"./public/lib.ts\\": -/*!***********************!*\\\\ - !*** ./public/lib.ts ***! - \\\\***********************/ -/*! no static exports found */ -/***/ (function(module, exports, __webpack_require__) { - -\\"use strict\\"; - - -Object.defineProperty(exports, \\"__esModule\\", { - value: true -}); -exports.fooLibFn = fooLibFn; - -/* - * 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 fooLibFn() { - return 'foo'; -} - -/***/ }) - -/******/ })[\\"plugin\\"]; -//# sourceMappingURL=foo.plugin.js.map" -`; diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index 6c280c1664de9..e93339c9b3cd7 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -104,6 +104,21 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { Fs.readFileSync(Path.resolve(MOCK_REPO_DIR, 'plugins/bar/target/public/bar.plugin.js'), 'utf8') ).toMatchSnapshot('bar bundle'); - expect(config.cache.getBundleModuleCount('foo')).toBe(3); - expect(config.cache.getBundleModuleCount('bar')).toBe(2); + const foo = config.bundles.find(b => b.id === 'foo')!; + expect(foo).toBeTruthy(); + foo.cache.refresh(); + expect(foo.getModuleCount()).toBe(3); + expect(foo.cache.getReferencedFiles()).toMatchInlineSnapshot(`Array []`); + + const bar = config.bundles.find(b => b.id === 'bar')!; + expect(bar).toBeTruthy(); + bar.cache.refresh(); + expect(bar.getModuleCount()).toBe(5); + expect(bar.cache.getReferencedFiles()).toMatchInlineSnapshot(` + Array [ + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/ext.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/index.ts, + /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/lib.ts, + ] + `); }); diff --git a/packages/kbn-optimizer/src/log_optimizer_state.test.ts b/packages/kbn-optimizer/src/log_optimizer_state.test.ts deleted file mode 100644 index bcc65b4d1472e..0000000000000 --- a/packages/kbn-optimizer/src/log_optimizer_state.test.ts +++ /dev/null @@ -1,127 +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 Path from 'path'; - -import * as Rx from 'rxjs'; -import { toArray } from 'rxjs/operators'; -import { REPO_ROOT, ToolingLog, ToolingLogCollectingWriter } from '@kbn/dev-utils'; - -import { OptimizerState } from './optimizer'; -import { OptimizerConfig } from './optimizer_config'; -import { logOptimizerState } from './log_optimizer_state'; - -it('produces expected messages and mirrors state updates downstream', async () => { - const logWriter = new ToolingLogCollectingWriter(); - const log = new ToolingLog(); - log.setWriters([logWriter]); - - const config = OptimizerConfig.create({ - repoRoot: REPO_ROOT, - maxWorkerCount: 2, - pluginScanDirs: [Path.resolve(__dirname, './__fixtures__/mock_repo/plugins')], - }); - - const stateUpdates: OptimizerState[] = [ - { - type: 'worker stdio', - chunk: Buffer.from('something from stderr'), - stream: 'stderr', - }, - { - type: 'worker stdio', - chunk: Buffer.from('something from stdout'), - stream: 'stdout', - }, - { - type: 'running', - durSec: 0, - compilerStates: [ - { - id: 'foo', - type: 'running', - }, - ], - }, - { - type: 'running', - durSec: 1, - compilerStates: [ - { - id: 'foo', - type: 'running', - }, - { - id: 'bar', - type: 'running', - }, - ], - }, - { - type: 'running', - durSec: 10, - compilerStates: [ - { - id: 'foo', - type: 'running', - }, - { - id: 'bar', - type: 'compiler success', - moduleCount: 50, - }, - ], - }, - { - type: 'compiler success', - durSec: 30, - compilerStates: [ - { - id: 'foo', - type: 'compiler success', - moduleCount: 100, - }, - { - id: 'bar', - type: 'compiler success', - moduleCount: 50, - }, - ], - }, - ]; - - const results = await Rx.from(stateUpdates) - .pipe(logOptimizerState(log, config), toArray()) - .toPromise(); - - expect(results).toEqual(stateUpdates.filter(s => s.type !== 'worker stdio')); - - expect(logWriter.messages).toMatchInlineSnapshot(` - Array [ - " info ⚙️ building 2 bundles using 2 workers", - " warn ⚙️ worker stderr something from stderr", - " warn ⚙️ worker stdout something from stdout", - " sill [foo] state = \\"running\\"", - " sill [bar] state = \\"running\\"", - " sill [bar] state = \\"compiler success\\" after 10 seconds", - " sill [foo] state = \\"compiler success\\" after 30 seconds", - " succ ⚙️ all bundles compiled successfully after 30 seconds", - ] - `); -}); diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index 14a3f7cf30ea8..363644e04f9e2 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -17,37 +17,50 @@ * under the License. */ -import { ToolingLog } from '@kbn/dev-utils'; import { inspect } from 'util'; -import { filter } from 'rxjs/operators'; + +import { ToolingLog } from '@kbn/dev-utils'; +import * as Rx from 'rxjs'; +import { tap } from 'rxjs/operators'; import { OptimizerConfig } from './optimizer_config'; -import { OptimizerState, OptimizerStateSummary } from './optimizer'; +import { OptimizerStateSummary } from './optimizer'; import { CompilerState, pipeClosure } from './common'; export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { - return pipeClosure(source => { + return pipeClosure((state$: Rx.Observable) => { const bundleStates = new Map(); - log.info( - `⚙️ building ${config.bundles.length} bundles using ${config.workers.length} workers${ - config.watch ? ' in watch mode' : '' - }` - ); - - return source.pipe( - filter((s): s is OptimizerStateSummary => { - if (s.type === 'worker stdio') { - const chunk = s.chunk.toString('utf8'); + return state$.pipe( + tap(s => { + if (s.event?.type === 'worker stdio') { + const chunk = s.event.chunk.toString('utf8'); log.warning( '⚙️ worker', - s.stream, + s.event.stream, chunk.slice(0, chunk.length - (chunk.endsWith('\n') ? 1 : 0)) ); - return false; + return; + } + + if (s.event?.type === 'worker started') { + log.debug(`worker started for bundles ${s.event.bundles.map(b => b.id).join(', ')}`); + return; + } + + if (s.event?.type === 'changes detected') { + log.debug(`changes detected...`); + return; + } + + if (s.summary === 'initialized') { + log.debug(`initialized after ${s.durSec} sec`); + log.debug(` version: ${s.version}`); + log.debug(` cached: ${s.offlineBundles.map(b => b.id)}`); + return; } - for (const { id, type } of s.compilerStates) { + for (const { bundleId: id, type } of s.compilerStates) { const prevBundleState = bundleStates.get(id); if (type === prevBundleState) { @@ -55,21 +68,21 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { } bundleStates.set(id, type); - log.verbose( - `[${id}] state = "${type}"${type !== 'running' ? ` after ${s.durSec} seconds` : ''}` + log.debug( + `[${id}] state = "${type}"${type !== 'running' ? ` after ${s.durSec} sec` : ''}` ); } - if (s.type === 'running') { + if (s.summary === 'running') { return true; } - if (s.type === 'compiler issue') { + if (s.summary === 'issue') { log.error('⚙️ webpack compile errors'); log.indent(4); for (const b of s.compilerStates) { if (b.type === 'compiler issue') { - log.error(`[${b.id}] build`); + log.error(`[${b.bundleId}] build`); log.indent(4); log.error(b.failure); log.indent(-4); @@ -79,11 +92,11 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { return true; } - if (s.type === 'compiler success') { + if (s.summary === 'success') { log.success( config.watch - ? `⚙️ watching for changes in all bundles after ${s.durSec} seconds` - : `⚙️ all bundles compiled successfully after ${s.durSec} seconds` + ? `⚙️ watching for changes in all bundles after ${s.durSec} sec` + : `⚙️ all bundles compiled successfully after ${s.durSec} sec` ); return true; } diff --git a/packages/kbn-optimizer/src/observe_worker.ts b/packages/kbn-optimizer/src/observe_worker.ts index ca7663ccbf957..ffc6ab14c02c0 100644 --- a/packages/kbn-optimizer/src/observe_worker.ts +++ b/packages/kbn-optimizer/src/observe_worker.ts @@ -24,7 +24,7 @@ import { inspect } from 'util'; import * as Rx from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { isWorkerMessage, WorkerMessage, WorkerConfig } from './common'; +import { isWorkerMessage, WorkerConfig, WorkerMessage, Bundle } from './common'; import { OptimizerConfig } from './optimizer_config'; export interface WorkerStdio { @@ -33,6 +33,13 @@ export interface WorkerStdio { chunk: Buffer; } +export interface WorkerStarted { + type: 'worker started'; + bundles: Bundle[]; +} + +export type WorkerStatus = WorkerStdio | WorkerStarted; + interface ProcResource extends Rx.Unsubscribable { proc: ChildProcess; } @@ -60,22 +67,25 @@ if (inspectFlagIndex !== -1) { function usingWorkerProc( config: OptimizerConfig, - worker: WorkerConfig, + workerConfig: WorkerConfig, + bundles: Bundle[], fn: (proc: ChildProcess) => Rx.Observable ) { return Rx.using( (): ProcResource => { - const proc = fork(require.resolve('./worker/run_worker'), [JSON.stringify(worker)], { + const args = [JSON.stringify(workerConfig), JSON.stringify(bundles.map(b => b.toSpec()))]; + + const proc = fork(require.resolve('./worker/run_worker'), args, { stdio: ['ignore', 'pipe', 'pipe', 'ipc'], execArgv: [ ...(inspectFlag && config.inspectWorkers ? [`${inspectFlag}=${inspectPortCounter++}`] : []), - ...(config.workers.length <= 2 ? ['--max-old-space-size=2048'] : []), + ...(config.maxWorkerCount <= 3 ? ['--max-old-space-size=2048'] : []), ], env: { ...process.env, - BROWSERSLIST_ENV: worker.dist ? 'production' : process.env.BROWSERSLIST_ENV || 'dev', + BROWSERSLIST_ENV: config.dist ? 'production' : process.env.BROWSERSLIST_ENV || 'dev', }, }); @@ -118,12 +128,17 @@ function observeStdio$(stream: Readable, name: WorkerStdio['stream']) { export function observeWorker( config: OptimizerConfig, - worker: WorkerConfig -): Rx.Observable { - return usingWorkerProc(config, worker, proc => { + workerConfig: WorkerConfig, + bundles: Bundle[] +): Rx.Observable { + return usingWorkerProc(config, workerConfig, bundles, proc => { let lastMessage: WorkerMessage; return Rx.merge( + Rx.of({ + type: 'worker started', + bundles, + }), observeStdio$(proc.stdout!, 'stdout'), observeStdio$(proc.stderr!, 'stderr'), Rx.fromEvent<[unknown]>(proc, 'message') @@ -156,7 +171,7 @@ export function observeWorker( 'worker error', ]; - if (!worker.watch) { + if (!config.watch) { terminalMsgTypes.push('compiler issue', 'compiler success'); } diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index 3654b96898291..b477d2b9de024 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -17,23 +17,47 @@ * under the License. */ +import { createHash } from 'crypto'; +import { inspect } from 'util'; + import * as Rx from 'rxjs'; -import { mergeMap, map, tap } from 'rxjs/operators'; -import { createFailError } from '@kbn/dev-utils'; +import { map, mergeMap, share } from 'rxjs/operators'; -import { observeWorker, WorkerStdio } from './observe_worker'; +import { observeWorker, WorkerStatus } from './observe_worker'; import { OptimizerConfig } from './optimizer_config'; -import { CompilerState, WorkerMessage, pipeClosure } from './common'; +import { getOptimizerVersion } from './get_optimizer_version'; +import { CompilerState, WorkerMessage, pipeClosure, Bundle, ascending, maybeMap } from './common'; +import { assignBundlesToWorkers } from './assign_bundles_to_workers'; +import { Watcher, ChangesStarted, Changes } from './watcher'; +import { getMtimes } from './get_mtimes'; export interface OptimizerStateSummary { - type: CompilerState['type']; + summary: 'initialized' | 'success' | 'running' | 'issue'; + version: string; + startTime: number; durSec: number; compilerStates: CompilerState[]; + onlineBundles: Bundle[]; + offlineBundles: Bundle[]; + event?: ChangesStarted | Changes | WorkerMessage | WorkerStatus; +} + +export interface OptimizerStartedWorker { + type: 'worker started'; + bundles: Bundle[]; +} + +export interface OptimizerComingOnline { + type: 'bringing bundle online'; + bundle: Bundle; } -export type OptimizerState = OptimizerStateSummary | WorkerStdio; +export { ChangesStarted }; +export type OptimizerNotif = OptimizerStartedWorker; -const getSummaryType = (states: CompilerState[]) => { +const msToSec = (ms: number) => Math.round(ms / 100) / 10; + +const getSummary = (states: CompilerState[]): OptimizerStateSummary['summary'] => { const types = states.map(s => s.type); if (types.includes('running')) { @@ -41,11 +65,11 @@ const getSummaryType = (states: CompilerState[]) => { } if (types.includes('compiler issue')) { - return 'compiler issue'; + return 'issue'; } if (types.every(s => s === 'compiler success')) { - return 'compiler success'; + return 'success'; } throw new Error(`unable to summarize bundle states: ${JSON.stringify(states)}`); @@ -54,65 +78,213 @@ const getSummaryType = (states: CompilerState[]) => { export class Optimizer { constructor(private readonly config: OptimizerConfig) {} + async getCachedBundles(optimizerVersion: string) { + const eligible = this.config.bundles.filter( + // only get the mtimes for files if the bundle was built + // with our version of the optimizer and there is a cache key + b => b.cache.getOptimizerVersion() === optimizerVersion && !!b.cache.getKey() + ); + + if (!eligible.length) { + return []; + } + + const mtimes = await getMtimes( + new Set( + eligible.reduce( + (acc: string[], bundle) => [...acc, ...(bundle.cache.getReferencedFiles() || [])], + [] + ) + ) + ); + + return eligible.filter(bundle => { + const cacheKey = createHash('sha1') + .update( + (bundle.cache.getReferencedFiles() || []) + .map(p => `${p}:${mtimes.get(p)}`) + .sort(ascending(l => l)) + .join('\n') + ) + .digest('hex'); + + return cacheKey === bundle.cache.getKey(); + }); + } + + /** + * Produce an observable that emits bundle objects when they + * should become "online", meaning that the cache on disk is + * no longer valid + */ + watchBundlesForChanges$(bundles: Iterable) { + return Watcher.using(watcher => { + // copy the list of offline bundles + const stillOffline = new Set(bundles); + + // recursively watch for changes in offline bundles until all the + // offline bundles have gone online + const nextBundlesToBringOnline$ = Rx.defer(() => + stillOffline.size ? watcher.getNextChange(stillOffline) : Rx.EMPTY + ).pipe( + mergeMap( + (event): ReturnType => { + if (event.type === 'changes detected') { + return Rx.of(event); + } + + for (const bundle of event.bundles) { + stillOffline.delete(bundle); + } + + return Rx.concat([event], nextBundlesToBringOnline$); + } + ) + ); + + return nextBundlesToBringOnline$; + }); + } + run() { - return Rx.from(this.config.workers).pipe( - mergeMap(worker => observeWorker(this.config, worker)), - pipeClosure(msg$ => { - let prevSummaryType: OptimizerStateSummary['type'] | undefined; - let startTime = Date.now(); - const compilerStates: CompilerState[] = []; - - return msg$.pipe( - map( - (msg: WorkerMessage | WorkerStdio): OptimizerState => { - if (msg.type === 'worker stdio') { - return msg; - } - - if (msg.type === 'worker error' || msg.type === 'compiler error') { - const error = new Error(msg.errorMessage); - error.stack = msg.errorStack; - throw error; - } - - const existingIndex = compilerStates.findIndex(s => s.id === msg.id); - if (existingIndex === -1) { - compilerStates.push(msg); - } else { - compilerStates.splice(existingIndex, 1, msg); - } - - if (msg.type === 'compiler success') { - this.config.cache.saveBundleModuleCount(msg.id, msg.moduleCount); - } - - const type = getSummaryType(compilerStates); - if (prevSummaryType !== 'running' && type === 'running') { - // reset start time now that we are running again - startTime = Date.now(); - } - - // stash summary type so we can reset startTime - prevSummaryType = type; - - return { - type, - durSec: Math.round((Date.now() - startTime) / 100) / 10, - compilerStates: Array.from(compilerStates), + return Rx.defer( + async (): Promise => { + const startTime = Date.now(); + const version = await getOptimizerVersion(); + const offlineBundles = await this.getCachedBundles(version); + const onlineBundles = this.config.bundles.filter(b => !offlineBundles.includes(b)); + + return { + summary: onlineBundles.length || this.config.watch ? 'initialized' : 'success', + version, + compilerStates: [], + durSec: msToSec(Date.now() - startTime), + offlineBundles, + onlineBundles, + startTime, + }; + } + ).pipe( + mergeMap(init => { + if (init.summary === 'success') { + return [init]; + } + + const change$ = this.config.watch + ? this.watchBundlesForChanges$(init.offlineBundles).pipe(share()) + : Rx.EMPTY; + + const workerMsg$ = Rx.concat( + // first batch is all the workers which weren't initially cached + Rx.of(init.onlineBundles), + // subsequent batches are defined by our change listener + change$.pipe(maybeMap(c => (c.type === 'changes' ? c.bundles : undefined))) + ).pipe( + mergeMap(bundles => + Rx.from(assignBundlesToWorkers(bundles, this.config.maxWorkerCount)).pipe( + mergeMap(assignment => + observeWorker( + this.config, + this.config.getWorkerConfig(init.version), + assignment.bundles + ) + ) + ) + ) + ); + + return Rx.concat( + Rx.of(init), + Rx.merge(change$, workerMsg$).pipe( + pipeClosure(event$ => { + let prev = init; + + const nextUpdate = ( + event: NonNullable, + changes?: Partial> + ): OptimizerStateSummary => { + const startTime = changes?.startTime ?? prev.startTime; + const next = { + ...prev, + ...changes, + event, + startTime, + durSec: msToSec(Date.now() - startTime), + }; + prev = next; + return next; }; - } - ), - tap({ - complete: () => { - if (this.config.watch) { - throw new Error('workers unexpected closed in watch mode'); - } - - if (prevSummaryType !== 'compiler success') { - throw createFailError('compilation failed'); - } - }, - }) + + return event$.pipe( + map( + (event): OptimizerStateSummary => { + if (event.type === 'worker error' || event.type === 'compiler error') { + // unrecoverable error states + const error = new Error(event.errorMessage); + error.stack = event.errorStack; + throw error; + } + + if (event.type === 'worker stdio' || event.type === 'worker started') { + return nextUpdate(event); + } + + if (event.type === 'changes detected') { + // switch to running early, before workers are started, so that + // base path proxy can prevent requests in the delay between changes + // and workers started + return nextUpdate(event, { + summary: 'running', + }); + } + + if (event.type === 'changes') { + const onlineBundles: Bundle[] = []; + const offlineBundles: Bundle[] = []; + for (const bundle of this.config.bundles) { + if (prev.onlineBundles.includes(bundle) || event.bundles.includes(bundle)) { + onlineBundles.push(bundle); + } else { + offlineBundles.push(bundle); + } + } + + return nextUpdate(event, { + summary: 'running', + onlineBundles, + offlineBundles, + startTime: prev.summary === 'running' ? prev.startTime : Date.now(), + }); + } + + if ( + event.type === 'compiler issue' || + event.type === 'compiler success' || + event.type === 'running' + ) { + const compilerStates: CompilerState[] = [ + ...prev.compilerStates.filter(c => c.bundleId !== event.bundleId), + event, + ]; + const summary = getSummary(compilerStates); + const newStartTime = + prev.summary !== 'running' && summary === 'running' + ? Date.now() + : prev.startTime; + + return nextUpdate(event, { + summary, + compilerStates, + startTime: newStartTime, + }); + } + + throw new Error(`unexpected optimizer event ${inspect(event)}`); + } + ) + ); + }) + ) ); }) ); diff --git a/packages/kbn-optimizer/src/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer_config.test.ts index 500016832cbff..703bb4337ddf6 100644 --- a/packages/kbn-optimizer/src/optimizer_config.test.ts +++ b/packages/kbn-optimizer/src/optimizer_config.test.ts @@ -19,8 +19,7 @@ jest.mock('./assign_bundles_to_workers.ts'); jest.mock('./new_platform_plugins.ts'); -jest.mock('./optimizer_cache.ts'); -jest.mock('./get_bundle_definitions.ts'); +jest.mock('./get_bundles.ts'); import Path from 'path'; import Os from 'os'; @@ -28,7 +27,6 @@ import Os from 'os'; import { REPO_ROOT, createAbsolutePathSerializer } from '@kbn/dev-utils'; import { OptimizerConfig } from './optimizer_config'; -import { OptimizerCache as OC } from './optimizer_cache'; jest.spyOn(Os, 'cpus').mockReturnValue(['foo'] as any); @@ -82,15 +80,6 @@ describe('OptimizerConfig::parseOptions()', () => { }).toThrowErrorMatchingInlineSnapshot(`"worker count must be a number"`); }); - it('validates that bundleMetdataPath is absolute', () => { - expect(() => { - OptimizerConfig.parseOptions({ - repoRoot: REPO_ROOT, - optimizerCachePath: 'foo/bar', - }); - }).toThrowErrorMatchingInlineSnapshot(`"optimizerCachePath must be absolute"`); - }); - it('applies defaults', () => { expect( OptimizerConfig.parseOptions({ @@ -98,10 +87,10 @@ describe('OptimizerConfig::parseOptions()', () => { }) ).toMatchInlineSnapshot(` Object { + "cache": true, "dist": false, "inspectWorkers": false, "maxWorkerCount": 2, - "optimizerCachePath": /data/.kbn-optimizer-cache.json, "pluginPaths": Array [], "pluginScanDirs": Array [ /src/plugins, @@ -117,14 +106,14 @@ describe('OptimizerConfig::parseOptions()', () => { expect( OptimizerConfig.parseOptions({ repoRoot: REPO_ROOT, - optimizerCachePath: false, + cache: false, }) ).toMatchInlineSnapshot(` Object { + "cache": false, "dist": false, "inspectWorkers": false, "maxWorkerCount": 2, - "optimizerCachePath": false, "pluginPaths": Array [], "pluginScanDirs": Array [ /src/plugins, @@ -144,10 +133,10 @@ describe('OptimizerConfig::parseOptions()', () => { }) ).toMatchInlineSnapshot(` Object { + "cache": true, "dist": false, "inspectWorkers": false, "maxWorkerCount": 2, - "optimizerCachePath": /data/.kbn-optimizer-cache.json, "pluginPaths": Array [], "pluginScanDirs": Array [ /src/plugins, @@ -168,10 +157,10 @@ describe('OptimizerConfig::parseOptions()', () => { }) ).toMatchInlineSnapshot(` Object { + "cache": true, "dist": false, "inspectWorkers": false, "maxWorkerCount": 2, - "optimizerCachePath": /data/.kbn-optimizer-cache.json, "pluginPaths": Array [], "pluginScanDirs": Array [ /src/plugins, @@ -190,10 +179,10 @@ describe('OptimizerConfig::parseOptions()', () => { }) ).toMatchInlineSnapshot(` Object { + "cache": true, "dist": false, "inspectWorkers": false, "maxWorkerCount": 2, - "optimizerCachePath": /data/.kbn-optimizer-cache.json, "pluginPaths": Array [], "pluginScanDirs": Array [ /x/y/z, @@ -213,10 +202,10 @@ describe('OptimizerConfig::parseOptions()', () => { }) ).toMatchInlineSnapshot(` Object { + "cache": true, "dist": false, "inspectWorkers": false, "maxWorkerCount": 100, - "optimizerCachePath": /data/.kbn-optimizer-cache.json, "pluginPaths": Array [], "pluginScanDirs": Array [], "profileWebpack": false, @@ -237,10 +226,7 @@ describe('OptimizerConfig::create()', () => { .assignBundlesToWorkers; const findNewPlatformPlugins: jest.Mock = jest.requireMock('./new_platform_plugins.ts') .findNewPlatformPlugins; - const OptimizerCache: jest.MockedClass = jest.requireMock('./optimizer_cache.ts') - .OptimizerCache; - const getBundleDefinitions: jest.Mock = jest.requireMock('./get_bundle_definitions.ts') - .getBundleDefinitions; + const getBundles: jest.Mock = jest.requireMock('./get_bundles.ts').getBundles; beforeEach(() => { if ('mock' in OptimizerConfig.parseOptions) { @@ -252,10 +238,10 @@ describe('OptimizerConfig::create()', () => { { config: Symbol('worker config 2') }, ]); findNewPlatformPlugins.mockReturnValue(Symbol('new platform plugins')); - getBundleDefinitions.mockReturnValue(Symbol('bundle definitions')); + getBundles.mockReturnValue(Symbol('bundles')); jest.spyOn(OptimizerConfig, 'parseOptions').mockImplementation((): any => ({ - optimizerCachePath: Symbol('parsed bundle metadata path'), + cache: Symbol('parsed cache'), dist: Symbol('parsed dist'), maxWorkerCount: Symbol('parsed max worker count'), pluginPaths: Symbol('parsed plugin paths'), @@ -263,29 +249,26 @@ describe('OptimizerConfig::create()', () => { repoRoot: Symbol('parsed repo root'), watch: Symbol('parsed watch'), inspectWorkers: Symbol('parsed inspect workers'), + profileWebpack: Symbol('parsed profile webpack'), })); }); - it('passes parsed options to findNewPlatformPlugins, OptimizerCache, getBundleDefinitions, and assignBundlesToWorkers', () => { + it('passes parsed options to findNewPlatformPlugins, getBundles, and assignBundlesToWorkers', () => { const config = OptimizerConfig.create({ repoRoot: REPO_ROOT, }); expect(config).toMatchInlineSnapshot(` OptimizerConfig { - "bundles": Symbol(bundle definitions), - "cache": OptimizerCache { - "getBundleModuleCount": [MockFunction], - "getState": [MockFunction], - "saveBundleModuleCount": [MockFunction], - "setState": [MockFunction], - }, + "bundles": Symbol(bundles), + "cache": Symbol(parsed cache), + "dist": Symbol(parsed dist), "inspectWorkers": Symbol(parsed inspect workers), + "maxWorkerCount": Symbol(parsed max worker count), + "plugins": Symbol(new platform plugins), + "profileWebpack": Symbol(parsed profile webpack), + "repoRoot": Symbol(parsed repo root), "watch": Symbol(parsed watch), - "workers": Array [ - Symbol(worker config 1), - Symbol(worker config 2), - ], } `); @@ -301,7 +284,7 @@ describe('OptimizerConfig::create()', () => { [Window], ], "invocationCallOrder": Array [ - 8, + 7, ], "results": Array [ Object { @@ -312,34 +295,7 @@ describe('OptimizerConfig::create()', () => { } `); - expect(OptimizerCache.mock).toMatchInlineSnapshot(` - Object { - "calls": Array [ - Array [ - Symbol(parsed bundle metadata path), - ], - ], - "instances": Array [ - OptimizerCache { - "getBundleModuleCount": [MockFunction], - "getState": [MockFunction], - "saveBundleModuleCount": [MockFunction], - "setState": [MockFunction], - }, - ], - "invocationCallOrder": Array [ - 9, - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], - } - `); - - expect(getBundleDefinitions.mock).toMatchInlineSnapshot(` + expect(getBundles.mock).toMatchInlineSnapshot(` Object { "calls": Array [ Array [ @@ -351,54 +307,12 @@ describe('OptimizerConfig::create()', () => { [Window], ], "invocationCallOrder": Array [ - 10, - ], - "results": Array [ - Object { - "type": "return", - "value": Symbol(bundle definitions), - }, - ], - } - `); - - expect(assignBundlesToWorkers.mock).toMatchInlineSnapshot(` - Object { - "calls": Array [ - Array [ - Object { - "bundles": Symbol(bundle definitions), - "cache": OptimizerCache { - "getBundleModuleCount": [MockFunction], - "getState": [MockFunction], - "saveBundleModuleCount": [MockFunction], - "setState": [MockFunction], - }, - "dist": Symbol(parsed dist), - "maxWorkerCount": Symbol(parsed max worker count), - "profileWebpack": undefined, - "repoRoot": Symbol(parsed repo root), - "watch": Symbol(parsed watch), - }, - ], - ], - "instances": Array [ - [Window], - ], - "invocationCallOrder": Array [ - 11, + 8, ], "results": Array [ Object { "type": "return", - "value": Array [ - Object { - "config": Symbol(worker config 1), - }, - Object { - "config": Symbol(worker config 2), - }, - ], + "value": Symbol(bundles), }, ], } diff --git a/packages/kbn-optimizer/src/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer_config.ts index 1b3c62d1845bf..aff3a6768c379 100644 --- a/packages/kbn-optimizer/src/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer_config.ts @@ -20,11 +20,9 @@ import Path from 'path'; import Os from 'os'; -import { findNewPlatformPlugins } from './new_platform_plugins'; -import { BundleDefinition, WorkerConfig } from './common'; -import { OptimizerCache } from './optimizer_cache'; -import { assignBundlesToWorkers } from './assign_bundles_to_workers'; -import { getBundleDefinitions } from './get_bundle_definitions'; +import { findNewPlatformPlugins, NewPlatformPlugin } from './new_platform_plugins'; +import { Bundle, WorkerConfig } from './common'; +import { getBundles } from './get_bundles'; interface Options { /** absolute path to root of the repo/build */ @@ -33,8 +31,8 @@ interface Options { watch?: boolean; /** the maximum number of workers that will be created */ maxWorkerCount?: number; - /** absolute path to the file where the optimizer cache will be written */ - optimizerCachePath?: string | false; + /** set to false to disabling writing/reading of caches */ + cache?: false; /** build assets suitable for use in the distributable */ dist?: boolean; /** enable webpack profiling, writes stats.json files to the root of each plugin's output dir */ @@ -59,7 +57,7 @@ interface ParsedOptions { watch: boolean; maxWorkerCount: number; profileWebpack: boolean; - optimizerCachePath: string | false; + cache: boolean; dist: boolean; pluginPaths: string[]; pluginScanDirs: string[]; @@ -74,6 +72,7 @@ export class OptimizerConfig { const examples = !!options.examples; const profileWebpack = !!options.profileWebpack; const inspectWorkers = !!options.inspectWorkers; + const cache = options.cache !== false; const repoRoot = options.repoRoot; if (!Path.isAbsolute(repoRoot)) { @@ -109,22 +108,13 @@ export class OptimizerConfig { throw new TypeError('worker count must be a number'); } - const optimizerCachePath = - options.optimizerCachePath === false - ? false - : options.optimizerCachePath || - Path.resolve(options.repoRoot, 'data/.kbn-optimizer-cache.json'); - if (optimizerCachePath && !Path.isAbsolute(optimizerCachePath)) { - throw new TypeError('optimizerCachePath must be absolute'); - } - return { watch, dist, repoRoot, maxWorkerCount, profileWebpack, - optimizerCachePath, + cache, pluginScanDirs, pluginPaths, inspectWorkers, @@ -133,37 +123,42 @@ export class OptimizerConfig { static create(inputOptions: Options) { const options = OptimizerConfig.parseOptions(inputOptions); - const plugins = findNewPlatformPlugins(options.pluginScanDirs, options.pluginPaths); - - const cache = new OptimizerCache(options.optimizerCachePath); - - const bundles = getBundleDefinitions(plugins, options.repoRoot); - - const workers = assignBundlesToWorkers({ - bundles, - cache, - maxWorkerCount: options.maxWorkerCount, - repoRoot: options.repoRoot, - watch: options.watch, - dist: options.dist, - profileWebpack: options.profileWebpack, - }); + const bundles = getBundles(plugins, options.repoRoot); return new OptimizerConfig( - cache, bundles, - workers.map(w => w.config), + options.cache, options.watch, - options.inspectWorkers + options.inspectWorkers, + plugins, + options.repoRoot, + options.maxWorkerCount, + options.dist, + options.profileWebpack ); } constructor( - public readonly cache: OptimizerCache, - public readonly bundles: BundleDefinition[], - public readonly workers: WorkerConfig[], + public readonly bundles: Bundle[], + public readonly cache: boolean, public readonly watch: boolean, - public readonly inspectWorkers: boolean + public readonly inspectWorkers: boolean, + public readonly plugins: NewPlatformPlugin[], + public readonly repoRoot: string, + public readonly maxWorkerCount: number, + public readonly dist: boolean, + public readonly profileWebpack: boolean ) {} + + getWorkerConfig(optimizerVersion: string): WorkerConfig { + return { + cache: this.cache, + dist: this.dist, + profileWebpack: this.profileWebpack, + repoRoot: this.repoRoot, + watch: this.watch, + optimizerVersion, + }; + } } diff --git a/packages/kbn-optimizer/src/watcher.ts b/packages/kbn-optimizer/src/watcher.ts new file mode 100644 index 0000000000000..5d897ec5ed802 --- /dev/null +++ b/packages/kbn-optimizer/src/watcher.ts @@ -0,0 +1,128 @@ +/* + * 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 * as Rx from 'rxjs'; +import { take, tap, debounceTime, map } from 'rxjs/operators'; +import Watchpack from 'watchpack'; + +import { pipeClosure, Bundle } from './common'; + +export interface ChangesStarted { + type: 'changes detected'; +} + +export interface Changes { + type: 'changes'; + bundles: Bundle[]; +} + +const debounceTimeBuffer = (time: number) => + pipeClosure((source$: Rx.Observable) => { + const buffer = new Set(); + return source$.pipe( + tap(item => buffer.add(item)), + debounceTime(time), + map(() => { + const items = Array.from(buffer); + buffer.clear(); + return items; + }) + ); + }); + +export class Watcher { + // Use watcher as an RxJS Resource so that it is automatically closed + static using(fn: (watcher: Watcher) => Rx.Observable) { + return Rx.using( + () => new Watcher(), + resource => fn(resource as Watcher) + ); + } + + private readonly watchpack = new Watchpack({ + aggregateTimeout: 0, + ignored: /node_modules\/([^\/]+[\/])*(?!package.json)([^\/]+)$/, + }); + + private readonly change$ = Rx.fromEvent<[string]>(this.watchpack, 'change'); + + public getNextChange(bundles: Iterable) { + return Rx.merge( + // emit ChangesStarted as soon as we have been triggered + this.change$.pipe( + take(1), + map( + (): ChangesStarted => ({ + type: 'changes detected', + }) + ) + ), + + // debounce and bufffer change events for 100 milliseconds to + // create final change notification + this.change$.pipe( + map(event => event[0]), + debounceTimeBuffer(100), + map( + (changes): Changes => { + const changedBundles: Bundle[] = []; + + findChangedBundles: for (const bundle of bundles) { + const referencedFiles = bundle.cache.getReferencedFiles(); + for (const change of changes) { + if (referencedFiles?.includes(change)) { + changedBundles.push(bundle); + continue findChangedBundles; + } + } + } + + return { + type: 'changes', + bundles: changedBundles, + }; + } + ), + take(1) + ), + + // call watchpack.watch after listerners are setup + Rx.defer(() => { + const watchPaths: string[] = []; + + for (const bundle of bundles) { + for (const path of bundle.cache.getReferencedFiles() || []) { + watchPaths.push(path); + } + } + + this.watchpack.watch(watchPaths, [], Date.now()); + return Rx.EMPTY; + }) + ); + } + + close() { + this.watchpack.close(); + } + + unsubscribe() { + this.close(); + } +} diff --git a/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts b/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts deleted file mode 100644 index 638b3e821277a..0000000000000 --- a/packages/kbn-optimizer/src/worker/block_legacy_code_plugin.ts +++ /dev/null @@ -1,55 +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 Path from 'path'; - -import webpack from 'webpack'; -import isPathInside from 'is-path-inside'; - -import { BundleDefinition } from '../common'; -import { WebpackResolveData } from './webpack_helpers'; - -const ANY_LEGACY_DIR = `${Path.sep}legacy${Path.sep}`; - -export class BlockLegacyCodePlugin { - constructor(private readonly def: BundleDefinition) {} - - apply(compiler: webpack.Compiler) { - compiler.hooks.normalModuleFactory.tap(BlockLegacyCodePlugin.name, normalModuleFactory => { - normalModuleFactory.hooks.afterResolve.tap( - BlockLegacyCodePlugin.name, - (resolveData: WebpackResolveData) => { - const { - rawRequest, - resourceResolveData: { context, path }, - } = resolveData; - - if (path.includes(ANY_LEGACY_DIR) && !isPathInside(path, resolveData.context)) { - const issuerRelative = Path.relative(this.def.sourceRoot, context.issuer); - const resolveRelative = Path.relative(this.def.sourceRoot, path); - // eslint-disable-next-line no-console - console.error( - `[${this.def.id}] is importing from legacy code:\nrequest: ${rawRequest}\nfrom: ${issuerRelative}\nresolved to: ${resolveRelative}` - ); - } - } - ); - }); - } -} diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts index 9f7b6ce32ff5b..439e98341cdf9 100644 --- a/packages/kbn-optimizer/src/worker/run_worker.ts +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -21,21 +21,34 @@ import 'source-map-support/register'; import Fs from 'fs'; import Path from 'path'; +import { inspect } from 'util'; +import { createHash } from 'crypto'; import webpack, { Stats } from 'webpack'; import * as Rx from 'rxjs'; import { mergeMap, map, mapTo, takeUntil } from 'rxjs/operators'; -import { CompilerMessages, WorkerMessages, maybeMap } from '../common'; -import { getWebpackConfig } from './webpack.config'; -import { isFailureStats, failedStatsToErrorMessage } from './webpack_helpers'; import { + CompilerMessages, + WorkerMessages, + maybeMap, parseWorkerConfig, - BundleDefinition, + Bundle, + parseBundles, WorkerConfig, isWorkerMessage, WorkerMessage, + ascending, } from '../common'; +import { getWebpackConfig } from './webpack.config'; +import { isFailureStats, failedStatsToErrorMessage } from './webpack_helpers'; +import { + isExternalModule, + isNormalModule, + isIgnoredModule, + WebpackNormalModule, + getModulePath, +} from './webpack_helpers'; const PLUGIN_NAME = '@kbn/optimizer'; const workerMsgs = new WorkerMessages(); @@ -61,10 +74,8 @@ setInterval(() => { } }, 1000).unref(); -const runWorker = (workerConfig: WorkerConfig) => { - const multiCompiler = webpack( - workerConfig.bundles.map(def => getWebpackConfig(def, workerConfig)) - ); +const runWorker = (workerConfig: WorkerConfig, bundles: Bundle[]) => { + const multiCompiler = webpack(bundles.map(def => getWebpackConfig(def, workerConfig))); return Rx.merge( /** @@ -76,8 +87,8 @@ const runWorker = (workerConfig: WorkerConfig) => { */ Rx.from(multiCompiler.compilers.entries()).pipe( mergeMap(([compilerIndex, compiler]) => { - const definition = workerConfig.bundles[compilerIndex]; - return observeCompiler(workerConfig, definition, compiler); + const bundle = bundles[compilerIndex]; + return observeCompiler(workerConfig, bundle, compiler); }) ), @@ -98,10 +109,10 @@ const runWorker = (workerConfig: WorkerConfig) => { const observeCompiler = ( workerConfig: WorkerConfig, - def: BundleDefinition, + bundle: Bundle, compiler: webpack.Compiler ) => { - const compilerMsgs = new CompilerMessages(def.id); + const compilerMsgs = new CompilerMessages(bundle.id); const done$ = new Rx.Subject(); const { beforeRun, watchRun, done } = compiler.hooks; @@ -126,7 +137,10 @@ const observeCompiler = ( } if (workerConfig.profileWebpack) { - Fs.writeFileSync(Path.resolve(def.outputDir, 'stats.json'), JSON.stringify(stats.toJson())); + Fs.writeFileSync( + Path.resolve(bundle.outputDir, 'stats.json'), + JSON.stringify(stats.toJson()) + ); } if (!workerConfig.watch) { @@ -139,8 +153,69 @@ const observeCompiler = ( }); } + const normalModules = stats.compilation.modules.filter( + (module): module is WebpackNormalModule => { + if (isNormalModule(module)) { + return true; + } + + if (isExternalModule(module) || isIgnoredModule(module)) { + return false; + } + + throw new Error(`Unexpected module type: ${inspect(module)}`); + } + ); + + const referencedFiles = new Set(); + + for (const module of normalModules) { + const path = getModulePath(module); + + const parsedPath = Path.parse(path); + const dirSegments = parsedPath.dir.split(Path.sep); + if (!dirSegments.includes('node_modules')) { + referencedFiles.add(path); + continue; + } + + const nmIndex = dirSegments.lastIndexOf('node_modules'); + const isScoped = dirSegments[nmIndex + 1].startsWith('@'); + referencedFiles.add( + Path.join( + parsedPath.root, + ...dirSegments.slice(0, nmIndex + 1 + (isScoped ? 2 : 1)), + 'package.json' + ) + ); + } + + const hashLines: string[] = []; + for (const file of referencedFiles) { + try { + // don't worry, these are cached by webpack + const stat = compiler.inputFileSystem.statSync(file); + hashLines.push(`${file}:${stat.mtimeMs}`); + } catch (error) { + if (error?.code === 'ENOENT') { + hashLines.push(`${file}:${undefined}`); + } else { + throw error; + } + } + } + + bundle.cache.set({ + optimizerVersion: workerConfig.optimizerVersion, + key: createHash('sha1') + .update(hashLines.sort(ascending(l => l)).join('\n')) + .digest('hex'), + moduleCount: normalModules.length, + files: Array.from(referencedFiles), + }); + return compilerMsgs.compilerSuccess({ - moduleCount: stats.compilation.modules.length, + moduleCount: normalModules.length, }); }) ); @@ -176,15 +251,12 @@ const exit = (code: number) => { }; Rx.defer(() => { - const parse = parseWorkerConfig(process.argv[2]); - - if (parse.error) { - throw parse.error; - } - - return Rx.of(parse.workerConfig); + return Rx.of({ + workerConfig: parseWorkerConfig(process.argv[2]), + bundles: parseBundles(process.argv[3]), + }); }) - .pipe(mergeMap(runWorker)) + .pipe(mergeMap(({ workerConfig, bundles }) => runWorker(workerConfig, bundles))) .subscribe( msg => { send(msg); diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index f124c9bc86dbd..69d12bcab0fd8 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -29,41 +29,41 @@ import webpackMerge from 'webpack-merge'; import { CleanWebpackPlugin } from 'clean-webpack-plugin'; import * as SharedDeps from '@kbn/ui-shared-deps'; -import { BundleDefinition, WorkerConfig } from '../common'; -// import { BlockLegacyCodePlugin } from './block_legacy_code_plugin'; +import { Bundle, WorkerConfig } from '../common'; const IS_CODE_COVERAGE = !!process.env.CODE_COVERAGE; const ISTANBUL_PRESET_PATH = require.resolve('@kbn/babel-preset/istanbul_preset'); const PUBLIC_PATH_PLACEHOLDER = '__REPLACE_WITH_PUBLIC_PATH__'; const BABEL_PRESET_PATH = require.resolve('@kbn/babel-preset/webpack_preset'); -export function getWebpackConfig(def: BundleDefinition, worker: WorkerConfig) { +export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) { const commonConfig: webpack.Configuration = { node: { fs: 'empty' }, - context: def.contextDir, + context: bundle.contextDir, cache: true, entry: { - [def.id]: def.entry, + [bundle.id]: bundle.entry, }, devtool: worker.dist ? false : '#cheap-source-map', profile: worker.profileWebpack, output: { - path: def.outputDir, + path: bundle.outputDir, filename: '[name].plugin.js', publicPath: PUBLIC_PATH_PLACEHOLDER, devtoolModuleFilenameTemplate: info => - `/${def.type}:${def.id}/${Path.relative(def.sourceRoot, info.absoluteResourcePath)}${ - info.query - }`, - jsonpFunction: `${def.id}_bundle_jsonpfunction`, - ...(def.type === 'plugin' + `/${bundle.type}:${bundle.id}/${Path.relative( + bundle.sourceRoot, + info.absoluteResourcePath + )}${info.query}`, + jsonpFunction: `${bundle.id}_bundle_jsonpfunction`, + ...(bundle.type === 'plugin' ? { // When the entry point is loaded, assign it's exported `plugin` // value to a key on the global `__kbnBundles__` object. // NOTE: Only actually used by new platform plugins - library: ['__kbnBundles__', `plugin/${def.id}`], + library: ['__kbnBundles__', `plugin/${bundle.id}`], libraryExport: 'plugin', } : {}), @@ -77,7 +77,7 @@ export function getWebpackConfig(def: BundleDefinition, worker: WorkerConfig) { ...SharedDeps.externals, }, - plugins: [new CleanWebpackPlugin() /* , new BlockLegacyCodePlugin(def) */], + plugins: [new CleanWebpackPlugin()], module: { // no parse rules for a few known large packages which have no require() statements @@ -148,7 +148,7 @@ export function getWebpackConfig(def: BundleDefinition, worker: WorkerConfig) { return { outputStyle: 'nested', includePaths: [Path.resolve(worker.repoRoot, 'node_modules')], - sourceMapRoot: `/${def.type}:${def.id}`, + sourceMapRoot: `/${bundle.type}:${bundle.id}`, importer: (url: string) => { if (darkMode && url.includes('eui_colors_light')) { return { file: url.replace('eui_colors_light', 'eui_colors_dark') }; diff --git a/packages/kbn-optimizer/src/worker/webpack_helpers.ts b/packages/kbn-optimizer/src/worker/webpack_helpers.ts index ea68f79de00bf..3f61a76bb79e8 100644 --- a/packages/kbn-optimizer/src/worker/webpack_helpers.ts +++ b/packages/kbn-optimizer/src/worker/webpack_helpers.ts @@ -99,3 +99,56 @@ export interface WebpackResolveData { path: string; }; } + +interface Dependency { + type: 'null' | 'cjs require'; + module: unknown; +} + +/** used for standard js/ts modules */ +export interface WebpackNormalModule { + type: string; + /** absolute path to file on disk */ + resource: string; + buildInfo: { + cacheable: boolean; + fileDependencies: Set; + }; + dependencies: Dependency[]; +} + +export function isNormalModule(module: any): module is WebpackNormalModule { + return module?.constructor?.name === 'NormalModule'; +} + +/** module used for ignored code */ +export interface WebpackIgnoredModule { + type: string; + /** unique string to identify this module with (starts with `ignored`) */ + identifierStr: string; + /** human readable identifier */ + readableIdentifierStr: string; +} + +export function isIgnoredModule(module: any): module is WebpackIgnoredModule { + return module?.constructor?.name === 'RawModule' && module.identifierStr?.startsWith('ignored '); +} + +/** module replacing imports for webpack externals */ +export interface WebpackExternalModule { + type: string; + id: string; + /** JS used to get instance of External */ + request: string; + /** module name that is handled by externals */ + userRequest: string; +} + +export function isExternalModule(module: any): module is WebpackExternalModule { + return module?.constructor?.name === 'ExternalModule'; +} + +export function getModulePath(module: WebpackNormalModule) { + const queryIndex = module.resource.indexOf('?'); + return queryIndex === -1 ? module.resource : module.resource.slice(0, queryIndex); +} diff --git a/src/cli/cluster/cluster_manager.ts b/src/cli/cluster/cluster_manager.ts index ea4a49dd84d84..a51b8649fa705 100644 --- a/src/cli/cluster/cluster_manager.ts +++ b/src/cli/cluster/cluster_manager.ts @@ -73,7 +73,7 @@ export class ClusterManager { // run @kbn/optimizer and write it's state to kbnOptimizerReady$ runKbnOptimizer(opts, config) .pipe( - map(state => state.type === 'compiler success'), + map(state => state.summary === 'success' || state.summary === 'issue'), tap({ error: error => { this.log.bad('New platform optimizer error', error.stack); diff --git a/src/dev/build/tasks/build_new_platform_plugins.js b/src/dev/build/tasks/build_new_platform_plugins.js index 57eaf5f288bd5..73b916feeb7d9 100644 --- a/src/dev/build/tasks/build_new_platform_plugins.js +++ b/src/dev/build/tasks/build_new_platform_plugins.js @@ -24,7 +24,7 @@ export const BuildNewPlatformPluginsTask = { async run(_, log, build) { const optimizerConfig = OptimizerConfig.create({ repoRoot: build.resolvePath(), - optimizerCachePath: false, + cache: false, oss: build.isOss(), examples: false, watch: false, diff --git a/src/plugins/data/public/_index.scss b/src/plugins/data/public/index.scss similarity index 100% rename from src/plugins/data/public/_index.scss rename to src/plugins/data/public/index.scss diff --git a/src/plugins/data/public/index.ts b/src/plugins/data/public/index.ts index b8becd2bd3fae..7b31c50a65b42 100644 --- a/src/plugins/data/public/index.ts +++ b/src/plugins/data/public/index.ts @@ -17,7 +17,7 @@ * under the License. */ -import './_index.scss'; +import './index.scss'; import { PluginInitializerContext } from '../../../core/public'; diff --git a/yarn.lock b/yarn.lock index 00f193657844c..c4bbc879c7ff0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4476,6 +4476,13 @@ "@types/glob" "*" fast-glob "^2.0.2" +"@types/graceful-fs@*": + version "4.1.3" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f" + integrity sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ== + dependencies: + "@types/node" "*" + "@types/graphql@^0.13.2": version "0.13.4" resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.13.4.tgz#55ae9c29f0fd6b85ee536f5c72b4769d5c5e06b1" @@ -5342,6 +5349,15 @@ dependencies: "@types/node" "*" +"@types/watchpack@^1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@types/watchpack/-/watchpack-1.1.5.tgz#e5622eb2a49e2239d94d8882275fbc7893147e97" + integrity sha512-9clzOLesGBv5/60QQ3UvpOPsRSNu4ybw4jUBq1aofGdA2NtS5dL2D/m6WAXycxdg+rcGOHTN2rgpTMAdJ4jMWg== + dependencies: + "@types/graceful-fs" "*" + "@types/node" "*" + chokidar "^2.1.2" + "@types/webpack-env@^1.13.7": version "1.14.1" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.14.1.tgz#0d8a53f308f017c53a5ddc3d07f4d6fa76b790d7" From 214ca6abe7a1a10ba97f5d1b90a994c412b0565d Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 18:06:05 -0700 Subject: [PATCH 15/83] update kbn/pm dist --- packages/kbn-pm/dist/index.js | 21658 ++++++++++++++++++-------------- 1 file changed, 12054 insertions(+), 9604 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index dd17b59555f61..e5db86b1e7358 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 @@ -46618,9 +46618,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); } @@ -46632,24 +46634,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 + } } } @@ -68964,7 +68970,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__); @@ -69072,13 +69078,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); @@ -69200,11 +69206,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; @@ -69506,8239 +69512,10374 @@ 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'; - - // remove path parts that are globby - do { - str = pathPosixDirname(str); - } while (isGlob(str) || globby.test(str)); +Glob.prototype._finish = function () { + assert(this instanceof Glob) + if (this.aborted) + return - // remove escape chars and return result - return str.replace(escaped, '$1'); -}; + if (this.realpath && !this._didRealpath) + return this._realpath() + common.finish(this) + this.emit('end', this.found) +} -/***/ }), -/* 601 */ -/***/ (function(module, exports, __webpack_require__) { +Glob.prototype._realpath = function () { + if (this._didRealpath) + return -/*! - * is-glob - * - * Copyright (c) 2014-2017, Jon Schlinkert. - * Released under the MIT License. - */ + this._didRealpath = true -var isExtglob = __webpack_require__(602); -var chars = { '{': '}', '(': ')', '[': ']'}; -var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; -var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; + var n = this.matches.length + if (n === 0) + return this._finish() -module.exports = function isGlob(str, options) { - if (typeof str !== 'string' || str === '') { - return false; - } + var self = this + for (var i = 0; i < this.matches.length; i++) + this._realpathSet(i, next) - if (isExtglob(str)) { - return true; + function next () { + if (--n === 0) + self._finish() } +} - var regex = strictRegex; - var match; +Glob.prototype._realpathSet = function (index, cb) { + var matchset = this.matches[index] + if (!matchset) + return cb() - // optionally relax regex - if (options && options.strict === false) { - regex = relaxedRegex; - } + var found = Object.keys(matchset) + var self = this + var n = found.length - while ((match = regex.exec(str))) { - if (match[2]) return true; - var idx = match.index + match[0].length; + if (n === 0) + return cb() - // 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; + 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() } - } + }) + }) +} - 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() + + 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 (Array.isArray(pattern)) { - return pattern.some(p => micromatch.contains(str, p, options)); +Glob.prototype._readdir = function (abs, inGlobStar, cb) { + if (this.aborted) + return + + 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) } - if (typeof pattern === 'string') { - if (isEmptyString(str) || isEmptyString(pattern)) { - return false; - } + var self = this + fs.readdir(abs, readdirCb(this, abs, cb)) +} - if (str.includes(pattern) || (str.startsWith('./') && str.slice(2).includes(pattern))) { - return true; - } +function readdirCb (self, abs, cb) { + return function (er, entries) { + if (er) + self._readdirError(abs, er, cb) + else + self._readdirEntries(abs, entries, cb) } +} - return micromatch.isMatch(str, pattern, { ...options, contains: true }); -}; +Glob.prototype._readdirEntries = function (abs, entries, cb) { + if (this.aborted) + return -/** - * 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'); + // 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 + } } - 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); + this.cache[abs] = entries + return cb(null, entries) +} - for (let pattern of [].concat(patterns)) { - let isMatch = picomatch(String(pattern), options); - if (items.some(item => isMatch(item))) { - return true; - } - } - return false; -}; +Glob.prototype._readdirError = function (f, er, cb) { + if (this.aborted) + return -/** - * 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 - */ + // 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 -micromatch.every = (list, patterns, options) => { - let items = [].concat(list); + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break - for (let pattern of [].concat(patterns)) { - let isMatch = picomatch(String(pattern), options); - if (!items.every(item => isMatch(item))) { - return false; - } + 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 true; -}; -/** - * 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 - */ + return cb() +} -micromatch.all = (str, patterns, options) => { - if (typeof str !== 'string') { - throw new TypeError(`Expected a string: "${util.inspect(str)}"`); - } +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) + }) +} - return [].concat(patterns).every(p => picomatch(p, options)(str)); -}; -/** - * 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._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + //console.error('pgs2', prefix, remain[0], entries) -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); + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return cb() - if (match) { - return match.slice(1).map(v => v === void 0 ? '' : v); - } -}; + // 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) -/** - * 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 - */ + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false, cb) -micromatch.makeRe = (...args) => picomatch.makeRe(...args); + var isSym = this.symlinks[abs] + var len = entries.length -/** - * 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 - */ + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return cb() -micromatch.scan = (...args) => picomatch.scan(...args); + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue -/** - * 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 - */ + // these two cases enter the inGlobStar state + var instead = gspref.concat(entries[i], remainWithoutGlobStar) + this._process(instead, index, true, 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)); - } + 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 - */ + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return -exports.encloseBrace = node => { - if (node.type !== 'brace') return false; - if ((node.commas >> 0 + node.ranges >> 0) === 0) { - node.invalid = true; - return true; - } - return false; -}; + // 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. -/** - * Returns true if a brace node is invalid. - */ + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) -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; -}; + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix.slice(-1) !== '/') + e = prefix + '/' + e + else + e = prefix + e + } -/** - * Returns true if a node is an open or close node - */ + 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 + } -exports.isOpenOrClose = node => { - if (node.type === 'open' || node.type === 'close') { - return true; + // 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) } - return node.open === true || node.close === true; -}; +} -/** - * Reduce an array of text nodes. - */ -exports.reduce = nodes => nodes.reduce((acc, node) => { - if (node.type === 'text') acc.push(node.value); - if (node.type === 'range') node.type = 'text'; - return acc; -}, []); +GlobSync.prototype._emitMatch = function (index, e) { + if (isIgnored(this, e)) + return -/** - * Flatten an array - */ + var abs = this._makeAbs(e) -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; -}; + if (this.mark) + e = this._mark(e) + if (this.absolute) { + e = abs + } -/***/ }), -/* 607 */ -/***/ (function(module, exports, __webpack_require__) { + if (this.matches[index][e]) + return -"use strict"; + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return + } + this.matches[index][e] = true -const fill = __webpack_require__(608); -const utils = __webpack_require__(606); + if (this.stat) + this._stat(e) +} -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 (node.isOpen === true) { - return prefix + node.value; - } - if (node.isClose === true) { - return 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 === 'open') { - 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 === 'close') { - return invalid ? (prefix + node.value) : ')'; - } + var isSym = lstat && lstat.isSymbolicLink() + this.symlinks[abs] = isSym - if (node.type === 'comma') { - return node.prev.type === 'comma' ? '' : (invalid ? 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.value) { - return node.value; - } + return entries +} - if (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); - let range = fill(...args, { ...options, wrap: false, toRegex: true }); +GlobSync.prototype._readdir = function (abs, inGlobStar) { + var entries - if (range.length !== 0) { - return args.length > 1 && range.length > 1 ? `(${range})` : range; - } - } + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs) - if (node.nodes) { - for (let child of node.nodes) { - output += walk(child, node); - } - } - return output; - }; + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return null - return walk(ast); -}; + if (Array.isArray(c)) + return c + } -module.exports = compile; + try { + return this._readdirEntries(abs, fs.readdirSync(abs)) + } catch (er) { + this._readdirError(abs, er) + return null + } +} +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 + } + } -/***/ }), -/* 608 */ -/***/ (function(module, exports, __webpack_require__) { + this.cache[abs] = entries -"use strict"; -/*! - * fill-range - * - * Copyright (c) 2014-present, Jon Schlinkert. - * Licensed under the MIT License. - */ + // 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 + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + 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; -}; - -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()) +} + +function alphasort (a, b) { + return a.localeCompare(b) +} + +function setupIgnores (self, options) { + self.ignore = options.ignore || [] + + if (!Array.isArray(self.ignore)) + self.ignore = [self.ignore] + + if (self.ignore.length) { + self.ignore = self.ignore.map(ignoreMap) } +} - if (typeof step === 'function') { - return fill(start, end, 1, { transform: step }); +// 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 }) } - if (isObject(step)) { - return fill(start, end, 0, step); + return { + matcher: new Minimatch(pattern, { dot: true }), + gmatcher: gmatcher } +} - let opts = { ...options }; - if (opts.capture === true) opts.wrap = true; - step = step || opts.step || 1; +function setopts (self, pattern, options) { + if (!options) + options = {} - if (!isNumber(step)) { - if (step != null && !isObject(step)) return invalidStep(step, opts); - return fill(start, end, 1, step); + // 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 } - if (isNumber(start) && isNumber(end)) { - return fillNumbers(start, end, step, opts); - } + 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 - return fillLetters(start, end, Math.max(Math.abs(step), 1), opts); -}; + 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 = fill; + setupIgnores(self, options) + 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 + } -/***/ }), -/* 609 */ -/***/ (function(module, exports, __webpack_require__) { + self.root = options.root || path.resolve(self.cwd, "/") + self.root = path.resolve(self.root) + if (process.platform === "win32") + self.root = self.root.replace(/\\/g, "/") -"use strict"; -/*! - * to-regex-range - * - * Copyright (c) 2015-present, Jon Schlinkert. - * Released under the MIT License. - */ + // 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 + // disable comments and negation in Minimatch. + // Note that they are not supported in Glob itself anyway. + options.nonegate = true + options.nocomment = true + self.minimatch = new Minimatch(pattern, options) + self.options = self.minimatch.options +} -const isNumber = __webpack_require__(610); +function finish (self) { + var nou = self.nounique + var all = nou ? [] : Object.create(null) -const toRegexRange = (min, max, options) => { - if (isNumber(min) === false) { - throw new TypeError('toRegexRange: expected the first argument to be a number'); + 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 + }) + } } - if (max === void 0 || min === max) { - return String(min); - } + if (!nou) + all = Object.keys(all) - if (isNumber(max) === false) { - throw new TypeError('toRegexRange: expected the second argument to be a number.'); - } + if (!self.nosort) + all = all.sort(self.nocase ? alphasorti : alphasort) - let opts = { relaxZeros: true, ...options }; - if (typeof opts.strictZeros === 'boolean') { - opts.relaxZeros = opts.strictZeros === false; + // 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 + }) + } } - 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 (self.ignore.length) + all = all.filter(function(m) { + return !isIgnored(self, m) + }) - if (toRegexRange.cache.hasOwnProperty(cacheKey)) { - return toRegexRange.cache[cacheKey].result; - } + self.found = all +} - let a = Math.min(min, max); - let b = Math.max(min, max); +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) === '/' - if (Math.abs(a - b) === 1) { - let result = min + '|' + max; - if (opts.capture) { - return `(${result})`; - } - if (opts.wrap === false) { - return result; + if (isDir && !slash) + m += '/' + else if (!isDir && slash) + m = m.slice(0, -1) + + if (m !== p) { + var mabs = makeAbs(self, m) + self.statCache[mabs] = self.statCache[abs] + self.cache[mabs] = self.cache[abs] } - return `(?:${result})`; } - let isPadded = hasPadding(min) || hasPadding(max); - let state = { min, max, a, b }; - let positives = []; - let negatives = []; - - if (isPadded) { - state.isPadded = isPadded; - state.maxLen = String(state.max).length; - } + return m +} - if (a < 0) { - let newMin = b < 0 ? Math.abs(b) : 1; - negatives = splitToPatterns(newMin, Math.abs(a), state, opts); - a = state.a = 0; +// 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) } - if (b >= 0) { - positives = splitToPatterns(a, b, state, opts); - } + if (process.platform === 'win32') + abs = abs.replace(/\\/g, '/') - state.negatives = negatives; - state.positives = positives; - state.result = collatePatterns(negatives, positives, opts); + return abs +} - 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; -}; +// 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 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('|'); + return self.ignore.some(function(item) { + return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path)) + }) } -function splitToRanges(min, max) { - let nines = 1; - let zeros = 1; +function childrenIgnored (self, path) { + if (!self.ignore.length) + return false - let stop = countNines(min, nines); - let stops = new Set([max]); + return self.ignore.some(function(item) { + return !!(item.gmatcher && item.gmatcher.match(path)) + }) +} - while (min <= stop && stop <= max) { - stops.add(stop); - nines += 1; - stop = countNines(min, nines); - } - stop = countZeros(max + 1, zeros) - 1; +/***/ }), +/* 597 */ +/***/ (function(module, exports, __webpack_require__) { - while (min < stop && stop <= max) { - stops.add(stop); - zeros += 1; - stop = countZeros(max + 1, zeros) - 1; - } +"use strict"; + +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; - stops = [...stops]; - stops.sort(compare); - return stops; -} -/** - * Convert a range to a regex pattern - * @param {Number} `start` - * @param {Number} `stop` - * @return {String} - */ +/***/ }), +/* 598 */ +/***/ (function(module, exports, __webpack_require__) { -function rangeToPattern(start, stop, options) { - if (start === stop) { - return { pattern: start, count: [], digits: 0 }; - } +"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; - 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]; +/***/ }), +/* 599 */ +/***/ (function(module, exports, __webpack_require__) { - if (startDigit === stopDigit) { - pattern += startDigit; +"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; - } else if (startDigit !== '0' || stopDigit !== '9') { - pattern += toCharacterClass(startDigit, stopDigit, options); - } else { - count++; - } - } +/***/ }), +/* 600 */ +/***/ (function(module, exports, __webpack_require__) { - if (count) { - pattern += options.shorthand === true ? '\\d' : '[0-9]'; - } +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function flatten(items) { + return items.reduce((collection, item) => [].concat(collection, item), []); +} +exports.flatten = flatten; - return { pattern, count: [count], digits }; -} -function splitToPatterns(min, max, tok, options) { - let ranges = splitToRanges(min, max); - let tokens = []; - let start = min; - let prev; +/***/ }), +/* 601 */ +/***/ (function(module, exports, __webpack_require__) { - for (let i = 0; i < ranges.length; i++) { - let max = ranges[i]; - let obj = rangeToPattern(String(start), String(max), options); - let zeros = ''; +"use strict"; + +Object.defineProperty(exports, "__esModule", { value: true }); +function isEnoentCodeError(error) { + return error.code === 'ENOENT'; +} +exports.isEnoentCodeError = isEnoentCodeError; - if (!tok.isPadded && prev && prev.pattern === obj.pattern) { - if (prev.count.length > 1) { - prev.count.pop(); - } - prev.count.push(obj.count[0]); - prev.string = prev.pattern + toQuantifier(prev.count); - start = max + 1; - continue; - } +/***/ }), +/* 602 */ +/***/ (function(module, exports, __webpack_require__) { - if (tok.isPadded) { - zeros = padZeros(max, tok, options); - } +"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; - obj.string = zeros + obj.pattern + toQuantifier(obj.count); - tokens.push(obj); - start = max + 1; - prev = obj; - } - return tokens; -} +/***/ }), +/* 603 */ +/***/ (function(module, exports, __webpack_require__) { -function filterPatterns(arr, comparison, prefix, intersection, options) { - let result = []; +"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; - for (let ele of arr) { - let { string } = ele; - // only push if _both_ are negative... - if (!intersection && !contains(comparison, 'string', string)) { - result.push(prefix + string); - } +/***/ }), +/* 604 */ +/***/ (function(module, exports, __webpack_require__) { - // or _both_ are positive - if (intersection && contains(comparison, 'string', string)) { - result.push(prefix + string); - } - } - return result; -} +"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; -/** - * Zip strings - */ -function zip(a, b) { - let arr = []; - for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]); - return arr; -} +/***/ }), +/* 605 */ +/***/ (function(module, exports, __webpack_require__) { -function compare(a, b) { - return a > b ? 1 : b > a ? -1 : 0; -} +"use strict"; -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)); -} +var isGlob = __webpack_require__(606); +var pathPosixDirname = __webpack_require__(16).posix.dirname; +var isWin32 = __webpack_require__(11).platform() === 'win32'; -function countZeros(integer, zeros) { - return integer - (integer % Math.pow(10, zeros)); -} +var slash = '/'; +var backslash = /\\/g; +var enclosure = /[\{\[].*[\/]*.*[\}\]]$/; +var globby = /(^|[^\\])([\{\[]|\([^\)]+$)/; +var escaped = /\\([\*\?\|\[\]\(\)\{\}])/g; -function toQuantifier(digits) { - let [start = 0, stop = ''] = digits; - if (stop || start > 1) { - return `{${start + (stop ? ',' + stop : '')}}`; +module.exports = function globParent(str) { + // flip windows path separators + if (isWin32 && str.indexOf(slash) < 0) { + str = str.replace(backslash, slash); } - return ''; -} - -function toCharacterClass(a, b, options) { - return `[${a}${(b - a === 1) ? '' : '-'}${b}]`; -} - -function hasPadding(str) { - return /^-?(0+)\d/.test(str); -} -function padZeros(value, tok, options) { - if (!tok.isPadded) { - return value; + // special case for strings ending in enclosure containing path separator + if (enclosure.test(str)) { + str += slash; } - let diff = Math.abs(tok.maxLen - String(value).length); - let relax = options.relaxZeros !== false; + // preserves full path in case of trailing path separator + str += 'a'; - 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}}`; - } - } -} - -/** - * Cache - */ - -toRegexRange.cache = {}; -toRegexRange.clearCache = () => (toRegexRange.cache = {}); - -/** - * Expose `toRegexRange` - */ + // remove path parts that are globby + do { + str = pathPosixDirname(str); + } while (isGlob(str) || globby.test(str)); -module.exports = toRegexRange; + // remove escape chars and return result + return str.replace(escaped, '$1'); +}; /***/ }), -/* 610 */ +/* 606 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; /*! - * is-number + * is-glob * - * Copyright (c) 2014-present, Jon Schlinkert. + * Copyright (c) 2014-2017, Jon Schlinkert. * Released under the MIT License. */ +var isExtglob = __webpack_require__(607); +var chars = { '{': '}', '(': ')', '[': ']'}; +var strictRegex = /\\(.)|(^!|\*|[\].+)]\?|\[[^\\\]]+\]|\{[^\\}]+\}|\(\?[:!=][^\\)]+\)|\([^|]+\|[^\\)]+\))/; +var relaxedRegex = /\\(.)|(^!|[*?{}()[\]]|\(\?)/; - -module.exports = function(num) { - if (typeof num === 'number') { - return num - num === 0; +module.exports = function isGlob(str, options) { + if (typeof str !== 'string' || str === '') { + return false; } - if (typeof num === 'string' && num.trim() !== '') { - return Number.isFinite ? Number.isFinite(+num) : isFinite(+num); + + if (isExtglob(str)) { + return true; } - return false; -}; + var regex = strictRegex; + var match; -/***/ }), -/* 611 */ -/***/ (function(module, exports, __webpack_require__) { + // optionally relax regex + if (options && options.strict === false) { + regex = relaxedRegex; + } -"use strict"; + while ((match = regex.exec(str))) { + if (match[2]) return true; + var idx = match.index + match[0].length; + + // 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; + } + } + str = str.slice(idx); + } + return false; +}; -const fill = __webpack_require__(608); -const stringify = __webpack_require__(605); -const utils = __webpack_require__(606); -const append = (queue = '', stash = '', enclose = false) => { - let result = []; +/***/ }), +/* 607 */ +/***/ (function(module, exports) { - queue = [].concat(queue); - stash = [].concat(stash); +/*! + * is-extglob + * + * Copyright (c) 2014-2016, Jon Schlinkert. + * Licensed under the MIT License. + */ - if (!stash.length) return queue; - if (!queue.length) { - return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; +module.exports = function isExtglob(str) { + if (typeof str !== 'string' || str === '') { + return false; } - 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)); - } - } + var match; + while ((match = /(\\).|([@?!+*]\(.*\))/g.exec(str))) { + if (match[2]) return true; + str = str.slice(match.index + match[0].length); } - return utils.flatten(result); -}; -const expand = (ast, options = {}) => { - let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit; + return false; +}; - let walk = (node, parent = {}) => { - node.queue = []; - let p = parent; - let q = parent.queue; +/***/ }), +/* 608 */ +/***/ (function(module, exports, __webpack_require__) { - while (p.type !== 'brace' && p.type !== 'root' && p.parent) { - p = p.parent; - q = p.queue; - } +"use strict"; - if (node.invalid || node.dollar) { - q.push(append(q.pop(), stringify(node, options))); - return; - } - if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { - q.push(append(q.pop(), ['{}'])); - return; - } +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 (node.nodes && node.ranges > 0) { - let args = utils.reduce(node.nodes); +/** + * 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 + */ - 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.'); - } +const micromatch = (list, patterns, options) => { + patterns = [].concat(patterns); + list = [].concat(list); - let range = fill(...args, options); - if (range.length === 0) { - range = stringify(node, options); - } + let omit = new Set(); + let keep = new Set(); + let items = new Set(); + let negatives = 0; - q.push(append(q.pop(), range)); - node.nodes = []; - return; + let onResult = state => { + items.add(state.output); + if (options && options.onResult) { + options.onResult(state); } + }; - let enclose = utils.encloseBrace(node); - let queue = node.queue; - let block = node; - - while (block.type !== 'brace' && block.type !== 'root' && block.parent) { - block = block.parent; - queue = block.queue; - } + 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++; - for (let i = 0; i < node.nodes.length; i++) { - let child = node.nodes[i]; + for (let item of list) { + let matched = isMatch(item, true); - if (child.type === 'comma' && node.type === 'brace') { - if (i === 1) queue.push(''); - queue.push(''); - continue; - } + let match = negated ? !matched.isMatch : matched.isMatch; + if (!match) continue; - if (child.type === 'close') { - q.push(append(q.pop(), queue, enclose)); - continue; + if (negated) { + omit.add(matched.output); + } else { + omit.delete(matched.output); + keep.add(matched.output); } + } + } - if (child.value && child.type !== 'open') { - queue.push(append(queue.pop(), child.value)); - continue; - } + let result = negatives === patterns.length ? [...items] : [...keep]; + let matches = result.filter(item => !omit.has(item)); - if (child.nodes) { - walk(child, node); - } + if (options && matches.length === 0) { + if (options.failglob === true) { + throw new Error(`No matches found for "${patterns.join(', ')}"`); } - return queue; - }; + if (options.nonull === true || options.nullglob === true) { + return options.unescape ? patterns.map(p => p.replace(/\\/g, '')) : patterns; + } + } - return utils.flatten(walk(ast)); + return matches; }; -module.exports = expand; - - -/***/ }), -/* 612 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - +/** + * Backwards compatibility + */ -const stringify = __webpack_require__(605); +micromatch.match = micromatch; /** - * Constants + * 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 */ -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); +micromatch.matcher = (pattern, options) => picomatch(pattern, options); /** - * parse + * 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 */ -const parse = (input, options = {}) => { - if (typeof input !== 'string') { - throw new TypeError('Expected a string'); - } - - 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})`); - } +micromatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); - 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 = {}; +/** + * Backwards compatibility + */ - /** - * Helpers - */ +micromatch.any = micromatch.isMatch; - const advance = () => input[index++]; - const push = node => { - if (node.type === 'text' && prev.type === 'dot') { - prev.type = 'text'; - } +/** + * 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 + */ - if (prev && prev.type === 'text' && node.type === 'text') { - prev.value += node.value; - return; - } +micromatch.not = (list, patterns, options = {}) => { + patterns = [].concat(patterns).map(String); + let result = new Set(); + let items = []; - block.nodes.push(node); - node.parent = block; - node.prev = prev; - prev = node; - return node; + let onResult = state => { + if (options.onResult) options.onResult(state); + items.push(state.output); }; - push({ type: 'bos' }); - - while (index < length) { - block = stack[stack.length - 1]; - value = advance(); - - /** - * Invalid chars - */ + let matches = micromatch(list, patterns, { ...options, onResult }); - if (value === CHAR_ZERO_WIDTH_NOBREAK_SPACE || value === CHAR_NO_BREAK_SPACE) { - continue; + for (let item of items) { + if (!matches.includes(item)) { + result.add(item); } + } + return [...result]; +}; - /** - * Escaped chars - */ +/** + * 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 (value === CHAR_BACKSLASH) { - push({ type: 'text', value: (options.keepEscaping ? value : '') + advance() }); - continue; - } +micromatch.contains = (str, pattern, options) => { + if (typeof str !== 'string') { + throw new TypeError(`Expected a string: "${util.inspect(str)}"`); + } - /** - * Right square bracket (literal): ']' - */ + if (Array.isArray(pattern)) { + return pattern.some(p => micromatch.contains(str, p, options)); + } - if (value === CHAR_RIGHT_SQUARE_BRACKET) { - push({ type: 'text', value: '\\' + value }); - continue; + if (typeof pattern === 'string') { + if (isEmptyString(str) || isEmptyString(pattern)) { + return false; } - /** - * Left square bracket: '[' - */ - - if (value === CHAR_LEFT_SQUARE_BRACKET) { - brackets++; - - let closed = true; - let next; + if (str.includes(pattern) || (str.startsWith('./') && str.slice(2).includes(pattern))) { + return true; + } + } - while (index < length && (next = advance())) { - value += next; + return micromatch.isMatch(str, pattern, { ...options, contains: true }); +}; - if (next === CHAR_LEFT_SQUARE_BRACKET) { - brackets++; - continue; - } +/** + * 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 (next === CHAR_BACKSLASH) { - value += advance(); - continue; - } +micromatch.matchKeys = (obj, patterns, options) => { + if (!utils.isObject(obj)) { + throw new TypeError('Expected the first argument to be an object'); + } + let keys = micromatch(Object.keys(obj), patterns, options); + let res = {}; + for (let key of keys) res[key] = obj[key]; + return res; +}; - if (next === CHAR_RIGHT_SQUARE_BRACKET) { - brackets--; +/** + * 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 + */ - if (brackets === 0) { - break; - } - } - } +micromatch.some = (list, patterns, options) => { + let items = [].concat(list); - push({ type: 'text', value }); - continue; + for (let pattern of [].concat(patterns)) { + let isMatch = picomatch(String(pattern), options); + if (items.some(item => isMatch(item))) { + return true; } + } + return false; +}; - /** - * 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; - } - - /** - * Quotes: '|"|` - */ - - if (value === CHAR_DOUBLE_QUOTE || value === CHAR_SINGLE_QUOTE || value === CHAR_BACKTICK) { - let open = value; - let next; - - if (options.keepQuotes !== true) { - value = ''; - } - - while (index < length && (next = advance())) { - if (next === CHAR_BACKSLASH) { - value += next + advance(); - continue; - } - - if (next === open) { - if (options.keepQuotes === true) value += next; - break; - } - - value += next; - } - - push({ type: 'text', value }); - continue; - } - - /** - * Left curly brace: '{' - */ - - 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: [] - }; - - block = push(brace); - stack.push(block); - push({ type: 'open', value }); - continue; - } - - /** - * Right curly brace: '}' - */ - - if (value === CHAR_RIGHT_CURLY_BRACE) { - if (block.type !== 'brace') { - push({ type: 'text', value }); - continue; - } - - let type = 'close'; - block = stack.pop(); - block.close = true; - - push({ type, value }); - depth--; - - block = stack[stack.length - 1]; - continue; - } - - /** - * 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; - } - - block.ranges++; - block.args = []; - continue; - } - - if (prev.type === 'range') { - siblings.pop(); +/** + * 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 + */ - let before = siblings[siblings.length - 1]; - before.value += prev.value + value; - prev = before; - block.ranges--; - continue; - } +micromatch.every = (list, patterns, options) => { + let items = [].concat(list); - push({ type: 'dot', value }); - continue; + for (let pattern of [].concat(patterns)) { + let isMatch = picomatch(String(pattern), options); + if (!items.every(item => isMatch(item))) { + return false; } - - /** - * 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 true; }; - -/***/ }), -/* 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 **all** of the given `patterns` match + * the specified string. * * ```js - * const picomatch = require('picomatch'); - * // picomatch(glob[, options]); + * const mm = require('micromatch'); + * // mm.all(string, patterns[, options]); * - * const isMatch = picomatch('*.!(*a)'); - * console.log(isMatch('a.a')); //=> false - * console.log(isMatch('a.b')); //=> true + * 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 * ``` - * @name picomatch - * @param {String|Array} `globs` One or more glob patterns. - * @param {Object=} `options` - * @return {Function=} Returns a matcher function. + * @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 */ -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'); - } - - 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); - } - - 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 (isMatch === false) { - result.isMatch = false; - return returnObject ? result : 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; - }; - - if (returnState) { - matcher.state = state; +micromatch.all = (str, patterns, options) => { + if (typeof str !== 'string') { + throw new TypeError(`Expected a string: "${util.inspect(str)}"`); } - return matcher; + return [].concat(patterns).every(p => picomatch(p, options)(str)); }; /** - * Test `input` with the given `regex`. This is used by the main - * `picomatch()` function to test the input 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.test(input, regex[, options]); + * const mm = require('micromatch'); + * // mm.capture(pattern, string[, options]); * - * console.log(picomatch.test('foo/bar', /^(?:([^/]*?)\/([^/]*?))$/)); - * // { isMatch: true, match: [ 'foo/', 'foo', 'bar' ], output: 'foo/bar' } + * console.log(mm.capture('test/*.js', 'test/foo.js')); + * //=> ['foo'] + * console.log(mm.capture('test/*.js', 'foo/bar.css')); + * //=> null * ``` - * @param {String} `input` String to test. - * @param {RegExp} `regex` - * @return {Object} Returns an object with matching info. + * @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.test = (input, regex, options, { glob, posix } = {}) => { - if (typeof input !== 'string') { - throw new TypeError('Expected input to be a string'); - } - - 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; - - if (match === false) { - output = format ? format(input) : input; - match = output === glob; - } +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 === false || opts.capture === true) { - if (opts.matchBase === true || opts.basename === true) { - match = picomatch.matchBase(input, regex, options, posix); - } else { - match = regex.exec(output); - } + if (match) { + return match.slice(1).map(v => v === void 0 ? '' : v); } - - return { isMatch: !!match, match, output }; }; /** - * Match the basename of a filepath. + * Create a regular expression from the given glob `pattern`. * * ```js - * const picomatch = require('picomatch'); - * // picomatch.matchBase(input, glob[, options]); - * console.log(picomatch.matchBase('foo/bar.js', '*.js'); // true + * const mm = require('micromatch'); + * // mm.makeRe(pattern[, options]); + * + * console.log(mm.makeRe('*.js')); + * //=> /^(?:(\.[\\\/])?(?!\.)(?=.)[^\/]*?\.js)$/ * ``` - * @param {String} `input` String to test. - * @param {RegExp|String} `glob` Glob pattern or regex created by [.makeRe](#makeRe). - * @return {Boolean} + * @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 */ -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.makeRe = (...args) => picomatch.makeRe(...args); /** - * Returns true if **any** of the given glob `patterns` match the specified `string`. + * Scan a glob pattern to separate the pattern into segments. Used + * by the [split](#split) method. * * ```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 + * const mm = require('micromatch'); + * const state = mm.scan(pattern[, options]); * ``` - * @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} `pattern` + * @param {Object} `options` + * @return {Object} Returns an object with * @api public */ -picomatch.isMatch = (str, patterns, options) => picomatch(patterns, options)(str); +micromatch.scan = (...args) => picomatch.scan(...args); /** * Parse a glob pattern to create the source string for a regular * expression. * * ```js - * const picomatch = require('picomatch'); - * const result = picomatch.parse(glob[, options]); + * 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 a regex source string. + * @return {Object} Returns an object with useful properties and output to be used as regex source string. * @api public */ -picomatch.parse = (glob, options) => parse(glob, options); +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 res; +}; /** - * Scan a glob pattern to separate the pattern into segments. + * Process the given brace `pattern`. * * ```js - * const picomatch = require('picomatch'); - * // picomatch.scan(input[, options]); + * const { braces } = require('micromatch'); + * console.log(braces('foo/{a,b,c}/bar')); + * //=> [ 'foo/(a|b|c)/bar' ] * - * const result = picomatch.scan('!./foo/*.js'); - * console.log(result); - * // { prefix: '!./', - * // input: '!./foo/*.js', - * // base: 'foo', - * // glob: '*.js', - * // negated: true, - * // isGlob: true } + * console.log(braces('foo/{a,b,c}/bar', { expand: true })); + * //=> [ 'foo/a/bar', 'foo/b/bar', 'foo/c/bar' ] * ``` - * @param {String} `input` Glob pattern to scan. - * @param {Object} `options` - * @return {Object} Returns an object with + * @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.scan = (input, options) => scan(input, options); +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); +}; /** - * 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 + * Expand braces */ -picomatch.makeRe = (input, options, returnOutput = false, returnState = false) => { - if (!input || typeof input !== 'string') { - throw new TypeError('Expected a non-empty string'); - } +micromatch.braceExpand = (pattern, options) => { + if (typeof pattern !== 'string') throw new TypeError('Expected a string'); + return micromatch.braces(pattern, { ...options, expand: true }); +}; - let opts = options || {}; - let prepend = opts.contains ? '' : '^'; - let append = opts.contains ? '' : '$'; - let state = { negated: false, fastpaths: true }; - let prefix = ''; - let output; +/** + * Expose micromatch + */ - if (input.startsWith('./')) { - input = input.slice(2); - prefix = state.prefix = './'; - } +module.exports = micromatch; - 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; - } +/***/ }), +/* 609 */ +/***/ (function(module, exports, __webpack_require__) { - if (returnOutput === true) { - return output; - } +"use strict"; - let source = `${prepend}(?:${output})${append}`; - if (state && state.negated === true) { - source = `^(?!${source}).*$`; - } - let regex = picomatch.toRegex(source, options); - if (returnState === true) { - regex.state = state; +const stringify = __webpack_require__(610); +const compile = __webpack_require__(612); +const expand = __webpack_require__(616); +const parse = __webpack_require__(617); + +/** + * 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 + */ + +const braces = (input, options = {}) => { + let output = []; + + 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)); } - return regex; + if (options && options.expand === true && options.nodupes === true) { + output = [...new Set(output)]; + } + return output; }; /** - * Create a regular expression from the given regex source string. + * Parse the given `str` with the given `options`. * * ```js - * const picomatch = require('picomatch'); - * // picomatch.toRegex(source[, options]); + * // 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 + */ + +braces.parse = (input, options = {}) => parse(input, options); + +/** + * Creates a braces string from an AST, or an AST node. * - * const { output } = picomatch.parse('*.js'); - * console.log(picomatch.toRegex(output)); - * //=> /^(?:(?!\.)(?=.)[^/]*?\.js)$/ + * ```js + * const braces = require('braces'); + * let ast = braces.parse('foo/{a,b}/bar'); + * console.log(stringify(ast.nodes[2])); //=> '{a,b}' * ``` - * @param {String} `source` Regular expression source string. + * @param {String} `input` Brace pattern or AST. * @param {Object} `options` - * @return {RegExp} + * @return {Array} Returns an array of expanded values. * @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 /$^/; +braces.stringify = (input, options = {}) => { + if (typeof input === 'string') { + return stringify(braces.parse(input, options), options); } + return stringify(input, options); }; /** - * Picomatch constants. - * @return {Object} + * 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 */ -picomatch.constants = __webpack_require__(618); +braces.compile = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); + } + return compile(input, options); +}; /** - * Expose "picomatch" + * 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 */ -module.exports = picomatch; - - -/***/ }), -/* 616 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +braces.expand = (input, options = {}) => { + if (typeof input === 'string') { + input = braces.parse(input, options); + } + let result = expand(input, options); -const utils = __webpack_require__(617); + // filter out empty strings if specified + if (options.noempty === true) { + result = result.filter(Boolean); + } -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); + // filter out duplicates if specified + if (options.nodupes === true) { + result = [...new Set(result)]; + } -const isPathSeparator = code => { - return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; + return result; }; /** - * 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 `!`). + * 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 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.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} `str` + * @param {String} `pattern` Brace pattern * @param {Object} `options` - * @return {Object} Returns an object with tokens and regex source string. + * @return {Array} Returns an array of expanded values. * @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; - - let eos = () => index >= length; - let advance = () => { - prev = code; - return input.charCodeAt(++index); - }; +braces.create = (input, options = {}) => { + if (input === '' || input.length < 3) { + return [input]; + } - while (index < length) { - code = advance(); - let next; + return options.expand !== true + ? braces.compile(input, options) + : braces.expand(input, options); +}; - if (code === CHAR_BACKWARD_SLASH) { - backslashes = true; - next = advance(); +/** + * Expose "braces" + */ - if (next === CHAR_LEFT_CURLY_BRACE) { - braceEscaped = true; - } - continue; - } +module.exports = braces; - if (braceEscaped === true || code === CHAR_LEFT_CURLY_BRACE) { - braces++; - while (!eos() && (next = advance())) { - if (next === CHAR_BACKWARD_SLASH) { - backslashes = true; - next = advance(); - continue; - } +/***/ }), +/* 610 */ +/***/ (function(module, exports, __webpack_require__) { - if (next === CHAR_LEFT_CURLY_BRACE) { - braces++; - continue; - } +"use strict"; - if (!braceEscaped && next === CHAR_DOT && (next = advance()) === CHAR_DOT) { - isGlob = true; - break; - } - if (!braceEscaped && next === CHAR_COMMA) { - isGlob = true; - break; - } +const utils = __webpack_require__(611); - if (next === CHAR_RIGHT_CURLY_BRACE) { - braces--; - if (braces === 0) { - braceEscaped = false; - break; - } - } - } - } +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 (code === CHAR_FORWARD_SLASH) { - if (prev === CHAR_DOT && index === (start + 1)) { - start += 2; - continue; + if (node.value) { + if ((invalidBlock || invalidNode) && utils.isOpenOrClose(node)) { + return '\\' + node.value; } - - lastIndex = index + 1; - continue; - } - - if (code === CHAR_ASTERISK) { - isGlob = true; - break; + return node.value; } - if (code === CHAR_ASTERISK || code === CHAR_QUESTION_MARK) { - isGlob = true; - break; + if (node.value) { + return node.value; } - if (code === CHAR_LEFT_SQUARE_BRACKET) { - while (!eos() && (next = advance())) { - if (next === CHAR_BACKWARD_SLASH) { - backslashes = true; - next = advance(); - continue; - } - - if (next === CHAR_RIGHT_SQUARE_BRACKET) { - isGlob = true; - break; - } + if (node.nodes) { + for (let child of node.nodes) { + output += stringify(child); } } + return output; + }; - let isExtglobChar = code === CHAR_PLUS - || code === CHAR_AT - || code === CHAR_EXCLAMATION_MARK; - - if (isExtglobChar && input.charCodeAt(index + 1) === CHAR_LEFT_PARENTHESES) { - isGlob = true; - break; - } + return stringify(ast); +}; - if (code === CHAR_EXCLAMATION_MARK && index === start) { - negated = true; - start++; - continue; - } - 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; - } - } - } +/***/ }), +/* 611 */ +/***/ (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; +exports.isInteger = num => { + if (typeof num === 'number') { + return Number.isInteger(num); } - - 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; + if (typeof num === 'string' && num.trim() !== '') { + return Number.isInteger(Number(num)); } + return false; +}; - if (base && base !== '' && base !== '/' && base !== input) { - if (isPathSeparator(base.charCodeAt(base.length - 1))) { - base = base.slice(0, -1); - } - } +/** + * Find a node of the given type + */ - if (opts.unescape === true) { - if (glob) glob = utils.removeBackslashes(glob); +exports.find = (node, type) => node.nodes.find(node => node.type === type); - if (base && backslashes === true) { - base = utils.removeBackslashes(base); - } - } +/** + * Find a node of the given type + */ - return { prefix, input: orig, base, glob, negated, isGlob }; +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 + */ -/***/ }), -/* 617 */ -/***/ (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.escapeNode = (block, n = 0, type) => { + let node = block.nodes[n]; + if (!node) return; -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, '/'); + if ((type && node.type === type) || node.type === 'open' || node.type === 'close') { + if (node.escaped !== true) { + node.value = '\\' + node.value; + node.escaped = true; + } + } +}; -exports.removeBackslashes = str => { - return str.replace(REGEX_REMOVE_BACKSLASH, match => { - return match === '\\' ? '' : match; - }); -} +/** + * Returns true if the given brace node should be enclosed in literal braces + */ -exports.supportsLookbehinds = () => { - let segs = process.version.slice(1).split('.'); - if (segs.length === 3 && +segs[0] >= 9 || (+segs[0] === 8 && +segs[1] >= 10)) { +exports.encloseBrace = node => { + if (node.type !== 'brace') return false; + if ((node.commas >> 0 + node.ranges >> 0) === 0) { + node.invalid = true; return true; } return false; }; -exports.isWindows = options => { - if (options && typeof options.windows === 'boolean') { - return options.windows; +/** + * Returns true if a brace node is invalid. + */ + +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; } - return win32 === true || path.sep === '\\'; + if (block.open !== true || block.close !== true) { + block.invalid = true; + return true; + } + return false; }; -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); -}; - - -/***/ }), -/* 618 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -const path = __webpack_require__(16); -const WIN_SLASH = '\\\\/'; -const WIN_NO_SLASH = `[^${WIN_SLASH}]`; - /** - * Posix glob regex + * Returns true if a node is an open or close node */ -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.isOpenOrClose = node => { + if (node.type === 'open' || node.type === 'close') { + return true; + } + return node.open === true || node.close === true; }; /** - * Windows glob regex + * Reduce an array of text nodes. */ -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.reduce = nodes => nodes.reduce((acc, node) => { + if (node.type === 'text') acc.push(node.value); + if (node.type === 'range') node.type = 'text'; + return acc; +}, []); /** - * POSIX Bracket Regex + * Flatten an array */ -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.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 (tok.value || tok.output) append(tok); - if (prev && prev.type === 'text' && tok.type === 'text') { - prev.value += tok.value; - return; - } + if (options.toRegex === true) { + return step > 1 + ? toSequence(parts, options) + : toRegex(range, null, { wrap: false, ...options }); + } - 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; - } + obj.string = zeros + obj.pattern + toQuantifier(obj.count); + tokens.push(obj); + start = max + 1; + prev = obj; + } - let output = ')'; + return tokens; +} - if (state.dots === true) { - let arr = tokens.slice(); - let range = []; +function filterPatterns(arr, comparison, prefix, intersection, options) { + let result = []; - 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); - } - } + for (let ele of arr) { + let { string } = ele; - output = expandRange(range, opts); - state.backtrack = true; - } + // only push if _both_ are negative... + if (!intersection && !contains(comparison, 'string', string)) { + result.push(prefix + string); + } - push({ type: 'brace', value, output }); - decrement('braces'); - continue; + // or _both_ are positive + if (intersection && contains(comparison, 'string', string)) { + result.push(prefix + string); } + } + return result; +} - /** - * Pipes - */ +/** + * Zip strings + */ - if (value === '|') { - if (extglobs.length > 0) { - extglobs[extglobs.length - 1].conditions++; - } - push({ type: 'text', value }); - continue; - } +function zip(a, b) { + let arr = []; + for (let i = 0; i < a.length; i++) arr.push([a[i], b[i]]); + return arr; +} - /** - * Commas - */ +function compare(a, b) { + return a > b ? 1 : b > a ? -1 : 0; +} - if (value === ',') { - let output = value; +function contains(arr, key, val) { + return arr.some(ele => ele[key] === val); +} - if (state.braces > 0 && stack[stack.length - 1] === 'braces') { - output = '|'; - } +function countNines(min, len) { + return Number(String(min).slice(0, -len) + '9'.repeat(len)); +} - push({ type: 'comma', value, output }); - continue; - } +function countZeros(integer, zeros) { + return integer - (integer % Math.pow(10, zeros)); +} - /** - * Slashes - */ +function toQuantifier(digits) { + let [start = 0, stop = ''] = digits; + if (stop || start > 1) { + return `{${start + (stop ? ',' + stop : '')}}`; + } + return ''; +} - 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 toCharacterClass(a, b, options) { + return `[${a}${(b - a === 1) ? '' : '-'}${b}]`; +} - push({ type: 'slash', value, output: SLASH_LITERAL }); - continue; - } +function hasPadding(str) { + return /^-?(0+)\d/.test(str); +} - /** - * Dots - */ +function padZeros(value, tok, options) { + if (!tok.isPadded) { + return value; + } - 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; - } + let diff = Math.abs(tok.maxLen - String(value).length); + let relax = options.relaxZeros !== false; - push({ type: 'dot', value, output: DOT_LITERAL }); - continue; + 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}}`; } + } +} - /** - * Question marks - */ +/** + * Cache + */ - if (value === '?') { - if (prev && prev.type === 'paren') { - let next = peek(); - let output = value; +toRegexRange.cache = {}; +toRegexRange.clearCache = () => (toRegexRange.cache = {}); - if (next === '<' && !utils.supportsLookbehinds()) { - throw new Error('Node.js v10 or higher is required for regex lookbehinds'); - } +/** + * Expose `toRegexRange` + */ - if (prev.value === '(' && !/[!=<:]/.test(next) || (next === '<' && !/[!=]/.test(peek(2)))) { - output = '\\' + value; - } +module.exports = toRegexRange; - push({ type: 'text', value, output }); - continue; - } - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('qmark', value); - continue; - } +/***/ }), +/* 615 */ +/***/ (function(module, exports, __webpack_require__) { - if (opts.dot !== true && (prev.type === 'slash' || prev.type === 'bos')) { - push({ type: 'qmark', value, output: QMARK_NO_DOT }); - continue; - } +"use strict"; +/*! + * is-number + * + * Copyright (c) 2014-present, Jon Schlinkert. + * Released under the MIT License. + */ - 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; - } - } +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 (opts.nonegate !== true && state.index === 0) { - negate(state); - continue; - } - } - /** - * Plus - */ +/***/ }), +/* 616 */ +/***/ (function(module, exports, __webpack_require__) { - if (value === '+') { - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('plus', value); - continue; - } +"use strict"; - 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; - } +const fill = __webpack_require__(613); +const stringify = __webpack_require__(610); +const utils = __webpack_require__(611); - push({ type: 'plus', value: PLUS_LITERAL }); - continue; - } +const append = (queue = '', stash = '', enclose = false) => { + let result = []; - /** - * Plain text - */ + queue = [].concat(queue); + stash = [].concat(stash); - if (value === '@') { - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - push({ type: 'at', value, output: '' }); - continue; - } + if (!stash.length) return queue; + if (!queue.length) { + return enclose ? utils.flatten(stash).map(ele => `{${ele}}`) : stash; + } - push({ type: 'text', value }); - continue; + 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); +}; - /** - * Plain text - */ +const expand = (ast, options = {}) => { + let rangeLimit = options.rangeLimit === void 0 ? 1000 : options.rangeLimit; - if (value !== '*') { - if (value === '$' || value === '^') { - value = '\\' + value; - } + let walk = (node, parent = {}) => { + node.queue = []; - let match = REGEX_NON_SPECIAL_CHAR.exec(input.slice(state.index + 1)); - if (match) { - value += match[0]; - state.index += match[0].length; - } + let p = parent; + let q = parent.queue; - push({ type: 'text', value }); - continue; + while (p.type !== 'brace' && p.type !== 'root' && p.parent) { + p = p.parent; + q = p.queue; } - /** - * 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 (node.invalid || node.dollar) { + q.push(append(q.pop(), stringify(node, options))); + return; } - if (opts.noextglob !== true && peek() === '(' && peek(2) !== '?') { - extglobOpen('star', value); - continue; + if (node.type === 'brace' && node.invalid !== true && node.nodes.length === 2) { + q.push(append(q.pop(), ['{}'])); + return; } - 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 (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) { -module.exports = runParallel +const path = __webpack_require__(16); +const scan = __webpack_require__(621); +const parse = __webpack_require__(624); +const utils = __webpack_require__(622); -function runParallel (tasks, cb) { - var results, pending, keys - var isSync = true +/** + * 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 + */ - if (Array.isArray(tasks)) { - results = [] - pending = tasks.length - } else { - keys = Object.keys(tasks) - results = {} - pending = keys.length +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; + }; } - function done (err) { - function end () { - if (cb) cb(err, results) - cb = null - } - if (isSync) process.nextTick(end) - else end() + if (typeof glob !== 'string' || glob === '') { + throw new TypeError('Expected pattern to be a non-empty string'); } - function each (i, err, result) { - results[i] = result - if (--pending === 0 || err) { - done(err) - } - } + let opts = options || {}; + let posix = utils.isWindows(options); + let regex = picomatch.makeRe(glob, options, false, true); + let state = regex.state; + delete regex.state; - 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) }) - }) + let isIgnored = () => false; + if (opts.ignore) { + let ignoreOpts = { ...options, ignore: null, onMatch: null, onResult: null }; + isIgnored = picomatch(opts.ignore, ignoreOpts, returnState); } - isSync = false -} + 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); + } -/***/ }), -/* 634 */ -/***/ (function(module, exports, __webpack_require__) { + if (isMatch === false) { + result.isMatch = false; + return returnObject ? result : false; + } -"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); + 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; + }; -/***/ }), -/* 635 */ -/***/ (function(module, exports, __webpack_require__) { + if (returnState) { + matcher.state = state; + } -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const fs = __webpack_require__(636); -exports.fs = fs; + 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 + */ -/***/ }), -/* 636 */ -/***/ (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 }); -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 (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; -/***/ }), -/* 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; + if (match === false) { + output = format ? format(input) : input; + match = output === glob; + } + 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); + } + } -/***/ }), -/* 638 */ -/***/ (function(module, exports, __webpack_require__) { + return { isMatch: !!match, match, output }; +}; -"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; -/***/ }), -/* 653 */ -/***/ (function(module, exports, __webpack_require__) { +const path = __webpack_require__(16); +const WIN_SLASH = '\\\\/'; +const WIN_NO_SLASH = `[^${WIN_SLASH}]`; -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -const utils = __webpack_require__(594); -class EntryTransformer { - constructor(_settings) { - this._settings = _settings; - } - getTransformer() { - return (entry) => this._transform(entry); - } - _transform(entry) { - let filepath = entry.path; - if (this._settings.absolute) { - filepath = utils.path.makeAbsolute(this._settings.cwd, filepath); - filepath = utils.path.unixify(filepath); - } - if (this._settings.markDirectories && entry.dirent.isDirectory()) { - filepath += '/'; - } - if (!this._settings.objectMode) { - return filepath; - } - return Object.assign({}, entry, { path: filepath }); - } -} -exports.default = EntryTransformer; +/** + * 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}*?`; -/***/ }), -/* 654 */ -/***/ (function(module, exports, __webpack_require__) { +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 +}; -"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; +/** + * Windows glob regex + */ +const WINDOWS_CHARS = { + ...POSIX_CHARS, -/***/ }), -/* 655 */ -/***/ (function(module, exports, __webpack_require__) { + 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}]|$)` +}; -"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; +/** + * 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; + } +}; /***/ }), -/* 656 */ +/* 624 */ /***/ (function(module, exports, __webpack_require__) { "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; -/***/ }), -/* 657 */ -/***/ (function(module, exports, __webpack_require__) { +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 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; + } + getTransformer() { + return (entry) => this._transform(entry); + } + _transform(entry) { + let filepath = entry.path; + if (this._settings.absolute) { + filepath = utils.path.makeAbsolute(this._settings.cwd, filepath); + filepath = utils.path.unixify(filepath); + } + if (this._settings.markDirectories && entry.dirent.isDirectory()) { + filepath += '/'; + } + if (!this._settings.objectMode) { + return filepath; + } + return Object.assign({}, entry, { path: filepath }); + } +} +exports.default = EntryTransformer; + + +/***/ }), +/* 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"; + +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); +}; + + +/***/ }), +/* 666 */ +/***/ (function(module, exports) { + +// 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, '#') + + const regex = makeRegex(pattern, negative, ignorecase) + + return new IgnoreRule( + origin, + pattern, + negative, + regex + ) +} + +const throwError = (message, Ctor) => { + throw new Ctor(message) +} + +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); + +module.exports = path_ => { + let cwd = process.cwd(); + + path_ = path.resolve(path_); -const SLASH = '/' -const KEY_IGNORE = typeof Symbol !== 'undefined' - ? Symbol.for('node-ignore') - /* istanbul ignore next */ - : 'node-ignore' + if (process.platform === 'win32') { + cwd = cwd.toLowerCase(); + path_ = path_.toLowerCase(); + } -const define = (object, key, value) => - Object.defineProperty(object, key, {value}) + return path_ === cwd; +}; -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. - : '' -) +/***/ }), +/* 670 */ +/***/ (function(module, exports, __webpack_require__) { -// > 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` +"use strict"; -// '`foo/`' should not continue with the '`..`' -const DEFAULT_REPLACER_PREFIX = [ +const path = __webpack_require__(16); - // > Trailing spaces are ignored unless they are quoted with backslash ("\") - [ - // (a\ ) -> (a ) - // (a ) -> (a) - // (a \ ) -> (a ) - /\\?\s+$/, - match => match.indexOf('\\') === 0 - ? ' ' - : '' - ], +module.exports = (childPath, parentPath) => { + childPath = path.resolve(childPath); + parentPath = path.resolve(parentPath); - // replace (\ ) with ' ' - [ - /\\\s/g, - () => ' ' - ], + if (process.platform === 'win32') { + childPath = childPath.toLowerCase(); + parentPath = parentPath.toLowerCase(); + } - // Escape metacharacters - // which is written down by users but means special for regular expressions. + if (childPath === parentPath) { + return false; + } - // > 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}` - ], + childPath += path.sep; + parentPath += path.sep; - [ - // > [abc] matches any character inside the brackets - // > (in this case a, b, or c); - /\[([^\]/]*)($|\])/g, - (match, p1, p2) => p2 === ']' - ? `[${sanitizeRange(p1)}]` - : `\\${match}` - ], + return childPath.startsWith(parentPath); +}; - [ - // > a question mark (?) matches a single character - /(?!\\)\?/g, - () => '[^/]' - ], - // leading slash - [ +/***/ }), +/* 671 */ +/***/ (function(module, exports, __webpack_require__) { - // > 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 - /^\//, - () => '^' - ], +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. +} - // replace special metacharacter slash after the leading slash - [ - /\//g, - () => '\\/' - ], +const defaultGlobOpts = { + nosort: true, + silent: true +} - [ - // > 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 '\\*' - /^\^*\\\*\\\*\\\//, +// for EMFILE handling +let timeout = 0 - // '**/foo' <-> 'foo' - () => '^(?:.*\\/)?' - ] -] +const isWindows = (process.platform === "win32") -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 - ? '(?:^|\\/)' +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] + }) - // > Otherwise, Git treats the pattern as a shell glob suitable for - // > consumption by fnmatch(3) - : '^' - } - ], + 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 +} - // two globstars - [ - // Use lookahead assertions so that we could match more than one `'/**'` - /\\\/\\\*\\\*(?=\\\/|$)/g, +const rimraf = (p, options, cb) => { + if (typeof options === 'function') { + cb = options + options = {} + } - // Zero, one or several directories - // should not use '*', or it will be replaced by the next replacer + 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') - // Check if it is not the last `'/**'` - (_, index, str) => index + 6 < str.length + defaults(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. - // '/**/' - ? '(?:\\/[^\\/]+)*' + let busyTries = 0 + let errState = null + let n = 0 - // case: /** - // > A trailing `"/**"` matches everything inside. + const next = (er) => { + errState = errState || er + if (--n === 0) + cb(errState) + } - // #21: everything inside but it should not include the current folder - : '\\/.+' - ], + const afterGlob = (er, results) => { + if (er) + return cb(er) - // intermediate wildcards - [ - // Never replace escaped '*' - // ignore rule '\*' will match the path '*' + n = results.length + if (n === 0) + return cb() - // 'abc.*/' -> go - // 'abc.*' -> skip this rule - /(^|[^\\]+)\\\*(?=.+)/g, + 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) + } - // '*.js' matches '.js' - // '*.js' doesn't match 'abc' - (_, p1) => `${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 ++) + } - // trailing wildcard - [ - /(\^|\\\/)?\\\*$/, - (_, p1) => { - const prefix = p1 - // '\^': - // '/*' does not match '' - // '/*' does not match everything + // already gone + if (er.code === "ENOENT") er = null + } - // '\\\/': - // 'abc/*' does not match 'abc/' - ? `${p1}[^/]+` + timeout = 0 + next(er) + } + rimraf_(p, options, CB) + }) + } - // 'a*' matches 'a' - // 'a*' matches 'aa' - : '[^/]*' + if (options.disableGlob || !glob.hasMagic(p)) + return afterGlob(null, [p]) - return `${prefix}(?=$|\\/$)` - } - ], + options.lstat(p, (er, stat) => { + if (!er) + return afterGlob(null, [p]) - [ - // unescape - /\\\\\\/g, - () => '\\' - ] -] + glob(p, options.glob, afterGlob) + }) -const POSITIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, +} - // 'f' - // matches - // - /f(end) - // - /f/ - // - (start)f(end) - // - (start)f/ - // doesn't match - // - oof - // - foo - // pseudo: - // -> (^|/)f(/|$) +// 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') - // ending - [ - // 'js' will not match 'js.' - // 'ab' will not match 'abc' - /(?:[^*/])$/, + // 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) - // 'js*' will not match 'a.js' - // 'js/' will not match 'a.js' - // 'js' will match 'a.js' and 'a.js/' - match => `${match}(?=$|\\/)` - ], + // Windows can EPERM on stat. Life is suffering. + if (er && er.code === "EPERM" && isWindows) + fixWinEPERM(p, options, er, cb) - ...DEFAULT_REPLACER_SUFFIX -] + if (st && st.isDirectory()) + return rmdir(p, options, er, cb) -const NEGATIVE_REPLACERS = [ - ...DEFAULT_REPLACER_PREFIX, + 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) + }) + }) +} - // #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. +const fixWinEPERM = (p, options, er, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') + if (er) + assert(er instanceof Error) - // eg: - // ['node_modules/*', '!node_modules'] - // should ignore `node_modules/a.js` - [ - /(?:[^*])$/, - match => `${match}(?=$|\\/$)` - ], + 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) + }) + }) +} - ...DEFAULT_REPLACER_SUFFIX -] +const fixWinEPERMSync = (p, options, er) => { + assert(p) + assert(options) + if (er) + assert(er instanceof Error) -// A simple cache, because an ignore rule only has only one certain meaning -const regexCache = Object.create(null) + try { + options.chmodSync(p, 0o666) + } catch (er2) { + if (er2.code === "ENOENT") + return + else + throw er + } -// @param {pattern} -const makeRegex = (pattern, negative, ignorecase) => { - const r = regexCache[pattern] - if (r) { - return r + let stats + try { + stats = options.statSync(p) + } catch (er3) { + if (er3.code === "ENOENT") + return + else + throw er } - const replacers = negative - ? NEGATIVE_REPLACERS - : POSITIVE_REPLACERS + if (stats.isDirectory()) + rmdirSync(p, options, er) + else + options.unlinkSync(p) +} - const source = replacers.reduce( - (prev, current) => prev.replace(current[0], current[1].bind(pattern)), - pattern - ) +const rmdir = (p, options, originalEr, cb) => { + assert(p) + assert(options) + if (originalEr) + assert(originalEr instanceof Error) + assert(typeof cb === 'function') - return regexCache[pattern] = ignorecase - ? new RegExp(source, 'i') - : new RegExp(source) + // 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' - -// > 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) +const rmkids = (p, options, cb) => { + assert(p) + assert(options) + assert(typeof cb === 'function') - // > A line starting with # serves as a comment. - && pattern.indexOf('#') !== 0 + 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) + }) + }) + }) +} -const splitPattern = pattern => pattern.split(REGEX_SPLITALL_CRLF) +// 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) -class IgnoreRule { - constructor ( - origin, - pattern, - negative, - regex - ) { - this.origin = origin - this.pattern = pattern - this.negative = negative - this.regex = regex - } -} + 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') -const createRule = (pattern, ignorecase) => { - const origin = pattern - let negative = false + let results - // > An optional prefix "!" which negates the pattern; - if (pattern.indexOf('!') === 0) { - negative = true - pattern = pattern.substr(1) + if (options.disableGlob || !glob.hasMagic(p)) { + results = [p] + } else { + try { + options.lstatSync(p) + results = [p] + } catch (er) { + results = glob.sync(p, options.glob) + } } - 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, '#') + if (!results.length) + return - const regex = makeRegex(pattern, negative, ignorecase) + for (let i = 0; i < results.length; i++) { + const p = results[i] - return new IgnoreRule( - origin, - pattern, - negative, - regex - ) -} + let st + try { + st = options.lstatSync(p) + } catch (er) { + if (er.code === "ENOENT") + return -const throwError = (message, Ctor) => { - throw new Ctor(message) -} + // Windows can EPERM on stat. Life is suffering. + if (er.code === "EPERM" && isWindows) + fixWinEPERMSync(p, options, er) + } -const checkPath = (path, originalPath, doThrow) => { - if (!isString(path)) { - return doThrow( - `path must be a string, but got \`${originalPath}\``, - TypeError - ) - } + 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 - // We don't know if we should ignore '', so throw - if (!path) { - return doThrow(`path must not be empty`, TypeError) + rmdirSync(p, options, er) + } } +} - // 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 rmdirSync = (p, options, originalEr) => { + assert(p) + assert(options) + if (originalEr) + assert(originalEr instanceof Error) - return true + 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 isNotRelative = path => REGEX_TEST_INVALID_PATH.test(path) +const rmkidsSync = (p, options) => { + assert(p) + assert(options) + options.readdirSync(p).forEach(f => rimrafSync(path.join(p, f), options)) -checkPath.isNotRelative = isNotRelative -checkPath.convert = p => p + // 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) +} -class Ignore { - constructor ({ - ignorecase = true - } = {}) { - this._rules = [] - this._ignorecase = ignorecase - define(this, KEY_IGNORE, true) - this._initCache() - } +module.exports = rimraf +rimraf.sync = rimrafSync - _initCache () { - this._ignoreCache = Object.create(null) - this._testCache = Object.create(null) - } - _addPattern (pattern) { - // #32 - if (pattern && pattern[KEY_IGNORE]) { - this._rules = this._rules.concat(pattern._rules) - this._added = true - return - } +/***/ }), +/* 672 */ +/***/ (function(module, exports, __webpack_require__) { - if (checkPattern(pattern)) { - const rule = createRule(pattern, this._ignorecase) - this._added = true - this._rules.push(rule) - } - } +"use strict"; - // @param {Array | string | Ignore} pattern - add (pattern) { - this._added = false +const AggregateError = __webpack_require__(673); - makeArray( - isString(pattern) - ? splitPattern(pattern) - : pattern - ).forEach(this._addPattern, this) +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'); + } - // Some rules have just added to the ignore, - // making the behavior changed. - if (this._added) { - this._initCache() - } + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } - return this - } + const ret = []; + const errors = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let isIterableDone = false; + let resolvingCount = 0; + let currentIndex = 0; - // legacy - addPattern (pattern) { - return this.add(pattern) - } + const next = () => { + if (isRejected) { + return; + } - // | ignored : unignored - // negative | 0:0 | 0:1 | 1:0 | 1:1 - // -------- | ------- | ------- | ------- | -------- - // 0 | TEST | TEST | SKIP | X - // 1 | TESTIF | SKIP | TEST | X + const nextItem = iterator.next(); + const i = currentIndex; + currentIndex++; - // - SKIP: always skip - // - TEST: always test - // - TESTIF: only test if checkUnignored - // - X: that never happen + if (nextItem.done) { + isIterableDone = true; - // @param {boolean} whether should check if the path is unignored, - // setting `checkUnignored` to `false` could reduce additional - // path matching. + if (resolvingCount === 0) { + if (!stopOnError && errors.length !== 0) { + reject(new AggregateError(errors)); + } else { + resolve(ret); + } + } - // @returns {TestResult} true if a file is ignored - _testOne (path, checkUnignored) { - let ignored = false - let unignored = false + return; + } - this._rules.forEach(rule => { - const {negative} = rule - if ( - unignored === negative && ignored !== unignored - || negative && !ignored && !unignored && !checkUnignored - ) { - return - } + resolvingCount++; - const matched = rule.regex.test(path) + (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(); + } + } + })(); + }; - if (matched) { - ignored = !negative - unignored = negative - } - }) + for (let i = 0; i < concurrency; i++) { + next(); - return { - ignored, - unignored - } - } + if (isIterableDone) { + break; + } + } + }); +}; - // @returns {TestResult} - _test (originalPath, cache, checkUnignored, slices) { - const path = originalPath - // Supports nullable path - && checkPath.convert(originalPath) - checkPath(path, originalPath, throwError) +/***/ }), +/* 673 */ +/***/ (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 indentString = __webpack_require__(674); +const cleanStack = __webpack_require__(675); - if (!slices) { - // path/to/a.js - // ['path', 'to', 'a.js'] - slices = path.split(SLASH) - } +const cleanInternalStack = stack => stack.replace(/\s+at .*aggregate-error\/index.js:\d+:\d+\)?/g, ''); - slices.pop() +class AggregateError extends Error { + constructor(errors) { + if (!Array.isArray(errors)) { + throw new TypeError(`Expected input to be an Array, got ${typeof errors}`); + } - // If the path has no parent directory, just test it - if (!slices.length) { - return cache[path] = this._testOne(path, checkUnignored) - } + errors = [...errors].map(error => { + if (error instanceof Error) { + return error; + } - const parent = this._t( - slices.join(SLASH) + SLASH, - cache, - checkUnignored, - slices - ) + 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 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) - } + return new Error(error); + }); - ignores (path) { - return this._test(path, this._ignoreCache, false).ignored - } + 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); - createFilter () { - return path => !this.ignores(path) - } + this.name = 'AggregateError'; - filter (paths) { - return makeArray(paths).filter(this.createFilter()) - } + Object.defineProperty(this, '_errors', {value: errors}); + } - // @returns {TestResult} - test (path) { - return this._test(path, this._testCache, true) - } + * [Symbol.iterator]() { + for (const error of this._errors) { + yield error; + } + } } -const factory = options => new Ignore(options) +module.exports = AggregateError; -const returnFalse = () => false -const isPathValid = path => - checkPath(path && checkPath.convert(path), path, returnFalse) +/***/ }), +/* 674 */ +/***/ (function(module, exports, __webpack_require__) { -factory.isPathValid = isPathValid +"use strict"; -// Fixes typescript -factory.default = factory -module.exports = factory +module.exports = (string, count = 1, options) => { + options = { + indent: ' ', + includeEmptyLines: false, + ...options + }; -// 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 string !== 'string') { + throw new TypeError( + `Expected \`input\` to be a \`string\`, got \`${typeof string}\`` + ); + } - checkPath.convert = makePosix + if (typeof count !== 'number') { + throw new TypeError( + `Expected \`count\` to be a \`number\`, got \`${typeof count}\`` + ); + } - // '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) -} + if (typeof options.indent !== 'string') { + throw new TypeError( + `Expected \`options.indent\` to be a \`string\`, got \`${typeof options.indent}\`` + ); + } + + if (count === 0) { + return string; + } + + 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(); - return path.replace(/\\/g, '/'); +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'); }; /***/ }), -/* 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 + + 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); } - callback(); - } -} + this.frameIndex = ++this.frameIndex % frames.length; -class UniqueStream extends ObjectTransform { - constructor() { - super(); - this._pushed = new Set(); + return frame + ' ' + this.text; } - - _transform(data, encoding, callback) { - if (!this._pushed.has(data)) { - this.push(data); - this._pushed.add(data); + clear() { + if (!this.enabled) { + return this; } - callback(); - } -} + this.stream.clearLine(); + this.stream.cursorTo(0); -module.exports = { - FilterStream, - UniqueStream -}; + return this; + } + render() { + this.clear(); + this.stream.write(this.frame()); + return this; + } + start(text) { + if (text) { + this.text = text; + } -/***/ }), -/* 664 */ -/***/ (function(module, exports, __webpack_require__) { + if (!this.enabled || this.id) { + return this; + } -var fs = __webpack_require__(23) -var polyfills = __webpack_require__(665) -var legacy = __webpack_require__(666) -var clone = __webpack_require__(667) + cliCursor.hide(this.stream); + this.render(); + this.id = setInterval(this.render.bind(this), this.interval); -var util = __webpack_require__(29) + return this; + } + stop() { + if (!this.enabled) { + return this; + } -/* istanbul ignore next - node 0.x polyfill */ -var gracefulQueue -var previousSymbol + clearInterval(this.id); + this.id = null; + this.frameIndex = 0; + this.clear(); + cliCursor.show(this.stream); -/* 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; + } + 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; + } -function noop () {} + // Legacy argument + // TODO: Deprecate sometime in the future + if (typeof options === 'string') { + options = { + symbol: options + }; + } -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) - } + options = options || {}; -// 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 - } - }) + this.stop(); + this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); - // 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() - } + return this; + } +} - if (typeof cb === 'function') - cb.apply(this, arguments) - }) - } +module.exports = function (opts) { + return new Ora(opts); +}; - Object.defineProperty(close, previousSymbol, { - value: fs$close - }) - return close - })(fs.close) +module.exports.promise = (action, options) => { + if (typeof action.then !== 'function') { + throw new TypeError('Parameter `action` must be a Promise'); + } - fs.closeSync = (function (fs$closeSync) { - function closeSync (fd) { - // This function uses the graceful-fs shared queue - fs$closeSync.apply(fs, arguments) - retry() - } + const spinner = new Ora(options); + spinner.start(); - Object.defineProperty(closeSync, previousSymbol, { - value: fs$closeSync - }) - return closeSync - })(fs.closeSync) + action.then( + () => { + spinner.succeed(); + }, + () => { + spinner.fail(); + } + ); - if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { - process.on('exit', function() { - debug(global[gracefulQueue]) - __webpack_require__(30).equal(global[gracefulQueue].length, 0) - }) - } -} + return spinner; +}; -module.exports = patch(clone(fs)) -if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) { - module.exports = patch(fs) - fs.__patched = true; -} -function patch (fs) { - // Everything that references the open() function needs to be in here - polyfills(fs) - fs.gracefulify = patch +/***/ }), +/* 677 */ +/***/ (function(module, exports, __webpack_require__) { - 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 +"use strict"; - return go$readFile(path, options, cb) +const escapeStringRegexp = __webpack_require__(3); +const ansiStyles = __webpack_require__(678); +const stdoutColor = __webpack_require__(679).stdout; - 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() - } - }) - } - } +const template = __webpack_require__(680); - var fs$writeFile = fs.writeFile - fs.writeFile = writeFile - function writeFile (path, data, options, cb) { - if (typeof options === 'function') - cb = options, options = null +const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); - return go$writeFile(path, data, options, cb) +// `supportsColor.level` → `ansiStyles.color[name]` mapping +const levelMapping = ['ansi', 'ansi', 'ansi256', 'ansi16m']; - 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() - } - }) - } - } +// `color-convert` models to exclude from the Chalk API due to conflicts and such +const skipModels = new Set(['gray']); - 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 +const styles = Object.create(null); - return go$appendFile(path, data, options, cb) +function applyOptions(obj, options) { + options = options || {}; - 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() - } - }) - } - } + // 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; +} - 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 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); - return go$readdir(args) + chalk.template = function () { + const args = [].slice.call(arguments); + return chalkTag.apply(null, [chalk.template].concat(args)); + }; - function go$readdir$cb (err, files) { - if (files && files.sort) - files.sort() + Object.setPrototypeOf(chalk, Chalk.prototype); + Object.setPrototypeOf(chalk.template, chalk); - if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) - enqueue([go$readdir, [args]]) + chalk.template.constructor = Chalk; - else { - if (typeof cb === 'function') - cb.apply(this, arguments) - retry() - } - } - } + return chalk.template; + } - function go$readdir (args) { - return fs$readdir.apply(fs, args) - } + applyOptions(this, options); +} - if (process.version.substr(0, 4) === 'v0.8') { - var legStreams = legacy(fs) - ReadStream = legStreams.ReadStream - WriteStream = legStreams.WriteStream - } +// Use bright blue on Windows as the normal blue color is illegible +if (isSimpleWindowsTerm) { + ansiStyles.blue.open = '\u001B[94m'; +} - var fs$ReadStream = fs.ReadStream - if (fs$ReadStream) { - ReadStream.prototype = Object.create(fs$ReadStream.prototype) - ReadStream.prototype.open = ReadStream$open - } +for (const key of Object.keys(ansiStyles)) { + ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); - var fs$WriteStream = fs.WriteStream - if (fs$WriteStream) { - WriteStream.prototype = Object.create(fs$WriteStream.prototype) - WriteStream.prototype.open = WriteStream$open - } + styles[key] = { + get() { + const codes = ansiStyles[key]; + return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); + } + }; +} - 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 - }) +styles.visible = { + get() { + return build.call(this, this._styles || [], true, 'visible'); + } +}; - // 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 - }) +ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); +for (const model of Object.keys(ansiStyles.color.ansi)) { + if (skipModels.has(model)) { + continue; + } - 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[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 ReadStream$open () { - var that = this - open(that.path, that.flags, that.mode, function (err, fd) { - if (err) { - if (that.autoClose) - that.destroy() +ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); +for (const model of Object.keys(ansiStyles.bgColor.ansi)) { + if (skipModels.has(model)) { + continue; + } - that.emit('error', err) - } else { - that.fd = fd - that.emit('open', fd) - that.read() - } - }) - } + 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 WriteStream (path, options) { - if (this instanceof WriteStream) - return fs$WriteStream.apply(this, arguments), this - else - return WriteStream.apply(Object.create(WriteStream.prototype), arguments) - } +const proto = Object.defineProperties(() => {}, styles); - 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) - } - }) - } +function build(_styles, _empty, key) { + const builder = function () { + return applyStyle.apply(builder, arguments); + }; - function createReadStream (path, options) { - return new fs.ReadStream(path, options) - } + builder._styles = _styles; + builder._empty = _empty; - function createWriteStream (path, options) { - return new fs.WriteStream(path, options) - } + const self = this; - var fs$open = fs.open - fs.open = open - function open (path, flags, mode, cb) { - if (typeof mode === 'function') - cb = mode, mode = null + Object.defineProperty(builder, 'level', { + enumerable: true, + get() { + return self.level; + }, + set(level) { + self.level = level; + } + }); - return go$open(path, flags, mode, cb) + Object.defineProperty(builder, 'enabled', { + enumerable: true, + get() { + return self.enabled; + }, + set(enabled) { + self.enabled = enabled; + } + }); - 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() - } - }) - } - } + // See below for fix regarding invisible grey/dim combination on Windows + builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; - return fs -} + // `__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 -function enqueue (elem) { - debug('ENQUEUE', elem[0].name, elem[1]) - global[gracefulQueue].push(elem) + return builder; } -function retry () { - var elem = global[gracefulQueue].shift() - if (elem) { - debug('RETRY', elem[0].name, elem[1]) - elem[0].apply(null, elem[1]) - } -} +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]); + if (argsLen === 0) { + return ''; + } -/***/ }), -/* 665 */ -/***/ (function(module, exports, __webpack_require__) { + if (argsLen > 1) { + // Don't slice `arguments`, it prevents V8 optimizations + for (let a = 1; a < argsLen; a++) { + str += ' ' + args[a]; + } + } -var constants = __webpack_require__(25) + if (!this.enabled || this.level <= 0 || !str) { + return this._empty ? '' : str; + } -var origCwd = process.cwd -var cwd = null + // 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 = ''; + } -var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform + 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; -process.cwd = function() { - if (!cwd) - cwd = origCwd.call(process) - return cwd -} -try { - process.cwd() -} catch (er) {} + // 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}`); + } -var chdir = process.chdir -process.chdir = function(d) { - cwd = null - chdir.call(process, d) + // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue + ansiStyles.dim.open = originalDim; + + return str; } -module.exports = patch +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(' '); + } -function patch (fs) { - // (re-)implement some things that are known busted or missing. + const args = [].slice.call(arguments, 2); + const parts = [strings.raw[0]]; - // 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) - } + for (let i = 1; i < strings.length; i++) { + parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); + parts.push(String(strings.raw[i])); + } - // lutimes implementation, or no-op - if (!fs.lutimes) { - patchLutimes(fs) - } + return template(chalk, parts.join('')); +} - // 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. +Object.defineProperties(Chalk.prototype, styles); - fs.chown = chownFix(fs.chown) - fs.fchown = chownFix(fs.fchown) - fs.lchown = chownFix(fs.lchown) +module.exports = Chalk(); // eslint-disable-line new-cap +module.exports.supportsColor = stdoutColor; +module.exports.default = module.exports; // For TypeScript - fs.chmod = chmodFix(fs.chmod) - fs.fchmod = chmodFix(fs.fchmod) - fs.lchmod = chmodFix(fs.lchmod) - fs.chownSync = chownFixSync(fs.chownSync) - fs.fchownSync = chownFixSync(fs.fchownSync) - fs.lchownSync = chownFixSync(fs.lchownSync) +/***/ }), +/* 678 */ +/***/ (function(module, exports, __webpack_require__) { - fs.chmodSync = chmodFixSync(fs.chmodSync) - fs.fchmodSync = chmodFixSync(fs.fchmodSync) - fs.lchmodSync = chmodFixSync(fs.lchmodSync) +"use strict"; +/* WEBPACK VAR INJECTION */(function(module) { +const colorConvert = __webpack_require__(6); - fs.stat = statFix(fs.stat) - fs.fstat = statFix(fs.fstat) - fs.lstat = statFix(fs.lstat) +const wrapAnsi16 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${code + offset}m`; +}; - fs.statSync = statFixSync(fs.statSync) - fs.fstatSync = statFixSync(fs.fstatSync) - fs.lstatSync = statFixSync(fs.lstatSync) +const wrapAnsi256 = (fn, offset) => function () { + const code = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};5;${code}m`; +}; - // 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 wrapAnsi16m = (fn, offset) => function () { + const rgb = fn.apply(colorConvert, arguments); + return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}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. +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], - // 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) - } + // 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], - // 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) - } + // 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] + } + }; - // This ensures `util.promisify` works as it does for native `fs.read`. - read.__proto__ = fs$read - return read - })(fs.read) + // Fix humans + styles.color.grey = styles.color.gray; - 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) + for (const groupName of Object.keys(styles)) { + const group = styles[groupName]; - 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) - }) - }) - }) - } + for (const styleName of Object.keys(group)) { + const style = group[styleName]; - fs.lchmodSync = function (path, mode) { - var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) + styles[styleName] = { + open: `\u001B[${style[0]}m`, + close: `\u001B[${style[1]}m` + }; - // 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 - } - } + group[styleName] = styles[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) - }) - }) - }) - } + codes.set(style[0], style[1]); + } - 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 - } + Object.defineProperty(styles, groupName, { + value: group, + enumerable: false + }); - } else { - fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) } - fs.lutimesSync = function () {} - } - } + Object.defineProperty(styles, 'codes', { + value: codes, + enumerable: false + }); + } - 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) - }) - } - } + const ansi2ansi = n => n; + const rgb2rgb = (r, g, b) => [r, g, b]; - 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 - } - } - } + 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) + }; - 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.bgColor.ansi = { + ansi: wrapAnsi16(ansi2ansi, 10) + }; + styles.bgColor.ansi256 = { + ansi256: wrapAnsi256(ansi2ansi, 10) + }; + styles.bgColor.ansi16m = { + rgb: wrapAnsi16m(rgb2rgb, 10) + }; - 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 - } - } - } + for (let key of Object.keys(colorConvert)) { + if (typeof colorConvert[key] !== 'object') { + continue; + } - 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) - } - } + const suite = colorConvert[key]; - 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; - } - } + if (key === 'ansi16') { + key = 'ansi'; + } - // 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 + if ('ansi16' in suite) { + styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); + styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); + } - if (er.code === "ENOSYS") - return true + if ('ansi256' in suite) { + styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); + styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); + } - var nonroot = !process.getuid || process.getuid() !== 0 - if (nonroot) { - if (er.code === "EINVAL" || er.code === "EPERM") - return true - } + if ('rgb' in suite) { + styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); + styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); + } + } - return false - } + 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__) { - 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 -} +"use strict"; -const rimraf = (p, options, cb) => { - if (typeof options === 'function') { - cb = options - options = {} - } +const mimicFn = __webpack_require__(684); - 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') +module.exports = (fn, opts) => { + // TODO: Remove this in v3 + if (opts === true) { + throw new TypeError('The second argument is now an options object'); + } - defaults(options) + if (typeof fn !== 'function') { + throw new TypeError('Expected a function'); + } - let busyTries = 0 - let errState = null - let n = 0 + opts = opts || {}; - const next = (er) => { - errState = errState || er - if (--n === 0) - cb(errState) - } + let ret; + let called = false; + const fnName = fn.displayName || fn.name || ''; - const afterGlob = (er, results) => { - if (er) - return cb(er) + const onetime = function () { + if (called) { + if (opts.throw === true) { + throw new Error(`Function \`${fnName}\` can only be called once`); + } - n = results.length - if (n === 0) - return cb() + return ret; + } + + called = true; + ret = fn.apply(this, arguments); + fn = null; + + return ret; + }; + + mimicFn(onetime, fn); + + return onetime; +}; + + +/***/ }), +/* 684 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; - 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) - } +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)); + } - // this one won't happen if graceful-fs is used. - if (er.code === "EMFILE" && timeout < options.emfileWait) { - return setTimeout(() => rimraf_(p, options, CB), timeout ++) - } + return to; +}; - // already gone - if (er.code === "ENOENT") er = null - } - timeout = 0 - next(er) - } - rimraf_(p, options, CB) - }) - } +/***/ }), +/* 685 */ +/***/ (function(module, exports, __webpack_require__) { - if (options.disableGlob || !glob.hasMagic(p)) - return afterGlob(null, [p]) +"use strict"; - options.lstat(p, (er, stat) => { - if (!er) - return afterGlob(null, [p]) +module.exports = __webpack_require__(686); - glob(p, options.glob, afterGlob) - }) -} +/***/ }), +/* 686 */ +/***/ (function(module) { -// 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') +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\":[\"🌲\",\"🎄\"]}}"); - // 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) +/***/ }), +/* 687 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - // Windows can EPERM on stat. Life is suffering. - if (er && er.code === "EPERM" && isWindows) - fixWinEPERM(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. + */ - if (st && st.isDirectory()) - return rmdir(p, options, er, cb) - 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 RunCommand = { + description: 'Run script defined in package.json in each package that contains that script.', + name: 'run', -const fixWinEPERMSync = (p, options, er) => { - assert(p) - assert(options) - if (er) - assert(er instanceof Error) + async run(projects, projectGraph, { + extraArgs + }) { + const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projects, projectGraph); - try { - options.chmodSync(p, 0o666) - } catch (er2) { - if (er2.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); + } - let stats - try { - stats = options.statSync(p) - } catch (er3) { - if (er3.code === "ENOENT") - return - else - throw er + 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. + */ - const next = () => { - if (isRejected) { - return; - } +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 nextItem = iterator.next(); - const i = currentIndex; - currentIndex++; +function waitUntilWatchIsReady(stream, opts = {}) { + const buildOutput$ = new rxjs__WEBPACK_IMPORTED_MODULE_0__["Subject"](); - if (nextItem.done) { - isIterableDone = true; + const onDataListener = data => buildOutput$.next(data.toString('utf-8')); - if (resolvingCount === 0) { - if (!stopOnError && errors.length !== 0) { - reject(new AggregateError(errors)); - } else { - resolve(ret); - } - } + const onEndListener = () => buildOutput$.complete(); - return; - } + const onErrorListener = e => buildOutput$.error(e); - resolvingCount++; + 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(); +} - (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(); - } - } - })(); - }; +/***/ }), +/* 690 */ +/***/ (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 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"; @@ -77772,2779 +79913,3002 @@ module.exports = (str, count, opts) => { /***/ }), -/* 674 */ +/* 692 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const os = __webpack_require__(11); +const stringWidth = __webpack_require__(693); +const stripAnsi = __webpack_require__(697); -const extractPathRegex = /\s+at.*(?:\(|\s)(.*)\)?/; -const pathRegex = /^(?:(?:(?:node|(?:internal\/[\w/]*|.*node_modules\/(?:babel-polyfill|pirates)\/.*)?\w+)\.js:\d+:\d+)|native)/; -const homeDir = os.homedir(); +const ESCAPES = new Set([ + '\u001B', + '\u009B' +]); -module.exports = (stack, options) => { - options = Object.assign({pretty: false}, options); +const END_CODE = 39; - return stack.replace(/\\/g, '/') - .split('\n') - .filter(line => { - const pathMatches = line.match(extractPathRegex); - if (pathMatches === null || !pathMatches[1]) { - return true; - } +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] +]); - const match = pathMatches[1]; +const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`; - // Electron - if ( - match.includes('.app/Contents/Resources/electron.asar') || - match.includes('.app/Contents/Resources/default_app.asar') - ) { - return false; - } +// 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 !pathRegex.test(match); - }) - .filter(line => line.trim() !== '') - .map(line => { - if (options.pretty) { - return line.replace(extractPathRegex, (m, p1) => m.replace(p1, p1.replace(homeDir, '~'))); - } +// 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); - return line; - }) - .join('\n'); -}; + let insideEscape = false; + let visible = stringWidth(stripAnsi(rows[rows.length - 1])); + for (const item of arr.entries()) { + const i = item[0]; + const char = item[1]; + const charLength = stringWidth(char); -/***/ }), -/* 675 */ -/***/ (function(module, exports, __webpack_require__) { + if (visible + charLength <= cols) { + rows[rows.length - 1] += char; + } else { + rows.push(char); + visible = 0; + } -"use strict"; + if (ESCAPES.has(char)) { + insideEscape = true; + } else if (insideEscape && char === 'm') { + insideEscape = false; + continue; + } -const chalk = __webpack_require__(676); -const cliCursor = __webpack_require__(680); -const cliSpinners = __webpack_require__(684); -const logSymbols = __webpack_require__(566); + if (insideEscape) { + continue; + } -class Ora { - constructor(options) { - if (typeof options === 'string') { - options = { - text: options - }; + visible += charLength; + + if (visible === cols && i < arr.length - 1) { + rows.push(''); + visible = 0; } + } - this.options = Object.assign({ - text: '', - color: 'cyan', - stream: process.stderr - }, options); + // 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(); + } +}; - 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 +// 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 || {}; - if (this.spinner.frames === undefined) { - throw new Error('Spinner must define `frames`'); + if (str.trim() === '') { + return options.trim === false ? str : str.trim(); + } + + let pre = ''; + let ret = ''; + let escapeCode; + + const lengths = wordLengths(str); + const words = str.split(' '); + const rows = ['']; + + for (const item of Array.from(words).entries()) { + const i = item[0]; + const word = item[1]; + + rows[rows.length - 1] = options.trim === false ? rows[rows.length - 1] : rows[rows.length - 1].trim(); + let rowLength = stringWidth(rows[rows.length - 1]); + + 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; + } + + rows[rows.length - 1] += ' '; + rowLength++; } - 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]; + // 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 (this.color) { - frame = chalk[this.color](frame); + if (rowLength + lengths[i] > cols && rowLength > 0) { + if (options.wordWrap === false && rowLength < cols) { + wrapWord(rows, word, cols); + continue; + } + + rows.push(''); } - this.frameIndex = ++this.frameIndex % frames.length; + if (rowLength + lengths[i] > cols && options.wordWrap === false) { + wrapWord(rows, word, cols); + continue; + } - return frame + ' ' + this.text; + rows[rows.length - 1] += word; } - clear() { - if (!this.enabled) { - return this; + + pre = rows.map(r => options.trim === false ? r : r.trim()).join('\n'); + + for (const item of Array.from(pre).entries()) { + const i = item[0]; + const char = item[1]; + + ret += char; + + if (ESCAPES.has(char)) { + const code = parseFloat(/\d[^m]*/.exec(pre.slice(i, i + 4))); + escapeCode = code === END_CODE ? null : code; } - this.stream.clearLine(); - this.stream.cursorTo(0); + const code = ESCAPE_CODES.get(Number(escapeCode)); - return this; + if (escapeCode && code) { + if (pre[i + 1] === '\n') { + ret += wrapAnsi(code); + } else if (char === '\n') { + ret += wrapAnsi(escapeCode); + } + } } - render() { - this.clear(); - this.stream.write(this.frame()); - return this; + return ret; +}; + +// 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'); +}; + + +/***/ }), +/* 693 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +const stripAnsi = __webpack_require__(694); +const isFullwidthCodePoint = __webpack_require__(696); + +module.exports = str => { + if (typeof str !== 'string' || str.length === 0) { + return 0; } - start(text) { - if (text) { - this.text = text; + + str = stripAnsi(str); + + let width = 0; + + for (let i = 0; i < str.length; i++) { + const code = str.codePointAt(i); + + // Ignore control characters + if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) { + continue; } - if (!this.enabled || this.id) { - return this; + // Ignore combining characters + if (code >= 0x300 && code <= 0x36F) { + continue; } - cliCursor.hide(this.stream); - this.render(); - this.id = setInterval(this.render.bind(this), this.interval); + // Surrogates + if (code > 0xFFFF) { + i++; + } - return this; + width += isFullwidthCodePoint(code) ? 2 : 1; } - stop() { - if (!this.enabled) { - return this; - } - clearInterval(this.id); - this.id = null; - this.frameIndex = 0; - this.clear(); - cliCursor.show(this.stream); + return width; +}; - 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; - } - // Legacy argument - // TODO: Deprecate sometime in the future - if (typeof options === 'string') { - options = { - symbol: options - }; - } +/***/ }), +/* 694 */ +/***/ (function(module, exports, __webpack_require__) { - options = options || {}; +"use strict"; - this.stop(); - this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); +const ansiRegex = __webpack_require__(695); - return this; +module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; + + +/***/ }), +/* 695 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +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('|'); + + return new RegExp(pattern, 'g'); +}; + + +/***/ }), +/* 696 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +/* eslint-disable yoda */ +module.exports = x => { + if (Number.isNaN(x)) { + return false; + } + + // 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; } -} -module.exports = function (opts) { - return new Ora(opts); + return false; }; -module.exports.promise = (action, options) => { - if (typeof action.then !== 'function') { - throw new TypeError('Parameter `action` must be a Promise'); - } - const spinner = new Ora(options); - spinner.start(); +/***/ }), +/* 697 */ +/***/ (function(module, exports, __webpack_require__) { - action.then( - () => { - spinner.succeed(); - }, - () => { - spinner.fail(); - } - ); +"use strict"; - return spinner; -}; +const ansiRegex = __webpack_require__(698); + +module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; /***/ }), -/* 676 */ +/* 698 */ /***/ (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); +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('|'); -const isSimpleWindowsTerm = process.platform === 'win32' && !(process.env.TERM || '').toLowerCase().startsWith('xterm'); + return new RegExp(pattern, 'g'); +}; -// `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']); +/***/ }), +/* 699 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { -const styles = Object.create(null); +"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. + */ -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; +const projectKey = Symbol('__project'); +function renderProjectsTree(rootPath, projects) { + const projectsTree = buildProjectsTree(rootPath, projects); + return treeToString(createTreeStructure(projectsTree)); } -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; +function treeToString(tree) { + return [tree.name].concat(childrenToStrings(tree.children, '')).join('\n'); +} - return chalk.template; - } +function childrenToStrings(tree, treePrefix) { + if (tree === undefined) { + return []; + } - applyOptions(this, options); + 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; } -// Use bright blue on Windows as the normal blue color is illegible -if (isSimpleWindowsTerm) { - ansiStyles.blue.open = '\u001B[94m'; -} +function createTreeStructure(tree) { + let name; + const children = []; -for (const key of Object.keys(ansiStyles)) { - ansiStyles[key].closeRe = new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g'); + 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`. - styles[key] = { - get() { - const codes = ansiStyles[key]; - return build.call(this, this._styles ? this._styles.concat(codes) : [codes], this._empty, key); - } - }; -} -styles.visible = { - get() { - return build.call(this, this._styles || [], true, 'visible'); - } -}; + if (project.size === 1 && project.has(projectKey)) { + const projectName = project.get(projectKey); + children.push({ + children: [], + name: dirOrProjectName(dir, projectName) + }); + continue; + } -ansiStyles.color.closeRe = new RegExp(escapeStringRegexp(ansiStyles.color.close), 'g'); -for (const model of Object.keys(ansiStyles.color.ansi)) { - if (skipModels.has(model)) { - continue; - } + const subtree = createTreeStructure(project); // If the name is specified, we know there's a package at the "root" of the + // subtree itself. - 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 (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. -ansiStyles.bgColor.closeRe = new RegExp(escapeStringRegexp(ansiStyles.bgColor.close), 'g'); -for (const model of Object.keys(ansiStyles.bgColor.ansi)) { - if (skipModels.has(model)) { - continue; - } - 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 (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; + } -const proto = Object.defineProperties(() => {}, styles); + children.push({ + children: subtree.children, + name: chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(dir.toString()) + }); + } -function build(_styles, _empty, key) { - const builder = function () { - return applyStyle.apply(builder, arguments); - }; + return { + name, + children + }; +} - builder._styles = _styles; - builder._empty = _empty; +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}})}`; +} - const self = this; +function buildProjectsTree(rootPath, projects) { + const tree = new Map(); - Object.defineProperty(builder, 'level', { - enumerable: true, - get() { - return self.level; - }, - set(level) { - self.level = level; - } - }); + 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); + } + } - Object.defineProperty(builder, 'enabled', { - enumerable: true, - get() { - return self.enabled; - }, - set(enabled) { - self.enabled = enabled; - } - }); + return tree; +} - // See below for fix regarding invisible grey/dim combination on Windows - builder.hasGrey = this.hasGrey || key === 'gray' || key === 'grey'; +function addProjectToTree(tree, pathParts, project) { + if (pathParts.length === 0) { + tree.set(projectKey, project.name); + } else { + const [currentDir, ...rest] = pathParts; - // `__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 (!tree.has(currentDir)) { + tree.set(currentDir, new Map()); + } - return builder; + const subtree = tree.get(currentDir); + addProjectToTree(subtree, rest, project); + } } -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]); +/***/ }), +/* 700 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - if (argsLen === 0) { - return ''; - } +"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; } - if (argsLen > 1) { - // Don't slice `arguments`, it prevents V8 optimizations - for (let a = 1; a < argsLen; a++) { - str += ' ' + args[a]; - } - } +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 (!this.enabled || this.level <= 0 || !str) { - return this._empty ? '' : str; - } +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; } - // 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 = ''; - } +/* + * 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. + */ - 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}`); - } - // Reset the original `dim` if we changed it to work around the Windows dimmed gray issue - ansiStyles.dim.open = originalDim; - return str; -} +/** + * 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. + */ -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(' '); - } +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 + })))); + } - const args = [].slice.call(arguments, 2); - const parts = [strings.raw[0]]; + constructor(allWorkspaceProjects) { + this.allWorkspaceProjects = allWorkspaceProjects; - for (let i = 1; i < strings.length; i++) { - parts.push(String(args[i - 1]).replace(/[{}\\]/g, '\\$&')); - parts.push(String(strings.raw[i])); - } + _defineProperty(this, "kibanaProject", void 0); - return template(chalk, parts.join('')); -} + const kibanaProject = allWorkspaceProjects.get('kibana'); -Object.defineProperties(Chalk.prototype, styles); + if (!kibanaProject) { + throw new TypeError('Unable to create Kibana object without all projects, including the Kibana project.'); + } -module.exports = Chalk(); // eslint-disable-line new-cap -module.exports.supportsColor = stdoutColor; -module.exports.default = module.exports; // For TypeScript + this.kibanaProject = kibanaProject; + } + /** make an absolute path by resolving subPath relative to the kibana repo */ -/***/ }), -/* 677 */ -/***/ (function(module, exports, __webpack_require__) { + 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 */ -"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`; -}; + 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 wrapAnsi256 = (fn, offset) => function () { - const code = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};5;${code}m`; -}; -const wrapAnsi16m = (fn, offset) => function () { - const rgb = fn.apply(colorConvert, arguments); - return `\u001B[${38 + offset};2;${rgb[0]};${rgb[1]};${rgb[2]}m`; -}; + getAllProjects() { + return new Map(this.allWorkspaceProjects); + } + /** determine if a project with the given name exists */ -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], - // 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], + hasProject(name) { + return this.allWorkspaceProjects.has(name); + } + /** get a specific project, throws if the name is not known (use hasProject() first) */ - // 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] - } - }; - // Fix humans - styles.color.grey = styles.color.gray; + getProject(name) { + const project = this.allWorkspaceProjects.get(name); - for (const groupName of Object.keys(styles)) { - const group = styles[groupName]; + if (!project) { + throw new Error(`No package with name "${name}" in the workspace`); + } - for (const styleName of Object.keys(group)) { - const style = group[styleName]; + return project; + } + /** get a project and all of the projects it depends on in a ProjectMap */ - styles[styleName] = { - open: `\u001B[${style[0]}m`, - close: `\u001B[${style[1]}m` - }; - group[styleName] = styles[styleName]; + 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 */ - codes.set(style[0], style[1]); - } - Object.defineProperty(styles, groupName, { - value: group, - enumerable: false - }); + 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); - Object.defineProperty(styles, 'codes', { - value: codes, - enumerable: false - }); - } + 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 ansi2ansi = n => n; - const rgb2rgb = (r, g, b) => [r, g, b]; + if (pathMatches && notExcluded && isIncluded) { + filteredProjects.set(project.name, project); + } + } - styles.color.close = '\u001B[39m'; - styles.bgColor.close = '\u001B[49m'; + return filteredProjects; + } - styles.color.ansi = { - ansi: wrapAnsi16(ansi2ansi, 0) - }; - styles.color.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 0) - }; - styles.color.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 0) - }; +} - styles.bgColor.ansi = { - ansi: wrapAnsi16(ansi2ansi, 10) - }; - styles.bgColor.ansi256 = { - ansi256: wrapAnsi256(ansi2ansi, 10) - }; - styles.bgColor.ansi16m = { - rgb: wrapAnsi16m(rgb2rgb, 10) - }; +/***/ }), +/* 701 */ +/***/ (function(module, exports, __webpack_require__) { - for (let key of Object.keys(colorConvert)) { - if (typeof colorConvert[key] !== 'object') { - continue; - } +"use strict"; - const suite = colorConvert[key]; +const minimatch = __webpack_require__(505); +const arrayUnion = __webpack_require__(702); +const arrayDiffer = __webpack_require__(703); +const arrify = __webpack_require__(704); - if (key === 'ansi16') { - key = 'ansi'; - } +module.exports = (list, patterns, options = {}) => { + list = arrify(list); + patterns = arrify(patterns); - if ('ansi16' in suite) { - styles.color.ansi[key] = wrapAnsi16(suite.ansi16, 0); - styles.bgColor.ansi[key] = wrapAnsi16(suite.ansi16, 10); - } + if (list.length === 0 || patterns.length === 0) { + return []; + } - if ('ansi256' in suite) { - styles.color.ansi256[key] = wrapAnsi256(suite.ansi256, 0); - styles.bgColor.ansi256[key] = wrapAnsi256(suite.ansi256, 10); - } + return patterns.reduce((result, pattern) => { + let process = arrayUnion; - if ('rgb' in suite) { - styles.color.ansi16m[key] = wrapAnsi16m(suite.rgb, 0); - styles.bgColor.ansi16m[key] = wrapAnsi16m(suite.rgb, 10); + if (pattern[0] === '!') { + pattern = pattern.slice(1); + process = arrayDiffer; } - } - - return styles; -} -// Make the export immutable -Object.defineProperty(module, 'exports', { - enumerable: true, - get: assembleStyles -}); + return process(result, minimatch.match(list, pattern, options)); + }, []); +}; -/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(5)(module))) /***/ }), -/* 678 */ +/* 702 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const os = __webpack_require__(11); -const hasFlag = __webpack_require__(12); - -const env = process.env; -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; -} +module.exports = (...arguments_) => { + return [...new Set([].concat(...arguments_))]; +}; -function translateLevel(level) { - if (level === 0) { - return false; - } - return { - level, - hasBasic: true, - has256: level >= 2, - has16m: level >= 3 - }; -} +/***/ }), +/* 703 */ +/***/ (function(module, exports, __webpack_require__) { -function supportsColor(stream) { - if (forceColor === false) { - return 0; - } +"use strict"; - if (hasFlag('color=16m') || - hasFlag('color=full') || - hasFlag('color=truecolor')) { - return 3; - } - if (hasFlag('color=256')) { - return 2; - } +const arrayDiffer = (array, ...values) => { + const rest = new Set([].concat(...values)); + return array.filter(element => !rest.has(element)); +}; - if (stream && !stream.isTTY && forceColor !== true) { - // VS code debugger doesn't have isTTY set - if (env.VSCODE_PID) { - return 1; - } - return 0; - } +module.exports = arrayDiffer; - const min = forceColor ? 1 : 0; - 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; - } +/***/ }), +/* 704 */ +/***/ (function(module, exports, __webpack_require__) { - return 1; - } +"use strict"; - if ('CI' in env) { - if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(sign => sign in env) || env.CI_NAME === 'codeship') { - return 1; - } - return min; +const arrify = value => { + if (value === null || value === undefined) { + return []; } - if ('TEAMCITY_VERSION' in env) { - return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0; + if (Array.isArray(value)) { + return value; } - if (env.COLORTERM === 'truecolor') { - return 3; + if (typeof value === 'string') { + return [value]; } - if ('TERM_PROGRAM' in env) { - const version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10); - - switch (env.TERM_PROGRAM) { - case 'iTerm.app': - return version >= 3 ? 3 : 2; - case 'Apple_Terminal': - return 2; - // No default - } + if (typeof value[Symbol.iterator] === 'function') { + return [...value]; } - if (/-256(color)?$/i.test(env.TERM)) { - return 2; - } + return [value]; +}; - if (/^screen|^xterm|^vt100|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) { - return 1; - } +module.exports = arrify; - if ('COLORTERM' in env) { - return 1; - } - if (env.TERM === 'dumb') { - return min; - } +/***/ }), +/* 705 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { - return min; -} +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* 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"]; }); -function getSupportLevel(stream) { - const level = supportsColor(stream); - return translateLevel(level); -} +/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(929); +/* 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 + * 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 = { - supportsColor: getSupportLevel, - stdout: getSupportLevel(process.stdout), - stderr: getSupportLevel(process.stderr) -}; /***/ }), -/* 679 */ -/***/ (function(module, exports, __webpack_require__) { +/* 706 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { "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__(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 + * 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 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 unescape(c) { - if ((c[0] === 'u' && c.length === 5) || (c[0] === 'x' && c.length === 3)) { - return String.fromCharCode(parseInt(c.slice(1), 16)); - } - - return ESCAPES.get(c) || c; -} -function parseArguments(name, args) { - const results = []; - const chunks = args.trim().split(/\s*,\s*/g); - let matches; - 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; - const results = []; - let matches; - while ((matches = STYLE_REGEX.exec(style)) !== null) { - const name = matches[1]; - if (matches[2]) { - const args = parseArguments(name, matches[2]); - results.push([name].concat(args)); - } else { - results.push([name]); - } - } +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(', ')}]`); - return results; + for (const batch of batchedProjects) { + for (const project of batch) { + await deleteTarget(project); + await buildProject(project); + await copyToBuild(project, kibanaRoot, buildRoot); + } + } } +/** + * 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. + */ -function buildStyle(chalk, styles) { - const enabled = {}; +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')]; - for (const layer of styles) { - for (const style of layer.styles) { - enabled[style[0]] = layer.inverse ? null : style.slice(1); - } - } + if (projects.has('x-pack')) { + projectsSubset.push(projects.get('x-pack')); + } - 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}`); - } + const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])(projectsSubset, projects, { + onlyProductionDependencies: true + }); // We remove Kibana, as we're already building Kibana - if (enabled[styleName].length > 0) { - current = current[styleName].apply(current, enabled[styleName]); - } else { - current = current[styleName]; - } - } - } + productionProjects.delete('kibana'); - return current; -} + if (onlyOSS) { + productionProjects.forEach(project => { + if (project.getBuildConfig().oss === false) { + productionProjects.delete(project.json.name); + } + }); + } -module.exports = (chalk, tmp) => { - const styles = []; - const chunks = []; - let chunk = []; + return productionProjects; +} - // 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'); - } +async function deleteTarget(project) { + const targetDir = project.targetLocation; - chunks.push(buildStyle(chalk, styles)(chunk.join(''))); - chunk = []; - styles.pop(); - } else { - chunk.push(chr); - } - }); + if (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isDirectory"])(targetDir)) { + await del__WEBPACK_IMPORTED_MODULE_1___default()(targetDir, { + force: true + }); + } +} - chunks.push(chunk.join('')); +async function buildProject(project) { + if (project.hasScript('build')) { + await project.runScript('build'); + } +} +/** + * 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. + */ - 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(''); -}; +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`. + 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); +} /***/ }), -/* 680 */ +/* 707 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const restoreCursor = __webpack_require__(681); - -let hidden = false; - -exports.show = stream => { - const s = stream || process.stderr; - - if (!s.isTTY) { - return; - } - - hidden = false; - s.write('\u001b[?25h'); +const EventEmitter = __webpack_require__(379); +const path = __webpack_require__(16); +const os = __webpack_require__(11); +const pAll = __webpack_require__(708); +const arrify = __webpack_require__(710); +const globby = __webpack_require__(711); +const isGlob = __webpack_require__(606); +const cpFile = __webpack_require__(914); +const junk = __webpack_require__(926); +const CpyError = __webpack_require__(927); + +const defaultOptions = { + ignoreJunk: true }; -exports.hide = stream => { - const s = stream || process.stderr; +const preprocessSourcePath = (source, options) => options.cwd ? path.resolve(options.cwd, source) : source; - if (!s.isTTY) { - return; - } +const preprocessDestinationPath = (source, destination, options) => { + let basename = path.basename(source); + const dirname = path.dirname(source); - restoreCursor(); - hidden = true; - s.write('\u001b[?25l'); -}; + if (typeof options.rename === 'string') { + basename = options.rename; + } else if (typeof options.rename === 'function') { + basename = options.rename(basename); + } -exports.toggle = (force, stream) => { - if (force !== undefined) { - hidden = force; + if (options.cwd) { + destination = path.resolve(options.cwd, destination); } - if (hidden) { - exports.show(stream); - } else { - exports.hide(stream); + if (options.parents) { + return path.join(destination, dirname, basename); } + + return path.join(destination, basename); }; +module.exports = (source, destination, { + concurrency = (os.cpus().length || 1) * 2, + ...options +} = {}) => { + const progressEmitter = new EventEmitter(); -/***/ }), -/* 681 */ -/***/ (function(module, exports, __webpack_require__) { + options = { + ...defaultOptions, + ...options + }; -"use strict"; + const promise = (async () => { + source = arrify(source); -const onetime = __webpack_require__(682); -const signalExit = __webpack_require__(377); + if (source.length === 0 || !destination) { + throw new CpyError('`source` and `destination` required'); + } -module.exports = onetime(() => { - signalExit(() => { - process.stderr.write('\u001b[?25h'); - }, {alwaysLast: true}); -}); + const copyStatus = new Map(); + let completedFiles = 0; + let completedSize = 0; + let files; + try { + files = await globby(source, options); -/***/ }), -/* 682 */ -/***/ (function(module, exports, __webpack_require__) { + if (options.ignoreJunk) { + files = files.filter(file => junk.not(path.basename(file))); + } + } catch (error) { + throw new CpyError(`Cannot glob \`${source}\`: ${error.message}`, error); + } -"use strict"; + const sourcePaths = source.filter(value => !isGlob(value)); -const mimicFn = __webpack_require__(683); + if (files.length === 0 || (sourcePaths.length > 0 && !sourcePaths.every(value => files.includes(value)))) { + throw new CpyError(`Cannot copy \`${source}\`: the file doesn't exist`); + } -module.exports = (fn, opts) => { - // TODO: Remove this in v3 - if (opts === true) { - throw new TypeError('The second argument is now an options object'); - } + const fileProgressHandler = event => { + const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; - if (typeof fn !== 'function') { - throw new TypeError('Expected a function'); - } + if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { + completedSize -= fileStatus.written; + completedSize += event.written; - opts = opts || {}; + if (event.percent === 1 && fileStatus.percent !== 1) { + completedFiles++; + } - let ret; - let called = false; - const fnName = fn.displayName || fn.name || ''; + copyStatus.set(event.src, { + written: event.written, + percent: event.percent + }); - const onetime = function () { - if (called) { - if (opts.throw === true) { - throw new Error(`Function \`${fnName}\` can only be called once`); + progressEmitter.emit('progress', { + totalFiles: files.length, + percent: completedFiles / files.length, + completedFiles, + completedSize + }); } + }; - return ret; - } + return pAll(files.map(sourcePath => { + return async () => { + const from = preprocessSourcePath(sourcePath, options); + const to = preprocessDestinationPath(sourcePath, destination, options); - called = true; - ret = fn.apply(this, arguments); - fn = null; + try { + await cpFile(from, to, options).on('progress', fileProgressHandler); + } catch (error) { + throw new CpyError(`Cannot copy from \`${from}\` to \`${to}\`: ${error.message}`, error); + } - return ret; - }; + return to; + }; + }), {concurrency}); + })(); - mimicFn(onetime, fn); + promise.on = (...arguments_) => { + progressEmitter.on(...arguments_); + return promise; + }; - return onetime; + return promise; }; /***/ }), -/* 683 */ +/* 708 */ /***/ (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)); - } +const pMap = __webpack_require__(709); - return to; -}; +module.exports = (iterable, options) => pMap(iterable, element => element(), options); +// TODO: Remove this for the next major release +module.exports.default = module.exports; /***/ }), -/* 684 */ +/* 709 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -module.exports = __webpack_require__(685); - - -/***/ }), -/* 685 */ -/***/ (function(module) { -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\":[\"🌲\",\"🎄\"]}}"); +const pMap = (iterable, mapper, options) => new Promise((resolve, reject) => { + options = Object.assign({ + concurrency: Infinity + }, options); -/***/ }), -/* 686 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (typeof mapper !== 'function') { + throw new TypeError('Mapper function is required'); + } -"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. - */ + const {concurrency} = options; + if (!(typeof concurrency === 'number' && concurrency >= 1)) { + throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); + } + const ret = []; + const iterator = iterable[Symbol.iterator](); + let isRejected = false; + let isIterableDone = false; + let resolvingCount = 0; + let currentIndex = 0; + const next = () => { + if (isRejected) { + return; + } -const RunCommand = { - description: 'Run script defined in package.json in each package that contains that script.', - name: 'run', + const nextItem = iterator.next(); + const i = currentIndex; + currentIndex++; - async run(projects, projectGraph, { - extraArgs - }) { - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projects, projectGraph); + if (nextItem.done) { + isIterableDone = true; - 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); - } + if (resolvingCount === 0) { + resolve(ret); + } - 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); - } - }); - } + return; + } -}; + resolvingCount++; -/***/ }), -/* 687 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + Promise.resolve(nextItem.value) + .then(element => mapper(element, i)) + .then( + value => { + ret[i] = value; + resolvingCount--; + next(); + }, + error => { + isRejected = true; + reject(error); + } + ); + }; -"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); -/* - * 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. - */ + for (let i = 0; i < concurrency; i++) { + next(); + if (isIterableDone) { + break; + } + } +}); +module.exports = pMap; +// TODO: Remove this for the next major release +module.exports.default = pMap; +/***/ }), +/* 710 */ +/***/ (function(module, exports, __webpack_require__) { +"use strict"; -/** - * 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. - */ -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. - */ +const arrify = value => { + if (value === null || value === undefined) { + return []; + } -const WatchCommand = { - description: 'Runs `kbn:watch` script for every project.', - name: 'watch', + if (Array.isArray(value)) { + return value; + } - async run(projects, projectGraph) { - const projectsToWatch = new Map(); + if (typeof value === 'string') { + return [value]; + } - 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); - } - } + if (typeof value[Symbol.iterator] === 'function') { + return [...value]; + } - 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; - } + return [value]; +}; - 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. +module.exports = arrify; - const shouldWatchKibanaProject = projectsToWatch.delete(kibanaProjectName); - const batchedProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_3__["topologicallyBatchProjects"])(projectsToWatch, projectGraph); - if (shouldWatchKibanaProject) { - batchedProjects.push([projects.get(kibanaProjectName)]); - } +/***/ }), +/* 711 */ +/***/ (function(module, exports, __webpack_require__) { - 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}).`)); - }); - } +"use strict"; -}; +const fs = __webpack_require__(23); +const arrayUnion = __webpack_require__(712); +const glob = __webpack_require__(714); +const fastGlob = __webpack_require__(719); +const dirGlob = __webpack_require__(907); +const gitignore = __webpack_require__(910); -/***/ }), -/* 688 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +const DEFAULT_FILTER = () => false; -"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 isNegative = pattern => pattern[0] === '!'; +const assertPatternsInput = patterns => { + if (!patterns.every(x => typeof x === 'string')) { + throw new TypeError('Patterns must be a string or an array of strings'); + } +}; -/** - * Number of milliseconds we wait before we fall back to the default watch handler. - */ +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 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 generateGlobTasks = (patterns, taskOptions) => { + patterns = arrayUnion([].concat(patterns)); + assertPatternsInput(patterns); + checkCwdOption(taskOptions); -const defaultHandlerReadinessTimeout = 2000; -/** - * Describes configurable watch options. - */ + const globTasks = []; -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]; -} + taskOptions = Object.assign({ + ignore: [], + expandDirectories: true + }, taskOptions); -function waitUntilWatchIsReady(stream, opts = {}) { - const buildOutput$ = new rxjs__WEBPACK_IMPORTED_MODULE_0__["Subject"](); + patterns.forEach((pattern, i) => { + if (isNegative(pattern)) { + return; + } - const onDataListener = data => buildOutput$.next(data.toString('utf-8')); + const ignore = patterns + .slice(i) + .filter(isNegative) + .map(pattern => pattern.slice(1)); - const onEndListener = () => buildOutput$.complete(); + const options = Object.assign({}, taskOptions, { + ignore: taskOptions.ignore.concat(ignore) + }); - const onErrorListener = e => buildOutput$.error(e); + globTasks.push({pattern, options}); + }); - 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(); -} + return globTasks; +}; -/***/ }), -/* 689 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { +const globDirs = (task, fn) => { + let options = {}; + if (task.options.cwd) { + options.cwd = task.options.cwd; + } -"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; } + 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); + } -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; } + return fn(task.pattern, options); +}; -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; } +const getPattern = (task, fn) => task.options.expandDirectories ? globDirs(task, fn) : [task.pattern]; -/* - * 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 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; -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) - }); +module.exports.sync = (patterns, options) => { + const globTasks = generateGlobTasks(patterns, options); - 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); - } + const getFilter = () => { + return options && options.gitignore ? + gitignore.sync({cwd: options.cwd, ignore: options.ignore}) : + DEFAULT_FILTER; + }; - 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`)); + const tasks = globTasks.reduce((tasks, task) => { + const newTask = getPattern(task, dirGlob.sync).map(globToTask(task)); + return tasks.concat(newTask); + }, []); - 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); + const filter = getFilter(); + return tasks.reduce( + (matches, task) => arrayUnion(matches, fastGlob.sync(task.pattern, task.options)), + [] + ).filter(p => !filter(p)); +}; - 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); - } +module.exports.generateGlobTasks = generateGlobTasks; - process.exit(1); - } -} +module.exports.hasMagic = (patterns, options) => [] + .concat(patterns) + .some(pattern => glob.hasMagic(pattern, options)); -function toArray(value) { - if (value == null) { - return []; - } +module.exports.gitignore = gitignore; - return Array.isArray(value) ? value : [value]; -} /***/ }), -/* 690 */ +/* 712 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const stringWidth = __webpack_require__(691); -const stripAnsi = __webpack_require__(695); - -const ESCAPES = new Set([ - '\u001B', - '\u009B' -]); +var arrayUniq = __webpack_require__(713); -const END_CODE = 39; +module.exports = function () { + return arrayUniq([].concat.apply([], arguments)); +}; -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] -]); -const wrapAnsi = code => `${ESCAPES.values().next().value}[${code}m`; +/***/ }), +/* 713 */ +/***/ (function(module, exports, __webpack_require__) { -// 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)); +"use strict"; -// 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); - let insideEscape = false; - let visible = stringWidth(stripAnsi(rows[rows.length - 1])); +// there's 3 implementations written in increasing order of efficiency - for (const item of arr.entries()) { - const i = item[0]; - const char = item[1]; - const charLength = stringWidth(char); +// 1 - no Set type is defined +function uniqNoSet(arr) { + var ret = []; - if (visible + charLength <= cols) { - rows[rows.length - 1] += char; - } else { - rows.push(char); - visible = 0; + for (var i = 0; i < arr.length; i++) { + if (ret.indexOf(arr[i]) === -1) { + ret.push(arr[i]); } + } - if (ESCAPES.has(char)) { - insideEscape = true; - } else if (insideEscape && char === 'm') { - insideEscape = false; - continue; - } + return ret; +} - if (insideEscape) { - continue; +// 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; } - visible += charLength; + return false; + }); +} - if (visible === cols && i < arr.length - 1) { - rows.push(''); - visible = 0; - } - } +// 3 - a standard Set type is defined and it has a forEach method +function uniqSetWithForEach(arr) { + var ret = []; - // 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(); - } -}; + (new Set(arr)).forEach(function (el) { + ret.push(el); + }); -// 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 ret; +} - if (str.trim() === '') { - return options.trim === false ? str : str.trim(); - } +// V8 currently has a broken implementation +// https://github.com/joyent/node/issues/8449 +function doesForEachActuallyWork() { + var ret = false; - let pre = ''; - let ret = ''; - let escapeCode; + (new Set([true])).forEach(function (el) { + ret = el; + }); - const lengths = wordLengths(str); - const words = str.split(' '); - const rows = ['']; + return ret === true; +} - for (const item of Array.from(words).entries()) { - const i = item[0]; - const word = item[1]; +if ('Set' in global) { + if (typeof Set.prototype.forEach === 'function' && doesForEachActuallyWork()) { + module.exports = uniqSetWithForEach; + } else { + module.exports = uniqSet; + } +} else { + module.exports = uniqNoSet; +} - rows[rows.length - 1] = options.trim === false ? rows[rows.length - 1] : rows[rows.length - 1].trim(); - let rowLength = stringWidth(rows[rows.length - 1]); - 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; - } +/***/ }), +/* 714 */ +/***/ (function(module, exports, __webpack_require__) { - rows[rows.length - 1] += ' '; - rowLength++; - } +// 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. - // 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; - } +module.exports = glob - if (rowLength + lengths[i] > cols && rowLength > 0) { - if (options.wordWrap === false && rowLength < cols) { - wrapWord(rows, word, cols); - continue; - } +var fs = __webpack_require__(23) +var rp = __webpack_require__(503) +var minimatch = __webpack_require__(505) +var Minimatch = minimatch.Minimatch +var inherits = __webpack_require__(715) +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__(717) +var common = __webpack_require__(718) +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 - rows.push(''); - } +var once = __webpack_require__(385) - if (rowLength + lengths[i] > cols && options.wordWrap === false) { - wrapWord(rows, word, cols); - continue; - } +function glob (pattern, options, cb) { + if (typeof options === 'function') cb = options, options = {} + if (!options) options = {} - rows[rows.length - 1] += word; - } + if (options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return globSync(pattern, options) + } - pre = rows.map(r => options.trim === false ? r : r.trim()).join('\n'); + return new Glob(pattern, options, cb) +} - for (const item of Array.from(pre).entries()) { - const i = item[0]; - const char = item[1]; +glob.sync = globSync +var GlobSync = glob.GlobSync = globSync.GlobSync - ret += char; +// old api surface +glob.glob = glob - if (ESCAPES.has(char)) { - const code = parseFloat(/\d[^m]*/.exec(pre.slice(i, i + 4))); - escapeCode = code === END_CODE ? null : code; - } +function extend (origin, add) { + if (add === null || typeof add !== 'object') { + return origin + } - const code = ESCAPE_CODES.get(Number(escapeCode)); + var keys = Object.keys(add) + var i = keys.length + while (i--) { + origin[keys[i]] = add[keys[i]] + } + return origin +} - if (escapeCode && code) { - if (pre[i + 1] === '\n') { - ret += wrapAnsi(code); - } else if (char === '\n') { - ret += wrapAnsi(escapeCode); - } - } - } +glob.hasMagic = function (pattern, options_) { + var options = extend({}, options_) + options.noprocess = true - return ret; -}; + var g = new Glob(pattern, options) + var set = g.minimatch.set -// 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'); -}; + if (!pattern) + return false + if (set.length > 1) + return true -/***/ }), -/* 691 */ -/***/ (function(module, exports, __webpack_require__) { + for (var j = 0; j < set[0].length; j++) { + if (typeof set[0][j] !== 'string') + return true + } -"use strict"; + return false +} -const stripAnsi = __webpack_require__(692); -const isFullwidthCodePoint = __webpack_require__(694); +glob.Glob = Glob +inherits(Glob, EE) +function Glob (pattern, options, cb) { + if (typeof options === 'function') { + cb = options + options = null + } -module.exports = str => { - if (typeof str !== 'string' || str.length === 0) { - return 0; - } + if (options && options.sync) { + if (cb) + throw new TypeError('callback provided to sync glob') + return new GlobSync(pattern, options) + } - str = stripAnsi(str); + if (!(this instanceof Glob)) + return new Glob(pattern, options, cb) - let width = 0; + setopts(this, pattern, options) + this._didRealPath = false - for (let i = 0; i < str.length; i++) { - const code = str.codePointAt(i); + // process each pattern in the minimatch set + var n = this.minimatch.set.length - // Ignore control characters - if (code <= 0x1F || (code >= 0x7F && code <= 0x9F)) { - continue; - } + // 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) - // Ignore combining characters - if (code >= 0x300 && code <= 0x36F) { - continue; - } + if (typeof cb === 'function') { + cb = once(cb) + this.on('error', cb) + this.on('end', function (matches) { + cb(null, matches) + }) + } - // Surrogates - if (code > 0xFFFF) { - i++; - } + var self = this + this._processing = 0 - width += isFullwidthCodePoint(code) ? 2 : 1; - } + this._emitQueue = [] + this._processQueue = [] + this.paused = false - return width; -}; + if (this.noprocess) + return this + if (n === 0) + return done() -/***/ }), -/* 692 */ -/***/ (function(module, exports, __webpack_require__) { + var sync = true + for (var i = 0; i < n; i ++) { + this._process(this.minimatch.set[i], i, false, done) + } + sync = false -"use strict"; + function done () { + --self._processing + if (self._processing <= 0) { + if (sync) { + process.nextTick(function () { + self._finish() + }) + } else { + self._finish() + } + } + } +} -const ansiRegex = __webpack_require__(693); +Glob.prototype._finish = function () { + assert(this instanceof Glob) + if (this.aborted) + return -module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; + if (this.realpath && !this._didRealpath) + return this._realpath() + common.finish(this) + this.emit('end', this.found) +} -/***/ }), -/* 693 */ -/***/ (function(module, exports, __webpack_require__) { +Glob.prototype._realpath = function () { + if (this._didRealpath) + return -"use strict"; + this._didRealpath = true + var n = this.matches.length + if (n === 0) + return this._finish() -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('|'); + var self = this + for (var i = 0; i < this.matches.length; i++) + this._realpathSet(i, next) - return new RegExp(pattern, 'g'); -}; + function next () { + if (--n === 0) + self._finish() + } +} +Glob.prototype._realpathSet = function (index, cb) { + var matchset = this.matches[index] + if (!matchset) + return cb() -/***/ }), -/* 694 */ -/***/ (function(module, exports, __webpack_require__) { + var found = Object.keys(matchset) + var self = this + var n = found.length -"use strict"; + if (n === 0) + return cb() -/* eslint-disable yoda */ -module.exports = x => { - if (Number.isNaN(x)) { - return false; - } + 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 - // 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; - } + if (--n === 0) { + self.matches[index] = set + cb() + } + }) + }) +} - return false; -}; +Glob.prototype._mark = function (p) { + return common.mark(this, p) +} +Glob.prototype._makeAbs = function (f) { + return common.makeAbs(this, f) +} -/***/ }), -/* 695 */ -/***/ (function(module, exports, __webpack_require__) { +Glob.prototype.abort = function () { + this.aborted = true + this.emit('abort') +} -"use strict"; +Glob.prototype.pause = function () { + if (!this.paused) { + this.paused = true + this.emit('pause') + } +} -const ansiRegex = __webpack_require__(696); +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]) + } + } + } +} -module.exports = input => typeof input === 'string' ? input.replace(ansiRegex(), '') : input; +Glob.prototype._process = function (pattern, index, inGlobStar, cb) { + assert(this instanceof Glob) + assert(typeof cb === 'function') + if (this.aborted) + return -/***/ }), -/* 696 */ -/***/ (function(module, exports, __webpack_require__) { + this._processing++ + if (this.paused) { + this._processQueue.push([pattern, index, inGlobStar, cb]) + return + } -"use strict"; + //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. -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('|'); + // 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 new RegExp(pattern, 'g'); -}; + 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 + } -/***/ }), -/* 697 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + var remain = pattern.slice(n) -"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. - */ + // 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) -const projectKey = Symbol('__project'); -function renderProjectsTree(rootPath, projects) { - const projectsTree = buildProjectsTree(rootPath, projects); - return treeToString(createTreeStructure(projectsTree)); -} + //if ignored, skip _processing + if (childrenIgnored(this, read)) + return cb() -function treeToString(tree) { - return [tree.name].concat(childrenToStrings(tree.children, '')).join('\n'); + 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) } -function childrenToStrings(tree, treePrefix) { - if (tree === undefined) { - return []; - } - - 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; +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) + }) } -function createTreeStructure(tree) { - let name; - const children = []; +Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { - 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 the abs isn't a dir, then nothing can match! + if (!entries) + return cb() + // 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 (project.size === 1 && project.has(projectKey)) { - const projectName = project.get(projectKey); - children.push({ - children: [], - name: dirOrProjectName(dir, projectName) - }); - continue; + 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) } + } - const subtree = createTreeStructure(project); // If the name is specified, we know there's a package at the "root" of the - // subtree itself. - - 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 (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; - } + //console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries) - children.push({ - children: subtree.children, - name: chalk__WEBPACK_IMPORTED_MODULE_0___default.a.dim(dir.toString()) - }); - } + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return cb() - return { - name, - children - }; -} + // 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. -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}})}`; -} + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) -function buildProjectsTree(rootPath, projects) { - const tree = new Map(); + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix !== '/') + e = prefix + '/' + e + else + e = prefix + e + } - 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); + 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() } - return tree; -} - -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()); + // 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 } - - const subtree = tree.get(currentDir); - addProjectToTree(subtree, rest, project); + this._process([e].concat(remain), index, inGlobStar, cb) } + 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; } - -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; } +Glob.prototype._emitMatch = function (index, e) { + if (this.aborted) + return -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; } + if (isIgnored(this, e)) + return -/* - * 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 (this.paused) { + this._emitQueue.push([index, e]) + return + } + var abs = isAbsolute(e) ? e : this._makeAbs(e) + if (this.mark) + e = this._mark(e) + if (this.absolute) + e = abs -/** - * 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. - */ + if (this.matches[index][e]) + return -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 - })))); + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return } - constructor(allWorkspaceProjects) { - this.allWorkspaceProjects = allWorkspaceProjects; - - _defineProperty(this, "kibanaProject", void 0); + this.matches[index][e] = true - const kibanaProject = allWorkspaceProjects.get('kibana'); + var st = this.statCache[abs] + if (st) + this.emit('stat', e, st) - if (!kibanaProject) { - throw new TypeError('Unable to create Kibana object without all projects, including the Kibana project.'); - } + this.emit('match', e) +} - this.kibanaProject = kibanaProject; - } - /** make an absolute path by resolving subPath relative to the kibana repo */ +Glob.prototype._readdirInGlobStar = function (abs, cb) { + if (this.aborted) + return + // follow all symlinked directories forever + // just proceed as if this is a non-globstar situation + if (this.follow) + return this._readdir(abs, false, cb) - 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 */ + var lstatkey = 'lstat\0' + abs + var self = this + var lstatcb = inflight(lstatkey, lstatcb_) + if (lstatcb) + fs.lstat(abs, lstatcb) - 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 */ + function lstatcb_ (er, lstat) { + if (er && er.code === 'ENOENT') + return cb() + var isSym = lstat && lstat.isSymbolicLink() + self.symlinks[abs] = isSym - getAllProjects() { - return new Map(this.allWorkspaceProjects); + // 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) } - /** determine if a project with the given name exists */ - +} - hasProject(name) { - return this.allWorkspaceProjects.has(name); - } - /** get a specific project, throws if the name is not known (use hasProject() first) */ +Glob.prototype._readdir = function (abs, inGlobStar, cb) { + if (this.aborted) + return + cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb) + if (!cb) + return - getProject(name) { - const project = this.allWorkspaceProjects.get(name); + //console.error('RD %j %j', +inGlobStar, abs) + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs, cb) - if (!project) { - throw new Error(`No package with name "${name}" in the workspace`); - } + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return cb() - return project; + if (Array.isArray(c)) + return cb(null, c) } - /** get a project and all of the projects it depends on in a ProjectMap */ + var self = this + fs.readdir(abs, readdirCb(this, abs, cb)) +} - getProjectAndDeps(name) { - const project = this.getProject(name); - return Object(_projects__WEBPACK_IMPORTED_MODULE_2__["includeTransitiveProjects"])([project], this.allWorkspaceProjects); +function readdirCb (self, abs, cb) { + return function (er, entries) { + if (er) + self._readdirError(abs, er, cb) + else + self._readdirEntries(abs, entries, cb) } - /** 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); +Glob.prototype._readdirEntries = function (abs, entries, cb) { + if (this.aborted) + return - if (pathMatches && notExcluded && isIncluded) { - filteredProjects.set(project.name, project); - } + // 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 filteredProjects; } + this.cache[abs] = entries + return cb(null, entries) } -/***/ }), -/* 699 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; +Glob.prototype._readdirError = function (f, er, cb) { + if (this.aborted) + return -const minimatch = __webpack_require__(505); -const arrayUnion = __webpack_require__(700); -const arrayDiffer = __webpack_require__(701); -const arrify = __webpack_require__(702); + // 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 -module.exports = (list, patterns, options = {}) => { - list = arrify(list); - patterns = arrify(patterns); + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break - if (list.length === 0 || patterns.length === 0) { - return []; - } + 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 patterns.reduce((result, pattern) => { - let process = arrayUnion; + return cb() +} - if (pattern[0] === '!') { - pattern = pattern.slice(1); - process = arrayDiffer; - } +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) + }) +} - return process(result, minimatch.match(list, pattern, options)); - }, []); -}; +Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) { + //console.error('pgs2', prefix, remain[0], entries) -/***/ }), -/* 700 */ -/***/ (function(module, exports, __webpack_require__) { + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return cb() -"use strict"; + // 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) + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false, cb) -module.exports = (...arguments_) => { - return [...new Set([].concat(...arguments_))]; -}; + 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() -/***/ }), -/* 701 */ -/***/ (function(module, exports, __webpack_require__) { + for (var i = 0; i < len; i++) { + var e = entries[i] + if (e.charAt(0) === '.' && !this.dot) + continue -"use strict"; + // 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) + } -const arrayDiffer = (array, ...values) => { - const rest = new Set([].concat(...values)); - return array.filter(element => !rest.has(element)); -}; + cb() +} -module.exports = arrayDiffer; +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) -/***/ }), -/* 702 */ -/***/ (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 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 += '/' + } + } -const arrify = value => { - if (value === null || value === undefined) { - return []; - } + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') - if (Array.isArray(value)) { - return value; - } + // Mark this as a match + this._emitMatch(index, prefix) + cb() +} - if (typeof value === 'string') { - return [value]; - } +// Returns either 'DIR', 'FILE', or false +Glob.prototype._stat = function (f, cb) { + var abs = this._makeAbs(f) + var needDir = f.slice(-1) === '/' - if (typeof value[Symbol.iterator] === 'function') { - return [...value]; - } + if (f.length > this.maxLength) + return cb() - return [value]; -}; + if (!this.stat && ownProp(this.cache, abs)) { + var c = this.cache[abs] -module.exports = arrify; + if (Array.isArray(c)) + c = 'DIR' + // It exists, but maybe not how we need it + if (!needDir || c === 'DIR') + return cb(null, c) -/***/ }), -/* 703 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + if (needDir && c === 'FILE') + return cb() -"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"]; }); + // otherwise we have to stat, because maybe c=true + // if we know it exists, but not what it is. + } -/* harmony import */ var _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(920); -/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "prepareExternalProjectDependencies", function() { return _prepare_project_dependencies__WEBPACK_IMPORTED_MODULE_1__["prepareExternalProjectDependencies"]; }); + 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) + } + } -/* - * 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. - */ + var self = this + var statcb = inflight('stat\0' + abs, lstatcb_) + if (statcb) + fs.lstat(abs, statcb) + 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) + } + } +} +Glob.prototype._stat2 = function (f, abs, er, stat, cb) { + if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) { + this.statCache[abs] = false + return cb() + } -/***/ }), -/* 704 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { + var needDir = f.slice(-1) === '/' + this.statCache[abs] = stat -"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. - */ + if (abs.slice(-1) === '/' && stat && !stat.isDirectory()) + return cb(null, false, stat) + var c = true + if (stat) + c = stat.isDirectory() ? 'DIR' : 'FILE' + this.cache[abs] = this.cache[abs] || c + if (needDir && c === 'FILE') + return cb() + return cb(null, c, stat) +} +/***/ }), +/* 715 */ +/***/ (function(module, exports, __webpack_require__) { +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__(716); +} -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(', ')}]`); +/***/ }), +/* 716 */ +/***/ (function(module, exports) { - for (const batch of batchedProjects) { - for (const project of batch) { - await deleteTarget(project); - await buildProject(project); - await copyToBuild(project, kibanaRoot, buildRoot); +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 } } } -/** - * 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')); - } +/***/ }), +/* 717 */ +/***/ (function(module, exports, __webpack_require__) { - const productionProjects = Object(_utils_projects__WEBPACK_IMPORTED_MODULE_7__["includeTransitiveProjects"])(projectsSubset, projects, { - onlyProductionDependencies: true - }); // We remove Kibana, as we're already building Kibana +module.exports = globSync +globSync.GlobSync = GlobSync - productionProjects.delete('kibana'); +var fs = __webpack_require__(23) +var rp = __webpack_require__(503) +var minimatch = __webpack_require__(505) +var Minimatch = minimatch.Minimatch +var Glob = __webpack_require__(714).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__(718) +var alphasort = common.alphasort +var alphasorti = common.alphasorti +var setopts = common.setopts +var ownProp = common.ownProp +var childrenIgnored = common.childrenIgnored +var isIgnored = common.isIgnored - if (onlyOSS) { - productionProjects.forEach(project => { - if (project.getBuildConfig().oss === false) { - productionProjects.delete(project.json.name); - } - }); - } +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') - return productionProjects; + return new GlobSync(pattern, options).found } -async function deleteTarget(project) { - const targetDir = project.targetLocation; +function GlobSync (pattern, options) { + if (!pattern) + throw new Error('must provide pattern') - if (await Object(_utils_fs__WEBPACK_IMPORTED_MODULE_4__["isDirectory"])(targetDir)) { - await del__WEBPACK_IMPORTED_MODULE_1___default()(targetDir, { - force: true - }); - } -} + 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') -async function buildProject(project) { - if (project.hasScript('build')) { - await project.runScript('build'); - } -} -/** - * 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. - */ + if (!(this instanceof GlobSync)) + return new GlobSync(pattern, options) + setopts(this, pattern, options) + + if (this.noprocess) + return this -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`. + 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() +} - 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); +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) } -/***/ }), -/* 705 */ -/***/ (function(module, exports, __webpack_require__) { -"use strict"; +GlobSync.prototype._process = function (pattern, index, inGlobStar) { + assert(this instanceof GlobSync) -const EventEmitter = __webpack_require__(379); -const path = __webpack_require__(16); -const os = __webpack_require__(11); -const pAll = __webpack_require__(706); -const arrify = __webpack_require__(708); -const globby = __webpack_require__(709); -const isGlob = __webpack_require__(601); -const cpFile = __webpack_require__(907); -const junk = __webpack_require__(917); -const CpyError = __webpack_require__(918); + // 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. -const defaultOptions = { - ignoreJunk: true -}; + // 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 -const preprocessSourcePath = (source, options) => options.cwd ? path.resolve(options.cwd, source) : source; + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break -const preprocessDestinationPath = (source, destination, options) => { - let basename = path.basename(source); - const dirname = path.dirname(source); + 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 + } - if (typeof options.rename === 'string') { - basename = options.rename; - } else if (typeof options.rename === 'function') { - basename = options.rename(basename); - } + var remain = pattern.slice(n) - if (options.cwd) { - destination = path.resolve(options.cwd, destination); - } + // 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 - if (options.parents) { - return path.join(destination, dirname, basename); - } + var abs = this._makeAbs(read) - return path.join(destination, basename); -}; + //if ignored, skip processing + if (childrenIgnored(this, read)) + return -module.exports = (source, destination, { - concurrency = (os.cpus().length || 1) * 2, - ...options -} = {}) => { - const progressEmitter = new EventEmitter(); + 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) +} - options = { - ...defaultOptions, - ...options - }; - const promise = (async () => { - source = arrify(source); +GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) { + var entries = this._readdir(abs, inGlobStar) - if (source.length === 0 || !destination) { - throw new CpyError('`source` and `destination` required'); - } + // if the abs isn't a dir, then nothing can match! + if (!entries) + return - const copyStatus = new Map(); - let completedFiles = 0; - let completedSize = 0; + // 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) === '.' - let files; - try { - files = await globby(source, options); + 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) + } + } - if (options.ignoreJunk) { - files = files.filter(file => junk.not(path.basename(file))); - } - } catch (error) { - throw new CpyError(`Cannot glob \`${source}\`: ${error.message}`, error); - } + var len = matchedEntries.length + // If there are no matched entries, then nothing matches. + if (len === 0) + return - const sourcePaths = source.filter(value => !isGlob(value)); + // 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 (files.length === 0 || (sourcePaths.length > 0 && !sourcePaths.every(value => files.includes(value)))) { - throw new CpyError(`Cannot copy \`${source}\`: the file doesn't exist`); - } + if (remain.length === 1 && !this.mark && !this.stat) { + if (!this.matches[index]) + this.matches[index] = Object.create(null) - const fileProgressHandler = event => { - const fileStatus = copyStatus.get(event.src) || {written: 0, percent: 0}; + for (var i = 0; i < len; i ++) { + var e = matchedEntries[i] + if (prefix) { + if (prefix.slice(-1) !== '/') + e = prefix + '/' + e + else + e = prefix + e + } - if (fileStatus.written !== event.written || fileStatus.percent !== event.percent) { - completedSize -= fileStatus.written; - completedSize += event.written; + 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 + } - if (event.percent === 1 && fileStatus.percent !== 1) { - completedFiles++; - } + // 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) + } +} - copyStatus.set(event.src, { - written: event.written, - percent: event.percent - }); - progressEmitter.emit('progress', { - totalFiles: files.length, - percent: completedFiles / files.length, - completedFiles, - completedSize - }); - } - }; +GlobSync.prototype._emitMatch = function (index, e) { + if (isIgnored(this, e)) + return - return pAll(files.map(sourcePath => { - return async () => { - const from = preprocessSourcePath(sourcePath, options); - const to = preprocessDestinationPath(sourcePath, destination, options); + var abs = this._makeAbs(e) - try { - await cpFile(from, to, options).on('progress', fileProgressHandler); - } catch (error) { - throw new CpyError(`Cannot copy from \`${from}\` to \`${to}\`: ${error.message}`, error); - } + if (this.mark) + e = this._mark(e) - return to; - }; - }), {concurrency}); - })(); + if (this.absolute) { + e = abs + } - promise.on = (...arguments_) => { - progressEmitter.on(...arguments_); - return promise; - }; + if (this.matches[index][e]) + return - return promise; -}; + if (this.nodir) { + var c = this.cache[abs] + if (c === 'DIR' || Array.isArray(c)) + return + } + this.matches[index][e] = true -/***/ }), -/* 706 */ -/***/ (function(module, exports, __webpack_require__) { + if (this.stat) + this._stat(e) +} -"use strict"; -const pMap = __webpack_require__(707); +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) -module.exports = (iterable, options) => pMap(iterable, element => element(), options); -// TODO: Remove this for the next major release -module.exports.default = module.exports; + var entries + var lstat + var stat + try { + lstat = fs.lstatSync(abs) + } catch (er) { + if (er.code === 'ENOENT') { + // lstat failed, doesn't exist + return null + } + } + var isSym = lstat && lstat.isSymbolicLink() + this.symlinks[abs] = isSym -/***/ }), -/* 707 */ -/***/ (function(module, exports, __webpack_require__) { + // 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) -"use strict"; + return entries +} +GlobSync.prototype._readdir = function (abs, inGlobStar) { + var entries -const pMap = (iterable, mapper, options) => new Promise((resolve, reject) => { - options = Object.assign({ - concurrency: Infinity - }, options); + if (inGlobStar && !ownProp(this.symlinks, abs)) + return this._readdirInGlobStar(abs) - if (typeof mapper !== 'function') { - throw new TypeError('Mapper function is required'); - } + if (ownProp(this.cache, abs)) { + var c = this.cache[abs] + if (!c || c === 'FILE') + return null - const {concurrency} = options; + if (Array.isArray(c)) + return c + } - if (!(typeof concurrency === 'number' && concurrency >= 1)) { - throw new TypeError(`Expected \`concurrency\` to be a number from 1 and up, got \`${concurrency}\` (${typeof concurrency})`); - } + try { + return this._readdirEntries(abs, fs.readdirSync(abs)) + } catch (er) { + this._readdirError(abs, er) + return null + } +} - const ret = []; - const iterator = iterable[Symbol.iterator](); - let isRejected = false; - let isIterableDone = false; - let resolvingCount = 0; - let currentIndex = 0; +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 next = () => { - if (isRejected) { - return; - } + this.cache[abs] = entries - const nextItem = iterator.next(); - const i = currentIndex; - currentIndex++; + // mark and cache dir-ness + return entries +} - if (nextItem.done) { - isIterableDone = true; +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 - if (resolvingCount === 0) { - resolve(ret); - } + case 'ENOENT': // not terribly unusual + case 'ELOOP': + case 'ENAMETOOLONG': + case 'UNKNOWN': + this.cache[this._makeAbs(f)] = false + break - return; - } + 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 + } +} - resolvingCount++; +GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) { - Promise.resolve(nextItem.value) - .then(element => mapper(element, i)) - .then( - value => { - ret[i] = value; - resolvingCount--; - next(); - }, - error => { - isRejected = true; - reject(error); - } - ); - }; + var entries = this._readdir(abs, inGlobStar) - for (let i = 0; i < concurrency; i++) { - next(); + // no entries means not a dir, so it can never have matches + // foo.txt/** doesn't match foo.txt + if (!entries) + return - if (isIterableDone) { - break; - } - } -}); + // 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) -module.exports = pMap; -// TODO: Remove this for the next major release -module.exports.default = pMap; + // the noGlobStar pattern exits the inGlobStar state + this._process(noGlobStar, index, false) + var len = entries.length + var isSym = this.symlinks[abs] -/***/ }), -/* 708 */ -/***/ (function(module, exports, __webpack_require__) { + // If it's a symlink, and we're in a globstar, then stop + if (isSym && inGlobStar) + return -"use strict"; + 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) -const arrify = value => { - if (value === null || value === undefined) { - return []; - } + var below = gspref.concat(entries[i], remain) + this._process(below, index, true) + } +} - if (Array.isArray(value)) { - return value; - } +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) - if (typeof value === 'string') { - return [value]; - } + if (!this.matches[index]) + this.matches[index] = Object.create(null) - if (typeof value[Symbol.iterator] === 'function') { - return [...value]; - } + // If it doesn't exist, then just mark the lack of results + if (!exists) + return - return [value]; -}; + 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 += '/' + } + } -module.exports = arrify; + if (process.platform === 'win32') + prefix = prefix.replace(/\\/g, '/') + // Mark this as a match + this._emitMatch(index, prefix) +} -/***/ }), -/* 709 */ -/***/ (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__(710); -const glob = __webpack_require__(502); -const fastGlob = __webpack_require__(712); -const dirGlob = __webpack_require__(900); -const gitignore = __webpack_require__(903); + 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); -}; +/***/ }), +/* 718 */ +/***/ (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, "/") -/***/ }), -/* 710 */ -/***/ (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__(711); + 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 + }) + } + } -/***/ }), -/* 711 */ -/***/ (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)) + }) } /***/ }), -/* 712 */ +/* 719 */ /***/ (function(module, exports, __webpack_require__) { -const pkg = __webpack_require__(713); +const pkg = __webpack_require__(720); module.exports = pkg.async; module.exports.default = pkg.async; @@ -80557,19 +82921,19 @@ module.exports.generateTasks = pkg.generateTasks; /***/ }), -/* 713 */ +/* 720 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var optionsManager = __webpack_require__(714); -var taskManager = __webpack_require__(715); -var reader_async_1 = __webpack_require__(871); -var reader_stream_1 = __webpack_require__(895); -var reader_sync_1 = __webpack_require__(896); -var arrayUtils = __webpack_require__(898); -var streamUtils = __webpack_require__(899); +var optionsManager = __webpack_require__(721); +var taskManager = __webpack_require__(722); +var reader_async_1 = __webpack_require__(878); +var reader_stream_1 = __webpack_require__(902); +var reader_sync_1 = __webpack_require__(903); +var arrayUtils = __webpack_require__(905); +var streamUtils = __webpack_require__(906); /** * Synchronous API. */ @@ -80635,7 +82999,7 @@ function isString(source) { /***/ }), -/* 714 */ +/* 721 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -80673,13 +83037,13 @@ exports.prepare = prepare; /***/ }), -/* 715 */ +/* 722 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var patternUtils = __webpack_require__(716); +var patternUtils = __webpack_require__(723); /** * Generate tasks based on parent directory of each pattern. */ @@ -80770,16 +83134,16 @@ exports.convertPatternGroupToTask = convertPatternGroupToTask; /***/ }), -/* 716 */ +/* 723 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var globParent = __webpack_require__(717); -var isGlob = __webpack_require__(720); -var micromatch = __webpack_require__(721); +var globParent = __webpack_require__(724); +var isGlob = __webpack_require__(727); +var micromatch = __webpack_require__(728); var GLOBSTAR = '**'; /** * Return true for static pattern. @@ -80925,15 +83289,15 @@ exports.matchAny = matchAny; /***/ }), -/* 717 */ +/* 724 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var path = __webpack_require__(16); -var isglob = __webpack_require__(718); -var pathDirname = __webpack_require__(719); +var isglob = __webpack_require__(725); +var pathDirname = __webpack_require__(726); var isWin32 = __webpack_require__(11).platform() === 'win32'; module.exports = function globParent(str) { @@ -80956,7 +83320,7 @@ module.exports = function globParent(str) { /***/ }), -/* 718 */ +/* 725 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -80966,7 +83330,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 === '') { @@ -80987,7 +83351,7 @@ module.exports = function isGlob(str) { /***/ }), -/* 719 */ +/* 726 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81137,7 +83501,7 @@ module.exports.win32 = win32; /***/ }), -/* 720 */ +/* 727 */ /***/ (function(module, exports, __webpack_require__) { /*! @@ -81147,7 +83511,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) { @@ -81189,7 +83553,7 @@ module.exports = function isGlob(str, options) { /***/ }), -/* 721 */ +/* 728 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -81200,18 +83564,18 @@ module.exports = function isGlob(str, options) { */ var util = __webpack_require__(29); -var braces = __webpack_require__(722); -var toRegex = __webpack_require__(824); -var extend = __webpack_require__(832); +var braces = __webpack_require__(729); +var toRegex = __webpack_require__(831); +var extend = __webpack_require__(839); /** * Local dependencies */ -var compilers = __webpack_require__(835); -var parsers = __webpack_require__(867); -var cache = __webpack_require__(868); -var utils = __webpack_require__(869); +var compilers = __webpack_require__(842); +var parsers = __webpack_require__(874); +var cache = __webpack_require__(875); +var utils = __webpack_require__(876); var MAX_LENGTH = 1024 * 64; /** @@ -82073,7 +84437,7 @@ module.exports = micromatch; /***/ }), -/* 722 */ +/* 729 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82083,18 +84447,18 @@ module.exports = micromatch; * Module dependencies */ -var toRegex = __webpack_require__(723); -var unique = __webpack_require__(735); -var extend = __webpack_require__(732); +var toRegex = __webpack_require__(730); +var unique = __webpack_require__(742); +var extend = __webpack_require__(739); /** * Local dependencies */ -var compilers = __webpack_require__(736); -var parsers = __webpack_require__(751); -var Braces = __webpack_require__(761); -var utils = __webpack_require__(737); +var compilers = __webpack_require__(743); +var parsers = __webpack_require__(758); +var Braces = __webpack_require__(768); +var utils = __webpack_require__(744); var MAX_LENGTH = 1024 * 64; var cache = {}; @@ -82398,15 +84762,15 @@ module.exports = braces; /***/ }), -/* 723 */ +/* 730 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(724); -var extend = __webpack_require__(732); -var not = __webpack_require__(734); +var define = __webpack_require__(731); +var extend = __webpack_require__(739); +var not = __webpack_require__(741); var MAX_LENGTH = 1024 * 64; /** @@ -82553,7 +84917,7 @@ module.exports.makeRe = makeRe; /***/ }), -/* 724 */ +/* 731 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82566,7 +84930,7 @@ module.exports.makeRe = makeRe; -var isDescriptor = __webpack_require__(725); +var isDescriptor = __webpack_require__(732); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -82591,7 +84955,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 725 */ +/* 732 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82604,9 +84968,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(726); -var isAccessor = __webpack_require__(727); -var isData = __webpack_require__(730); +var typeOf = __webpack_require__(733); +var isAccessor = __webpack_require__(734); +var isData = __webpack_require__(737); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -82620,7 +84984,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 726 */ +/* 733 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -82773,7 +85137,7 @@ function isBuffer(val) { /***/ }), -/* 727 */ +/* 734 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -82786,7 +85150,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(728); +var typeOf = __webpack_require__(735); // accessor descriptor properties var accessor = { @@ -82849,10 +85213,10 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 728 */ +/* 735 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(729); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -82971,7 +85335,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 729 */ +/* 736 */ /***/ (function(module, exports) { /*! @@ -82998,7 +85362,7 @@ function isSlowBuffer (obj) { /***/ }), -/* 730 */ +/* 737 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83011,7 +85375,7 @@ function isSlowBuffer (obj) { -var typeOf = __webpack_require__(731); +var typeOf = __webpack_require__(738); // data descriptor properties var data = { @@ -83060,10 +85424,10 @@ module.exports = isDataDescriptor; /***/ }), -/* 731 */ +/* 738 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(729); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -83182,13 +85546,13 @@ module.exports = function kindOf(val) { /***/ }), -/* 732 */ +/* 739 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(733); +var isObject = __webpack_require__(740); module.exports = function extend(o/*, objects*/) { if (!isObject(o)) { o = {}; } @@ -83222,7 +85586,7 @@ function hasOwn(obj, key) { /***/ }), -/* 733 */ +/* 740 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83242,13 +85606,13 @@ module.exports = function isExtendable(val) { /***/ }), -/* 734 */ +/* 741 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(732); +var extend = __webpack_require__(739); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -83315,7 +85679,7 @@ module.exports = toRegex; /***/ }), -/* 735 */ +/* 742 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -83365,13 +85729,13 @@ module.exports.immutable = function uniqueImmutable(arr) { /***/ }), -/* 736 */ +/* 743 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(737); +var utils = __webpack_require__(744); module.exports = function(braces, options) { braces.compiler @@ -83654,25 +86018,25 @@ function hasQueue(node) { /***/ }), -/* 737 */ +/* 744 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var splitString = __webpack_require__(738); +var splitString = __webpack_require__(745); var utils = module.exports; /** * Module dependencies */ -utils.extend = __webpack_require__(732); -utils.flatten = __webpack_require__(744); -utils.isObject = __webpack_require__(742); -utils.fillRange = __webpack_require__(745); -utils.repeat = __webpack_require__(750); -utils.unique = __webpack_require__(735); +utils.extend = __webpack_require__(739); +utils.flatten = __webpack_require__(751); +utils.isObject = __webpack_require__(749); +utils.fillRange = __webpack_require__(752); +utils.repeat = __webpack_require__(757); +utils.unique = __webpack_require__(742); utils.define = function(obj, key, val) { Object.defineProperty(obj, key, { @@ -84004,7 +86368,7 @@ utils.escapeRegex = function(str) { /***/ }), -/* 738 */ +/* 745 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84017,7 +86381,7 @@ utils.escapeRegex = function(str) { -var extend = __webpack_require__(739); +var extend = __webpack_require__(746); module.exports = function(str, options, fn) { if (typeof str !== 'string') { @@ -84182,14 +86546,14 @@ function keepEscaping(opts, str, idx) { /***/ }), -/* 739 */ +/* 746 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(740); -var assignSymbols = __webpack_require__(743); +var isExtendable = __webpack_require__(747); +var assignSymbols = __webpack_require__(750); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -84249,7 +86613,7 @@ function isEnum(obj, key) { /***/ }), -/* 740 */ +/* 747 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84262,7 +86626,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(741); +var isPlainObject = __webpack_require__(748); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -84270,7 +86634,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 741 */ +/* 748 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84283,7 +86647,7 @@ module.exports = function isExtendable(val) { -var isObject = __webpack_require__(742); +var isObject = __webpack_require__(749); function isObjectObject(o) { return isObject(o) === true @@ -84314,7 +86678,7 @@ module.exports = function isPlainObject(o) { /***/ }), -/* 742 */ +/* 749 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84333,7 +86697,7 @@ module.exports = function isObject(val) { /***/ }), -/* 743 */ +/* 750 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84380,7 +86744,7 @@ module.exports = function(receiver, objects) { /***/ }), -/* 744 */ +/* 751 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84409,7 +86773,7 @@ function flat(arr, res) { /***/ }), -/* 745 */ +/* 752 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84423,10 +86787,10 @@ function flat(arr, res) { var util = __webpack_require__(29); -var isNumber = __webpack_require__(746); -var extend = __webpack_require__(732); -var repeat = __webpack_require__(748); -var toRegex = __webpack_require__(749); +var isNumber = __webpack_require__(753); +var extend = __webpack_require__(739); +var repeat = __webpack_require__(755); +var toRegex = __webpack_require__(756); /** * Return a range of numbers or letters. @@ -84624,7 +86988,7 @@ module.exports = fillRange; /***/ }), -/* 746 */ +/* 753 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84637,7 +87001,7 @@ module.exports = fillRange; -var typeOf = __webpack_require__(747); +var typeOf = __webpack_require__(754); module.exports = function isNumber(num) { var type = typeOf(num); @@ -84653,10 +87017,10 @@ module.exports = function isNumber(num) { /***/ }), -/* 747 */ +/* 754 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(729); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -84775,7 +87139,7 @@ module.exports = function kindOf(val) { /***/ }), -/* 748 */ +/* 755 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84852,7 +87216,7 @@ function repeat(str, num) { /***/ }), -/* 749 */ +/* 756 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -84865,8 +87229,8 @@ function repeat(str, num) { -var repeat = __webpack_require__(748); -var isNumber = __webpack_require__(746); +var repeat = __webpack_require__(755); +var isNumber = __webpack_require__(753); var cache = {}; function toRegexRange(min, max, options) { @@ -85153,7 +87517,7 @@ module.exports = toRegexRange; /***/ }), -/* 750 */ +/* 757 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -85178,14 +87542,14 @@ module.exports = function repeat(ele, num) { /***/ }), -/* 751 */ +/* 758 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Node = __webpack_require__(752); -var utils = __webpack_require__(737); +var Node = __webpack_require__(759); +var utils = __webpack_require__(744); /** * Braces parsers @@ -85545,15 +87909,15 @@ function concatNodes(pos, node, parent, options) { /***/ }), -/* 752 */ +/* 759 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(742); -var define = __webpack_require__(753); -var utils = __webpack_require__(760); +var isObject = __webpack_require__(749); +var define = __webpack_require__(760); +var utils = __webpack_require__(767); var ownNames; /** @@ -86044,7 +88408,7 @@ exports = module.exports = Node; /***/ }), -/* 753 */ +/* 760 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86057,7 +88421,7 @@ exports = module.exports = Node; -var isDescriptor = __webpack_require__(754); +var isDescriptor = __webpack_require__(761); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -86082,7 +88446,7 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 754 */ +/* 761 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86095,9 +88459,9 @@ module.exports = function defineProperty(obj, prop, val) { -var typeOf = __webpack_require__(755); -var isAccessor = __webpack_require__(756); -var isData = __webpack_require__(758); +var typeOf = __webpack_require__(762); +var isAccessor = __webpack_require__(763); +var isData = __webpack_require__(765); module.exports = function isDescriptor(obj, key) { if (typeOf(obj) !== 'object') { @@ -86111,7 +88475,7 @@ module.exports = function isDescriptor(obj, key) { /***/ }), -/* 755 */ +/* 762 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -86246,7 +88610,7 @@ function isBuffer(val) { /***/ }), -/* 756 */ +/* 763 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86259,7 +88623,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(757); +var typeOf = __webpack_require__(764); // accessor descriptor properties var accessor = { @@ -86322,7 +88686,7 @@ module.exports = isAccessorDescriptor; /***/ }), -/* 757 */ +/* 764 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -86457,7 +88821,7 @@ function isBuffer(val) { /***/ }), -/* 758 */ +/* 765 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -86470,7 +88834,7 @@ function isBuffer(val) { -var typeOf = __webpack_require__(759); +var typeOf = __webpack_require__(766); module.exports = function isDataDescriptor(obj, prop) { // data descriptor properties @@ -86513,7 +88877,7 @@ module.exports = function isDataDescriptor(obj, prop) { /***/ }), -/* 759 */ +/* 766 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -86648,13 +89012,13 @@ function isBuffer(val) { /***/ }), -/* 760 */ +/* 767 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(747); +var typeOf = __webpack_require__(754); var utils = module.exports; /** @@ -87674,17 +90038,17 @@ function assert(val, message) { /***/ }), -/* 761 */ +/* 768 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(732); -var Snapdragon = __webpack_require__(762); -var compilers = __webpack_require__(736); -var parsers = __webpack_require__(751); -var utils = __webpack_require__(737); +var extend = __webpack_require__(739); +var Snapdragon = __webpack_require__(769); +var compilers = __webpack_require__(743); +var parsers = __webpack_require__(758); +var utils = __webpack_require__(744); /** * Customize Snapdragon parser and renderer @@ -87785,17 +90149,17 @@ module.exports = Braces; /***/ }), -/* 762 */ +/* 769 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var Base = __webpack_require__(763); -var define = __webpack_require__(724); -var Compiler = __webpack_require__(792); -var Parser = __webpack_require__(821); -var utils = __webpack_require__(801); +var Base = __webpack_require__(770); +var define = __webpack_require__(731); +var Compiler = __webpack_require__(799); +var Parser = __webpack_require__(828); +var utils = __webpack_require__(808); var regexCache = {}; var cache = {}; @@ -87966,20 +90330,20 @@ module.exports.Parser = Parser; /***/ }), -/* 763 */ +/* 770 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var define = __webpack_require__(764); -var CacheBase = __webpack_require__(765); -var Emitter = __webpack_require__(766); -var isObject = __webpack_require__(742); -var merge = __webpack_require__(783); -var pascal = __webpack_require__(786); -var cu = __webpack_require__(787); +var define = __webpack_require__(771); +var CacheBase = __webpack_require__(772); +var Emitter = __webpack_require__(773); +var isObject = __webpack_require__(749); +var merge = __webpack_require__(790); +var pascal = __webpack_require__(793); +var cu = __webpack_require__(794); /** * Optionally define a custom `cache` namespace to use. @@ -88408,7 +90772,7 @@ module.exports.namespace = namespace; /***/ }), -/* 764 */ +/* 771 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88421,7 +90785,7 @@ module.exports.namespace = namespace; -var isDescriptor = __webpack_require__(754); +var isDescriptor = __webpack_require__(761); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -88446,21 +90810,21 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 765 */ +/* 772 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(742); -var Emitter = __webpack_require__(766); -var visit = __webpack_require__(767); -var toPath = __webpack_require__(770); -var union = __webpack_require__(771); -var del = __webpack_require__(775); -var get = __webpack_require__(773); -var has = __webpack_require__(780); -var set = __webpack_require__(774); +var isObject = __webpack_require__(749); +var Emitter = __webpack_require__(773); +var visit = __webpack_require__(774); +var toPath = __webpack_require__(777); +var union = __webpack_require__(778); +var del = __webpack_require__(782); +var get = __webpack_require__(780); +var has = __webpack_require__(787); +var set = __webpack_require__(781); /** * Create a `Cache` constructor that when instantiated will @@ -88714,7 +91078,7 @@ module.exports.namespace = namespace; /***/ }), -/* 766 */ +/* 773 */ /***/ (function(module, exports, __webpack_require__) { @@ -88883,7 +91247,7 @@ Emitter.prototype.hasListeners = function(event){ /***/ }), -/* 767 */ +/* 774 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88896,8 +91260,8 @@ Emitter.prototype.hasListeners = function(event){ -var visit = __webpack_require__(768); -var mapVisit = __webpack_require__(769); +var visit = __webpack_require__(775); +var mapVisit = __webpack_require__(776); module.exports = function(collection, method, val) { var result; @@ -88920,7 +91284,7 @@ module.exports = function(collection, method, val) { /***/ }), -/* 768 */ +/* 775 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -88933,7 +91297,7 @@ module.exports = function(collection, method, val) { -var isObject = __webpack_require__(742); +var isObject = __webpack_require__(749); module.exports = function visit(thisArg, method, target, val) { if (!isObject(thisArg) && typeof thisArg !== 'function') { @@ -88960,14 +91324,14 @@ module.exports = function visit(thisArg, method, target, val) { /***/ }), -/* 769 */ +/* 776 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var visit = __webpack_require__(768); +var visit = __webpack_require__(775); /** * Map `visit` over an array of objects. @@ -89004,7 +91368,7 @@ function isObject(val) { /***/ }), -/* 770 */ +/* 777 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89017,7 +91381,7 @@ function isObject(val) { -var typeOf = __webpack_require__(747); +var typeOf = __webpack_require__(754); module.exports = function toPath(args) { if (typeOf(args) !== 'arguments') { @@ -89044,16 +91408,16 @@ function filter(arr) { /***/ }), -/* 771 */ +/* 778 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isObject = __webpack_require__(733); -var union = __webpack_require__(772); -var get = __webpack_require__(773); -var set = __webpack_require__(774); +var isObject = __webpack_require__(740); +var union = __webpack_require__(779); +var get = __webpack_require__(780); +var set = __webpack_require__(781); module.exports = function unionValue(obj, prop, value) { if (!isObject(obj)) { @@ -89081,7 +91445,7 @@ function arrayify(val) { /***/ }), -/* 772 */ +/* 779 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89117,7 +91481,7 @@ module.exports = function union(init) { /***/ }), -/* 773 */ +/* 780 */ /***/ (function(module, exports) { /*! @@ -89173,7 +91537,7 @@ function toString(val) { /***/ }), -/* 774 */ +/* 781 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89186,10 +91550,10 @@ function toString(val) { -var split = __webpack_require__(738); -var extend = __webpack_require__(732); -var isPlainObject = __webpack_require__(741); -var isObject = __webpack_require__(733); +var split = __webpack_require__(745); +var extend = __webpack_require__(739); +var isPlainObject = __webpack_require__(748); +var isObject = __webpack_require__(740); module.exports = function(obj, prop, val) { if (!isObject(obj)) { @@ -89235,7 +91599,7 @@ function isValidKey(key) { /***/ }), -/* 775 */ +/* 782 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89248,8 +91612,8 @@ function isValidKey(key) { -var isObject = __webpack_require__(742); -var has = __webpack_require__(776); +var isObject = __webpack_require__(749); +var has = __webpack_require__(783); module.exports = function unset(obj, prop) { if (!isObject(obj)) { @@ -89274,7 +91638,7 @@ module.exports = function unset(obj, prop) { /***/ }), -/* 776 */ +/* 783 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89287,9 +91651,9 @@ module.exports = function unset(obj, prop) { -var isObject = __webpack_require__(777); -var hasValues = __webpack_require__(779); -var get = __webpack_require__(773); +var isObject = __webpack_require__(784); +var hasValues = __webpack_require__(786); +var get = __webpack_require__(780); module.exports = function(obj, prop, noZero) { if (isObject(obj)) { @@ -89300,7 +91664,7 @@ module.exports = function(obj, prop, noZero) { /***/ }), -/* 777 */ +/* 784 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89313,7 +91677,7 @@ module.exports = function(obj, prop, noZero) { -var isArray = __webpack_require__(778); +var isArray = __webpack_require__(785); module.exports = function isObject(val) { return val != null && typeof val === 'object' && isArray(val) === false; @@ -89321,7 +91685,7 @@ module.exports = function isObject(val) { /***/ }), -/* 778 */ +/* 785 */ /***/ (function(module, exports) { var toString = {}.toString; @@ -89332,7 +91696,7 @@ module.exports = Array.isArray || function (arr) { /***/ }), -/* 779 */ +/* 786 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89375,7 +91739,7 @@ module.exports = function hasValue(o, noZero) { /***/ }), -/* 780 */ +/* 787 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89388,9 +91752,9 @@ module.exports = function hasValue(o, noZero) { -var isObject = __webpack_require__(742); -var hasValues = __webpack_require__(781); -var get = __webpack_require__(773); +var isObject = __webpack_require__(749); +var hasValues = __webpack_require__(788); +var get = __webpack_require__(780); module.exports = function(val, prop) { return hasValues(isObject(val) && prop ? get(val, prop) : val); @@ -89398,7 +91762,7 @@ module.exports = function(val, prop) { /***/ }), -/* 781 */ +/* 788 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89411,8 +91775,8 @@ module.exports = function(val, prop) { -var typeOf = __webpack_require__(782); -var isNumber = __webpack_require__(746); +var typeOf = __webpack_require__(789); +var isNumber = __webpack_require__(753); module.exports = function hasValue(val) { // is-number checks for NaN and other edge cases @@ -89465,10 +91829,10 @@ module.exports = function hasValue(val) { /***/ }), -/* 782 */ +/* 789 */ /***/ (function(module, exports, __webpack_require__) { -var isBuffer = __webpack_require__(729); +var isBuffer = __webpack_require__(736); var toString = Object.prototype.toString; /** @@ -89590,14 +91954,14 @@ module.exports = function kindOf(val) { /***/ }), -/* 783 */ +/* 790 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(784); -var forIn = __webpack_require__(785); +var isExtendable = __webpack_require__(791); +var forIn = __webpack_require__(792); function mixinDeep(target, objects) { var len = arguments.length, i = 0; @@ -89661,7 +92025,7 @@ module.exports = mixinDeep; /***/ }), -/* 784 */ +/* 791 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89674,7 +92038,7 @@ module.exports = mixinDeep; -var isPlainObject = __webpack_require__(741); +var isPlainObject = __webpack_require__(748); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -89682,7 +92046,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 785 */ +/* 792 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -89705,7 +92069,7 @@ module.exports = function forIn(obj, fn, thisArg) { /***/ }), -/* 786 */ +/* 793 */ /***/ (function(module, exports) { /*! @@ -89732,14 +92096,14 @@ module.exports = pascalcase; /***/ }), -/* 787 */ +/* 794 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; var util = __webpack_require__(29); -var utils = __webpack_require__(788); +var utils = __webpack_require__(795); /** * Expose class utils @@ -90104,7 +92468,7 @@ cu.bubble = function(Parent, events) { /***/ }), -/* 788 */ +/* 795 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90118,10 +92482,10 @@ var utils = {}; * Lazily required module dependencies */ -utils.union = __webpack_require__(772); -utils.define = __webpack_require__(724); -utils.isObj = __webpack_require__(742); -utils.staticExtend = __webpack_require__(789); +utils.union = __webpack_require__(779); +utils.define = __webpack_require__(731); +utils.isObj = __webpack_require__(749); +utils.staticExtend = __webpack_require__(796); /** @@ -90132,7 +92496,7 @@ module.exports = utils; /***/ }), -/* 789 */ +/* 796 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90145,8 +92509,8 @@ module.exports = utils; -var copy = __webpack_require__(790); -var define = __webpack_require__(724); +var copy = __webpack_require__(797); +var define = __webpack_require__(731); var util = __webpack_require__(29); /** @@ -90229,15 +92593,15 @@ module.exports = extend; /***/ }), -/* 790 */ +/* 797 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var typeOf = __webpack_require__(747); -var copyDescriptor = __webpack_require__(791); -var define = __webpack_require__(724); +var typeOf = __webpack_require__(754); +var copyDescriptor = __webpack_require__(798); +var define = __webpack_require__(731); /** * Copy static properties, prototype properties, and descriptors from one object to another. @@ -90410,7 +92774,7 @@ module.exports.has = has; /***/ }), -/* 791 */ +/* 798 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90498,16 +92862,16 @@ function isObject(val) { /***/ }), -/* 792 */ +/* 799 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(793); -var define = __webpack_require__(724); -var debug = __webpack_require__(795)('snapdragon:compiler'); -var utils = __webpack_require__(801); +var use = __webpack_require__(800); +var define = __webpack_require__(731); +var debug = __webpack_require__(802)('snapdragon:compiler'); +var utils = __webpack_require__(808); /** * Create a new `Compiler` with the given `options`. @@ -90661,7 +93025,7 @@ Compiler.prototype = { // source map support if (opts.sourcemap) { - var sourcemaps = __webpack_require__(820); + var sourcemaps = __webpack_require__(827); sourcemaps(this); this.mapVisit(this.ast.nodes); this.applySourceMaps(); @@ -90682,7 +93046,7 @@ module.exports = Compiler; /***/ }), -/* 793 */ +/* 800 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90695,7 +93059,7 @@ module.exports = Compiler; -var utils = __webpack_require__(794); +var utils = __webpack_require__(801); module.exports = function base(app, opts) { if (!utils.isObject(app) && typeof app !== 'function') { @@ -90810,7 +93174,7 @@ module.exports = function base(app, opts) { /***/ }), -/* 794 */ +/* 801 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -90824,8 +93188,8 @@ var utils = {}; * Lazily required module dependencies */ -utils.define = __webpack_require__(724); -utils.isObject = __webpack_require__(742); +utils.define = __webpack_require__(731); +utils.isObject = __webpack_require__(749); utils.isString = function(val) { @@ -90840,7 +93204,7 @@ module.exports = utils; /***/ }), -/* 795 */ +/* 802 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -90849,14 +93213,14 @@ module.exports = utils; */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(796); + module.exports = __webpack_require__(803); } else { - module.exports = __webpack_require__(799); + module.exports = __webpack_require__(806); } /***/ }), -/* 796 */ +/* 803 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -90865,7 +93229,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(797); +exports = module.exports = __webpack_require__(804); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -91047,7 +93411,7 @@ function localstorage() { /***/ }), -/* 797 */ +/* 804 */ /***/ (function(module, exports, __webpack_require__) { @@ -91063,7 +93427,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(798); +exports.humanize = __webpack_require__(805); /** * The currently active debug mode names, and names to skip. @@ -91255,7 +93619,7 @@ function coerce(val) { /***/ }), -/* 798 */ +/* 805 */ /***/ (function(module, exports) { /** @@ -91413,7 +93777,7 @@ function plural(ms, n, name) { /***/ }), -/* 799 */ +/* 806 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -91429,7 +93793,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(797); +exports = module.exports = __webpack_require__(804); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -91608,7 +93972,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(800); + var net = __webpack_require__(807); stream = new net.Socket({ fd: fd, readable: false, @@ -91667,13 +94031,13 @@ exports.enable(load()); /***/ }), -/* 800 */ +/* 807 */ /***/ (function(module, exports) { module.exports = require("net"); /***/ }), -/* 801 */ +/* 808 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -91683,9 +94047,9 @@ module.exports = require("net"); * Module dependencies */ -exports.extend = __webpack_require__(732); -exports.SourceMap = __webpack_require__(802); -exports.sourceMapResolve = __webpack_require__(813); +exports.extend = __webpack_require__(739); +exports.SourceMap = __webpack_require__(809); +exports.sourceMapResolve = __webpack_require__(820); /** * Convert backslash in the given string to forward slashes @@ -91728,7 +94092,7 @@ exports.last = function(arr, n) { /***/ }), -/* 802 */ +/* 809 */ /***/ (function(module, exports, __webpack_require__) { /* @@ -91736,13 +94100,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__(803).SourceMapGenerator; -exports.SourceMapConsumer = __webpack_require__(809).SourceMapConsumer; -exports.SourceNode = __webpack_require__(812).SourceNode; +exports.SourceMapGenerator = __webpack_require__(810).SourceMapGenerator; +exports.SourceMapConsumer = __webpack_require__(816).SourceMapConsumer; +exports.SourceNode = __webpack_require__(819).SourceNode; /***/ }), -/* 803 */ +/* 810 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -91752,10 +94116,10 @@ exports.SourceNode = __webpack_require__(812).SourceNode; * http://opensource.org/licenses/BSD-3-Clause */ -var base64VLQ = __webpack_require__(804); -var util = __webpack_require__(806); -var ArraySet = __webpack_require__(807).ArraySet; -var MappingList = __webpack_require__(808).MappingList; +var base64VLQ = __webpack_require__(811); +var util = __webpack_require__(813); +var ArraySet = __webpack_require__(814).ArraySet; +var MappingList = __webpack_require__(815).MappingList; /** * An instance of the SourceMapGenerator represents a source map which is @@ -92164,7 +94528,7 @@ exports.SourceMapGenerator = SourceMapGenerator; /***/ }), -/* 804 */ +/* 811 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92204,7 +94568,7 @@ exports.SourceMapGenerator = SourceMapGenerator; * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var base64 = __webpack_require__(805); +var base64 = __webpack_require__(812); // 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, @@ -92310,7 +94674,7 @@ exports.decode = function base64VLQ_decode(aStr, aIndex, aOutParam) { /***/ }), -/* 805 */ +/* 812 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92383,7 +94747,7 @@ exports.decode = function (charCode) { /***/ }), -/* 806 */ +/* 813 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92806,7 +95170,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate /***/ }), -/* 807 */ +/* 814 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92816,7 +95180,7 @@ exports.compareByGeneratedPositionsInflated = compareByGeneratedPositionsInflate * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(806); +var util = __webpack_require__(813); var has = Object.prototype.hasOwnProperty; var hasNativeMap = typeof Map !== "undefined"; @@ -92933,7 +95297,7 @@ exports.ArraySet = ArraySet; /***/ }), -/* 808 */ +/* 815 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -92943,7 +95307,7 @@ exports.ArraySet = ArraySet; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(806); +var util = __webpack_require__(813); /** * Determine whether mappingB is after mappingA with respect to generated @@ -93018,7 +95382,7 @@ exports.MappingList = MappingList; /***/ }), -/* 809 */ +/* 816 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -93028,11 +95392,11 @@ exports.MappingList = MappingList; * http://opensource.org/licenses/BSD-3-Clause */ -var util = __webpack_require__(806); -var binarySearch = __webpack_require__(810); -var ArraySet = __webpack_require__(807).ArraySet; -var base64VLQ = __webpack_require__(804); -var quickSort = __webpack_require__(811).quickSort; +var util = __webpack_require__(813); +var binarySearch = __webpack_require__(817); +var ArraySet = __webpack_require__(814).ArraySet; +var base64VLQ = __webpack_require__(811); +var quickSort = __webpack_require__(818).quickSort; function SourceMapConsumer(aSourceMap) { var sourceMap = aSourceMap; @@ -94106,7 +96470,7 @@ exports.IndexedSourceMapConsumer = IndexedSourceMapConsumer; /***/ }), -/* 810 */ +/* 817 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94223,7 +96587,7 @@ exports.search = function search(aNeedle, aHaystack, aCompare, aBias) { /***/ }), -/* 811 */ +/* 818 */ /***/ (function(module, exports) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94343,7 +96707,7 @@ exports.quickSort = function (ary, comparator) { /***/ }), -/* 812 */ +/* 819 */ /***/ (function(module, exports, __webpack_require__) { /* -*- Mode: js; js-indent-level: 2; -*- */ @@ -94353,8 +96717,8 @@ exports.quickSort = function (ary, comparator) { * http://opensource.org/licenses/BSD-3-Clause */ -var SourceMapGenerator = __webpack_require__(803).SourceMapGenerator; -var util = __webpack_require__(806); +var SourceMapGenerator = __webpack_require__(810).SourceMapGenerator; +var util = __webpack_require__(813); // Matches a Windows-style `\r\n` newline or a `\n` newline used by all other // operating systems these days (capturing the result). @@ -94762,17 +97126,17 @@ exports.SourceNode = SourceNode; /***/ }), -/* 813 */ +/* 820 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014, 2015, 2016, 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var sourceMappingURL = __webpack_require__(814) -var resolveUrl = __webpack_require__(815) -var decodeUriComponent = __webpack_require__(816) -var urix = __webpack_require__(818) -var atob = __webpack_require__(819) +var sourceMappingURL = __webpack_require__(821) +var resolveUrl = __webpack_require__(822) +var decodeUriComponent = __webpack_require__(823) +var urix = __webpack_require__(825) +var atob = __webpack_require__(826) @@ -95070,7 +97434,7 @@ module.exports = { /***/ }), -/* 814 */ +/* 821 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;// Copyright 2014 Simon Lydell @@ -95133,7 +97497,7 @@ void (function(root, factory) { /***/ }), -/* 815 */ +/* 822 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -95151,13 +97515,13 @@ module.exports = resolveUrl /***/ }), -/* 816 */ +/* 823 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2017 Simon Lydell // X11 (“MIT”) Licensed. (See LICENSE.) -var decodeUriComponent = __webpack_require__(817) +var decodeUriComponent = __webpack_require__(824) function customDecodeUriComponent(string) { // `decodeUriComponent` turns `+` into ` `, but that's not wanted. @@ -95168,7 +97532,7 @@ module.exports = customDecodeUriComponent /***/ }), -/* 817 */ +/* 824 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95269,7 +97633,7 @@ module.exports = function (encodedURI) { /***/ }), -/* 818 */ +/* 825 */ /***/ (function(module, exports, __webpack_require__) { // Copyright 2014 Simon Lydell @@ -95292,7 +97656,7 @@ module.exports = urix /***/ }), -/* 819 */ +/* 826 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95306,7 +97670,7 @@ module.exports = atob.atob = atob; /***/ }), -/* 820 */ +/* 827 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -95314,8 +97678,8 @@ module.exports = atob.atob = atob; var fs = __webpack_require__(23); var path = __webpack_require__(16); -var define = __webpack_require__(724); -var utils = __webpack_require__(801); +var define = __webpack_require__(731); +var utils = __webpack_require__(808); /** * Expose `mixin()`. @@ -95458,19 +97822,19 @@ exports.comment = function(node) { /***/ }), -/* 821 */ +/* 828 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var use = __webpack_require__(793); +var use = __webpack_require__(800); var util = __webpack_require__(29); -var Cache = __webpack_require__(822); -var define = __webpack_require__(724); -var debug = __webpack_require__(795)('snapdragon:parser'); -var Position = __webpack_require__(823); -var utils = __webpack_require__(801); +var Cache = __webpack_require__(829); +var define = __webpack_require__(731); +var debug = __webpack_require__(802)('snapdragon:parser'); +var Position = __webpack_require__(830); +var utils = __webpack_require__(808); /** * Create a new `Parser` with the given `input` and `options`. @@ -95998,7 +98362,7 @@ module.exports = Parser; /***/ }), -/* 822 */ +/* 829 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96105,13 +98469,13 @@ MapCache.prototype.del = function mapDelete(key) { /***/ }), -/* 823 */ +/* 830 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var define = __webpack_require__(724); +var define = __webpack_require__(731); /** * Store position for a node @@ -96126,16 +98490,16 @@ module.exports = function Position(start, parser) { /***/ }), -/* 824 */ +/* 831 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var safe = __webpack_require__(825); -var define = __webpack_require__(831); -var extend = __webpack_require__(832); -var not = __webpack_require__(834); +var safe = __webpack_require__(832); +var define = __webpack_require__(838); +var extend = __webpack_require__(839); +var not = __webpack_require__(841); var MAX_LENGTH = 1024 * 64; /** @@ -96288,10 +98652,10 @@ module.exports.makeRe = makeRe; /***/ }), -/* 825 */ +/* 832 */ /***/ (function(module, exports, __webpack_require__) { -var parse = __webpack_require__(826); +var parse = __webpack_require__(833); var types = parse.types; module.exports = function (re, opts) { @@ -96337,13 +98701,13 @@ function isRegExp (x) { /***/ }), -/* 826 */ +/* 833 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(827); -var types = __webpack_require__(828); -var sets = __webpack_require__(829); -var positions = __webpack_require__(830); +var util = __webpack_require__(834); +var types = __webpack_require__(835); +var sets = __webpack_require__(836); +var positions = __webpack_require__(837); module.exports = function(regexpStr) { @@ -96625,11 +98989,11 @@ module.exports.types = types; /***/ }), -/* 827 */ +/* 834 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(828); -var sets = __webpack_require__(829); +var types = __webpack_require__(835); +var sets = __webpack_require__(836); // All of these are private and only used by randexp. @@ -96742,7 +99106,7 @@ exports.error = function(regexp, msg) { /***/ }), -/* 828 */ +/* 835 */ /***/ (function(module, exports) { module.exports = { @@ -96758,10 +99122,10 @@ module.exports = { /***/ }), -/* 829 */ +/* 836 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(828); +var types = __webpack_require__(835); var INTS = function() { return [{ type: types.RANGE , from: 48, to: 57 }]; @@ -96846,10 +99210,10 @@ exports.anyChar = function() { /***/ }), -/* 830 */ +/* 837 */ /***/ (function(module, exports, __webpack_require__) { -var types = __webpack_require__(828); +var types = __webpack_require__(835); exports.wordBoundary = function() { return { type: types.POSITION, value: 'b' }; @@ -96869,7 +99233,7 @@ exports.end = function() { /***/ }), -/* 831 */ +/* 838 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96882,8 +99246,8 @@ exports.end = function() { -var isobject = __webpack_require__(742); -var isDescriptor = __webpack_require__(754); +var isobject = __webpack_require__(749); +var isDescriptor = __webpack_require__(761); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -96914,14 +99278,14 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 832 */ +/* 839 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(833); -var assignSymbols = __webpack_require__(743); +var isExtendable = __webpack_require__(840); +var assignSymbols = __webpack_require__(750); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -96981,7 +99345,7 @@ function isEnum(obj, key) { /***/ }), -/* 833 */ +/* 840 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -96994,7 +99358,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(741); +var isPlainObject = __webpack_require__(748); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -97002,14 +99366,14 @@ module.exports = function isExtendable(val) { /***/ }), -/* 834 */ +/* 841 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extend = __webpack_require__(832); -var safe = __webpack_require__(825); +var extend = __webpack_require__(839); +var safe = __webpack_require__(832); /** * The main export is a function that takes a `pattern` string and an `options` object. @@ -97081,14 +99445,14 @@ module.exports = toRegex; /***/ }), -/* 835 */ +/* 842 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var nanomatch = __webpack_require__(836); -var extglob = __webpack_require__(851); +var nanomatch = __webpack_require__(843); +var extglob = __webpack_require__(858); module.exports = function(snapdragon) { var compilers = snapdragon.compiler.compilers; @@ -97165,7 +99529,7 @@ function escapeExtglobs(compiler) { /***/ }), -/* 836 */ +/* 843 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -97176,17 +99540,17 @@ function escapeExtglobs(compiler) { */ var util = __webpack_require__(29); -var toRegex = __webpack_require__(723); -var extend = __webpack_require__(837); +var toRegex = __webpack_require__(730); +var extend = __webpack_require__(844); /** * Local dependencies */ -var compilers = __webpack_require__(839); -var parsers = __webpack_require__(840); -var cache = __webpack_require__(843); -var utils = __webpack_require__(845); +var compilers = __webpack_require__(846); +var parsers = __webpack_require__(847); +var cache = __webpack_require__(850); +var utils = __webpack_require__(852); var MAX_LENGTH = 1024 * 64; /** @@ -98010,14 +100374,14 @@ module.exports = nanomatch; /***/ }), -/* 837 */ +/* 844 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var isExtendable = __webpack_require__(838); -var assignSymbols = __webpack_require__(743); +var isExtendable = __webpack_require__(845); +var assignSymbols = __webpack_require__(750); module.exports = Object.assign || function(obj/*, objects*/) { if (obj === null || typeof obj === 'undefined') { @@ -98077,7 +100441,7 @@ function isEnum(obj, key) { /***/ }), -/* 838 */ +/* 845 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98090,7 +100454,7 @@ function isEnum(obj, key) { -var isPlainObject = __webpack_require__(741); +var isPlainObject = __webpack_require__(748); module.exports = function isExtendable(val) { return isPlainObject(val) || typeof val === 'function' || Array.isArray(val); @@ -98098,7 +100462,7 @@ module.exports = function isExtendable(val) { /***/ }), -/* 839 */ +/* 846 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98444,15 +100808,15 @@ module.exports = function(nanomatch, options) { /***/ }), -/* 840 */ +/* 847 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regexNot = __webpack_require__(734); -var toRegex = __webpack_require__(723); -var isOdd = __webpack_require__(841); +var regexNot = __webpack_require__(741); +var toRegex = __webpack_require__(730); +var isOdd = __webpack_require__(848); /** * Characters to use in negation regex (we want to "not" match @@ -98838,7 +101202,7 @@ module.exports.not = NOT_REGEX; /***/ }), -/* 841 */ +/* 848 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98851,7 +101215,7 @@ module.exports.not = NOT_REGEX; -var isNumber = __webpack_require__(842); +var isNumber = __webpack_require__(849); module.exports = function isOdd(i) { if (!isNumber(i)) { @@ -98865,7 +101229,7 @@ module.exports = function isOdd(i) { /***/ }), -/* 842 */ +/* 849 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98893,14 +101257,14 @@ module.exports = function isNumber(num) { /***/ }), -/* 843 */ +/* 850 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(844))(); +module.exports = new (__webpack_require__(851))(); /***/ }), -/* 844 */ +/* 851 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -98913,7 +101277,7 @@ module.exports = new (__webpack_require__(844))(); -var MapCache = __webpack_require__(822); +var MapCache = __webpack_require__(829); /** * Create a new `FragmentCache` with an optional object to use for `caches`. @@ -99035,7 +101399,7 @@ exports = module.exports = FragmentCache; /***/ }), -/* 845 */ +/* 852 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99048,14 +101412,14 @@ var path = __webpack_require__(16); * Module dependencies */ -var isWindows = __webpack_require__(846)(); -var Snapdragon = __webpack_require__(762); -utils.define = __webpack_require__(847); -utils.diff = __webpack_require__(848); -utils.extend = __webpack_require__(837); -utils.pick = __webpack_require__(849); -utils.typeOf = __webpack_require__(850); -utils.unique = __webpack_require__(735); +var isWindows = __webpack_require__(853)(); +var Snapdragon = __webpack_require__(769); +utils.define = __webpack_require__(854); +utils.diff = __webpack_require__(855); +utils.extend = __webpack_require__(844); +utils.pick = __webpack_require__(856); +utils.typeOf = __webpack_require__(857); +utils.unique = __webpack_require__(742); /** * Returns true if the given value is effectively an empty string @@ -99421,7 +101785,7 @@ utils.unixify = function(options) { /***/ }), -/* 846 */ +/* 853 */ /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! @@ -99449,7 +101813,7 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ /***/ }), -/* 847 */ +/* 854 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99462,8 +101826,8 @@ var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_ -var isobject = __webpack_require__(742); -var isDescriptor = __webpack_require__(754); +var isobject = __webpack_require__(749); +var isDescriptor = __webpack_require__(761); var define = (typeof Reflect !== 'undefined' && Reflect.defineProperty) ? Reflect.defineProperty : Object.defineProperty; @@ -99494,7 +101858,7 @@ module.exports = function defineProperty(obj, key, val) { /***/ }), -/* 848 */ +/* 855 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99548,7 +101912,7 @@ function diffArray(one, two) { /***/ }), -/* 849 */ +/* 856 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99561,7 +101925,7 @@ function diffArray(one, two) { -var isObject = __webpack_require__(742); +var isObject = __webpack_require__(749); module.exports = function pick(obj, keys) { if (!isObject(obj) && typeof obj !== 'function') { @@ -99590,7 +101954,7 @@ module.exports = function pick(obj, keys) { /***/ }), -/* 850 */ +/* 857 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -99725,7 +102089,7 @@ function isBuffer(val) { /***/ }), -/* 851 */ +/* 858 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -99735,18 +102099,18 @@ function isBuffer(val) { * Module dependencies */ -var extend = __webpack_require__(732); -var unique = __webpack_require__(735); -var toRegex = __webpack_require__(723); +var extend = __webpack_require__(739); +var unique = __webpack_require__(742); +var toRegex = __webpack_require__(730); /** * Local dependencies */ -var compilers = __webpack_require__(852); -var parsers = __webpack_require__(863); -var Extglob = __webpack_require__(866); -var utils = __webpack_require__(865); +var compilers = __webpack_require__(859); +var parsers = __webpack_require__(870); +var Extglob = __webpack_require__(873); +var utils = __webpack_require__(872); var MAX_LENGTH = 1024 * 64; /** @@ -100063,13 +102427,13 @@ module.exports = extglob; /***/ }), -/* 852 */ +/* 859 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(853); +var brackets = __webpack_require__(860); /** * Extglob compilers @@ -100239,7 +102603,7 @@ module.exports = function(extglob) { /***/ }), -/* 853 */ +/* 860 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100249,17 +102613,17 @@ module.exports = function(extglob) { * Local dependencies */ -var compilers = __webpack_require__(854); -var parsers = __webpack_require__(856); +var compilers = __webpack_require__(861); +var parsers = __webpack_require__(863); /** * Module dependencies */ -var debug = __webpack_require__(858)('expand-brackets'); -var extend = __webpack_require__(732); -var Snapdragon = __webpack_require__(762); -var toRegex = __webpack_require__(723); +var debug = __webpack_require__(865)('expand-brackets'); +var extend = __webpack_require__(739); +var Snapdragon = __webpack_require__(769); +var toRegex = __webpack_require__(730); /** * Parses the given POSIX character class `pattern` and returns a @@ -100457,13 +102821,13 @@ module.exports = brackets; /***/ }), -/* 854 */ +/* 861 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var posix = __webpack_require__(855); +var posix = __webpack_require__(862); module.exports = function(brackets) { brackets.compiler @@ -100551,7 +102915,7 @@ module.exports = function(brackets) { /***/ }), -/* 855 */ +/* 862 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -100580,14 +102944,14 @@ module.exports = { /***/ }), -/* 856 */ +/* 863 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var utils = __webpack_require__(857); -var define = __webpack_require__(724); +var utils = __webpack_require__(864); +var define = __webpack_require__(731); /** * Text regex @@ -100806,14 +103170,14 @@ module.exports.TEXT_REGEX = TEXT_REGEX; /***/ }), -/* 857 */ +/* 864 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var toRegex = __webpack_require__(723); -var regexNot = __webpack_require__(734); +var toRegex = __webpack_require__(730); +var regexNot = __webpack_require__(741); var cached; /** @@ -100847,7 +103211,7 @@ exports.createRegex = function(pattern, include) { /***/ }), -/* 858 */ +/* 865 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -100856,14 +103220,14 @@ exports.createRegex = function(pattern, include) { */ if (typeof process !== 'undefined' && process.type === 'renderer') { - module.exports = __webpack_require__(859); + module.exports = __webpack_require__(866); } else { - module.exports = __webpack_require__(862); + module.exports = __webpack_require__(869); } /***/ }), -/* 859 */ +/* 866 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -100872,7 +103236,7 @@ if (typeof process !== 'undefined' && process.type === 'renderer') { * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(860); +exports = module.exports = __webpack_require__(867); exports.log = log; exports.formatArgs = formatArgs; exports.save = save; @@ -101054,7 +103418,7 @@ function localstorage() { /***/ }), -/* 860 */ +/* 867 */ /***/ (function(module, exports, __webpack_require__) { @@ -101070,7 +103434,7 @@ exports.coerce = coerce; exports.disable = disable; exports.enable = enable; exports.enabled = enabled; -exports.humanize = __webpack_require__(861); +exports.humanize = __webpack_require__(868); /** * The currently active debug mode names, and names to skip. @@ -101262,7 +103626,7 @@ function coerce(val) { /***/ }), -/* 861 */ +/* 868 */ /***/ (function(module, exports) { /** @@ -101420,7 +103784,7 @@ function plural(ms, n, name) { /***/ }), -/* 862 */ +/* 869 */ /***/ (function(module, exports, __webpack_require__) { /** @@ -101436,7 +103800,7 @@ var util = __webpack_require__(29); * Expose `debug()` as the module. */ -exports = module.exports = __webpack_require__(860); +exports = module.exports = __webpack_require__(867); exports.init = init; exports.log = log; exports.formatArgs = formatArgs; @@ -101615,7 +103979,7 @@ function createWritableStdioStream (fd) { case 'PIPE': case 'TCP': - var net = __webpack_require__(800); + var net = __webpack_require__(807); stream = new net.Socket({ fd: fd, readable: false, @@ -101674,15 +104038,15 @@ exports.enable(load()); /***/ }), -/* 863 */ +/* 870 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var brackets = __webpack_require__(853); -var define = __webpack_require__(864); -var utils = __webpack_require__(865); +var brackets = __webpack_require__(860); +var define = __webpack_require__(871); +var utils = __webpack_require__(872); /** * Characters to use in text regex (we want to "not" match @@ -101837,7 +104201,7 @@ module.exports = parsers; /***/ }), -/* 864 */ +/* 871 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101850,7 +104214,7 @@ module.exports = parsers; -var isDescriptor = __webpack_require__(754); +var isDescriptor = __webpack_require__(761); module.exports = function defineProperty(obj, prop, val) { if (typeof obj !== 'object' && typeof obj !== 'function') { @@ -101875,14 +104239,14 @@ module.exports = function defineProperty(obj, prop, val) { /***/ }), -/* 865 */ +/* 872 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var regex = __webpack_require__(734); -var Cache = __webpack_require__(844); +var regex = __webpack_require__(741); +var Cache = __webpack_require__(851); /** * Utils @@ -101951,7 +104315,7 @@ utils.createRegex = function(str) { /***/ }), -/* 866 */ +/* 873 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -101961,16 +104325,16 @@ utils.createRegex = function(str) { * Module dependencies */ -var Snapdragon = __webpack_require__(762); -var define = __webpack_require__(864); -var extend = __webpack_require__(732); +var Snapdragon = __webpack_require__(769); +var define = __webpack_require__(871); +var extend = __webpack_require__(739); /** * Local dependencies */ -var compilers = __webpack_require__(852); -var parsers = __webpack_require__(863); +var compilers = __webpack_require__(859); +var parsers = __webpack_require__(870); /** * Customize Snapdragon parser and renderer @@ -102036,16 +104400,16 @@ module.exports = Extglob; /***/ }), -/* 867 */ +/* 874 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -var extglob = __webpack_require__(851); -var nanomatch = __webpack_require__(836); -var regexNot = __webpack_require__(734); -var toRegex = __webpack_require__(824); +var extglob = __webpack_require__(858); +var nanomatch = __webpack_require__(843); +var regexNot = __webpack_require__(741); +var toRegex = __webpack_require__(831); var not; /** @@ -102126,14 +104490,14 @@ function textRegex(pattern) { /***/ }), -/* 868 */ +/* 875 */ /***/ (function(module, exports, __webpack_require__) { -module.exports = new (__webpack_require__(844))(); +module.exports = new (__webpack_require__(851))(); /***/ }), -/* 869 */ +/* 876 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102146,13 +104510,13 @@ var path = __webpack_require__(16); * Module dependencies */ -var Snapdragon = __webpack_require__(762); -utils.define = __webpack_require__(831); -utils.diff = __webpack_require__(848); -utils.extend = __webpack_require__(832); -utils.pick = __webpack_require__(849); -utils.typeOf = __webpack_require__(870); -utils.unique = __webpack_require__(735); +var Snapdragon = __webpack_require__(769); +utils.define = __webpack_require__(838); +utils.diff = __webpack_require__(855); +utils.extend = __webpack_require__(839); +utils.pick = __webpack_require__(856); +utils.typeOf = __webpack_require__(877); +utils.unique = __webpack_require__(742); /** * Returns true if the platform is windows, or `path.sep` is `\\`. @@ -102449,7 +104813,7 @@ utils.unixify = function(options) { /***/ }), -/* 870 */ +/* 877 */ /***/ (function(module, exports) { var toString = Object.prototype.toString; @@ -102584,7 +104948,7 @@ function isBuffer(val) { /***/ }), -/* 871 */ +/* 878 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102603,9 +104967,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(872); -var reader_1 = __webpack_require__(885); -var fs_stream_1 = __webpack_require__(889); +var readdir = __webpack_require__(879); +var reader_1 = __webpack_require__(892); +var fs_stream_1 = __webpack_require__(896); var ReaderAsync = /** @class */ (function (_super) { __extends(ReaderAsync, _super); function ReaderAsync() { @@ -102666,15 +105030,15 @@ exports.default = ReaderAsync; /***/ }), -/* 872 */ +/* 879 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const readdirSync = __webpack_require__(873); -const readdirAsync = __webpack_require__(881); -const readdirStream = __webpack_require__(884); +const readdirSync = __webpack_require__(880); +const readdirAsync = __webpack_require__(888); +const readdirStream = __webpack_require__(891); module.exports = exports = readdirAsyncPath; exports.readdir = exports.readdirAsync = exports.async = readdirAsyncPath; @@ -102758,7 +105122,7 @@ function readdirStreamStat (dir, options) { /***/ }), -/* 873 */ +/* 880 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102766,11 +105130,11 @@ function readdirStreamStat (dir, options) { module.exports = readdirSync; -const DirectoryReader = __webpack_require__(874); +const DirectoryReader = __webpack_require__(881); let syncFacade = { - fs: __webpack_require__(879), - forEach: __webpack_require__(880), + fs: __webpack_require__(886), + forEach: __webpack_require__(887), sync: true }; @@ -102799,7 +105163,7 @@ function readdirSync (dir, options, internalOptions) { /***/ }), -/* 874 */ +/* 881 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -102808,9 +105172,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__(875); -const stat = __webpack_require__(877); -const call = __webpack_require__(878); +const normalizeOptions = __webpack_require__(882); +const stat = __webpack_require__(884); +const call = __webpack_require__(885); /** * Asynchronously reads the contents of a directory and streams the results @@ -103186,14 +105550,14 @@ module.exports = DirectoryReader; /***/ }), -/* 875 */ +/* 882 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const globToRegExp = __webpack_require__(876); +const globToRegExp = __webpack_require__(883); module.exports = normalizeOptions; @@ -103370,7 +105734,7 @@ function normalizeOptions (options, internalOptions) { /***/ }), -/* 876 */ +/* 883 */ /***/ (function(module, exports) { module.exports = function (glob, opts) { @@ -103507,13 +105871,13 @@ module.exports = function (glob, opts) { /***/ }), -/* 877 */ +/* 884 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const call = __webpack_require__(878); +const call = __webpack_require__(885); module.exports = stat; @@ -103588,7 +105952,7 @@ function symlinkStat (fs, path, lstats, callback) { /***/ }), -/* 878 */ +/* 885 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103649,14 +106013,14 @@ function callOnce (fn) { /***/ }), -/* 879 */ +/* 886 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const call = __webpack_require__(878); +const call = __webpack_require__(885); /** * A facade around {@link fs.readdirSync} that allows it to be called @@ -103720,7 +106084,7 @@ exports.lstat = function (path, callback) { /***/ }), -/* 880 */ +/* 887 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103749,7 +106113,7 @@ function syncForEach (array, iterator, done) { /***/ }), -/* 881 */ +/* 888 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103757,12 +106121,12 @@ function syncForEach (array, iterator, done) { module.exports = readdirAsync; -const maybe = __webpack_require__(882); -const DirectoryReader = __webpack_require__(874); +const maybe = __webpack_require__(889); +const DirectoryReader = __webpack_require__(881); let asyncFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(883), + forEach: __webpack_require__(890), async: true }; @@ -103804,7 +106168,7 @@ function readdirAsync (dir, options, callback, internalOptions) { /***/ }), -/* 882 */ +/* 889 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103831,7 +106195,7 @@ module.exports = function maybe (cb, promise) { /***/ }), -/* 883 */ +/* 890 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103867,7 +106231,7 @@ function asyncForEach (array, iterator, done) { /***/ }), -/* 884 */ +/* 891 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -103875,11 +106239,11 @@ function asyncForEach (array, iterator, done) { module.exports = readdirStream; -const DirectoryReader = __webpack_require__(874); +const DirectoryReader = __webpack_require__(881); let streamFacade = { fs: __webpack_require__(23), - forEach: __webpack_require__(883), + forEach: __webpack_require__(890), async: true }; @@ -103899,16 +106263,16 @@ function readdirStream (dir, options, internalOptions) { /***/ }), -/* 885 */ +/* 892 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var path = __webpack_require__(16); -var deep_1 = __webpack_require__(886); -var entry_1 = __webpack_require__(888); -var pathUtil = __webpack_require__(887); +var deep_1 = __webpack_require__(893); +var entry_1 = __webpack_require__(895); +var pathUtil = __webpack_require__(894); var Reader = /** @class */ (function () { function Reader(options) { this.options = options; @@ -103974,14 +106338,14 @@ exports.default = Reader; /***/ }), -/* 886 */ +/* 893 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(887); -var patternUtils = __webpack_require__(716); +var pathUtils = __webpack_require__(894); +var patternUtils = __webpack_require__(723); var DeepFilter = /** @class */ (function () { function DeepFilter(options, micromatchOptions) { this.options = options; @@ -104064,7 +106428,7 @@ exports.default = DeepFilter; /***/ }), -/* 887 */ +/* 894 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104095,14 +106459,14 @@ exports.makeAbsolute = makeAbsolute; /***/ }), -/* 888 */ +/* 895 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -var pathUtils = __webpack_require__(887); -var patternUtils = __webpack_require__(716); +var pathUtils = __webpack_require__(894); +var patternUtils = __webpack_require__(723); var EntryFilter = /** @class */ (function () { function EntryFilter(options, micromatchOptions) { this.options = options; @@ -104187,7 +106551,7 @@ exports.default = EntryFilter; /***/ }), -/* 889 */ +/* 896 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104207,8 +106571,8 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(27); -var fsStat = __webpack_require__(890); -var fs_1 = __webpack_require__(894); +var fsStat = __webpack_require__(897); +var fs_1 = __webpack_require__(901); var FileSystemStream = /** @class */ (function (_super) { __extends(FileSystemStream, _super); function FileSystemStream() { @@ -104258,14 +106622,14 @@ exports.default = FileSystemStream; /***/ }), -/* 890 */ +/* 897 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const optionsManager = __webpack_require__(891); -const statProvider = __webpack_require__(893); +const optionsManager = __webpack_require__(898); +const statProvider = __webpack_require__(900); /** * Asynchronous API. */ @@ -104296,13 +106660,13 @@ exports.statSync = statSync; /***/ }), -/* 891 */ +/* 898 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fsAdapter = __webpack_require__(892); +const fsAdapter = __webpack_require__(899); function prepare(opts) { const options = Object.assign({ fs: fsAdapter.getFileSystemAdapter(opts ? opts.fs : undefined), @@ -104315,7 +106679,7 @@ exports.prepare = prepare; /***/ }), -/* 892 */ +/* 899 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104338,7 +106702,7 @@ exports.getFileSystemAdapter = getFileSystemAdapter; /***/ }), -/* 893 */ +/* 900 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104390,7 +106754,7 @@ exports.isFollowedSymlink = isFollowedSymlink; /***/ }), -/* 894 */ +/* 901 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104421,7 +106785,7 @@ exports.default = FileSystem; /***/ }), -/* 895 */ +/* 902 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104441,9 +106805,9 @@ var __extends = (this && this.__extends) || (function () { })(); Object.defineProperty(exports, "__esModule", { value: true }); var stream = __webpack_require__(27); -var readdir = __webpack_require__(872); -var reader_1 = __webpack_require__(885); -var fs_stream_1 = __webpack_require__(889); +var readdir = __webpack_require__(879); +var reader_1 = __webpack_require__(892); +var fs_stream_1 = __webpack_require__(896); var TransformStream = /** @class */ (function (_super) { __extends(TransformStream, _super); function TransformStream(reader) { @@ -104511,7 +106875,7 @@ exports.default = ReaderStream; /***/ }), -/* 896 */ +/* 903 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104530,9 +106894,9 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var readdir = __webpack_require__(872); -var reader_1 = __webpack_require__(885); -var fs_sync_1 = __webpack_require__(897); +var readdir = __webpack_require__(879); +var reader_1 = __webpack_require__(892); +var fs_sync_1 = __webpack_require__(904); var ReaderSync = /** @class */ (function (_super) { __extends(ReaderSync, _super); function ReaderSync() { @@ -104592,7 +106956,7 @@ exports.default = ReaderSync; /***/ }), -/* 897 */ +/* 904 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104611,8 +106975,8 @@ var __extends = (this && this.__extends) || (function () { }; })(); Object.defineProperty(exports, "__esModule", { value: true }); -var fsStat = __webpack_require__(890); -var fs_1 = __webpack_require__(894); +var fsStat = __webpack_require__(897); +var fs_1 = __webpack_require__(901); var FileSystemSync = /** @class */ (function (_super) { __extends(FileSystemSync, _super); function FileSystemSync() { @@ -104658,7 +107022,7 @@ exports.default = FileSystemSync; /***/ }), -/* 898 */ +/* 905 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104674,7 +107038,7 @@ exports.flatten = flatten; /***/ }), -/* 899 */ +/* 906 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104695,13 +107059,13 @@ exports.merge = merge; /***/ }), -/* 900 */ +/* 907 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); -const pathType = __webpack_require__(901); +const pathType = __webpack_require__(908); const getExtensions = extensions => extensions.length > 1 ? `{${extensions.join(',')}}` : extensions[0]; @@ -104767,13 +107131,13 @@ module.exports.sync = (input, opts) => { /***/ }), -/* 901 */ +/* 908 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); -const pify = __webpack_require__(902); +const pify = __webpack_require__(909); function type(fn, fn2, fp) { if (typeof fp !== 'string') { @@ -104816,7 +107180,7 @@ exports.symlinkSync = typeSync.bind(null, 'lstatSync', 'isSymbolicLink'); /***/ }), -/* 902 */ +/* 909 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -104907,17 +107271,17 @@ module.exports = (obj, opts) => { /***/ }), -/* 903 */ +/* 910 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const fs = __webpack_require__(23); const path = __webpack_require__(16); -const fastGlob = __webpack_require__(712); -const gitIgnore = __webpack_require__(904); -const pify = __webpack_require__(905); -const slash = __webpack_require__(906); +const fastGlob = __webpack_require__(719); +const gitIgnore = __webpack_require__(911); +const pify = __webpack_require__(912); +const slash = __webpack_require__(913); const DEFAULT_IGNORE = [ '**/node_modules/**', @@ -105015,7 +107379,7 @@ module.exports.sync = options => { /***/ }), -/* 904 */ +/* 911 */ /***/ (function(module, exports) { // A simple implementation of make-array @@ -105484,7 +107848,7 @@ module.exports = options => new IgnoreBase(options) /***/ }), -/* 905 */ +/* 912 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105559,7 +107923,7 @@ module.exports = (input, options) => { /***/ }), -/* 906 */ +/* 913 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -105577,17 +107941,17 @@ module.exports = input => { /***/ }), -/* 907 */ +/* 914 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const path = __webpack_require__(16); const {constants: fsConstants} = __webpack_require__(23); -const pEvent = __webpack_require__(908); -const CpFileError = __webpack_require__(911); -const fs = __webpack_require__(913); -const ProgressEmitter = __webpack_require__(916); +const pEvent = __webpack_require__(915); +const CpFileError = __webpack_require__(918); +const fs = __webpack_require__(922); +const ProgressEmitter = __webpack_require__(925); const cpFileAsync = async (source, destination, options, progressEmitter) => { let readError; @@ -105701,12 +108065,12 @@ module.exports.sync = (source, destination, options) => { /***/ }), -/* 908 */ +/* 915 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pTimeout = __webpack_require__(909); +const pTimeout = __webpack_require__(916); const symbolAsyncIterator = Symbol.asyncIterator || '@@asyncIterator'; @@ -105997,12 +108361,12 @@ module.exports.iterator = (emitter, event, options) => { /***/ }), -/* 909 */ +/* 916 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const pFinally = __webpack_require__(910); +const pFinally = __webpack_require__(917); class TimeoutError extends Error { constructor(message) { @@ -106048,7 +108412,7 @@ module.exports.TimeoutError = TimeoutError; /***/ }), -/* 910 */ +/* 917 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106070,12 +108434,12 @@ module.exports = (promise, onFinally) => { /***/ }), -/* 911 */ +/* 918 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(912); +const NestedError = __webpack_require__(919); class CpFileError extends NestedError { constructor(message, nested) { @@ -106089,10 +108453,10 @@ module.exports = CpFileError; /***/ }), -/* 912 */ +/* 919 */ /***/ (function(module, exports, __webpack_require__) { -var inherits = __webpack_require__(509); +var inherits = __webpack_require__(920); var NestedError = function (message, nested) { this.nested = nested; @@ -106143,16 +108507,58 @@ module.exports = NestedError; /***/ }), -/* 913 */ +/* 920 */ +/***/ (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__(921); +} + + +/***/ }), +/* 921 */ +/***/ (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 + } +} + + +/***/ }), +/* 922 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; const {promisify} = __webpack_require__(29); const fs = __webpack_require__(22); -const makeDir = __webpack_require__(914); -const pEvent = __webpack_require__(908); -const CpFileError = __webpack_require__(911); +const makeDir = __webpack_require__(923); +const pEvent = __webpack_require__(915); +const CpFileError = __webpack_require__(918); const stat = promisify(fs.stat); const lstat = promisify(fs.lstat); @@ -106249,7 +108655,7 @@ exports.copyFileSync = (source, destination, flags) => { /***/ }), -/* 914 */ +/* 923 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -106257,7 +108663,7 @@ exports.copyFileSync = (source, destination, flags) => { const fs = __webpack_require__(23); const path = __webpack_require__(16); const {promisify} = __webpack_require__(29); -const semver = __webpack_require__(915); +const semver = __webpack_require__(924); const defaults = { mode: 0o777 & (~process.umask()), @@ -106406,7 +108812,7 @@ module.exports.sync = (input, options) => { /***/ }), -/* 915 */ +/* 924 */ /***/ (function(module, exports) { exports = module.exports = SemVer @@ -106440,75 +108846,80 @@ var MAX_SAFE_COMPONENT_LENGTH = 16 // The actual regexps go on exports.re var re = exports.re = [] var src = exports.src = [] +var t = exports.tokens = {} var R = 0 +function tok (n) { + t[n] = R++ +} + // The following Regular Expressions can be used for tokenizing, // validating, and parsing SemVer version strings. // ## Numeric Identifier // A single `0`, or a non-zero digit followed by zero or more digits. -var NUMERICIDENTIFIER = R++ -src[NUMERICIDENTIFIER] = '0|[1-9]\\d*' -var NUMERICIDENTIFIERLOOSE = R++ -src[NUMERICIDENTIFIERLOOSE] = '[0-9]+' +tok('NUMERICIDENTIFIER') +src[t.NUMERICIDENTIFIER] = '0|[1-9]\\d*' +tok('NUMERICIDENTIFIERLOOSE') +src[t.NUMERICIDENTIFIERLOOSE] = '[0-9]+' // ## Non-numeric Identifier // Zero or more digits, followed by a letter or hyphen, and then zero or // more letters, digits, or hyphens. -var NONNUMERICIDENTIFIER = R++ -src[NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*' +tok('NONNUMERICIDENTIFIER') +src[t.NONNUMERICIDENTIFIER] = '\\d*[a-zA-Z-][a-zA-Z0-9-]*' // ## Main Version // Three dot-separated numeric identifiers. -var MAINVERSION = R++ -src[MAINVERSION] = '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')\\.' + - '(' + src[NUMERICIDENTIFIER] + ')' +tok('MAINVERSION') +src[t.MAINVERSION] = '(' + src[t.NUMERICIDENTIFIER] + ')\\.' + + '(' + src[t.NUMERICIDENTIFIER] + ')\\.' + + '(' + src[t.NUMERICIDENTIFIER] + ')' -var MAINVERSIONLOOSE = R++ -src[MAINVERSIONLOOSE] = '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')\\.' + - '(' + src[NUMERICIDENTIFIERLOOSE] + ')' +tok('MAINVERSIONLOOSE') +src[t.MAINVERSIONLOOSE] = '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')\\.' + + '(' + src[t.NUMERICIDENTIFIERLOOSE] + ')' // ## Pre-release Version Identifier // A numeric identifier, or a non-numeric identifier. -var PRERELEASEIDENTIFIER = R++ -src[PRERELEASEIDENTIFIER] = '(?:' + src[NUMERICIDENTIFIER] + - '|' + src[NONNUMERICIDENTIFIER] + ')' +tok('PRERELEASEIDENTIFIER') +src[t.PRERELEASEIDENTIFIER] = '(?:' + src[t.NUMERICIDENTIFIER] + + '|' + src[t.NONNUMERICIDENTIFIER] + ')' -var PRERELEASEIDENTIFIERLOOSE = R++ -src[PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[NUMERICIDENTIFIERLOOSE] + - '|' + src[NONNUMERICIDENTIFIER] + ')' +tok('PRERELEASEIDENTIFIERLOOSE') +src[t.PRERELEASEIDENTIFIERLOOSE] = '(?:' + src[t.NUMERICIDENTIFIERLOOSE] + + '|' + src[t.NONNUMERICIDENTIFIER] + ')' // ## Pre-release Version // Hyphen, followed by one or more dot-separated pre-release version // identifiers. -var PRERELEASE = R++ -src[PRERELEASE] = '(?:-(' + src[PRERELEASEIDENTIFIER] + - '(?:\\.' + src[PRERELEASEIDENTIFIER] + ')*))' +tok('PRERELEASE') +src[t.PRERELEASE] = '(?:-(' + src[t.PRERELEASEIDENTIFIER] + + '(?:\\.' + src[t.PRERELEASEIDENTIFIER] + ')*))' -var PRERELEASELOOSE = R++ -src[PRERELEASELOOSE] = '(?:-?(' + src[PRERELEASEIDENTIFIERLOOSE] + - '(?:\\.' + src[PRERELEASEIDENTIFIERLOOSE] + ')*))' +tok('PRERELEASELOOSE') +src[t.PRERELEASELOOSE] = '(?:-?(' + src[t.PRERELEASEIDENTIFIERLOOSE] + + '(?:\\.' + src[t.PRERELEASEIDENTIFIERLOOSE] + ')*))' // ## Build Metadata Identifier // Any combination of digits, letters, or hyphens. -var BUILDIDENTIFIER = R++ -src[BUILDIDENTIFIER] = '[0-9A-Za-z-]+' +tok('BUILDIDENTIFIER') +src[t.BUILDIDENTIFIER] = '[0-9A-Za-z-]+' // ## Build Metadata // Plus sign, followed by one or more period-separated build metadata // identifiers. -var BUILD = R++ -src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + - '(?:\\.' + src[BUILDIDENTIFIER] + ')*))' +tok('BUILD') +src[t.BUILD] = '(?:\\+(' + src[t.BUILDIDENTIFIER] + + '(?:\\.' + src[t.BUILDIDENTIFIER] + ')*))' // ## Full Version String // A main version, followed optionally by a pre-release version and @@ -106519,129 +108930,133 @@ src[BUILD] = '(?:\\+(' + src[BUILDIDENTIFIER] + // capturing group, because it should not ever be used in version // comparison. -var FULL = R++ -var FULLPLAIN = 'v?' + src[MAINVERSION] + - src[PRERELEASE] + '?' + - src[BUILD] + '?' +tok('FULL') +tok('FULLPLAIN') +src[t.FULLPLAIN] = 'v?' + src[t.MAINVERSION] + + src[t.PRERELEASE] + '?' + + src[t.BUILD] + '?' -src[FULL] = '^' + FULLPLAIN + '$' +src[t.FULL] = '^' + src[t.FULLPLAIN] + '$' // like full, but allows v1.2.3 and =1.2.3, which people do sometimes. // also, 1.0.0alpha1 (prerelease without the hyphen) which is pretty // common in the npm registry. -var LOOSEPLAIN = '[v=\\s]*' + src[MAINVERSIONLOOSE] + - src[PRERELEASELOOSE] + '?' + - src[BUILD] + '?' +tok('LOOSEPLAIN') +src[t.LOOSEPLAIN] = '[v=\\s]*' + src[t.MAINVERSIONLOOSE] + + src[t.PRERELEASELOOSE] + '?' + + src[t.BUILD] + '?' -var LOOSE = R++ -src[LOOSE] = '^' + LOOSEPLAIN + '$' +tok('LOOSE') +src[t.LOOSE] = '^' + src[t.LOOSEPLAIN] + '$' -var GTLT = R++ -src[GTLT] = '((?:<|>)?=?)' +tok('GTLT') +src[t.GTLT] = '((?:<|>)?=?)' // Something like "2.*" or "1.2.x". // Note that "x.x" is a valid xRange identifer, meaning "any version" // Only the first item is strictly required. -var XRANGEIDENTIFIERLOOSE = R++ -src[XRANGEIDENTIFIERLOOSE] = src[NUMERICIDENTIFIERLOOSE] + '|x|X|\\*' -var XRANGEIDENTIFIER = R++ -src[XRANGEIDENTIFIER] = src[NUMERICIDENTIFIER] + '|x|X|\\*' - -var XRANGEPLAIN = R++ -src[XRANGEPLAIN] = '[v=\\s]*(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIER] + ')' + - '(?:' + src[PRERELEASE] + ')?' + - src[BUILD] + '?' + +tok('XRANGEIDENTIFIERLOOSE') +src[t.XRANGEIDENTIFIERLOOSE] = src[t.NUMERICIDENTIFIERLOOSE] + '|x|X|\\*' +tok('XRANGEIDENTIFIER') +src[t.XRANGEIDENTIFIER] = src[t.NUMERICIDENTIFIER] + '|x|X|\\*' + +tok('XRANGEPLAIN') +src[t.XRANGEPLAIN] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' + + '(?:\\.(' + src[t.XRANGEIDENTIFIER] + ')' + + '(?:' + src[t.PRERELEASE] + ')?' + + src[t.BUILD] + '?' + ')?)?' -var XRANGEPLAINLOOSE = R++ -src[XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:\\.(' + src[XRANGEIDENTIFIERLOOSE] + ')' + - '(?:' + src[PRERELEASELOOSE] + ')?' + - src[BUILD] + '?' + +tok('XRANGEPLAINLOOSE') +src[t.XRANGEPLAINLOOSE] = '[v=\\s]*(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' + + '(?:\\.(' + src[t.XRANGEIDENTIFIERLOOSE] + ')' + + '(?:' + src[t.PRERELEASELOOSE] + ')?' + + src[t.BUILD] + '?' + ')?)?' -var XRANGE = R++ -src[XRANGE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAIN] + '$' -var XRANGELOOSE = R++ -src[XRANGELOOSE] = '^' + src[GTLT] + '\\s*' + src[XRANGEPLAINLOOSE] + '$' +tok('XRANGE') +src[t.XRANGE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAIN] + '$' +tok('XRANGELOOSE') +src[t.XRANGELOOSE] = '^' + src[t.GTLT] + '\\s*' + src[t.XRANGEPLAINLOOSE] + '$' // Coercion. // Extract anything that could conceivably be a part of a valid semver -var COERCE = R++ -src[COERCE] = '(?:^|[^\\d])' + +tok('COERCE') +src[t.COERCE] = '(^|[^\\d])' + '(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '})' + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + '(?:\\.(\\d{1,' + MAX_SAFE_COMPONENT_LENGTH + '}))?' + '(?:$|[^\\d])' +tok('COERCERTL') +re[t.COERCERTL] = new RegExp(src[t.COERCE], 'g') // Tilde ranges. // Meaning is "reasonably at or greater than" -var LONETILDE = R++ -src[LONETILDE] = '(?:~>?)' +tok('LONETILDE') +src[t.LONETILDE] = '(?:~>?)' -var TILDETRIM = R++ -src[TILDETRIM] = '(\\s*)' + src[LONETILDE] + '\\s+' -re[TILDETRIM] = new RegExp(src[TILDETRIM], 'g') +tok('TILDETRIM') +src[t.TILDETRIM] = '(\\s*)' + src[t.LONETILDE] + '\\s+' +re[t.TILDETRIM] = new RegExp(src[t.TILDETRIM], 'g') var tildeTrimReplace = '$1~' -var TILDE = R++ -src[TILDE] = '^' + src[LONETILDE] + src[XRANGEPLAIN] + '$' -var TILDELOOSE = R++ -src[TILDELOOSE] = '^' + src[LONETILDE] + src[XRANGEPLAINLOOSE] + '$' +tok('TILDE') +src[t.TILDE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAIN] + '$' +tok('TILDELOOSE') +src[t.TILDELOOSE] = '^' + src[t.LONETILDE] + src[t.XRANGEPLAINLOOSE] + '$' // Caret ranges. // Meaning is "at least and backwards compatible with" -var LONECARET = R++ -src[LONECARET] = '(?:\\^)' +tok('LONECARET') +src[t.LONECARET] = '(?:\\^)' -var CARETTRIM = R++ -src[CARETTRIM] = '(\\s*)' + src[LONECARET] + '\\s+' -re[CARETTRIM] = new RegExp(src[CARETTRIM], 'g') +tok('CARETTRIM') +src[t.CARETTRIM] = '(\\s*)' + src[t.LONECARET] + '\\s+' +re[t.CARETTRIM] = new RegExp(src[t.CARETTRIM], 'g') var caretTrimReplace = '$1^' -var CARET = R++ -src[CARET] = '^' + src[LONECARET] + src[XRANGEPLAIN] + '$' -var CARETLOOSE = R++ -src[CARETLOOSE] = '^' + src[LONECARET] + src[XRANGEPLAINLOOSE] + '$' +tok('CARET') +src[t.CARET] = '^' + src[t.LONECARET] + src[t.XRANGEPLAIN] + '$' +tok('CARETLOOSE') +src[t.CARETLOOSE] = '^' + src[t.LONECARET] + src[t.XRANGEPLAINLOOSE] + '$' // A simple gt/lt/eq thing, or just "" to indicate "any version" -var COMPARATORLOOSE = R++ -src[COMPARATORLOOSE] = '^' + src[GTLT] + '\\s*(' + LOOSEPLAIN + ')$|^$' -var COMPARATOR = R++ -src[COMPARATOR] = '^' + src[GTLT] + '\\s*(' + FULLPLAIN + ')$|^$' +tok('COMPARATORLOOSE') +src[t.COMPARATORLOOSE] = '^' + src[t.GTLT] + '\\s*(' + src[t.LOOSEPLAIN] + ')$|^$' +tok('COMPARATOR') +src[t.COMPARATOR] = '^' + src[t.GTLT] + '\\s*(' + src[t.FULLPLAIN] + ')$|^$' // An expression to strip any whitespace between the gtlt and the thing // it modifies, so that `> 1.2.3` ==> `>1.2.3` -var COMPARATORTRIM = R++ -src[COMPARATORTRIM] = '(\\s*)' + src[GTLT] + - '\\s*(' + LOOSEPLAIN + '|' + src[XRANGEPLAIN] + ')' +tok('COMPARATORTRIM') +src[t.COMPARATORTRIM] = '(\\s*)' + src[t.GTLT] + + '\\s*(' + src[t.LOOSEPLAIN] + '|' + src[t.XRANGEPLAIN] + ')' // this one has to use the /g flag -re[COMPARATORTRIM] = new RegExp(src[COMPARATORTRIM], 'g') +re[t.COMPARATORTRIM] = new RegExp(src[t.COMPARATORTRIM], 'g') var comparatorTrimReplace = '$1$2$3' // Something like `1.2.3 - 1.2.4` // Note that these all use the loose form, because they'll be // checked against either the strict or loose comparator form // later. -var HYPHENRANGE = R++ -src[HYPHENRANGE] = '^\\s*(' + src[XRANGEPLAIN] + ')' + +tok('HYPHENRANGE') +src[t.HYPHENRANGE] = '^\\s*(' + src[t.XRANGEPLAIN] + ')' + '\\s+-\\s+' + - '(' + src[XRANGEPLAIN] + ')' + + '(' + src[t.XRANGEPLAIN] + ')' + '\\s*$' -var HYPHENRANGELOOSE = R++ -src[HYPHENRANGELOOSE] = '^\\s*(' + src[XRANGEPLAINLOOSE] + ')' + +tok('HYPHENRANGELOOSE') +src[t.HYPHENRANGELOOSE] = '^\\s*(' + src[t.XRANGEPLAINLOOSE] + ')' + '\\s+-\\s+' + - '(' + src[XRANGEPLAINLOOSE] + ')' + + '(' + src[t.XRANGEPLAINLOOSE] + ')' + '\\s*$' // Star ranges basically just allow anything at all. -var STAR = R++ -src[STAR] = '(<|>)?=?\\s*\\*' +tok('STAR') +src[t.STAR] = '(<|>)?=?\\s*\\*' // Compile to actual regexp objects. // All are flag-free, unless they were created above with a flag. @@ -106673,7 +109088,7 @@ function parse (version, options) { return null } - var r = options.loose ? re[LOOSE] : re[FULL] + var r = options.loose ? re[t.LOOSE] : re[t.FULL] if (!r.test(version)) { return null } @@ -106728,7 +109143,7 @@ function SemVer (version, options) { this.options = options this.loose = !!options.loose - var m = version.trim().match(options.loose ? re[LOOSE] : re[FULL]) + var m = version.trim().match(options.loose ? re[t.LOOSE] : re[t.FULL]) if (!m) { throw new TypeError('Invalid Version: ' + version) @@ -107189,7 +109604,7 @@ function Comparator (comp, options) { var ANY = {} Comparator.prototype.parse = function (comp) { - var r = this.options.loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var r = this.options.loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR] var m = comp.match(r) if (!m) { @@ -107344,18 +109759,18 @@ Range.prototype.parseRange = function (range) { var loose = this.options.loose range = range.trim() // `1.2.3 - 1.2.4` => `>=1.2.3 <=1.2.4` - var hr = loose ? re[HYPHENRANGELOOSE] : re[HYPHENRANGE] + var hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE] range = range.replace(hr, hyphenReplace) debug('hyphen replace', range) // `> 1.2.3 < 1.2.5` => `>1.2.3 <1.2.5` - range = range.replace(re[COMPARATORTRIM], comparatorTrimReplace) - debug('comparator trim', range, re[COMPARATORTRIM]) + range = range.replace(re[t.COMPARATORTRIM], comparatorTrimReplace) + debug('comparator trim', range, re[t.COMPARATORTRIM]) // `~ 1.2.3` => `~1.2.3` - range = range.replace(re[TILDETRIM], tildeTrimReplace) + range = range.replace(re[t.TILDETRIM], tildeTrimReplace) // `^ 1.2.3` => `^1.2.3` - range = range.replace(re[CARETTRIM], caretTrimReplace) + range = range.replace(re[t.CARETTRIM], caretTrimReplace) // normalize spaces range = range.split(/\s+/).join(' ') @@ -107363,7 +109778,7 @@ Range.prototype.parseRange = function (range) { // At this point, the range is completely trimmed and // ready to be split into comparators. - var compRe = loose ? re[COMPARATORLOOSE] : re[COMPARATOR] + var compRe = loose ? re[t.COMPARATORLOOSE] : re[t.COMPARATOR] var set = range.split(' ').map(function (comp) { return parseComparator(comp, this.options) }, this).join(' ').split(/\s+/) @@ -107463,7 +109878,7 @@ function replaceTildes (comp, options) { } function replaceTilde (comp, options) { - var r = options.loose ? re[TILDELOOSE] : re[TILDE] + var r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE] return comp.replace(r, function (_, M, m, p, pr) { debug('tilde', comp, _, M, m, p, pr) var ret @@ -107504,7 +109919,7 @@ function replaceCarets (comp, options) { function replaceCaret (comp, options) { debug('caret', comp, options) - var r = options.loose ? re[CARETLOOSE] : re[CARET] + var r = options.loose ? re[t.CARETLOOSE] : re[t.CARET] return comp.replace(r, function (_, M, m, p, pr) { debug('caret', comp, _, M, m, p, pr) var ret @@ -107563,7 +109978,7 @@ function replaceXRanges (comp, options) { function replaceXRange (comp, options) { comp = comp.trim() - var r = options.loose ? re[XRANGELOOSE] : re[XRANGE] + var r = options.loose ? re[t.XRANGELOOSE] : re[t.XRANGE] return comp.replace(r, function (ret, gtlt, M, m, p, pr) { debug('xRange', comp, ret, gtlt, M, m, p, pr) var xM = isX(M) @@ -107575,10 +109990,14 @@ function replaceXRange (comp, options) { gtlt = '' } + // if we're including prereleases in the match, then we need + // to fix this to -0, the lowest possible prerelease value + pr = options.includePrerelease ? '-0' : '' + if (xM) { if (gtlt === '>' || gtlt === '<') { // nothing is allowed - ret = '<0.0.0' + ret = '<0.0.0-0' } else { // nothing is forbidden ret = '*' @@ -107615,11 +110034,12 @@ function replaceXRange (comp, options) { } } - ret = gtlt + M + '.' + m + '.' + p + ret = gtlt + M + '.' + m + '.' + p + pr } else if (xm) { - ret = '>=' + M + '.0.0 <' + (+M + 1) + '.0.0' + ret = '>=' + M + '.0.0' + pr + ' <' + (+M + 1) + '.0.0' + pr } else if (xp) { - ret = '>=' + M + '.' + m + '.0 <' + M + '.' + (+m + 1) + '.0' + ret = '>=' + M + '.' + m + '.0' + pr + + ' <' + M + '.' + (+m + 1) + '.0' + pr } debug('xRange return', ret) @@ -107633,10 +110053,10 @@ function replaceXRange (comp, options) { function replaceStars (comp, options) { debug('replaceStars', comp, options) // Looseness is ignored here. star is always as loose as it gets! - return comp.trim().replace(re[STAR], '') + return comp.trim().replace(re[t.STAR], '') } -// This function is passed to string.replace(re[HYPHENRANGE]) +// This function is passed to string.replace(re[t.HYPHENRANGE]) // M, m, patch, prerelease, build // 1.2 - 3.4.5 => >=1.2.0 <=3.4.5 // 1.2.3 - 3.4 => >=1.2.0 <3.5.0 Any 3.4.x will do @@ -107947,24 +110367,54 @@ function coerce (version, options) { return version } + if (typeof version === 'number') { + version = String(version) + } + if (typeof version !== 'string') { return null } - var match = version.match(re[COERCE]) + options = options || {} - if (match == null) { + var match = null + if (!options.rtl) { + match = version.match(re[t.COERCE]) + } else { + // Find the right-most coercible string that does not share + // a terminus with a more left-ward coercible string. + // Eg, '1.2.3.4' wants to coerce '2.3.4', not '3.4' or '4' + // + // Walk through the string checking with a /g regexp + // Manually set the index so as to pick up overlapping matches. + // Stop when we get a match that ends at the string end, since no + // coercible string can be more right-ward without the same terminus. + var next + while ((next = re[t.COERCERTL].exec(version)) && + (!match || match.index + match[0].length !== version.length) + ) { + if (!match || + next.index + next[0].length !== match.index + match[0].length) { + match = next + } + re[t.COERCERTL].lastIndex = next.index + next[1].length + next[2].length + } + // leave it in a clean state + re[t.COERCERTL].lastIndex = -1 + } + + if (match === null) { return null } - return parse(match[1] + - '.' + (match[2] || '0') + - '.' + (match[3] || '0'), options) + return parse(match[2] + + '.' + (match[3] || '0') + + '.' + (match[4] || '0'), options) } /***/ }), -/* 916 */ +/* 925 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -108005,7 +110455,7 @@ module.exports = ProgressEmitter; /***/ }), -/* 917 */ +/* 926 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -108051,12 +110501,12 @@ exports.default = module.exports; /***/ }), -/* 918 */ +/* 927 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; -const NestedError = __webpack_require__(919); +const NestedError = __webpack_require__(928); class CpyError extends NestedError { constructor(message, nested) { @@ -108070,7 +110520,7 @@ module.exports = CpyError; /***/ }), -/* 919 */ +/* 928 */ /***/ (function(module, exports, __webpack_require__) { var inherits = __webpack_require__(29).inherits; @@ -108126,7 +110576,7 @@ module.exports = NestedError; /***/ }), -/* 920 */ +/* 929 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; From de191ca51f24eec9945293b3c27cd9c71c14828b Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 21:25:53 -0700 Subject: [PATCH 16/83] don't check for cache if --no-cache is passed --- packages/kbn-optimizer/src/optimizer.ts | 2 +- packages/kbn-optimizer/src/optimizer_config.ts | 2 +- src/cli/cluster/run_kbn_optimizer.ts | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index b477d2b9de024..79dbfdb406c68 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -151,7 +151,7 @@ export class Optimizer { async (): Promise => { const startTime = Date.now(); const version = await getOptimizerVersion(); - const offlineBundles = await this.getCachedBundles(version); + const offlineBundles = this.config.cache ? await this.getCachedBundles(version) : []; const onlineBundles = this.config.bundles.filter(b => !offlineBundles.includes(b)); return { diff --git a/packages/kbn-optimizer/src/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer_config.ts index aff3a6768c379..a0f238c660587 100644 --- a/packages/kbn-optimizer/src/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer_config.ts @@ -32,7 +32,7 @@ interface Options { /** the maximum number of workers that will be created */ maxWorkerCount?: number; /** set to false to disabling writing/reading of caches */ - cache?: false; + cache?: boolean; /** build assets suitable for use in the distributable */ dist?: boolean; /** enable webpack profiling, writes stats.json files to the root of each plugin's output dir */ diff --git a/src/cli/cluster/run_kbn_optimizer.ts b/src/cli/cluster/run_kbn_optimizer.ts index e4451331ddaa4..f05701464ac69 100644 --- a/src/cli/cluster/run_kbn_optimizer.ts +++ b/src/cli/cluster/run_kbn_optimizer.ts @@ -31,6 +31,7 @@ export function runKbnOptimizer(opts: Record, config: LegacyConfig) oss: !!opts.oss, examples: !!opts.runExamples, pluginPaths: config.get('plugins.paths'), + cache: config.get('optimize.useBundleCache') !== false, }); const dim = Chalk.dim('np bld'); From 8a06c59222ccec6ab9f0f38712ba52769ff9d4a5 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 21:27:56 -0700 Subject: [PATCH 17/83] update renovate config --- renovate.json5 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/renovate.json5 b/renovate.json5 index 23017bad5361d..642c4a98b5799 100644 --- a/renovate.json5 +++ b/renovate.json5 @@ -937,6 +937,14 @@ '@types/vinyl-fs', ], }, + { + groupSlug: 'watchpack', + groupName: 'watchpack related packages', + packageNames: [ + 'watchpack', + '@types/watchpack', + ], + }, { groupSlug: 'webpack', groupName: 'webpack related packages', From c61bb2fc72edef23aacfdffab16de5898d842ef4 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 21:47:36 -0700 Subject: [PATCH 18/83] standardize on index.scss, move console styles over --- src/legacy/core_plugins/console_legacy/index.ts | 2 -- src/plugins/console/public/index.scss | 1 + src/plugins/console/public/index.ts | 2 ++ .../console_legacy => plugins/console}/public/styles/_app.scss | 0 .../index.scss => plugins/console/public/styles/_index.scss} | 2 -- .../console}/public/styles/components/_help.scss | 0 .../console}/public/styles/components/_history.scss | 2 -- .../console}/public/styles/components/_index.scss | 0 .../public/{_index.scss => index.scss} | 0 src/plugins/dashboard_embeddable_container/public/index.ts | 2 +- src/plugins/embeddable/public/{_index.scss => index.scss} | 0 src/plugins/embeddable/public/index.ts | 2 +- src/plugins/expressions/public/{_index.scss => index.scss} | 0 src/plugins/expressions/public/index.ts | 2 +- src/plugins/inspector/public/index.scss | 1 + src/plugins/inspector/public/index.ts | 2 +- x-pack/plugins/searchprofiler/public/index.scss | 1 + x-pack/plugins/security/public/{_index.scss => index.scss} | 0 x-pack/plugins/security/public/index.ts | 2 +- 19 files changed, 10 insertions(+), 11 deletions(-) create mode 100644 src/plugins/console/public/index.scss rename src/{legacy/core_plugins/console_legacy => plugins/console}/public/styles/_app.scss (100%) rename src/{legacy/core_plugins/console_legacy/public/styles/index.scss => plugins/console/public/styles/_index.scss} (77%) rename src/{legacy/core_plugins/console_legacy => plugins/console}/public/styles/components/_help.scss (100%) rename src/{legacy/core_plugins/console_legacy => plugins/console}/public/styles/components/_history.scss (89%) rename src/{legacy/core_plugins/console_legacy => plugins/console}/public/styles/components/_index.scss (100%) rename src/plugins/dashboard_embeddable_container/public/{_index.scss => index.scss} (100%) rename src/plugins/embeddable/public/{_index.scss => index.scss} (100%) rename src/plugins/expressions/public/{_index.scss => index.scss} (100%) create mode 100644 src/plugins/inspector/public/index.scss create mode 100644 x-pack/plugins/searchprofiler/public/index.scss rename x-pack/plugins/security/public/{_index.scss => index.scss} (100%) diff --git a/src/legacy/core_plugins/console_legacy/index.ts b/src/legacy/core_plugins/console_legacy/index.ts index 65547e1ee5406..af080fd5ace9c 100644 --- a/src/legacy/core_plugins/console_legacy/index.ts +++ b/src/legacy/core_plugins/console_legacy/index.ts @@ -19,7 +19,6 @@ import { first } from 'rxjs/operators'; import { head } from 'lodash'; -import { resolve } from 'path'; import url from 'url'; // TODO: Remove this hack once we can get the ES config we need for Console proxy a better way. @@ -40,7 +39,6 @@ export default function(kibana: any) { }, uiExports: { - styleSheetPaths: resolve(__dirname, 'public/styles/index.scss'), injectDefaultVars: () => ({ elasticsearchUrl: url.format( Object.assign(url.parse(head(_legacyEsConfig.hosts)), { auth: false }) diff --git a/src/plugins/console/public/index.scss b/src/plugins/console/public/index.scss new file mode 100644 index 0000000000000..370ec54a85539 --- /dev/null +++ b/src/plugins/console/public/index.scss @@ -0,0 +1 @@ +@import 'styles/index' diff --git a/src/plugins/console/public/index.ts b/src/plugins/console/public/index.ts index 2af9d1d16af02..3fec5ff828065 100644 --- a/src/plugins/console/public/index.ts +++ b/src/plugins/console/public/index.ts @@ -17,6 +17,8 @@ * under the License. */ +import './index.scss'; + import { ConsoleUIPlugin } from './plugin'; export { ConsoleUIPlugin as Plugin }; diff --git a/src/legacy/core_plugins/console_legacy/public/styles/_app.scss b/src/plugins/console/public/styles/_app.scss similarity index 100% rename from src/legacy/core_plugins/console_legacy/public/styles/_app.scss rename to src/plugins/console/public/styles/_app.scss diff --git a/src/legacy/core_plugins/console_legacy/public/styles/index.scss b/src/plugins/console/public/styles/_index.scss similarity index 77% rename from src/legacy/core_plugins/console_legacy/public/styles/index.scss rename to src/plugins/console/public/styles/_index.scss index dc45f6cfdacf5..22dc0e5833d2c 100644 --- a/src/legacy/core_plugins/console_legacy/public/styles/index.scss +++ b/src/plugins/console/public/styles/_index.scss @@ -1,5 +1,3 @@ -@import 'src/legacy/ui/public/styles/styling_constants'; - // Prefix all styles with "con" to avoid conflicts. // Examples // conChart diff --git a/src/legacy/core_plugins/console_legacy/public/styles/components/_help.scss b/src/plugins/console/public/styles/components/_help.scss similarity index 100% rename from src/legacy/core_plugins/console_legacy/public/styles/components/_help.scss rename to src/plugins/console/public/styles/components/_help.scss diff --git a/src/legacy/core_plugins/console_legacy/public/styles/components/_history.scss b/src/plugins/console/public/styles/components/_history.scss similarity index 89% rename from src/legacy/core_plugins/console_legacy/public/styles/components/_history.scss rename to src/plugins/console/public/styles/components/_history.scss index efd72245b3c48..5ce5cb52351b8 100644 --- a/src/legacy/core_plugins/console_legacy/public/styles/components/_history.scss +++ b/src/plugins/console/public/styles/components/_history.scss @@ -1,5 +1,3 @@ -@import 'src/legacy/ui/public/styles/_styling_constants'; - .conHistory { @include euiBottomShadow; padding: $euiSizeM; diff --git a/src/legacy/core_plugins/console_legacy/public/styles/components/_index.scss b/src/plugins/console/public/styles/components/_index.scss similarity index 100% rename from src/legacy/core_plugins/console_legacy/public/styles/components/_index.scss rename to src/plugins/console/public/styles/components/_index.scss diff --git a/src/plugins/dashboard_embeddable_container/public/_index.scss b/src/plugins/dashboard_embeddable_container/public/index.scss similarity index 100% rename from src/plugins/dashboard_embeddable_container/public/_index.scss rename to src/plugins/dashboard_embeddable_container/public/index.scss diff --git a/src/plugins/dashboard_embeddable_container/public/index.ts b/src/plugins/dashboard_embeddable_container/public/index.ts index cd0b7d4157fa8..e5f55c06b290c 100644 --- a/src/plugins/dashboard_embeddable_container/public/index.ts +++ b/src/plugins/dashboard_embeddable_container/public/index.ts @@ -17,7 +17,7 @@ * under the License. */ -import './_index.scss'; +import './index.scss'; import { PluginInitializerContext } from '../../../core/public'; import { DashboardEmbeddableContainerPublicPlugin } from './plugin'; diff --git a/src/plugins/embeddable/public/_index.scss b/src/plugins/embeddable/public/index.scss similarity index 100% rename from src/plugins/embeddable/public/_index.scss rename to src/plugins/embeddable/public/index.scss diff --git a/src/plugins/embeddable/public/index.ts b/src/plugins/embeddable/public/index.ts index c446a8ec45a9d..f84308d77ab90 100644 --- a/src/plugins/embeddable/public/index.ts +++ b/src/plugins/embeddable/public/index.ts @@ -17,7 +17,7 @@ * under the License. */ -import './_index.scss'; +import './index.scss'; import { PluginInitializerContext } from 'src/core/public'; import { EmbeddablePublicPlugin } from './plugin'; diff --git a/src/plugins/expressions/public/_index.scss b/src/plugins/expressions/public/index.scss similarity index 100% rename from src/plugins/expressions/public/_index.scss rename to src/plugins/expressions/public/index.scss diff --git a/src/plugins/expressions/public/index.ts b/src/plugins/expressions/public/index.ts index 3b6316379314e..3a0e243d09381 100644 --- a/src/plugins/expressions/public/index.ts +++ b/src/plugins/expressions/public/index.ts @@ -17,7 +17,7 @@ * under the License. */ -import './_index.scss'; +import './index.scss'; import { PluginInitializerContext } from '../../../core/public'; import { ExpressionsPublicPlugin } from './plugin'; diff --git a/src/plugins/inspector/public/index.scss b/src/plugins/inspector/public/index.scss new file mode 100644 index 0000000000000..57820cf70cc3f --- /dev/null +++ b/src/plugins/inspector/public/index.scss @@ -0,0 +1 @@ +@import 'views/index' diff --git a/src/plugins/inspector/public/index.ts b/src/plugins/inspector/public/index.ts index d81bb0b99ed2c..b6ed1ec4e9f11 100644 --- a/src/plugins/inspector/public/index.ts +++ b/src/plugins/inspector/public/index.ts @@ -17,7 +17,7 @@ * under the License. */ -import './views/_index.scss'; +import './index.scss'; import { PluginInitializerContext } from '../../../core/public'; import { InspectorPublicPlugin } from './plugin'; diff --git a/x-pack/plugins/searchprofiler/public/index.scss b/x-pack/plugins/searchprofiler/public/index.scss new file mode 100644 index 0000000000000..370ec54a85539 --- /dev/null +++ b/x-pack/plugins/searchprofiler/public/index.scss @@ -0,0 +1 @@ +@import 'styles/index' diff --git a/x-pack/plugins/security/public/_index.scss b/x-pack/plugins/security/public/index.scss similarity index 100% rename from x-pack/plugins/security/public/_index.scss rename to x-pack/plugins/security/public/index.scss diff --git a/x-pack/plugins/security/public/index.ts b/x-pack/plugins/security/public/index.ts index e298130e3a727..df340b09334e0 100644 --- a/x-pack/plugins/security/public/index.ts +++ b/x-pack/plugins/security/public/index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import './_index.scss'; +import './index.scss'; import { PluginInitializer } from 'src/core/public'; import { SecurityPlugin, SecurityPluginSetup, SecurityPluginStart } from './plugin'; From 785a77c8f2cbe41b4d9ce1eb8466e6e9d3d1cb28 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 23:18:16 -0700 Subject: [PATCH 19/83] add support for --no-cache to cli --- packages/kbn-optimizer/src/cli.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts index ff896ee621748..0f41dc6de0c42 100644 --- a/packages/kbn-optimizer/src/cli.ts +++ b/packages/kbn-optimizer/src/cli.ts @@ -39,6 +39,11 @@ run( throw createFlagError('expected --oss to have no value'); } + const cache = flags.cache ?? true; + if (typeof cache !== 'boolean') { + throw createFlagError('expected --cache to have no value'); + } + const dist = flags.dist ?? false; if (typeof dist !== 'boolean') { throw createFlagError('expected --dist to have no value'); @@ -77,21 +82,25 @@ run( maxWorkerCount, oss, dist, + cache, examples, profileWebpack, extraPluginScanDirs, inspectWorkers, }); - const state$ = await new Optimizer(config).run(); - await state$.pipe(logOptimizerState(log, config)).toPromise(); + await new Optimizer(config) + .run() + .pipe(logOptimizerState(log, config)) + .toPromise(); }, { flags: { - boolean: ['watch', 'oss', 'examples', 'dist', 'profile', 'inspect-workers'], + boolean: ['watch', 'oss', 'examples', 'dist', 'cache', 'profile', 'inspect-workers'], string: ['workers', 'scan-dir'], default: { examples: true, + cache: true, 'inspect-workers': true, }, help: ` @@ -99,6 +108,7 @@ run( --workers max number of workers to use --oss only build oss plugins --profile profile the webpack builds and write stats.json files to build outputs + --no-cache disable the cache --no-examples don't build the example plugins --dist build new platform plugins in a way that is suitable for inclusion in the Kibana distributable --scan-dir add a directory to the list of directories scanned for plugins (specify as many times as necessary) From 3422ac8ac0d26eee7b7cc5881311f354210742e5 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 23:18:44 -0700 Subject: [PATCH 20/83] include worker config vars in optimizer version --- packages/kbn-optimizer/src/get_optimizer_version.ts | 11 ++++++----- packages/kbn-optimizer/src/optimizer.ts | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/kbn-optimizer/src/get_optimizer_version.ts b/packages/kbn-optimizer/src/get_optimizer_version.ts index 8c095bec7421c..f60bff1cee492 100644 --- a/packages/kbn-optimizer/src/get_optimizer_version.ts +++ b/packages/kbn-optimizer/src/get_optimizer_version.ts @@ -24,7 +24,7 @@ import execa from 'execa'; import { REPO_ROOT } from '@kbn/dev-utils'; import { getMtimes } from './get_mtimes'; import { getChanges } from './get_changes'; -import { ascending } from './common'; +import { OptimizerConfig } from './optimizer_config'; const OPTIMIZER_DIR = Path.dirname(require.resolve('../package.json')); const RELATIVE_DIR = Path.relative(REPO_ROOT, OPTIMIZER_DIR); @@ -41,10 +41,11 @@ async function getLastCommit() { return stdout.trim() || undefined; } -export async function getOptimizerVersion() { - const cacheLines: string[] = []; - - cacheLines.push(`lastCommit:${await getLastCommit()}`); +export async function getOptimizerVersion(config: OptimizerConfig) { + const cacheLines: string[] = [ + `lastCommit:${await getLastCommit()}`, + `workerConfig:${JSON.stringify(config.getWorkerConfig('-'))}`, + ]; const changes = (await getChanges(REPO_ROOT, [OPTIMIZER_DIR])).get(OPTIMIZER_DIR); if (changes) { diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index 79dbfdb406c68..8e4802d7d13e5 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -150,7 +150,7 @@ export class Optimizer { return Rx.defer( async (): Promise => { const startTime = Date.now(); - const version = await getOptimizerVersion(); + const version = await getOptimizerVersion(this.config); const offlineBundles = this.config.cache ? await this.getCachedBundles(version) : []; const onlineBundles = this.config.bundles.filter(b => !offlineBundles.includes(b)); From c01562ed58a5972fb43ede27d1805f3e045eb040 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 23:19:09 -0700 Subject: [PATCH 21/83] ignore concatenated modules --- packages/kbn-optimizer/src/worker/run_worker.ts | 3 ++- packages/kbn-optimizer/src/worker/webpack_helpers.ts | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts index 439e98341cdf9..34c8327bb015f 100644 --- a/packages/kbn-optimizer/src/worker/run_worker.ts +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -46,6 +46,7 @@ import { isExternalModule, isNormalModule, isIgnoredModule, + isConcatenatedModule, WebpackNormalModule, getModulePath, } from './webpack_helpers'; @@ -159,7 +160,7 @@ const observeCompiler = ( return true; } - if (isExternalModule(module) || isIgnoredModule(module)) { + if (isExternalModule(module) || isIgnoredModule(module) || isConcatenatedModule(module)) { return false; } diff --git a/packages/kbn-optimizer/src/worker/webpack_helpers.ts b/packages/kbn-optimizer/src/worker/webpack_helpers.ts index 3f61a76bb79e8..a11c85c64198e 100644 --- a/packages/kbn-optimizer/src/worker/webpack_helpers.ts +++ b/packages/kbn-optimizer/src/worker/webpack_helpers.ts @@ -148,6 +148,18 @@ export function isExternalModule(module: any): module is WebpackExternalModule { return module?.constructor?.name === 'ExternalModule'; } +/** module replacing imports for webpack externals */ +export interface WebpackConcatenatedModule { + type: string; + id: number; + dependencies: Dependency[]; + usedExports: string[]; +} + +export function isConcatenatedModule(module: any): module is WebpackConcatenatedModule { + return module?.constructor?.name === 'ConcatenatedModule'; +} + export function getModulePath(module: WebpackNormalModule) { const queryIndex = module.resource.indexOf('?'); return queryIndex === -1 ? module.resource : module.resource.slice(0, queryIndex); From 7f2d3303167fbb675197c6a57bcbcf1504da8d31 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 4 Feb 2020 23:36:50 -0700 Subject: [PATCH 22/83] update integration test --- .../basic_optimization.test.ts.snap | 525 +++++++++++++++++- .../basic_optimization.test.ts | 42 +- 2 files changed, 542 insertions(+), 25 deletions(-) diff --git a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap index a978851334f8d..706f79978beee 100644 --- a/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap +++ b/packages/kbn-optimizer/src/integration_tests/__snapshots__/basic_optimization.test.ts.snap @@ -5,26 +5,26 @@ OptimizerConfig { "bundles": Array [ Bundle { "cache": BundleCache { - "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public/.kbn-optimizer-cache, + "path": /plugins/bar/target/public/.kbn-optimizer-cache, "state": undefined, }, - "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, + "contextDir": /plugins/bar, "entry": "./public/index", "id": "bar", - "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar/target/public, - "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, + "outputDir": /plugins/bar/target/public, + "sourceRoot": , "type": "plugin", }, Bundle { "cache": BundleCache { - "path": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public/.kbn-optimizer-cache, + "path": /plugins/foo/target/public/.kbn-optimizer-cache, "state": undefined, }, - "contextDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, + "contextDir": /plugins/foo, "entry": "./public/index", "id": "foo", - "outputDir": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/target/public, - "sourceRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, + "outputDir": /plugins/foo/target/public, + "sourceRoot": , "type": "plugin", }, ], @@ -34,23 +34,524 @@ OptimizerConfig { "maxWorkerCount": 1, "plugins": Array [ Object { - "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/bar, + "directory": /plugins/bar, "id": "bar", "isUiPlugin": true, }, Object { - "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/baz, + "directory": /plugins/baz, "id": "baz", "isUiPlugin": false, }, Object { - "directory": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo, + "directory": /plugins/foo, "id": "foo", "isUiPlugin": true, }, ], "profileWebpack": false, - "repoRoot": /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo, + "repoRoot": , "watch": false, } `; + +exports[`builds expected bundles, saves bundle counts to metadata: bar bundle 1`] = ` +"var __kbnBundles__ = typeof __kbnBundles__ === \\"object\\" ? __kbnBundles__ : {}; __kbnBundles__[\\"plugin/bar\\"] = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = \\"__REPLACE_WITH_PUBLIC_PATH__\\"; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = \\"./public/index.ts\\"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ \\"../foo/public/ext.ts\\": +/*!****************************!*\\\\ + !*** ../foo/public/ext.ts ***! + \\\\****************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); +exports.ext = void 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. + */ +const ext = 'TRUE'; +exports.ext = ext; + +/***/ }), + +/***/ \\"../foo/public/index.ts\\": +/*!******************************!*\\\\ + !*** ../foo/public/index.ts ***! + \\\\******************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); + +var _lib = __webpack_require__(/*! ./lib */ \\"../foo/public/lib.ts\\"); + +Object.keys(_lib).forEach(function (key) { + if (key === \\"default\\" || key === \\"__esModule\\") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _lib[key]; + } + }); +}); + +var _ext = __webpack_require__(/*! ./ext */ \\"../foo/public/ext.ts\\"); + +Object.keys(_ext).forEach(function (key) { + if (key === \\"default\\" || key === \\"__esModule\\") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _ext[key]; + } + }); +}); + +/***/ }), + +/***/ \\"../foo/public/lib.ts\\": +/*!****************************!*\\\\ + !*** ../foo/public/lib.ts ***! + \\\\****************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); +exports.fooLibFn = fooLibFn; + +/* + * 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 fooLibFn() { + return 'foo'; +} + +/***/ }), + +/***/ \\"./public/index.ts\\": +/*!*************************!*\\\\ + !*** ./public/index.ts ***! + \\\\*************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); +var _exportNames = { + fooLibFn: true +}; +Object.defineProperty(exports, \\"fooLibFn\\", { + enumerable: true, + get: function () { + return _index.fooLibFn; + } +}); + +var _index = __webpack_require__(/*! ../../foo/public/index */ \\"../foo/public/index.ts\\"); + +var _lib = __webpack_require__(/*! ./lib */ \\"./public/lib.ts\\"); + +Object.keys(_lib).forEach(function (key) { + if (key === \\"default\\" || key === \\"__esModule\\") return; + if (Object.prototype.hasOwnProperty.call(_exportNames, key)) return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _lib[key]; + } + }); +}); + +/***/ }), + +/***/ \\"./public/lib.ts\\": +/*!***********************!*\\\\ + !*** ./public/lib.ts ***! + \\\\***********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); +exports.barLibFn = barLibFn; + +/* + * 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 barLibFn() { + return 'bar'; +} + +/***/ }) + +/******/ })[\\"plugin\\"]; +//# sourceMappingURL=bar.plugin.js.map" +`; + +exports[`builds expected bundles, saves bundle counts to metadata: foo bundle 1`] = ` +"var __kbnBundles__ = typeof __kbnBundles__ === \\"object\\" ? __kbnBundles__ : {}; __kbnBundles__[\\"plugin/foo\\"] = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); +/******/ } +/******/ }; +/******/ +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ +/******/ // create a fake namespace object +/******/ // mode & 1: value is a module id, require it +/******/ // mode & 2: merge all properties of value into the ns +/******/ // mode & 4: return value when already ns object +/******/ // mode & 8|1: behave like require +/******/ __webpack_require__.t = function(value, mode) { +/******/ if(mode & 1) value = __webpack_require__(value); +/******/ if(mode & 8) return value; +/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; +/******/ var ns = Object.create(null); +/******/ __webpack_require__.r(ns); +/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); +/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); +/******/ return ns; +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = \\"__REPLACE_WITH_PUBLIC_PATH__\\"; +/******/ +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = \\"./public/index.ts\\"); +/******/ }) +/************************************************************************/ +/******/ ({ + +/***/ \\"./public/ext.ts\\": +/*!***********************!*\\\\ + !*** ./public/ext.ts ***! + \\\\***********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); +exports.ext = void 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. + */ +const ext = 'TRUE'; +exports.ext = ext; + +/***/ }), + +/***/ \\"./public/index.ts\\": +/*!*************************!*\\\\ + !*** ./public/index.ts ***! + \\\\*************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); + +var _lib = __webpack_require__(/*! ./lib */ \\"./public/lib.ts\\"); + +Object.keys(_lib).forEach(function (key) { + if (key === \\"default\\" || key === \\"__esModule\\") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _lib[key]; + } + }); +}); + +var _ext = __webpack_require__(/*! ./ext */ \\"./public/ext.ts\\"); + +Object.keys(_ext).forEach(function (key) { + if (key === \\"default\\" || key === \\"__esModule\\") return; + Object.defineProperty(exports, key, { + enumerable: true, + get: function () { + return _ext[key]; + } + }); +}); + +/***/ }), + +/***/ \\"./public/lib.ts\\": +/*!***********************!*\\\\ + !*** ./public/lib.ts ***! + \\\\***********************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +\\"use strict\\"; + + +Object.defineProperty(exports, \\"__esModule\\", { + value: true +}); +exports.fooLibFn = fooLibFn; + +/* + * 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 fooLibFn() { + return 'foo'; +} + +/***/ }) + +/******/ })[\\"plugin\\"]; +//# sourceMappingURL=foo.plugin.js.map" +`; diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index e93339c9b3cd7..dc7ae3a35e6d7 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -25,14 +25,14 @@ import del from 'del'; import { toArray, tap } from 'rxjs/operators'; import { createAbsolutePathSerializer } from '@kbn/dev-utils'; -import { Optimizer, OptimizerConfig, OptimizerState } from '@kbn/optimizer'; - -expect.addSnapshotSerializer(createAbsolutePathSerializer()); +import { Optimizer, OptimizerConfig, OptimizerStateSummary } from '@kbn/optimizer'; const TMP_DIR = Path.resolve(__dirname, '../__fixtures__/__tmp__'); const MOCK_REPO_SRC = Path.resolve(__dirname, '../__fixtures__/mock_repo'); const MOCK_REPO_DIR = Path.resolve(TMP_DIR, 'mock_repo'); +expect.addSnapshotSerializer(createAbsolutePathSerializer(MOCK_REPO_DIR)); + beforeEach(async () => { await del(TMP_DIR); await cpy('**/*', MOCK_REPO_DIR, { @@ -61,16 +61,16 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { .run() .pipe( tap(state => { - if (state.type === 'worker stdio') { + if (state.event?.type === 'worker stdio') { // eslint-disable-next-line no-console - console.log('worker', state.stream, state.chunk.toString('utf8')); + console.log('worker', state.event.stream, state.event.chunk.toString('utf8')); } }), toArray() ) .toPromise(); - const assert = (statement: string, truth: boolean, altStates?: OptimizerState[]) => { + const assert = (statement: string, truth: boolean, altStates?: OptimizerStateSummary[]) => { if (!truth) { throw new Error( `expected optimizer to ${statement}, states: ${inspect(altStates || states, { @@ -81,19 +81,27 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { } }; - const runningStates = states.filter(s => s.type === 'running'); + const initializedStates = states.filter(s => s.summary === 'initialized' && !s.event); + assert('produce one raw initialized event', initializedStates.length === 1); + + const workerStarted = states.filter(s => s.event?.type === 'worker started'); + assert('produce one worker started state', workerStarted.length === 1); + + const runningStates = states.filter(s => s.summary === 'running'); assert( 'produce two or three "running" states', runningStates.length === 2 || runningStates.length === 3 ); - const successStates = states.filter(s => s.type === 'compiler success'); + const successStates = states.filter(s => s.summary === 'success'); assert( 'produce one "compiler success" states', successStates.length === 1 || successStates.length === 2 ); - const otherStates = states.filter(s => s.type !== 'compiler success' && s.type !== 'running'); + const otherStates = states.filter( + s => s.summary !== 'success' && s.summary !== 'running' && s.summary !== 'initialized' + ); assert('produce zero unexpected states', otherStates.length === 0, otherStates); expect( @@ -108,7 +116,13 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { expect(foo).toBeTruthy(); foo.cache.refresh(); expect(foo.getModuleCount()).toBe(3); - expect(foo.cache.getReferencedFiles()).toMatchInlineSnapshot(`Array []`); + expect(foo.cache.getReferencedFiles()).toMatchInlineSnapshot(` + Array [ + /plugins/foo/public/ext.ts, + /plugins/foo/public/index.ts, + /plugins/foo/public/lib.ts, + ] + `); const bar = config.bundles.find(b => b.id === 'bar')!; expect(bar).toBeTruthy(); @@ -116,9 +130,11 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { expect(bar.getModuleCount()).toBe(5); expect(bar.cache.getReferencedFiles()).toMatchInlineSnapshot(` Array [ - /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/ext.ts, - /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/index.ts, - /packages/kbn-optimizer/src/__fixtures__/__tmp__/mock_repo/plugins/foo/public/lib.ts, + /plugins/foo/public/ext.ts, + /plugins/foo/public/index.ts, + /plugins/foo/public/lib.ts, + /plugins/bar/public/index.ts, + /plugins/bar/public/lib.ts, ] `); }); From 5ab02081ae5918f68df4bac201a19d40a965979b Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 5 Feb 2020 10:32:13 -0700 Subject: [PATCH 23/83] add safari to browserslist to avoid user-agent warnings in dev --- .browserslistrc | 1 + 1 file changed, 1 insertion(+) diff --git a/.browserslistrc b/.browserslistrc index d74cd2310c939..89114f393c462 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -6,3 +6,4 @@ Safari 7 # for PhantomJS support: https://github.com/elastic/kibana/issues/27136 [dev] last 1 chrome versions last 1 firefox versions +last 1 safari versions From 23d069de9a4112778c755b9df88871f6bc48ced5 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 5 Feb 2020 11:39:24 -0700 Subject: [PATCH 24/83] update docs, clean up optimizer message/misc naming --- packages/kbn-optimizer/README.md | 43 +++-- .../src/common/compiler_messages.ts | 24 +-- .../src/common/worker_messages.ts | 34 ++-- .../basic_optimization.test.ts | 29 +-- .../kbn-optimizer/src/log_optimizer_state.ts | 55 +++--- packages/kbn-optimizer/src/observe_worker.ts | 16 +- packages/kbn-optimizer/src/optimizer.ts | 168 ++++++++++-------- .../kbn-optimizer/src/worker/run_worker.ts | 16 +- src/cli/cluster/cluster_manager.ts | 2 +- 9 files changed, 205 insertions(+), 182 deletions(-) diff --git a/packages/kbn-optimizer/README.md b/packages/kbn-optimizer/README.md index ed079f7f1bf35..5c5f5ebd6ecc6 100644 --- a/packages/kbn-optimizer/README.md +++ b/packages/kbn-optimizer/README.md @@ -20,9 +20,17 @@ The `@kbn/optimizer` is automatically executed from the dev cli, the Kibana buil You can limit the number of workers the optimizer uses in all of these places by setting the `KBN_OPTIMIZER_MAX_WORKERS` environment variable. You might want to do this if your system struggles to keep up while the optimizer is getting started and building all plugins as fast as possible. Setting `KBN_OPTIMIZER_MAX_WORKERS=1` will cause the optimizer to take the longest amount of time but will have the smallest impact on other components of your system. +## Caching + +Bundles built by the the optimizer include a cache file which describes the information needed to determine if the bundle needs to be rebuilt when the optimizer is restarted. Caching is enabled by default and is very aggressive about invalidating the cache output, but if you need to disable caching you can specify the `--optimize.useBundleCache=false` flag to the dev cli, or `--no-cache` to `node scripts/build_new_platform_plugins`. + +When a bundle is determined to be up-to-date a worker is not started for the bundle. If running the optimizer with the `--dev/--watch` flag, then all the files referenced by cached bundles are watched for changes. Once a change is detected in any of the files referenced by the built bundle a worker is started. If a file is changed that is referenced by several bundles then workers will be started for each bundle, combining workers together to respect the worker limit. + +The worker maximum is only enforced when workers are started, when subsequent workers are started the number of workers to start will behave as though there are no workers running. This greatly simplifies the logic as we don't ever have to reallocate bundles to workers and provides the best performance in most cases. + ## API -To run the optimizer from code, you can import the [`Optimizer`][Optimizer] and [`OptimizerConfig`][OptimizerConfig] classes. Create an [`OptimizerConfig`][OptimizerConfig] instance by calling it's static `create()` method with some options, then pass it to the [`Optimizer`][Optimizer] constructor. Calling `Optimizer#run()` will return an observable of [`OptimizerState`][Optimizer] objects, which are either bits of stdio from the workers or [`OptimizerStateSummary`][Optimizer] objects. You can use the [`logOptimizerState()`][LogOptimizerState] helper to write the relevant bits of state to a tooling log. +To run the optimizer from code, you can import the [`Optimizer`][Optimizer] and [`OptimizerConfig`][OptimizerConfig] classes. Create an [`OptimizerConfig`][OptimizerConfig] instance by calling it's static `create()` method with some options, then pass it to the [`Optimizer`][Optimizer] constructor. Calling `Optimizer#run()` will return an observable of [`OptimizerMsg`][Optimizer] objects, which are summaries of the optimizer state plus an optional `event` property which describes the internal events occuring and may be of use. You can use the [`logOptimizerState()`][LogOptimizerState] helper to write the relevant bits of state to a tooling log or checkout it's implementation to see how the internal events like [`WorkerStdio`][ObserveWorker] and [`WorkerStarted`][ObserveWorker] are used. Example: ```ts @@ -53,34 +61,32 @@ This is essentially what we're doing in [`script/build_new_platform_plugins`][Cl ## Internals -The optimizer runs webpack instances in worker processes. Each worker is configured to build one or more plugins via a [`WorkerConfig`][WorkerConfig] object (created by [`OptimizerConfig`][OptimizerConfig]) which is JSON serialized and passed to the worker as it's only argument. +The optimizer runs webpack instances in worker processes. Each worker is configured via a [`WorkerConfig`][WorkerConfig] object and an array of [`Bundle`][Bundle] objects which are JSON serialized and passed to the worker as it's arguments. Plugins/bundles are assigned to workers based on the number of modules historically seen in each bundle in an effort to evenly distribute the load across the worker pool (see [`assignBundlesToWorkers`][AssignBundlesToWorkers]). -The number of workers available is automatically chosen by dividing the number of cores available by 3 (minimum of 2). +The number of workers that will be started at any time is automatically chosen by dividing the number of cores available by 3 (minimum of 2). -The [`WorkerConfig`][WorkerConfig] includes the location of the repo (it might be one of many builds, or the main repo), wether we are running in watch mode, wether we are building a distributable, and a list of [`BundleDefinition`][BundleDefinition] objects which include the details necessary to create a webpack config for a specific plugin's bundle (created using [`webpack.config.ts`][WebpackConfig]). +The [`WorkerConfig`][WorkerConfig] includes the location of the repo (it might be one of many builds, or the main repo), wether we are running in watch mode, wether we are building a distributable, and other global config items. -Each worker communicates state back to the main process by sending [`WorkerMessage`][WorkerMessage] and [`CompilerMessage`][CompilerMessage] objects using IPC. +The [`Bundle`][Bundle] objects which include the details necessary to create a webpack config for a specific plugin's bundle (created using [`webpack.config.ts`][WebpackConfig]). -The Optimizer captures all of these messages and produces a stream of [`OptimizerStateSummary`][Optimizer] and [`WorkerStdio`][ObserveWorker] objects. Workers shouldn't produce any data on their stdio streams, but when they do it's probably because something is wrong so make sure to show them to users somehow. All other messages represent the total state of all workers. +Each worker communicates state back to the main process by sending [`WorkerMsg`][WorkerMsg] and [`CompilerMsg`][CompilerMsg] objects using IPC. -```ts -interface OptimizerStateSummary { - type: 'running' | 'compiler issue' | 'compiler success'; - durSec: number; - bundles: BundleState[]; -} -``` +The Optimizer captures all of these messages and produces a stream of [`OptimizerMsg`][Optimizer] objects. -Optimizer state summary types: +Optimizer state phases:
+
'initialized'
+
Initial event emitted by the optimizer once it's don't initializing its internal state.
'running'
Emitted when any worker is in a running state. To determine which compilers are running, look for BundleState objects with type 'running'.
-
'compiler issue'
+
'issue'
Emitted when all workers are done running and any compiler completed with a 'compiler issue' status. Compiler issues include things like "unable to resolve module" or syntax errors in the source modules and can be fixed by users when running in watch mode.
-
'compiler success'
+
'success'
Emitted when all workers are done running and all compilers completed with 'compiler success'.
+
'reallocating'
+
Emitted when the files referenced by a cached bundle have changed, before the worker has been started up to update that bundle.
Workers have several error message they may emit which indicate unrecoverable errors. When any of those messages are received the stream will error and the workers will be torn down. @@ -91,8 +97,9 @@ For an example of how to handle these states checkout the [`logOptimizerState()` [Cli]: src/cli.ts [Optimizer]: src/optimizer.ts [ObserveWorker]: src/observe_worker.ts -[CompilerMessage]: src/common/compiler_messages.ts -[WorkerMessage]: src/common/worker_messages.ts +[CompilerMsg]: src/common/compiler_messages.ts +[WorkerMsg]: src/common/worker_messages.ts +[Bundle]: src/common/bundle.ts [WebpackConfig]: src/worker/webpack.config.ts [BundleDefinition]: src/common/bundle_definition.ts [WorkerConfig]: src/common/worker_config.ts diff --git a/packages/kbn-optimizer/src/common/compiler_messages.ts b/packages/kbn-optimizer/src/common/compiler_messages.ts index 8308f49751030..ab65033ea77ad 100644 --- a/packages/kbn-optimizer/src/common/compiler_messages.ts +++ b/packages/kbn-optimizer/src/common/compiler_messages.ts @@ -21,10 +21,10 @@ * Message sent when a compiler encouters an unresolvable error. * The worker will be shut down following this message. */ -export interface CompilerErrorMessage { +export interface CompilerErrorMsg { type: 'compiler error'; id: string; - errorMessage: string; + errorMsg: string; errorStack?: string; } @@ -32,7 +32,7 @@ export interface CompilerErrorMessage { * Message sent when a compiler starts running, either for the first * time or because of changes detected when watching. */ -export interface CompilerRunningMessage { +export interface CompilerRunningMsg { type: 'running'; bundleId: string; } @@ -43,7 +43,7 @@ export interface CompilerRunningMessage { * watch mode these issues can be fixed by the user. * (ie. unresolved import, syntax error, etc.) */ -export interface CompilerIssueMessage { +export interface CompilerIssueMsg { type: 'compiler issue'; bundleId: string; failure: string; @@ -53,25 +53,25 @@ export interface CompilerIssueMessage { * Message sent when a compiler completes successfully and * the bundle has been written to disk or updated on disk. */ -export interface CompilerSuccessMessage { +export interface CompilerSuccessMsg { type: 'compiler success'; bundleId: string; moduleCount: number; } -export type CompilerState = CompilerRunningMessage | CompilerIssueMessage | CompilerSuccessMessage; +export type CompilerState = CompilerRunningMsg | CompilerIssueMsg | CompilerSuccessMsg; -export class CompilerMessages { +export class CompilerMsgs { constructor(private bundle: string) {} - running(): CompilerRunningMessage { + running(): CompilerRunningMsg { return { bundleId: this.bundle, type: 'running', }; } - compilerFailure(options: { failure: string }): CompilerIssueMessage { + compilerFailure(options: { failure: string }): CompilerIssueMsg { return { bundleId: this.bundle, type: 'compiler issue', @@ -79,7 +79,7 @@ export class CompilerMessages { }; } - compilerSuccess(options: { moduleCount: number }): CompilerSuccessMessage { + compilerSuccess(options: { moduleCount: number }): CompilerSuccessMsg { return { bundleId: this.bundle, type: 'compiler success', @@ -87,11 +87,11 @@ export class CompilerMessages { }; } - error(error: Error): CompilerErrorMessage { + error(error: Error): CompilerErrorMsg { return { id: this.bundle, type: 'compiler error', - errorMessage: error.message, + errorMsg: error.message, errorStack: error.stack, }; } diff --git a/packages/kbn-optimizer/src/common/worker_messages.ts b/packages/kbn-optimizer/src/common/worker_messages.ts index 323904b598fe7..d3c03f483d7e8 100644 --- a/packages/kbn-optimizer/src/common/worker_messages.ts +++ b/packages/kbn-optimizer/src/common/worker_messages.ts @@ -18,31 +18,31 @@ */ import { - CompilerRunningMessage, - CompilerIssueMessage, - CompilerSuccessMessage, - CompilerErrorMessage, + CompilerRunningMsg, + CompilerIssueMsg, + CompilerSuccessMsg, + CompilerErrorMsg, } from './compiler_messages'; -export type WorkerMessage = - | CompilerRunningMessage - | CompilerIssueMessage - | CompilerSuccessMessage - | CompilerErrorMessage - | WorkerErrorMessage; +export type WorkerMsg = + | CompilerRunningMsg + | CompilerIssueMsg + | CompilerSuccessMsg + | CompilerErrorMsg + | WorkerErrorMsg; /** * Message sent when the worker encounters an error that it can't * recover from, no more messages will be sent and the worker * will exit after this message. */ -export interface WorkerErrorMessage { +export interface WorkerErrorMsg { type: 'worker error'; - errorMessage: string; + errorMsg: string; errorStack?: string; } -const WORKER_STATE_TYPES: ReadonlyArray = [ +const WORKER_STATE_TYPES: ReadonlyArray = [ 'running', 'compiler issue', 'compiler success', @@ -50,14 +50,14 @@ const WORKER_STATE_TYPES: ReadonlyArray = [ 'worker error', ]; -export const isWorkerMessage = (value: any): value is WorkerMessage => +export const isWorkerMsg = (value: any): value is WorkerMsg => typeof value === 'object' && value && WORKER_STATE_TYPES.includes(value.type); -export class WorkerMessages { - error(error: Error): WorkerErrorMessage { +export class WorkerMsgs { + error(error: Error): WorkerErrorMsg { return { type: 'worker error', - errorMessage: error.message, + errorMsg: error.message, errorStack: error.stack, }; } diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index dc7ae3a35e6d7..5fe1b83f556bf 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -25,7 +25,7 @@ import del from 'del'; import { toArray, tap } from 'rxjs/operators'; import { createAbsolutePathSerializer } from '@kbn/dev-utils'; -import { Optimizer, OptimizerConfig, OptimizerStateSummary } from '@kbn/optimizer'; +import { Optimizer, OptimizerConfig, OptimizerMsg } from '@kbn/optimizer'; const TMP_DIR = Path.resolve(__dirname, '../__fixtures__/__tmp__'); const MOCK_REPO_SRC = Path.resolve(__dirname, '../__fixtures__/mock_repo'); @@ -57,7 +57,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { const optimizer = new Optimizer(config); - const states = await optimizer + const msgs = await optimizer .run() .pipe( tap(state => { @@ -70,10 +70,10 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { ) .toPromise(); - const assert = (statement: string, truth: boolean, altStates?: OptimizerStateSummary[]) => { + const assert = (statement: string, truth: boolean, altStates?: OptimizerMsg[]) => { if (!truth) { throw new Error( - `expected optimizer to ${statement}, states: ${inspect(altStates || states, { + `expected optimizer to ${statement}, states: ${inspect(altStates || msgs, { colors: true, depth: Infinity, })}` @@ -81,26 +81,29 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { } }; - const initializedStates = states.filter(s => s.summary === 'initialized' && !s.event); - assert('produce one raw initialized event', initializedStates.length === 1); + const initializedStates = msgs.filter(msg => msg.state.phase === 'initialized'); + assert('produce at least one initialized event', initializedStates.length >= 1); - const workerStarted = states.filter(s => s.event?.type === 'worker started'); - assert('produce one worker started state', workerStarted.length === 1); + const workerStarted = msgs.filter(msg => msg.event?.type === 'worker started'); + assert('produce one worker started event', workerStarted.length === 1); - const runningStates = states.filter(s => s.summary === 'running'); + const runningStates = msgs.filter(msg => msg.state.phase === 'running'); assert( 'produce two or three "running" states', runningStates.length === 2 || runningStates.length === 3 ); - const successStates = states.filter(s => s.summary === 'success'); + const successStates = msgs.filter(msg => msg.state.phase === 'success'); assert( - 'produce one "compiler success" states', + 'produce one or two "compiler success" states', successStates.length === 1 || successStates.length === 2 ); - const otherStates = states.filter( - s => s.summary !== 'success' && s.summary !== 'running' && s.summary !== 'initialized' + const otherStates = msgs.filter( + msg => + msg.state.phase !== 'success' && + msg.state.phase !== 'running' && + msg.state.phase !== 'initialized' ); assert('produce zero unexpected states', otherStates.length === 0, otherStates); diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index 363644e04f9e2..e148b347f687f 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -24,43 +24,46 @@ import * as Rx from 'rxjs'; import { tap } from 'rxjs/operators'; import { OptimizerConfig } from './optimizer_config'; -import { OptimizerStateSummary } from './optimizer'; +import { OptimizerMsg } from './optimizer'; import { CompilerState, pipeClosure } from './common'; export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { - return pipeClosure((state$: Rx.Observable) => { + return pipeClosure((msg$: Rx.Observable) => { const bundleStates = new Map(); + let loggedInit = false; - return state$.pipe( - tap(s => { - if (s.event?.type === 'worker stdio') { - const chunk = s.event.chunk.toString('utf8'); + return msg$.pipe( + tap(msg => { + const { event, state } = msg; + + if (state.phase === 'initialized' && !loggedInit) { + loggedInit = true; + log.debug(`initialized after ${state.durSec} sec`); + log.debug(` version: ${state.version}`); + log.debug(` cached: ${state.offlineBundles.map(b => b.id)}`); + } + + if (event?.type === 'worker stdio') { + const chunk = event.chunk.toString('utf8'); log.warning( '⚙️ worker', - s.event.stream, + event.stream, chunk.slice(0, chunk.length - (chunk.endsWith('\n') ? 1 : 0)) ); return; } - if (s.event?.type === 'worker started') { - log.debug(`worker started for bundles ${s.event.bundles.map(b => b.id).join(', ')}`); + if (event?.type === 'worker started') { + log.debug(`worker started for bundles ${event.bundles.map(b => b.id).join(', ')}`); return; } - if (s.event?.type === 'changes detected') { + if (event?.type === 'changes detected') { log.debug(`changes detected...`); return; } - if (s.summary === 'initialized') { - log.debug(`initialized after ${s.durSec} sec`); - log.debug(` version: ${s.version}`); - log.debug(` cached: ${s.offlineBundles.map(b => b.id)}`); - return; - } - - for (const { bundleId: id, type } of s.compilerStates) { + for (const { bundleId: id, type } of state.compilerStates) { const prevBundleState = bundleStates.get(id); if (type === prevBundleState) { @@ -69,18 +72,18 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { bundleStates.set(id, type); log.debug( - `[${id}] state = "${type}"${type !== 'running' ? ` after ${s.durSec} sec` : ''}` + `[${id}] state = "${type}"${type !== 'running' ? ` after ${state.durSec} sec` : ''}` ); } - if (s.summary === 'running') { + if (state.phase === 'running') { return true; } - if (s.summary === 'issue') { + if (state.phase === 'issue') { log.error('⚙️ webpack compile errors'); log.indent(4); - for (const b of s.compilerStates) { + for (const b of state.compilerStates) { if (b.type === 'compiler issue') { log.error(`[${b.bundleId}] build`); log.indent(4); @@ -92,16 +95,16 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { return true; } - if (s.summary === 'success') { + if (state.phase === 'success') { log.success( config.watch - ? `⚙️ watching for changes in all bundles after ${s.durSec} sec` - : `⚙️ all bundles compiled successfully after ${s.durSec} sec` + ? `⚙️ watching for changes in all bundles after ${state.durSec} sec` + : `⚙️ all bundles compiled successfully after ${state.durSec} sec` ); return true; } - throw new Error(`unhandled optimizer state: ${inspect(s)}`); + throw new Error(`unhandled optimizer message: ${inspect(msg)}`); }) ); }); diff --git a/packages/kbn-optimizer/src/observe_worker.ts b/packages/kbn-optimizer/src/observe_worker.ts index ffc6ab14c02c0..e652672aca4fe 100644 --- a/packages/kbn-optimizer/src/observe_worker.ts +++ b/packages/kbn-optimizer/src/observe_worker.ts @@ -24,7 +24,7 @@ import { inspect } from 'util'; import * as Rx from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { isWorkerMessage, WorkerConfig, WorkerMessage, Bundle } from './common'; +import { isWorkerMsg, WorkerConfig, WorkerMsg, Bundle } from './common'; import { OptimizerConfig } from './optimizer_config'; export interface WorkerStdio { @@ -130,9 +130,9 @@ export function observeWorker( config: OptimizerConfig, workerConfig: WorkerConfig, bundles: Bundle[] -): Rx.Observable { +): Rx.Observable { return usingWorkerProc(config, workerConfig, bundles, proc => { - let lastMessage: WorkerMessage; + let lastMsg: WorkerMsg; return Rx.merge( Rx.of({ @@ -145,11 +145,11 @@ export function observeWorker( .pipe( // validate the messages from the process map(([msg]) => { - if (!isWorkerMessage(msg)) { + if (!isWorkerMsg(msg)) { throw new Error(`unexpected message from worker: ${JSON.stringify(msg)}`); } - lastMessage = msg; + lastMsg = msg; return msg; }) ) @@ -166,7 +166,7 @@ export function observeWorker( // throw into stream on unexpected exits, or emit to trigger the stream to close Rx.fromEvent<[number | void]>(proc, 'exit').pipe( map(([code]) => { - const terminalMsgTypes: Array = [ + const terminalMsgTypes: Array = [ 'compiler error', 'worker error', ]; @@ -176,14 +176,14 @@ export function observeWorker( } // verify that this is an expected exit state - if (code === 0 && lastMessage && terminalMsgTypes.includes(lastMessage.type)) { + if (code === 0 && lastMsg && terminalMsgTypes.includes(lastMsg.type)) { // emit undefined so that takeUntil completes the observable return; } throw new Error( `worker exitted unexpectedly with code ${code} [last message: ${inspect( - lastMessage + lastMsg )}]` ); }) diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index 8e4802d7d13e5..e31062a3e49f7 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -26,20 +26,24 @@ import { map, mergeMap, share } from 'rxjs/operators'; import { observeWorker, WorkerStatus } from './observe_worker'; import { OptimizerConfig } from './optimizer_config'; import { getOptimizerVersion } from './get_optimizer_version'; -import { CompilerState, WorkerMessage, pipeClosure, Bundle, ascending, maybeMap } from './common'; +import { CompilerState, WorkerMsg, pipeClosure, Bundle, ascending, maybeMap } from './common'; import { assignBundlesToWorkers } from './assign_bundles_to_workers'; import { Watcher, ChangesStarted, Changes } from './watcher'; import { getMtimes } from './get_mtimes'; -export interface OptimizerStateSummary { - summary: 'initialized' | 'success' | 'running' | 'issue'; +export interface OptimizerMsg { + state: OptimizerState; + event?: ChangesStarted | Changes | WorkerMsg | WorkerStatus; +} + +export interface OptimizerState { + phase: 'initialized' | 'reallocating' | 'success' | 'running' | 'issue'; version: string; startTime: number; durSec: number; compilerStates: CompilerState[]; onlineBundles: Bundle[]; offlineBundles: Bundle[]; - event?: ChangesStarted | Changes | WorkerMessage | WorkerStatus; } export interface OptimizerStartedWorker { @@ -57,7 +61,7 @@ export type OptimizerNotif = OptimizerStartedWorker; const msToSec = (ms: number) => Math.round(ms / 100) / 10; -const getSummary = (states: CompilerState[]): OptimizerStateSummary['summary'] => { +const getPhase = (states: CompilerState[]): OptimizerState['phase'] => { const types = states.map(s => s.type); if (types.includes('running')) { @@ -148,14 +152,14 @@ export class Optimizer { run() { return Rx.defer( - async (): Promise => { + async (): Promise => { const startTime = Date.now(); const version = await getOptimizerVersion(this.config); const offlineBundles = this.config.cache ? await this.getCachedBundles(version) : []; const onlineBundles = this.config.bundles.filter(b => !offlineBundles.includes(b)); return { - summary: onlineBundles.length || this.config.watch ? 'initialized' : 'success', + phase: onlineBundles.length || this.config.watch ? 'initialized' : 'success', version, compilerStates: [], durSec: msToSec(Date.now() - startTime), @@ -165,76 +169,87 @@ export class Optimizer { }; } ).pipe( - mergeMap(init => { - if (init.summary === 'success') { - return [init]; - } + mergeMap( + (initState): Rx.Observable => { + if (initState.phase === 'success') { + return Rx.of({ + state: initState, + }); + } - const change$ = this.config.watch - ? this.watchBundlesForChanges$(init.offlineBundles).pipe(share()) - : Rx.EMPTY; - - const workerMsg$ = Rx.concat( - // first batch is all the workers which weren't initially cached - Rx.of(init.onlineBundles), - // subsequent batches are defined by our change listener - change$.pipe(maybeMap(c => (c.type === 'changes' ? c.bundles : undefined))) - ).pipe( - mergeMap(bundles => - Rx.from(assignBundlesToWorkers(bundles, this.config.maxWorkerCount)).pipe( - mergeMap(assignment => - observeWorker( - this.config, - this.config.getWorkerConfig(init.version), - assignment.bundles + const change$ = this.config.watch + ? this.watchBundlesForChanges$(initState.offlineBundles).pipe(share()) + : Rx.EMPTY; + + const workerMsg$ = Rx.concat( + // first batch is all the workers which weren't initially cached + Rx.of(initState.onlineBundles), + // subsequent batches are defined by our change listener + change$.pipe(maybeMap(c => (c.type === 'changes' ? c.bundles : undefined))) + ).pipe( + mergeMap(bundles => + Rx.from(assignBundlesToWorkers(bundles, this.config.maxWorkerCount)).pipe( + mergeMap(assignment => + observeWorker( + this.config, + this.config.getWorkerConfig(initState.version), + assignment.bundles + ) ) ) ) - ) - ); - - return Rx.concat( - Rx.of(init), - Rx.merge(change$, workerMsg$).pipe( - pipeClosure(event$ => { - let prev = init; - - const nextUpdate = ( - event: NonNullable, - changes?: Partial> - ): OptimizerStateSummary => { - const startTime = changes?.startTime ?? prev.startTime; - const next = { - ...prev, - ...changes, - event, - startTime, - durSec: msToSec(Date.now() - startTime), + ); + + return Rx.concat( + Rx.of({ state: initState }), + Rx.merge(change$, workerMsg$).pipe( + pipeClosure(event$ => { + let prevState = initState; + + const update = ( + event: NonNullable, + stateChanges?: Partial> + ) => { + // reset start time if we are transitioning into running + const startTime = + (prevState.phase === 'success' || prevState.phase === 'issue') && + stateChanges?.phase === 'running' + ? Date.now() + : prevState.startTime; + + const next: OptimizerMsg = { + event, + state: { + ...prevState, + ...stateChanges, + startTime, + durSec: msToSec(Date.now() - startTime), + }, + }; + + prevState = next.state; + return next; }; - prev = next; - return next; - }; - return event$.pipe( - map( - (event): OptimizerStateSummary => { + return event$.pipe( + map(event => { if (event.type === 'worker error' || event.type === 'compiler error') { // unrecoverable error states - const error = new Error(event.errorMessage); + const error = new Error(event.errorMsg); error.stack = event.errorStack; throw error; } if (event.type === 'worker stdio' || event.type === 'worker started') { - return nextUpdate(event); + return update(event); } if (event.type === 'changes detected') { // switch to running early, before workers are started, so that // base path proxy can prevent requests in the delay between changes // and workers started - return nextUpdate(event, { - summary: 'running', + return update(event, { + phase: 'reallocating', }); } @@ -242,18 +257,20 @@ export class Optimizer { const onlineBundles: Bundle[] = []; const offlineBundles: Bundle[] = []; for (const bundle of this.config.bundles) { - if (prev.onlineBundles.includes(bundle) || event.bundles.includes(bundle)) { + if ( + prevState.onlineBundles.includes(bundle) || + event.bundles.includes(bundle) + ) { onlineBundles.push(bundle); } else { offlineBundles.push(bundle); } } - return nextUpdate(event, { - summary: 'running', + return update(event, { + phase: 'running', onlineBundles, offlineBundles, - startTime: prev.summary === 'running' ? prev.startTime : Date.now(), }); } @@ -263,30 +280,23 @@ export class Optimizer { event.type === 'running' ) { const compilerStates: CompilerState[] = [ - ...prev.compilerStates.filter(c => c.bundleId !== event.bundleId), + ...prevState.compilerStates.filter(c => c.bundleId !== event.bundleId), event, ]; - const summary = getSummary(compilerStates); - const newStartTime = - prev.summary !== 'running' && summary === 'running' - ? Date.now() - : prev.startTime; - - return nextUpdate(event, { - summary, + return update(event, { + phase: getPhase(compilerStates), compilerStates, - startTime: newStartTime, }); } throw new Error(`unexpected optimizer event ${inspect(event)}`); - } - ) - ); - }) - ) - ); - }) + }) + ); + }) + ) + ); + } + ) ); } } diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts index 34c8327bb015f..4b1fe33ace14b 100644 --- a/packages/kbn-optimizer/src/worker/run_worker.ts +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -29,15 +29,15 @@ import * as Rx from 'rxjs'; import { mergeMap, map, mapTo, takeUntil } from 'rxjs/operators'; import { - CompilerMessages, - WorkerMessages, + CompilerMsgs, + WorkerMsgs, maybeMap, parseWorkerConfig, Bundle, parseBundles, WorkerConfig, - isWorkerMessage, - WorkerMessage, + isWorkerMsg, + WorkerMsg, ascending, } from '../common'; import { getWebpackConfig } from './webpack.config'; @@ -52,12 +52,12 @@ import { } from './webpack_helpers'; const PLUGIN_NAME = '@kbn/optimizer'; -const workerMsgs = new WorkerMessages(); +const workerMsgs = new WorkerMsgs(); if (!process.send) { throw new Error('worker process was not started with an IPC channel'); } -const send = (msg: WorkerMessage) => { +const send = (msg: WorkerMsg) => { if (!process.send) { // parent is gone process.exit(0); @@ -113,7 +113,7 @@ const observeCompiler = ( bundle: Bundle, compiler: webpack.Compiler ) => { - const compilerMsgs = new CompilerMessages(bundle.id); + const compilerMsgs = new CompilerMsgs(bundle.id); const done$ = new Rx.Subject(); const { beforeRun, watchRun, done } = compiler.hooks; @@ -263,7 +263,7 @@ Rx.defer(() => { send(msg); }, error => { - if (isWorkerMessage(error)) { + if (isWorkerMsg(error)) { send(error); } else { send(workerMsgs.error(error)); diff --git a/src/cli/cluster/cluster_manager.ts b/src/cli/cluster/cluster_manager.ts index a51b8649fa705..2f308915fb332 100644 --- a/src/cli/cluster/cluster_manager.ts +++ b/src/cli/cluster/cluster_manager.ts @@ -73,7 +73,7 @@ export class ClusterManager { // run @kbn/optimizer and write it's state to kbnOptimizerReady$ runKbnOptimizer(opts, config) .pipe( - map(state => state.summary === 'success' || state.summary === 'issue'), + map(({ state }) => state.phase === 'success' || state.phase === 'issue'), tap({ error: error => { this.log.bad('New platform optimizer error', error.stack); From 78ed6b8d652433b6a82f3139307fdc13d51e2398 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 5 Feb 2020 12:35:21 -0700 Subject: [PATCH 25/83] always handle initialized messages, don't ignore states that are attached to specific events --- .../kbn-optimizer/src/log_optimizer_state.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index e148b347f687f..dc3e6c7706d86 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -36,13 +36,6 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { tap(msg => { const { event, state } = msg; - if (state.phase === 'initialized' && !loggedInit) { - loggedInit = true; - log.debug(`initialized after ${state.durSec} sec`); - log.debug(` version: ${state.version}`); - log.debug(` cached: ${state.offlineBundles.map(b => b.id)}`); - } - if (event?.type === 'worker stdio') { const chunk = event.chunk.toString('utf8'); log.warning( @@ -50,16 +43,24 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { event.stream, chunk.slice(0, chunk.length - (chunk.endsWith('\n') ? 1 : 0)) ); - return; } if (event?.type === 'worker started') { log.debug(`worker started for bundles ${event.bundles.map(b => b.id).join(', ')}`); - return; } if (event?.type === 'changes detected') { log.debug(`changes detected...`); + } + + if (state.phase === 'initialized') { + if (!loggedInit) { + loggedInit = true; + log.debug(`initialized after ${state.durSec} sec`); + log.debug(` version: ${state.version}`); + log.debug(` cached: ${state.offlineBundles.map(b => b.id)}`); + } + return; } From 18aa8fc0ef7464a5117d984b43350d1e463d2868 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 5 Feb 2020 15:21:12 -0700 Subject: [PATCH 26/83] reword caching docs, add environment var to disable caching --- packages/kbn-optimizer/README.md | 14 ++-- .../src/optimizer_config.test.ts | 83 +++++++++++++++++++ .../kbn-optimizer/src/optimizer_config.ts | 2 +- 3 files changed, 92 insertions(+), 7 deletions(-) diff --git a/packages/kbn-optimizer/README.md b/packages/kbn-optimizer/README.md index 5c5f5ebd6ecc6..0059ff2d5ebe2 100644 --- a/packages/kbn-optimizer/README.md +++ b/packages/kbn-optimizer/README.md @@ -18,15 +18,17 @@ To make front-end code easier to debug the optimizer uses the `BROWSERSLIST_ENV= The `@kbn/optimizer` is automatically executed from the dev cli, the Kibana build scripts, and in CI. If you're running Kibana locally in some other way you might need to build the plugins manually, which you can do by running `node scripts/build_new_platform_plugins` (pass `--help` for options). -You can limit the number of workers the optimizer uses in all of these places by setting the `KBN_OPTIMIZER_MAX_WORKERS` environment variable. You might want to do this if your system struggles to keep up while the optimizer is getting started and building all plugins as fast as possible. Setting `KBN_OPTIMIZER_MAX_WORKERS=1` will cause the optimizer to take the longest amount of time but will have the smallest impact on other components of your system. +### Worker count -## Caching +You can limit the number of workers the optimizer uses by setting the `KBN_OPTIMIZER_MAX_WORKERS` environment variable. You might want to do this if your system struggles to keep up while the optimizer is getting started and building all plugins as fast as possible. Setting `KBN_OPTIMIZER_MAX_WORKERS=1` will cause the optimizer to take the longest amount of time but will have the smallest impact on other components of your system. -Bundles built by the the optimizer include a cache file which describes the information needed to determine if the bundle needs to be rebuilt when the optimizer is restarted. Caching is enabled by default and is very aggressive about invalidating the cache output, but if you need to disable caching you can specify the `--optimize.useBundleCache=false` flag to the dev cli, or `--no-cache` to `node scripts/build_new_platform_plugins`. +We only limit the number of workers we will start at any given time. If we start more workers later we will limit the number of workers we start at that time by the maximum, but we don't take into account the number of workers already started because it is assumed that those workers are doing very little work. This greatly simplifies the logic as we don't ever have to reallocate workers and provides the best performance in most cases. -When a bundle is determined to be up-to-date a worker is not started for the bundle. If running the optimizer with the `--dev/--watch` flag, then all the files referenced by cached bundles are watched for changes. Once a change is detected in any of the files referenced by the built bundle a worker is started. If a file is changed that is referenced by several bundles then workers will be started for each bundle, combining workers together to respect the worker limit. +### Caching + +Bundles built by the the optimizer include a cache file which describes the information needed to determine if the bundle needs to be rebuilt when the optimizer is restarted. Caching is enabled by default and is very aggressive about invalidating the cache output, but if you need to disable caching you can pass the `--optimize.useBundleCache=false` flag to the dev cli, `--no-cache` to `node scripts/build_new_platform_plugins`, or set the `KBN_OPTIMIZER_NO_CACHE` environment variable to anything (env overrides other settings). -The worker maximum is only enforced when workers are started, when subsequent workers are started the number of workers to start will behave as though there are no workers running. This greatly simplifies the logic as we don't ever have to reallocate bundles to workers and provides the best performance in most cases. +When a bundle is determined to be up-to-date a worker is not started for the bundle. If running the optimizer with the `--dev/--watch` flag, then all the files referenced by cached bundles are watched for changes. Once a change is detected in any of the files referenced by the built bundle a worker is started. If a file is changed that is referenced by several bundles then workers will be started for each bundle, combining workers together to respect the worker limit. ## API @@ -75,7 +77,7 @@ Each worker communicates state back to the main process by sending [`WorkerMsg`] The Optimizer captures all of these messages and produces a stream of [`OptimizerMsg`][Optimizer] objects. -Optimizer state phases: +Optimizer phases:
'initialized'
Initial event emitted by the optimizer once it's don't initializing its internal state.
diff --git a/packages/kbn-optimizer/src/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer_config.test.ts index 703bb4337ddf6..5e0c2db0ae97f 100644 --- a/packages/kbn-optimizer/src/optimizer_config.test.ts +++ b/packages/kbn-optimizer/src/optimizer_config.test.ts @@ -34,6 +34,7 @@ expect.addSnapshotSerializer(createAbsolutePathSerializer()); beforeEach(() => { delete process.env.KBN_OPTIMIZER_MAX_WORKERS; + delete process.env.KBN_OPTIMIZER_NO_CACHE; jest.clearAllMocks(); }); @@ -213,6 +214,88 @@ describe('OptimizerConfig::parseOptions()', () => { "watch": false, } `); + + process.env.KBN_OPTIMIZER_NO_CACHE = '0'; + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + pluginScanDirs: [], + }) + ).toMatchInlineSnapshot(` + Object { + "cache": false, + "dist": false, + "inspectWorkers": false, + "maxWorkerCount": 100, + "pluginPaths": Array [], + "pluginScanDirs": Array [], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); + + process.env.KBN_OPTIMIZER_NO_CACHE = '1'; + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + pluginScanDirs: [], + }) + ).toMatchInlineSnapshot(` + Object { + "cache": false, + "dist": false, + "inspectWorkers": false, + "maxWorkerCount": 100, + "pluginPaths": Array [], + "pluginScanDirs": Array [], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); + + process.env.KBN_OPTIMIZER_NO_CACHE = '1'; + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + pluginScanDirs: [], + cache: true, + }) + ).toMatchInlineSnapshot(` + Object { + "cache": false, + "dist": false, + "inspectWorkers": false, + "maxWorkerCount": 100, + "pluginPaths": Array [], + "pluginScanDirs": Array [], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); + + delete process.env.KBN_OPTIMIZER_NO_CACHE; + expect( + OptimizerConfig.parseOptions({ + repoRoot: REPO_ROOT, + pluginScanDirs: [], + cache: true, + }) + ).toMatchInlineSnapshot(` + Object { + "cache": true, + "dist": false, + "inspectWorkers": false, + "maxWorkerCount": 100, + "pluginPaths": Array [], + "pluginScanDirs": Array [], + "profileWebpack": false, + "repoRoot": , + "watch": false, + } + `); }); }); diff --git a/packages/kbn-optimizer/src/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer_config.ts index a0f238c660587..113a4e30ab362 100644 --- a/packages/kbn-optimizer/src/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer_config.ts @@ -72,7 +72,7 @@ export class OptimizerConfig { const examples = !!options.examples; const profileWebpack = !!options.profileWebpack; const inspectWorkers = !!options.inspectWorkers; - const cache = options.cache !== false; + const cache = options.cache !== false && !process.env.KBN_OPTIMIZER_NO_CACHE; const repoRoot = options.repoRoot; if (!Path.isAbsolute(repoRoot)) { From c77c8e185ec58cd509a7f1848d8aeca805d7477a Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 5 Feb 2020 17:11:04 -0700 Subject: [PATCH 27/83] tweak logging and don't use optimizer.useBundleCache as that's disabled in dev --- packages/kbn-optimizer/README.md | 2 +- packages/kbn-optimizer/src/log_optimizer_state.ts | 14 ++++++++------ src/cli/cluster/run_kbn_optimizer.ts | 1 - 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/kbn-optimizer/README.md b/packages/kbn-optimizer/README.md index 0059ff2d5ebe2..69cdb959cf323 100644 --- a/packages/kbn-optimizer/README.md +++ b/packages/kbn-optimizer/README.md @@ -26,7 +26,7 @@ We only limit the number of workers we will start at any given time. If we start ### Caching -Bundles built by the the optimizer include a cache file which describes the information needed to determine if the bundle needs to be rebuilt when the optimizer is restarted. Caching is enabled by default and is very aggressive about invalidating the cache output, but if you need to disable caching you can pass the `--optimize.useBundleCache=false` flag to the dev cli, `--no-cache` to `node scripts/build_new_platform_plugins`, or set the `KBN_OPTIMIZER_NO_CACHE` environment variable to anything (env overrides other settings). +Bundles built by the the optimizer include a cache file which describes the information needed to determine if the bundle needs to be rebuilt when the optimizer is restarted. Caching is enabled by default and is very aggressive about invalidating the cache output, but if you need to disable caching you can pass `--no-cache` to `node scripts/build_new_platform_plugins`, or set the `KBN_OPTIMIZER_NO_CACHE` environment variable to anything (env overrides everything). When a bundle is determined to be up-to-date a worker is not started for the bundle. If running the optimizer with the `--dev/--watch` flag, then all the files referenced by cached bundles are watched for changes. Once a change is detected in any of the files referenced by the built bundle a worker is started. If a file is changed that is referenced by several bundles then workers will be started for each bundle, combining workers together to respect the worker limit. diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index dc3e6c7706d86..5ce5ed772949f 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -46,19 +46,21 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { } if (event?.type === 'worker started') { - log.debug(`worker started for bundles ${event.bundles.map(b => b.id).join(', ')}`); + log.info(`⚙️ worker started for bundles ${event.bundles.map(b => b.id).join(', ')}`); } if (event?.type === 'changes detected') { - log.debug(`changes detected...`); + log.debug(`⚙️ changes detected...`); } if (state.phase === 'initialized') { if (!loggedInit) { loggedInit = true; - log.debug(`initialized after ${state.durSec} sec`); - log.debug(` version: ${state.version}`); - log.debug(` cached: ${state.offlineBundles.map(b => b.id)}`); + log.info( + `⚙️ @kbn/optimizer intialized, ${state.offlineBundles.length} bundles cached` + ); + log.debug(`version: ${state.version}`); + log.debug(`cached: ${state.offlineBundles.map(b => b.id)}`); } return; @@ -73,7 +75,7 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { bundleStates.set(id, type); log.debug( - `[${id}] state = "${type}"${type !== 'running' ? ` after ${state.durSec} sec` : ''}` + `⚙️ [${id}] state = "${type}"${type !== 'running' ? ` after ${state.durSec} sec` : ''}` ); } diff --git a/src/cli/cluster/run_kbn_optimizer.ts b/src/cli/cluster/run_kbn_optimizer.ts index f05701464ac69..e4451331ddaa4 100644 --- a/src/cli/cluster/run_kbn_optimizer.ts +++ b/src/cli/cluster/run_kbn_optimizer.ts @@ -31,7 +31,6 @@ export function runKbnOptimizer(opts: Record, config: LegacyConfig) oss: !!opts.oss, examples: !!opts.runExamples, pluginPaths: config.get('plugins.paths'), - cache: config.get('optimize.useBundleCache') !== false, }); const dim = Chalk.dim('np bld'); From 7c15bc0ab9b5199a8bb70b690b70c8fedee0ae90 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 5 Feb 2020 17:15:26 -0700 Subject: [PATCH 28/83] handle change notifications --- packages/kbn-optimizer/src/log_optimizer_state.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index 5ce5ed772949f..1b9563862ca5c 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -49,8 +49,9 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { log.info(`⚙️ worker started for bundles ${event.bundles.map(b => b.id).join(', ')}`); } - if (event?.type === 'changes detected') { + if (state.phase === 'reallocating') { log.debug(`⚙️ changes detected...`); + return; } if (state.phase === 'initialized') { From 58f4d577e9f512a75f3a3d3f2b3ad39e198a4ad0 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 5 Feb 2020 17:18:01 -0700 Subject: [PATCH 29/83] batch changes for 1 second --- packages/kbn-optimizer/src/watcher.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/kbn-optimizer/src/watcher.ts b/packages/kbn-optimizer/src/watcher.ts index 5d897ec5ed802..064a8d259af3e 100644 --- a/packages/kbn-optimizer/src/watcher.ts +++ b/packages/kbn-optimizer/src/watcher.ts @@ -74,11 +74,11 @@ export class Watcher { ) ), - // debounce and bufffer change events for 100 milliseconds to - // create final change notification + // debounce and bufffer change events for 1 second to create + // final change notification this.change$.pipe( map(event => event[0]), - debounceTimeBuffer(100), + debounceTimeBuffer(1000), map( (changes): Changes => { const changedBundles: Bundle[] = []; From 60800b04885c5cc4e49ec5b6a394f6bf97c1d03e Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 13:14:38 -0700 Subject: [PATCH 30/83] rename CompilerState type to CompilerMsg --- packages/kbn-optimizer/src/common/compiler_messages.ts | 2 +- packages/kbn-optimizer/src/log_optimizer_state.ts | 4 ++-- packages/kbn-optimizer/src/optimizer.ts | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/kbn-optimizer/src/common/compiler_messages.ts b/packages/kbn-optimizer/src/common/compiler_messages.ts index ab65033ea77ad..5f2e9d518bfa6 100644 --- a/packages/kbn-optimizer/src/common/compiler_messages.ts +++ b/packages/kbn-optimizer/src/common/compiler_messages.ts @@ -59,7 +59,7 @@ export interface CompilerSuccessMsg { moduleCount: number; } -export type CompilerState = CompilerRunningMsg | CompilerIssueMsg | CompilerSuccessMsg; +export type CompilerMsg = CompilerRunningMsg | CompilerIssueMsg | CompilerSuccessMsg; export class CompilerMsgs { constructor(private bundle: string) {} diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index 1b9563862ca5c..0b28583ce1f45 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -25,11 +25,11 @@ import { tap } from 'rxjs/operators'; import { OptimizerConfig } from './optimizer_config'; import { OptimizerMsg } from './optimizer'; -import { CompilerState, pipeClosure } from './common'; +import { CompilerMsg, pipeClosure } from './common'; export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { return pipeClosure((msg$: Rx.Observable) => { - const bundleStates = new Map(); + const bundleStates = new Map(); let loggedInit = false; return msg$.pipe( diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index e31062a3e49f7..5048d53e00228 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -26,7 +26,7 @@ import { map, mergeMap, share } from 'rxjs/operators'; import { observeWorker, WorkerStatus } from './observe_worker'; import { OptimizerConfig } from './optimizer_config'; import { getOptimizerVersion } from './get_optimizer_version'; -import { CompilerState, WorkerMsg, pipeClosure, Bundle, ascending, maybeMap } from './common'; +import { CompilerMsg, WorkerMsg, pipeClosure, Bundle, ascending, maybeMap } from './common'; import { assignBundlesToWorkers } from './assign_bundles_to_workers'; import { Watcher, ChangesStarted, Changes } from './watcher'; import { getMtimes } from './get_mtimes'; @@ -41,7 +41,7 @@ export interface OptimizerState { version: string; startTime: number; durSec: number; - compilerStates: CompilerState[]; + compilerStates: CompilerMsg[]; onlineBundles: Bundle[]; offlineBundles: Bundle[]; } @@ -61,7 +61,7 @@ export type OptimizerNotif = OptimizerStartedWorker; const msToSec = (ms: number) => Math.round(ms / 100) / 10; -const getPhase = (states: CompilerState[]): OptimizerState['phase'] => { +const getPhase = (states: CompilerMsg[]): OptimizerState['phase'] => { const types = states.map(s => s.type); if (types.includes('running')) { @@ -279,7 +279,7 @@ export class Optimizer { event.type === 'compiler success' || event.type === 'running' ) { - const compilerStates: CompilerState[] = [ + const compilerStates: CompilerMsg[] = [ ...prevState.compilerStates.filter(c => c.bundleId !== event.bundleId), event, ]; From 442ec85b6b615d966a64626b3f3aa0b81dbb305c Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 13:23:16 -0700 Subject: [PATCH 31/83] getChanges() no longer needs to assign changes to dirs --- packages/kbn-optimizer/package.json | 1 - packages/kbn-optimizer/src/get_changes.ts | 44 ++++--------------- .../src/get_optimizer_version.ts | 9 ++-- yarn.lock | 2 +- 4 files changed, 13 insertions(+), 43 deletions(-) diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json index ab08172553265..b1ce9e8937256 100644 --- a/packages/kbn-optimizer/package.json +++ b/packages/kbn-optimizer/package.json @@ -24,7 +24,6 @@ "css-loader": "^3.4.2", "del": "^5.1.0", "file-loader": "^4.2.0", - "is-path-inside": "^3.0.2", "istanbul-instrumenter-loader": "^3.0.1", "jest-raw-loader": "^1.0.1", "loader-utils": "^1.2.3", diff --git a/packages/kbn-optimizer/src/get_changes.ts b/packages/kbn-optimizer/src/get_changes.ts index c1526e6114ae2..0c03b029c0dc4 100644 --- a/packages/kbn-optimizer/src/get_changes.ts +++ b/packages/kbn-optimizer/src/get_changes.ts @@ -20,40 +20,37 @@ import Path from 'path'; import execa from 'execa'; -import isPathInside from 'is-path-inside'; - -import { descending } from './common'; export type Changes = Map; /** * get the changes in all the context directories (plugin public paths) */ -export async function getChanges(repoRoot: string, dirs: string[]) { - const { stdout } = await execa('git', ['ls-files', '-dmt', '--', ...dirs], { - cwd: repoRoot, +export async function getChanges(dir: string) { + const { stdout } = await execa('git', ['ls-files', '-dmt', '--', dir], { + cwd: dir, }); + const changes: Changes = new Map(); const output = stdout.trim(); - const unassignedChanges: Changes = new Map(); if (output) { for (const line of output.split('\n')) { const [tag, ...pathParts] = line.trim().split(' '); - const path = Path.resolve(repoRoot, pathParts.join(' ')); + const path = Path.resolve(dir, pathParts.join(' ')); switch (tag) { case 'M': case 'C': // for some reason ls-files returns deleted files as both deleted // and modified, so make sure not to overwrite changes already // tracked as "deleted" - if (unassignedChanges.get(path) !== 'deleted') { - unassignedChanges.set(path, 'modified'); + if (changes.get(path) !== 'deleted') { + changes.set(path, 'modified'); } break; case 'R': - unassignedChanges.set(path, 'deleted'); + changes.set(path, 'deleted'); break; default: @@ -62,28 +59,5 @@ export async function getChanges(repoRoot: string, dirs: string[]) { } } - const changesByDir = new Map(); - const dirsBySpecificity = Array.from(dirs).sort(descending(dir => dir.length)); - - for (const dir of dirsBySpecificity) { - const ownChanges: Changes = new Map(); - for (const [path, type] of unassignedChanges) { - if (isPathInside(path, dir)) { - ownChanges.set(path, type); - unassignedChanges.delete(path); - } - } - - changesByDir.set(dir, ownChanges); - } - - if (unassignedChanges.size) { - throw new Error( - `unable to assign all change paths to a project: ${JSON.stringify( - Array.from(unassignedChanges.entries()) - )}` - ); - } - - return changesByDir; + return changes; } diff --git a/packages/kbn-optimizer/src/get_optimizer_version.ts b/packages/kbn-optimizer/src/get_optimizer_version.ts index f60bff1cee492..66dbc3124781c 100644 --- a/packages/kbn-optimizer/src/get_optimizer_version.ts +++ b/packages/kbn-optimizer/src/get_optimizer_version.ts @@ -47,12 +47,9 @@ export async function getOptimizerVersion(config: OptimizerConfig) { `workerConfig:${JSON.stringify(config.getWorkerConfig('-'))}`, ]; - const changes = (await getChanges(REPO_ROOT, [OPTIMIZER_DIR])).get(OPTIMIZER_DIR); - if (changes) { - const mtimes = await getMtimes(changes.keys()); - for (const [path, mtime] of mtimes) { - cacheLines.push(`mtime:${path}:${mtime}`); - } + const mtimes = await getMtimes((await getChanges(OPTIMIZER_DIR)).keys()); + for (const [path, mtime] of mtimes) { + cacheLines.push(`mtime:${path}:${mtime}`); } return createHash('sha1') diff --git a/yarn.lock b/yarn.lock index 34852ee049e2d..8d91de2133cf5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17405,7 +17405,7 @@ is-path-inside@^2.1.0: dependencies: path-is-inside "^1.0.2" -is-path-inside@^3.0.1, is-path-inside@^3.0.2: +is-path-inside@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== From af9c89a6873b10bfb19cefc82d17a93f72393a9d Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 13:23:58 -0700 Subject: [PATCH 32/83] remove unused deps --- packages/kbn-optimizer/package.json | 3 --- yarn.lock | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json index b1ce9e8937256..4e113eb90405a 100644 --- a/packages/kbn-optimizer/package.json +++ b/packages/kbn-optimizer/package.json @@ -25,19 +25,16 @@ "del": "^5.1.0", "file-loader": "^4.2.0", "istanbul-instrumenter-loader": "^3.0.1", - "jest-raw-loader": "^1.0.1", "loader-utils": "^1.2.3", "node-sass": "^4.13.0", "postcss-loader": "^3.0.0", "raw-loader": "^3.1.0", "rxjs": "^6.5.3", "sass-loader": "^8.0.2", - "script-loader": "^0.7.2", "style-loader": "^1.1.3", "terser-webpack-plugin": "^2.1.2", "tinymath": "1.2.1", "url-loader": "^2.2.0", - "val-loader": "^1.1.1", "watchpack": "^1.6.0", "webpack": "^4.41.5", "webpack-merge": "^4.2.2" diff --git a/yarn.lock b/yarn.lock index 8d91de2133cf5..b0ee84c7680d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -26485,7 +26485,7 @@ screenfull@^5.0.0: resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.0.0.tgz#5c2010c0e84fd4157bf852877698f90b8cbe96f6" integrity sha512-yShzhaIoE9OtOhWVyBBffA6V98CDCoyHTsp8228blmqYy1Z5bddzE/4FPiJKlr8DVR4VBiiUyfPzIQPIYDkeMA== -script-loader@0.7.2, script-loader@^0.7.2: +script-loader@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/script-loader/-/script-loader-0.7.2.tgz#2016db6f86f25f5cf56da38915d83378bb166ba7" integrity sha512-UMNLEvgOAQuzK8ji8qIscM3GIrRCWN6MmMXGD4SD5l6cSycgGsCo0tX5xRnfQcoghqct0tjHjcykgI1PyBE2aA== From 37c5c0dfde13b95f8e744e4cc9635e4545b42d1b Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 13:24:46 -0700 Subject: [PATCH 33/83] split up run_worker.ts and share cacheKey generation logic --- packages/kbn-optimizer/src/common/bundle.ts | 18 +- packages/kbn-optimizer/src/optimizer.ts | 13 +- .../kbn-optimizer/src/worker/run_compilers.ts | 210 ++++++++++++++++ .../kbn-optimizer/src/worker/run_worker.ts | 234 +++--------------- 4 files changed, 255 insertions(+), 220 deletions(-) create mode 100644 packages/kbn-optimizer/src/worker/run_compilers.ts diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts index c39af73bd7206..4a28a2578af3a 100644 --- a/packages/kbn-optimizer/src/common/bundle.ts +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -18,10 +18,11 @@ */ import Path from 'path'; +import { createHash } from 'crypto'; import { BundleCache } from './bundle_cache'; import { UnknownVals } from './ts_helpers'; -import { includes } from './array_helpers'; +import { includes, ascending } from './array_helpers'; export const VALID_BUNDLE_TYPES = ['plugin' as const]; @@ -105,10 +106,23 @@ export class Bundle { this.cache = new BundleCache(Path.resolve(this.outputDir, '.kbn-optimizer-cache')); } - public getModuleCount() { + getModuleCount() { return this.cache.getModuleCount(); } + createCacheKey(mtimes: Map) { + return createHash('sha1') + .update( + [ + `bundleSpec:${JSON.stringify(this.toSpec())}`, + ...(this.cache.getReferencedFiles() || []).map(p => `${p}:${mtimes.get(p)}`), + ] + .sort(ascending(l => l)) + .join('\n') + ) + .digest('hex'); + } + toSpec(): BundleSpec { return { type: this.type, diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index 5048d53e00228..78c972b69a6c4 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -102,18 +102,7 @@ export class Optimizer { ) ); - return eligible.filter(bundle => { - const cacheKey = createHash('sha1') - .update( - (bundle.cache.getReferencedFiles() || []) - .map(p => `${p}:${mtimes.get(p)}`) - .sort(ascending(l => l)) - .join('\n') - ) - .digest('hex'); - - return cacheKey === bundle.cache.getKey(); - }); + return eligible.filter(bundle => bundle.createCacheKey(mtimes) === bundle.cache.getKey()); } /** diff --git a/packages/kbn-optimizer/src/worker/run_compilers.ts b/packages/kbn-optimizer/src/worker/run_compilers.ts new file mode 100644 index 0000000000000..cef88160330c7 --- /dev/null +++ b/packages/kbn-optimizer/src/worker/run_compilers.ts @@ -0,0 +1,210 @@ +/* + * 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 'source-map-support/register'; + +import Fs from 'fs'; +import Path from 'path'; +import { inspect } from 'util'; +import { createHash } from 'crypto'; + +import webpack, { Stats } from 'webpack'; +import * as Rx from 'rxjs'; +import { mergeMap, map, mapTo, takeUntil } from 'rxjs/operators'; + +import { CompilerMsgs, CompilerMsg, maybeMap, Bundle, WorkerConfig, ascending } from '../common'; +import { getWebpackConfig } from './webpack.config'; +import { isFailureStats, failedStatsToErrorMessage } from './webpack_helpers'; +import { + isExternalModule, + isNormalModule, + isIgnoredModule, + isConcatenatedModule, + WebpackNormalModule, + getModulePath, +} from './webpack_helpers'; + +const PLUGIN_NAME = '@kbn/optimizer'; + +/** + * Create an Observable for a specific child compiler + bundle + */ +const observeCompiler = ( + workerConfig: WorkerConfig, + bundle: Bundle, + compiler: webpack.Compiler +): Rx.Observable => { + const compilerMsgs = new CompilerMsgs(bundle.id); + const done$ = new Rx.Subject(); + const { beforeRun, watchRun, done } = compiler.hooks; + + /** + * Called by webpack as a single run compilation is starting + */ + const started$ = Rx.merge( + Rx.fromEventPattern(cb => beforeRun.tap(PLUGIN_NAME, cb)), + Rx.fromEventPattern(cb => watchRun.tap(PLUGIN_NAME, cb)) + ).pipe(mapTo(compilerMsgs.running())); + + /** + * Called by webpack as any compilation is complete. If the + * needAdditionalPass property is set then another compilation + * is about to be started, so we shouldn't send complete quite yet + */ + const complete$ = Rx.fromEventPattern(cb => done.tap(PLUGIN_NAME, cb)).pipe( + maybeMap(stats => { + // @ts-ignore not included in types, but it is real https://github.com/webpack/webpack/blob/ab4fa8ddb3f433d286653cd6af7e3aad51168649/lib/Watching.js#L58 + if (stats.compilation.needAdditionalPass) { + return undefined; + } + + if (workerConfig.profileWebpack) { + Fs.writeFileSync( + Path.resolve(bundle.outputDir, 'stats.json'), + JSON.stringify(stats.toJson()) + ); + } + + if (!workerConfig.watch) { + process.nextTick(() => done$.next()); + } + + if (isFailureStats(stats)) { + return compilerMsgs.compilerFailure({ + failure: failedStatsToErrorMessage(stats), + }); + } + + const normalModules = stats.compilation.modules.filter( + (module): module is WebpackNormalModule => { + if (isNormalModule(module)) { + return true; + } + + if (isExternalModule(module) || isIgnoredModule(module) || isConcatenatedModule(module)) { + return false; + } + + throw new Error(`Unexpected module type: ${inspect(module)}`); + } + ); + + const referencedFiles = new Set(); + + for (const module of normalModules) { + const path = getModulePath(module); + + const parsedPath = Path.parse(path); + const dirSegments = parsedPath.dir.split(Path.sep); + if (!dirSegments.includes('node_modules')) { + referencedFiles.add(path); + continue; + } + + const nmIndex = dirSegments.lastIndexOf('node_modules'); + const isScoped = dirSegments[nmIndex + 1].startsWith('@'); + referencedFiles.add( + Path.join( + parsedPath.root, + ...dirSegments.slice(0, nmIndex + 1 + (isScoped ? 2 : 1)), + 'package.json' + ) + ); + } + + const mtimes = new Map( + Array.from(referencedFiles).map((path): [string, number | undefined] => { + try { + return [path, compiler.inputFileSystem.statSync(path)?.mtime]; + } catch (error) { + if (error?.code === 'ENOENT') { + return [path, undefined]; + } + + throw error; + } + }) + ); + + bundle.cache.set({ + optimizerVersion: workerConfig.optimizerVersion, + key: bundle.createCacheKey(mtimes), + moduleCount: normalModules.length, + files: Array.from(referencedFiles), + }); + + return compilerMsgs.compilerSuccess({ + moduleCount: normalModules.length, + }); + }) + ); + + /** + * Called whenever the compilation results in an error that + * prevets assets from being emitted, and prevents watching + * from continuing. + */ + const error$ = Rx.fromEventPattern(cb => compiler.hooks.failed.tap(PLUGIN_NAME, cb)).pipe( + map(error => { + throw compilerMsgs.error(error); + }) + ); + + /** + * Merge events into a single stream, if we're not watching + * complete the stream after our first complete$ event + */ + return Rx.merge(started$, complete$, error$).pipe(takeUntil(done$)); +}; + +/** + * Run webpack compilers + */ +export const runCompilers = (workerConfig: WorkerConfig, bundles: Bundle[]) => { + const multiCompiler = webpack(bundles.map(def => getWebpackConfig(def, workerConfig))); + + return Rx.merge( + /** + * convert each compiler into an event stream that represents + * the status of each compiler, if we aren't watching the streams + * will complete after the compilers are complete. + * + * If a significant error occurs the stream will error + */ + Rx.from(multiCompiler.compilers.entries()).pipe( + mergeMap(([compilerIndex, compiler]) => { + const bundle = bundles[compilerIndex]; + return observeCompiler(workerConfig, bundle, compiler); + }) + ), + + /** + * compilers have been hooked up for their events, trigger run()/watch() + */ + Rx.defer(() => { + if (!workerConfig.watch) { + multiCompiler.run(() => {}); + } else { + multiCompiler.watch({}, () => {}); + } + + return []; + }) + ); +}; diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts index 4b1fe33ace14b..f6cf37d3514a6 100644 --- a/packages/kbn-optimizer/src/worker/run_worker.ts +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -17,42 +17,24 @@ * under the License. */ -import 'source-map-support/register'; - -import Fs from 'fs'; -import Path from 'path'; -import { inspect } from 'util'; -import { createHash } from 'crypto'; - -import webpack, { Stats } from 'webpack'; import * as Rx from 'rxjs'; -import { mergeMap, map, mapTo, takeUntil } from 'rxjs/operators'; +import { mergeMap } from 'rxjs/operators'; -import { - CompilerMsgs, - WorkerMsgs, - maybeMap, - parseWorkerConfig, - Bundle, - parseBundles, - WorkerConfig, - isWorkerMsg, - WorkerMsg, - ascending, -} from '../common'; -import { getWebpackConfig } from './webpack.config'; -import { isFailureStats, failedStatsToErrorMessage } from './webpack_helpers'; -import { - isExternalModule, - isNormalModule, - isIgnoredModule, - isConcatenatedModule, - WebpackNormalModule, - getModulePath, -} from './webpack_helpers'; +import { parseBundles, parseWorkerConfig, WorkerMsg, isWorkerMsg, WorkerMsgs } from '../common'; +import { runCompilers } from './run_compilers'; + +/** + ** + ** + ** Entry file for optimizer workers, this hooks into the process, handles + ** sending messages to the parent, makes sure the worker exits properly + ** and triggers all the compilers by calling runCompilers() + ** + ** + **/ -const PLUGIN_NAME = '@kbn/optimizer'; const workerMsgs = new WorkerMsgs(); + if (!process.send) { throw new Error('worker process was not started with an IPC channel'); } @@ -66,179 +48,10 @@ const send = (msg: WorkerMsg) => { } }; -// check for connected parent on an unref'd timer rather than listening -// to "disconnect" since that listner prevents the process from exiting -setInterval(() => { - if (!process.connected) { - // parent is gone - process.exit(0); - } -}, 1000).unref(); - -const runWorker = (workerConfig: WorkerConfig, bundles: Bundle[]) => { - const multiCompiler = webpack(bundles.map(def => getWebpackConfig(def, workerConfig))); - - return Rx.merge( - /** - * convert each compiler into an event stream that represents - * the status of each compiler, if we aren't watching the streams - * will complete after the compilers are complete. - * - * If a significant error occurs the stream will error - */ - Rx.from(multiCompiler.compilers.entries()).pipe( - mergeMap(([compilerIndex, compiler]) => { - const bundle = bundles[compilerIndex]; - return observeCompiler(workerConfig, bundle, compiler); - }) - ), - - /** - * compilers have been hooked up for their events, trigger run()/watch() - */ - Rx.defer(() => { - if (!workerConfig.watch) { - multiCompiler.run(() => {}); - } else { - multiCompiler.watch({}, () => {}); - } - - return []; - }) - ); -}; - -const observeCompiler = ( - workerConfig: WorkerConfig, - bundle: Bundle, - compiler: webpack.Compiler -) => { - const compilerMsgs = new CompilerMsgs(bundle.id); - const done$ = new Rx.Subject(); - const { beforeRun, watchRun, done } = compiler.hooks; - - /** - * Called by webpack as a single run compilation is starting - */ - const started$ = Rx.merge( - Rx.fromEventPattern(cb => beforeRun.tap(PLUGIN_NAME, cb)), - Rx.fromEventPattern(cb => watchRun.tap(PLUGIN_NAME, cb)) - ).pipe(mapTo(compilerMsgs.running())); - - /** - * Called by webpack as any compilation is complete. If the - * needAdditionalPass property is set then another compilation - * is about to be started, so we shouldn't send complete quite yet - */ - const complete$ = Rx.fromEventPattern(cb => done.tap(PLUGIN_NAME, cb)).pipe( - maybeMap(stats => { - // @ts-ignore not included in types, but it is real https://github.com/webpack/webpack/blob/ab4fa8ddb3f433d286653cd6af7e3aad51168649/lib/Watching.js#L58 - if (stats.compilation.needAdditionalPass) { - return undefined; - } - - if (workerConfig.profileWebpack) { - Fs.writeFileSync( - Path.resolve(bundle.outputDir, 'stats.json'), - JSON.stringify(stats.toJson()) - ); - } - - if (!workerConfig.watch) { - process.nextTick(() => done$.next()); - } - - if (isFailureStats(stats)) { - return compilerMsgs.compilerFailure({ - failure: failedStatsToErrorMessage(stats), - }); - } - - const normalModules = stats.compilation.modules.filter( - (module): module is WebpackNormalModule => { - if (isNormalModule(module)) { - return true; - } - - if (isExternalModule(module) || isIgnoredModule(module) || isConcatenatedModule(module)) { - return false; - } - - throw new Error(`Unexpected module type: ${inspect(module)}`); - } - ); - - const referencedFiles = new Set(); - - for (const module of normalModules) { - const path = getModulePath(module); - - const parsedPath = Path.parse(path); - const dirSegments = parsedPath.dir.split(Path.sep); - if (!dirSegments.includes('node_modules')) { - referencedFiles.add(path); - continue; - } - - const nmIndex = dirSegments.lastIndexOf('node_modules'); - const isScoped = dirSegments[nmIndex + 1].startsWith('@'); - referencedFiles.add( - Path.join( - parsedPath.root, - ...dirSegments.slice(0, nmIndex + 1 + (isScoped ? 2 : 1)), - 'package.json' - ) - ); - } - - const hashLines: string[] = []; - for (const file of referencedFiles) { - try { - // don't worry, these are cached by webpack - const stat = compiler.inputFileSystem.statSync(file); - hashLines.push(`${file}:${stat.mtimeMs}`); - } catch (error) { - if (error?.code === 'ENOENT') { - hashLines.push(`${file}:${undefined}`); - } else { - throw error; - } - } - } - - bundle.cache.set({ - optimizerVersion: workerConfig.optimizerVersion, - key: createHash('sha1') - .update(hashLines.sort(ascending(l => l)).join('\n')) - .digest('hex'), - moduleCount: normalModules.length, - files: Array.from(referencedFiles), - }); - - return compilerMsgs.compilerSuccess({ - moduleCount: normalModules.length, - }); - }) - ); - - /** - * Called whenever the compilation results in an error that - * prevets assets from being emitted, and prevents watching - * from continuing. - */ - const error$ = Rx.fromEventPattern(cb => compiler.hooks.failed.tap(PLUGIN_NAME, cb)).pipe( - map(error => { - throw compilerMsgs.error(error); - }) - ); - - /** - * Merge events into a single stream, if we're not watching - * complete the stream after our first complete$ event - */ - return Rx.merge(started$, complete$, error$).pipe(takeUntil(done$)); -}; - +/** + * set the exitCode and wait for the process to exit, if it + * doesn't exit naturally do so forcibly and fail. + */ const exit = (code: number) => { process.exitCode = code; setTimeout(() => { @@ -251,13 +64,22 @@ const exit = (code: number) => { }, 5000).unref(); }; +// check for connected parent on an unref'd timer rather than listening +// to "disconnect" since that listner prevents the process from exiting +setInterval(() => { + if (!process.connected) { + // parent is gone + process.exit(0); + } +}, 1000).unref(); + Rx.defer(() => { return Rx.of({ workerConfig: parseWorkerConfig(process.argv[2]), bundles: parseBundles(process.argv[3]), }); }) - .pipe(mergeMap(({ workerConfig, bundles }) => runWorker(workerConfig, bundles))) + .pipe(mergeMap(({ workerConfig, bundles }) => runCompilers(workerConfig, bundles))) .subscribe( msg => { send(msg); From 2395ee12b5ec8a0c082885502ebe2f4cb82b9132 Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 13:28:11 -0700 Subject: [PATCH 34/83] add a couple docs --- packages/kbn-optimizer/src/common/bundle.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts index 4a28a2578af3a..d546deb05069e 100644 --- a/packages/kbn-optimizer/src/common/bundle.ts +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -110,6 +110,12 @@ export class Bundle { return this.cache.getModuleCount(); } + /** + * Calculate the cache key for this bundle based from current + * mtime values. + * + * @param mtimes pre-fetched mtimes (ms || undefined) for all referenced files + */ createCacheKey(mtimes: Map) { return createHash('sha1') .update( @@ -123,6 +129,11 @@ export class Bundle { .digest('hex'); } + /** + * Get the raw "specification" for the bundle, this object is JSON serialized + * in the cache key, passed to worker processes so they know what bundles + * to build, and passed to the Bundle constructor to rebuild the Bundle object. + */ toSpec(): BundleSpec { return { type: this.type, @@ -135,6 +146,10 @@ export class Bundle { } } +/** + * Parse a JSON string containing an array of BundleSpec objects into an array + * of Bundle objects, validating everything. + */ export function parseBundles(json: string) { try { if (typeof json !== 'string') { From 4e34191100c6d7aab2d37e86aa886c78695f08a3 Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 13:31:46 -0700 Subject: [PATCH 35/83] update tests and remove unused imports --- .../kbn-optimizer/src/get_changes.test.ts | 39 ++++++++----------- packages/kbn-optimizer/src/optimizer.ts | 3 +- .../kbn-optimizer/src/worker/run_compilers.ts | 3 +- 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/packages/kbn-optimizer/src/get_changes.test.ts b/packages/kbn-optimizer/src/get_changes.test.ts index 65b4205ba6386..04a6dfb3e3625 100644 --- a/packages/kbn-optimizer/src/get_changes.test.ts +++ b/packages/kbn-optimizer/src/get_changes.test.ts @@ -28,36 +28,29 @@ it('parses git ls-files output', async () => { execa.mockImplementation((cmd, args, options) => { expect(cmd).toBe('git'); - expect(args).toEqual(['ls-files', '-dmt', '--', '/foo/bar/x', '/foo/bar/y']); + expect(args).toEqual(['ls-files', '-dmt', '--', '/foo/bar/x']); expect(options).toEqual({ - cwd: '/foo/bar', + cwd: '/foo/bar/x', }); return { stdout: [ - 'C x/kbn-optimizer/package.json', - 'C x/kbn-optimizer/src/common/bundle.ts', - 'R x/kbn-optimizer/src/common/bundles.ts', - 'C x/kbn-optimizer/src/common/bundles.ts', - 'R x/kbn-optimizer/src/get_bundle_definitions.test.ts', - 'C x/kbn-optimizer/src/get_bundle_definitions.test.ts', - 'C y/src/plugins/data/public/index.ts', + 'C kbn-optimizer/package.json', + 'C kbn-optimizer/src/common/bundle.ts', + 'R kbn-optimizer/src/common/bundles.ts', + 'C kbn-optimizer/src/common/bundles.ts', + 'R kbn-optimizer/src/get_bundle_definitions.test.ts', + 'C kbn-optimizer/src/get_bundle_definitions.test.ts', ].join('\n'), }; }); - await expect(getChanges('/foo/bar', ['/foo/bar/x', '/foo/bar/y'])).resolves - .toMatchInlineSnapshot(` - Map { - "/foo/bar/x" => Map { - "/foo/bar/x/kbn-optimizer/package.json" => "modified", - "/foo/bar/x/kbn-optimizer/src/common/bundle.ts" => "modified", - "/foo/bar/x/kbn-optimizer/src/common/bundles.ts" => "deleted", - "/foo/bar/x/kbn-optimizer/src/get_bundle_definitions.test.ts" => "deleted", - }, - "/foo/bar/y" => Map { - "/foo/bar/y/src/plugins/data/public/index.ts" => "modified", - }, - } - `); + await expect(getChanges('/foo/bar/x')).resolves.toMatchInlineSnapshot(` + Map { + "/foo/bar/x/kbn-optimizer/package.json" => "modified", + "/foo/bar/x/kbn-optimizer/src/common/bundle.ts" => "modified", + "/foo/bar/x/kbn-optimizer/src/common/bundles.ts" => "deleted", + "/foo/bar/x/kbn-optimizer/src/get_bundle_definitions.test.ts" => "deleted", + } + `); }); diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index 78c972b69a6c4..a2cef5fe92b8e 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -17,7 +17,6 @@ * under the License. */ -import { createHash } from 'crypto'; import { inspect } from 'util'; import * as Rx from 'rxjs'; @@ -26,7 +25,7 @@ import { map, mergeMap, share } from 'rxjs/operators'; import { observeWorker, WorkerStatus } from './observe_worker'; import { OptimizerConfig } from './optimizer_config'; import { getOptimizerVersion } from './get_optimizer_version'; -import { CompilerMsg, WorkerMsg, pipeClosure, Bundle, ascending, maybeMap } from './common'; +import { CompilerMsg, WorkerMsg, pipeClosure, Bundle, maybeMap } from './common'; import { assignBundlesToWorkers } from './assign_bundles_to_workers'; import { Watcher, ChangesStarted, Changes } from './watcher'; import { getMtimes } from './get_mtimes'; diff --git a/packages/kbn-optimizer/src/worker/run_compilers.ts b/packages/kbn-optimizer/src/worker/run_compilers.ts index cef88160330c7..2af355b76d673 100644 --- a/packages/kbn-optimizer/src/worker/run_compilers.ts +++ b/packages/kbn-optimizer/src/worker/run_compilers.ts @@ -22,13 +22,12 @@ import 'source-map-support/register'; import Fs from 'fs'; import Path from 'path'; import { inspect } from 'util'; -import { createHash } from 'crypto'; import webpack, { Stats } from 'webpack'; import * as Rx from 'rxjs'; import { mergeMap, map, mapTo, takeUntil } from 'rxjs/operators'; -import { CompilerMsgs, CompilerMsg, maybeMap, Bundle, WorkerConfig, ascending } from '../common'; +import { CompilerMsgs, CompilerMsg, maybeMap, Bundle, WorkerConfig } from '../common'; import { getWebpackConfig } from './webpack.config'; import { isFailureStats, failedStatsToErrorMessage } from './webpack_helpers'; import { From 610f65fb912a8fdde42629ad5fa44e21fb27e706 Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 13:49:07 -0700 Subject: [PATCH 36/83] specify files when creating bundle cache key --- packages/kbn-optimizer/src/common/bundle.ts | 18 +++++++----------- packages/kbn-optimizer/src/optimizer.ts | 6 +++++- .../kbn-optimizer/src/worker/run_compilers.ts | 9 +++++---- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts index d546deb05069e..3c6bf31808d04 100644 --- a/packages/kbn-optimizer/src/common/bundle.ts +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -116,17 +116,13 @@ export class Bundle { * * @param mtimes pre-fetched mtimes (ms || undefined) for all referenced files */ - createCacheKey(mtimes: Map) { - return createHash('sha1') - .update( - [ - `bundleSpec:${JSON.stringify(this.toSpec())}`, - ...(this.cache.getReferencedFiles() || []).map(p => `${p}:${mtimes.get(p)}`), - ] - .sort(ascending(l => l)) - .join('\n') - ) - .digest('hex'); + createCacheKey(files: string[], mtimes: Map) { + return [ + `bundleSpec:${JSON.stringify(this.toSpec())}`, + ...files.map(p => `path:${p}:${mtimes.get(p)}`), + ] + .sort(ascending(l => l)) + .join('\n'); } /** diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index a2cef5fe92b8e..13a64e632f9a5 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -101,7 +101,11 @@ export class Optimizer { ) ); - return eligible.filter(bundle => bundle.createCacheKey(mtimes) === bundle.cache.getKey()); + return eligible.filter( + bundle => + bundle.cache.getKey() === + bundle.createCacheKey(bundle.cache.getReferencedFiles() || [], mtimes) + ); } /** diff --git a/packages/kbn-optimizer/src/worker/run_compilers.ts b/packages/kbn-optimizer/src/worker/run_compilers.ts index 2af355b76d673..8af5cee03d70a 100644 --- a/packages/kbn-optimizer/src/worker/run_compilers.ts +++ b/packages/kbn-optimizer/src/worker/run_compilers.ts @@ -127,10 +127,11 @@ const observeCompiler = ( ); } + const files = Array.from(referencedFiles); const mtimes = new Map( - Array.from(referencedFiles).map((path): [string, number | undefined] => { + files.map((path): [string, number | undefined] => { try { - return [path, compiler.inputFileSystem.statSync(path)?.mtime]; + return [path, compiler.inputFileSystem.statSync(path)?.mtimeMs]; } catch (error) { if (error?.code === 'ENOENT') { return [path, undefined]; @@ -143,9 +144,9 @@ const observeCompiler = ( bundle.cache.set({ optimizerVersion: workerConfig.optimizerVersion, - key: bundle.createCacheKey(mtimes), + key: bundle.createCacheKey(files, mtimes), moduleCount: normalModules.length, - files: Array.from(referencedFiles), + files, }); return compilerMsgs.compilerSuccess({ From 943bdcda727f7404227063cde10e5a6f21b8a83b Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 14:50:34 -0700 Subject: [PATCH 37/83] remove one more unused import --- packages/kbn-optimizer/src/common/bundle.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts index 3c6bf31808d04..f183dd26de28b 100644 --- a/packages/kbn-optimizer/src/common/bundle.ts +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -18,7 +18,6 @@ */ import Path from 'path'; -import { createHash } from 'crypto'; import { BundleCache } from './bundle_cache'; import { UnknownVals } from './ts_helpers'; From 2eb2cd48b1dc1fdeb1c6c70042aa7a2ba51f5b4c Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 16:48:12 -0700 Subject: [PATCH 38/83] match existing dev cli output more closely --- packages/kbn-dev-utils/src/index.ts | 7 +-- .../kbn-dev-utils/src/tooling_log/index.ts | 2 +- .../tooling_log/tooling_log_text_writer.ts | 24 +++++---- .../kbn-optimizer/src/log_optimizer_state.ts | 18 +++---- packages/kbn-optimizer/src/optimizer.ts | 2 +- src/cli/cluster/run_kbn_optimizer.ts | 49 ++++++++++++++----- 6 files changed, 62 insertions(+), 40 deletions(-) diff --git a/packages/kbn-dev-utils/src/index.ts b/packages/kbn-dev-utils/src/index.ts index 714ed56ac4703..305e29a0e41df 100644 --- a/packages/kbn-dev-utils/src/index.ts +++ b/packages/kbn-dev-utils/src/index.ts @@ -18,12 +18,7 @@ */ export { withProcRunner, ProcRunner } from './proc_runner'; -export { - ToolingLog, - ToolingLogTextWriter, - pickLevelFromFlags, - ToolingLogCollectingWriter, -} from './tooling_log'; +export * from './tooling_log'; export { createAbsolutePathSerializer } from './serializers'; export { CA_CERT_PATH, diff --git a/packages/kbn-dev-utils/src/tooling_log/index.ts b/packages/kbn-dev-utils/src/tooling_log/index.ts index 1f5afac26d561..f8009a255f010 100644 --- a/packages/kbn-dev-utils/src/tooling_log/index.ts +++ b/packages/kbn-dev-utils/src/tooling_log/index.ts @@ -19,5 +19,5 @@ export { ToolingLog } from './tooling_log'; export { ToolingLogTextWriter, ToolingLogTextWriterConfig } from './tooling_log_text_writer'; -export { pickLevelFromFlags, LogLevel } from './log_levels'; +export { pickLevelFromFlags, parseLogLevel, LogLevel } from './log_levels'; export { ToolingLogCollectingWriter } from './tooling_log_collecting_writer'; diff --git a/packages/kbn-dev-utils/src/tooling_log/tooling_log_text_writer.ts b/packages/kbn-dev-utils/src/tooling_log/tooling_log_text_writer.ts index 65b625de9f308..b8c12433a0ebb 100644 --- a/packages/kbn-dev-utils/src/tooling_log/tooling_log_text_writer.ts +++ b/packages/kbn-dev-utils/src/tooling_log/tooling_log_text_writer.ts @@ -82,20 +82,28 @@ export class ToolingLogTextWriter implements Writer { } } - write({ type, indent, args }: Message) { - if (!shouldWriteType(this.level, type)) { + write(msg: Message) { + if (!shouldWriteType(this.level, msg.type)) { return false; } - const txt = type === 'error' ? stringifyError(args[0]) : format(args[0], ...args.slice(1)); - const prefix = has(MSG_PREFIXES, type) ? MSG_PREFIXES[type] : ''; + const prefix = has(MSG_PREFIXES, msg.type) ? MSG_PREFIXES[msg.type] : ''; + ToolingLogTextWriter.write(this.writeTo, prefix, msg); + return true; + } + + static write(writeTo: ToolingLogTextWriter['writeTo'], prefix: string, msg: Message) { + const txt = + msg.type === 'error' + ? stringifyError(msg.args[0]) + : format(msg.args[0], ...msg.args.slice(1)); (prefix + txt).split('\n').forEach((line, i) => { let lineIndent = ''; - if (indent > 0) { + if (msg.indent > 0) { // if we are indenting write some spaces followed by a symbol - lineIndent += ' '.repeat(indent - 1); + lineIndent += ' '.repeat(msg.indent - 1); lineIndent += line.startsWith('-') ? '└' : '│'; } @@ -105,9 +113,7 @@ export class ToolingLogTextWriter implements Writer { lineIndent += PREFIX_INDENT; } - this.writeTo.write(`${lineIndent}${line}\n`); + writeTo.write(`${lineIndent}${line}\n`); }); - - return true; } } diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index 0b28583ce1f45..38675982ffa03 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -39,27 +39,25 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { if (event?.type === 'worker stdio') { const chunk = event.chunk.toString('utf8'); log.warning( - '⚙️ worker', + `worker`, event.stream, chunk.slice(0, chunk.length - (chunk.endsWith('\n') ? 1 : 0)) ); } if (event?.type === 'worker started') { - log.info(`⚙️ worker started for bundles ${event.bundles.map(b => b.id).join(', ')}`); + log.info(`worker started for bundles ${event.bundles.map(b => b.id).join(', ')}`); } if (state.phase === 'reallocating') { - log.debug(`⚙️ changes detected...`); + log.debug(`changes detected...`); return; } if (state.phase === 'initialized') { if (!loggedInit) { loggedInit = true; - log.info( - `⚙️ @kbn/optimizer intialized, ${state.offlineBundles.length} bundles cached` - ); + log.info(`intialized, ${state.offlineBundles.length} bundles cached`); log.debug(`version: ${state.version}`); log.debug(`cached: ${state.offlineBundles.map(b => b.id)}`); } @@ -76,7 +74,7 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { bundleStates.set(id, type); log.debug( - `⚙️ [${id}] state = "${type}"${type !== 'running' ? ` after ${state.durSec} sec` : ''}` + `[${id}] state = "${type}"${type !== 'running' ? ` after ${state.durSec} sec` : ''}` ); } @@ -85,7 +83,7 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { } if (state.phase === 'issue') { - log.error('⚙️ webpack compile errors'); + log.error(`webpack compile errors`); log.indent(4); for (const b of state.compilerStates) { if (b.type === 'compiler issue') { @@ -102,8 +100,8 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { if (state.phase === 'success') { log.success( config.watch - ? `⚙️ watching for changes in all bundles after ${state.durSec} sec` - : `⚙️ all bundles compiled successfully after ${state.durSec} sec` + ? `watching for changes in all bundles after ${state.durSec} sec` + : `all bundles compiled successfully after ${state.durSec} sec` ); return true; } diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index 13a64e632f9a5..e5631a7764690 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -205,7 +205,7 @@ export class Optimizer { // reset start time if we are transitioning into running const startTime = (prevState.phase === 'success' || prevState.phase === 'issue') && - stateChanges?.phase === 'running' + (stateChanges?.phase === 'running' || stateChanges?.phase === 'reallocating') ? Date.now() : prevState.startTime; diff --git a/src/cli/cluster/run_kbn_optimizer.ts b/src/cli/cluster/run_kbn_optimizer.ts index e4451331ddaa4..f03861b671dd5 100644 --- a/src/cli/cluster/run_kbn_optimizer.ts +++ b/src/cli/cluster/run_kbn_optimizer.ts @@ -19,7 +19,13 @@ import Chalk from 'chalk'; import moment from 'moment'; -import { ToolingLog, pickLevelFromFlags, REPO_ROOT } from '@kbn/dev-utils'; +import { + ToolingLog, + pickLevelFromFlags, + ToolingLogTextWriter, + parseLogLevel, + REPO_ROOT, +} from '@kbn/dev-utils'; import { OptimizerConfig, Optimizer, logOptimizerState } from '@kbn/optimizer'; import { LegacyConfig } from '../../core/server/legacy'; @@ -34,23 +40,40 @@ export function runKbnOptimizer(opts: Record, config: LegacyConfig) }); const dim = Chalk.dim('np bld'); + const name = Chalk.magentaBright('@kbn/optimizer'); const time = () => moment().format('HH:mm:ss.SSS'); - const toolingLog = new ToolingLog({ - level: pickLevelFromFlags(opts), - writeTo: { - write: chunk => { - const trailingNewLine = chunk[chunk.length - 1] === '\n'; + const level = (msgType: string) => { + switch (msgType) { + case 'info': + return Chalk.green(msgType); + case 'success': + return Chalk.cyan(msgType); + case 'debug': + return Chalk.gray(msgType); + default: + return msgType; + } + }; + const { flags: levelFlags } = parseLogLevel(pickLevelFromFlags(opts)); + const toolingLog = new ToolingLog(); + const has = (obj: T, x: any): x is keyof T => obj.hasOwnProperty(x); - process.stdout.write( - chunk - .slice(0, chunk.length - (trailingNewLine ? 1 : 0)) - .split('\n') - .map(line => `${dim} log [${time()}] ${line}`) - .join('\n') + (trailingNewLine ? '\n' : '') + toolingLog.setWriters([ + { + write(msg) { + if (has(levelFlags, msg.type) && !levelFlags[msg.type]) { + return false; + } + + ToolingLogTextWriter.write( + process.stdout, + `${dim} log [${time()}] [${level(msg.type)}][${name}] `, + msg ); + return true; }, }, - }); + ]); const optimizer = new Optimizer(optimizerConfig); return optimizer.run().pipe(logOptimizerState(toolingLog, optimizerConfig)); From 793a008a3ec44211b58b9c099046b42618b1cda2 Mon Sep 17 00:00:00 2001 From: spalger Date: Thu, 6 Feb 2020 17:31:34 -0700 Subject: [PATCH 39/83] update kbn/pm dist --- packages/kbn-pm/dist/index.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index aae9d940bbdaf..5eaab33b6fa38 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -4490,11 +4490,7 @@ const tslib_1 = __webpack_require__(36); var proc_runner_1 = __webpack_require__(37); exports.withProcRunner = proc_runner_1.withProcRunner; exports.ProcRunner = proc_runner_1.ProcRunner; -var tooling_log_1 = __webpack_require__(415); -exports.ToolingLog = tooling_log_1.ToolingLog; -exports.ToolingLogTextWriter = tooling_log_1.ToolingLogTextWriter; -exports.pickLevelFromFlags = tooling_log_1.pickLevelFromFlags; -exports.ToolingLogCollectingWriter = tooling_log_1.ToolingLogCollectingWriter; +tslib_1.__exportStar(__webpack_require__(415), exports); var serializers_1 = __webpack_require__(420); exports.createAbsolutePathSerializer = serializers_1.createAbsolutePathSerializer; var certs_1 = __webpack_require__(445); @@ -36634,6 +36630,7 @@ var tooling_log_text_writer_1 = __webpack_require__(417); exports.ToolingLogTextWriter = tooling_log_text_writer_1.ToolingLogTextWriter; var log_levels_1 = __webpack_require__(418); exports.pickLevelFromFlags = log_levels_1.pickLevelFromFlags; +exports.parseLogLevel = log_levels_1.parseLogLevel; var tooling_log_collecting_writer_1 = __webpack_require__(419); exports.ToolingLogCollectingWriter = tooling_log_collecting_writer_1.ToolingLogCollectingWriter; @@ -36789,17 +36786,23 @@ class ToolingLogTextWriter { throw new Error('ToolingLogTextWriter requires the `writeTo` option be set to a stream (like process.stdout)'); } } - write({ type, indent, args }) { - if (!shouldWriteType(this.level, type)) { + write(msg) { + if (!shouldWriteType(this.level, msg.type)) { return false; } - const txt = type === 'error' ? stringifyError(args[0]) : util_1.format(args[0], ...args.slice(1)); - const prefix = has(MSG_PREFIXES, type) ? MSG_PREFIXES[type] : ''; + const prefix = has(MSG_PREFIXES, msg.type) ? MSG_PREFIXES[msg.type] : ''; + ToolingLogTextWriter.write(this.writeTo, prefix, msg); + return true; + } + static write(writeTo, prefix, msg) { + const txt = msg.type === 'error' + ? stringifyError(msg.args[0]) + : util_1.format(msg.args[0], ...msg.args.slice(1)); (prefix + txt).split('\n').forEach((line, i) => { let lineIndent = ''; - if (indent > 0) { + if (msg.indent > 0) { // if we are indenting write some spaces followed by a symbol - lineIndent += ' '.repeat(indent - 1); + lineIndent += ' '.repeat(msg.indent - 1); lineIndent += line.startsWith('-') ? '└' : '│'; } if (line && prefix && i > 0) { @@ -36807,9 +36810,8 @@ class ToolingLogTextWriter { // the first if this message gets a prefix lineIndent += PREFIX_INDENT; } - this.writeTo.write(`${lineIndent}${line}\n`); + writeTo.write(`${lineIndent}${line}\n`); }); - return true; } } exports.ToolingLogTextWriter = ToolingLogTextWriter; From eb7c282cad8f27c07858627befebe3021d839345 Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 09:20:02 -0700 Subject: [PATCH 40/83] set KBN_NP_PLUGINS_BUILT to avoid warning in CI --- packages/kbn-test/src/functional_tests/tasks.js | 6 +++++- test/scripts/jenkins_build_kibana.sh | 3 +++ test/scripts/jenkins_xpack_build_kibana.sh | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/kbn-test/src/functional_tests/tasks.js b/packages/kbn-test/src/functional_tests/tasks.js index 44b3bd9f2a2c6..3408b53d65f4d 100644 --- a/packages/kbn-test/src/functional_tests/tasks.js +++ b/packages/kbn-test/src/functional_tests/tasks.js @@ -62,10 +62,14 @@ export async function runTests(options) { if (!process.env.KBN_NP_PLUGINS_BUILT) { const log = options.createLogger(); log.warning('❗️❗️❗️'); + log.warning('❗️❗️❗️'); + log.warning('❗️❗️❗️'); log.warning( - "Don't forget to use `node scripts/build_new_platform_plugins` to build plugins you plan on testing" + " Don't forget to use `node scripts/build_new_platform_plugins` to build plugins you plan on testing" ); log.warning('❗️❗️❗️'); + log.warning('❗️❗️❗️'); + log.warning('❗️❗️❗️'); } for (const configPath of options.configs) { diff --git a/test/scripts/jenkins_build_kibana.sh b/test/scripts/jenkins_build_kibana.sh index 1f7f021d961ce..938168db687b8 100755 --- a/test/scripts/jenkins_build_kibana.sh +++ b/test/scripts/jenkins_build_kibana.sh @@ -8,6 +8,9 @@ node scripts/build_new_platform_plugins \ --scan-dir "$KIBANA_DIR/test/plugin_functional/plugins" \ --verbose; +# doesn't persist, also set in kibanaPipeline.groovy +export KBN_NP_PLUGINS_BUILT=true + echo " -> downloading es snapshot" node scripts/es snapshot --license=oss --download-only; diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh index 016c7cfbec6ba..cb6b031b1ae00 100755 --- a/test/scripts/jenkins_xpack_build_kibana.sh +++ b/test/scripts/jenkins_xpack_build_kibana.sh @@ -8,6 +8,9 @@ node scripts/build_new_platform_plugins \ --scan-dir "$XPACK_DIR/test/plugin_functional/plugins" \ --verbose; +# doesn't persist, also set in kibanaPipeline.groovy +export KBN_NP_PLUGINS_BUILT=true + echo " -> downloading es snapshot" node scripts/es snapshot --download-only; From 4f1217b0dd07c9c741735babdfe5eacf765c434b Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 10:33:22 -0700 Subject: [PATCH 41/83] avoid extending global window type --- .../test_suites/core_plugins/rendering.ts | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 975a3cdd205ae..20824f492ccc3 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -22,16 +22,6 @@ import expect from '@kbn/expect'; import '../../plugins/core_provider_plugin/types'; import { PluginFunctionalProviderContext } from '../../services'; -declare global { - interface Window { - /** - * We use this global variable to track page history changes to ensure that - * navigation is done without causing a full page reload. - */ - __RENDERING_SESSION__: string[]; - } -} - // eslint-disable-next-line import/no-default-export export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) { const PageObjects = getPageObjects(['common']); @@ -46,10 +36,10 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider await appsMenu.clickLink(title); return browser.execute(() => { if (!('__RENDERING_SESSION__' in window)) { - window.__RENDERING_SESSION__ = []; + (window as any).__RENDERING_SESSION__ = []; } - window.__RENDERING_SESSION__.push(window.location.pathname); + (window as any).__RENDERING_SESSION__.push(window.location.pathname); }); }; const getLegacyMode = () => @@ -64,7 +54,7 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider }); const exists = (selector: string) => testSubjects.exists(selector); const findLoadingMessage = () => testSubjects.find('kbnLoadingMessage'); - const getRenderingSession = () => browser.execute(() => window.__RENDERING_SESSION__); + const getRenderingSession = () => browser.execute(() => (window as any).__RENDERING_SESSION__); describe('rendering service', () => { it('renders "core" application', async () => { From 33bdf9655b629b293831f67c3edc2990392b8085 Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 11:42:50 -0700 Subject: [PATCH 42/83] add note to keep pluginScanDirs in sync --- packages/kbn-optimizer/src/optimizer_config.ts | 8 +++++++- src/core/server/config/env.ts | 5 +++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/src/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer_config.ts index 113a4e30ab362..8ab3b7d8d0b18 100644 --- a/packages/kbn-optimizer/src/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer_config.ts @@ -79,11 +79,17 @@ export class OptimizerConfig { throw new TypeError('repoRoot must be an absolute path'); } + /** + * BEWARE: this needs to stay roughly synchronized with + * `src/core/server/config/env.ts` which determins which paths + * should be searched for plugins to load + */ const pluginScanDirs = options.pluginScanDirs || [ Path.resolve(repoRoot, 'src/plugins'), - Path.resolve(repoRoot, 'plugins'), ...(oss ? [] : [Path.resolve(repoRoot, 'x-pack/plugins')]), + Path.resolve(repoRoot, 'plugins'), ...(examples ? [Path.resolve('examples')] : []), + Path.resolve(repoRoot, '../kibana-extra'), ]; if (!pluginScanDirs.every(p => Path.isAbsolute(p))) { throw new TypeError('pluginScanDirs must all be absolute paths'); diff --git a/src/core/server/config/env.ts b/src/core/server/config/env.ts index db363fcd4d751..05a8f40a09a88 100644 --- a/src/core/server/config/env.ts +++ b/src/core/server/config/env.ts @@ -100,6 +100,11 @@ export class Env { this.binDir = resolve(this.homeDir, 'bin'); this.logDir = resolve(this.homeDir, 'log'); + /** + * BEWARE: this needs to stay roughly synchronized with the @kbn/optimizer + * `packages/kbn-optimizer/src/optimizer_config.ts` determines the paths + * that should be searched for plugins to build + */ this.pluginSearchPaths = [ resolve(this.homeDir, 'src', 'plugins'), ...(options.cliArgs.oss ? [] : [resolve(this.homeDir, 'x-pack', 'plugins')]), From 6c034e747dcdae15d788a7b85012f6bc9dd50359 Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 12:11:17 -0700 Subject: [PATCH 43/83] pass browserslistEnv in workerConfig so it is used for cache key --- packages/kbn-optimizer/src/common/worker_config.ts | 7 +++++++ packages/kbn-optimizer/src/observe_worker.ts | 4 ---- packages/kbn-optimizer/src/optimizer_config.ts | 1 + packages/kbn-optimizer/src/worker/run_worker.ts | 9 ++++++++- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/kbn-optimizer/src/common/worker_config.ts b/packages/kbn-optimizer/src/common/worker_config.ts index f5aa5da794e7f..400beec5051b6 100644 --- a/packages/kbn-optimizer/src/common/worker_config.ts +++ b/packages/kbn-optimizer/src/common/worker_config.ts @@ -27,6 +27,7 @@ export interface WorkerConfig { readonly dist: boolean; readonly cache: boolean; readonly profileWebpack: boolean; + readonly browserslistEnv: string; readonly optimizerVersion: string; } @@ -72,6 +73,11 @@ export function parseWorkerConfig(json: string): WorkerConfig { throw new Error('`optimizerVersion` must be a string'); } + const browserslistEnv = parsed.browserslistEnv; + if (typeof browserslistEnv !== 'string') { + throw new Error('`browserslistEnv` must be a string'); + } + return { repoRoot, cache, @@ -79,6 +85,7 @@ export function parseWorkerConfig(json: string): WorkerConfig { dist, profileWebpack, optimizerVersion, + browserslistEnv, }; } catch (error) { throw new Error(`unable to parse worker config: ${error.message}`); diff --git a/packages/kbn-optimizer/src/observe_worker.ts b/packages/kbn-optimizer/src/observe_worker.ts index e652672aca4fe..5c303888c5418 100644 --- a/packages/kbn-optimizer/src/observe_worker.ts +++ b/packages/kbn-optimizer/src/observe_worker.ts @@ -83,10 +83,6 @@ function usingWorkerProc( : []), ...(config.maxWorkerCount <= 3 ? ['--max-old-space-size=2048'] : []), ], - env: { - ...process.env, - BROWSERSLIST_ENV: config.dist ? 'production' : process.env.BROWSERSLIST_ENV || 'dev', - }, }); return { diff --git a/packages/kbn-optimizer/src/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer_config.ts index 8ab3b7d8d0b18..cd1bdd5a64fb1 100644 --- a/packages/kbn-optimizer/src/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer_config.ts @@ -165,6 +165,7 @@ export class OptimizerConfig { repoRoot: this.repoRoot, watch: this.watch, optimizerVersion, + browserslistEnv: this.dist ? 'production' : process.env.BROWSERSLIST_ENV || 'dev', }; } } diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts index f6cf37d3514a6..235d5da7f7e99 100644 --- a/packages/kbn-optimizer/src/worker/run_worker.ts +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -79,7 +79,14 @@ Rx.defer(() => { bundles: parseBundles(process.argv[3]), }); }) - .pipe(mergeMap(({ workerConfig, bundles }) => runCompilers(workerConfig, bundles))) + .pipe( + mergeMap(({ workerConfig, bundles }) => { + // set BROWSERSLIST_ENV so that style/babel loaders see it before running compilers + process.env.BROWSERSLIST_ENV = workerConfig.browserslistEnv; + + return runCompilers(workerConfig, bundles); + }) + ) .subscribe( msg => { send(msg); From dff0ad23b25ef77017c0d4ac7155b11a7f7d6ddb Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 12:12:43 -0700 Subject: [PATCH 44/83] load commons.bundle.js in parallel too --- src/legacy/ui/ui_render/bootstrap/template.js.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/legacy/ui/ui_render/bootstrap/template.js.hbs b/src/legacy/ui/ui_render/bootstrap/template.js.hbs index 94f6c4223b8c4..166b37b0e1c61 100644 --- a/src/legacy/ui/ui_render/bootstrap/template.js.hbs +++ b/src/legacy/ui/ui_render/bootstrap/template.js.hbs @@ -20,8 +20,8 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { '{{this}}', {{/each}} '{{regularBundlePath}}/kbn-ui-shared-deps/{{sharedDepsFilename}}', + '{{regularBundlePath}}/commons.bundle.js', ], - '{{regularBundlePath}}/commons.bundle.js', '{{regularBundlePath}}/{{appId}}.bundle.js' ]; From db4aaf7c0e34ebe1b2e3202ec71fb4a116bc2fd6 Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 13:07:06 -0700 Subject: [PATCH 45/83] emit initialized+success states if all bundles are cached --- packages/kbn-optimizer/src/optimizer.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index e5631a7764690..835bc6a28723e 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -151,7 +151,7 @@ export class Optimizer { const onlineBundles = this.config.bundles.filter(b => !offlineBundles.includes(b)); return { - phase: onlineBundles.length || this.config.watch ? 'initialized' : 'success', + phase: 'initialized', version, compilerStates: [], durSec: msToSec(Date.now() - startTime), @@ -163,12 +163,6 @@ export class Optimizer { ).pipe( mergeMap( (initState): Rx.Observable => { - if (initState.phase === 'success') { - return Rx.of({ - state: initState, - }); - } - const change$ = this.config.watch ? this.watchBundlesForChanges$(initState.offlineBundles).pipe(share()) : Rx.EMPTY; @@ -193,7 +187,13 @@ export class Optimizer { ); return Rx.concat( - Rx.of({ state: initState }), + Rx.from([ + { state: initState }, + // emit a success state if there are no online bundles + ...(!initState.onlineBundles.length + ? [{ state: { ...initState, phase: 'success' as const } }] + : []), + ]), Rx.merge(change$, workerMsg$).pipe( pipeClosure(event$ => { let prevState = initState; From 09917156fba7de2c7172cb247532a40e96e1019b Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 13:23:49 -0700 Subject: [PATCH 46/83] load bootstraps as quickly as possible --- .../ui/ui_render/bootstrap/template.js.hbs | 99 ++++++++++--------- 1 file changed, 50 insertions(+), 49 deletions(-) diff --git a/src/legacy/ui/ui_render/bootstrap/template.js.hbs b/src/legacy/ui/ui_render/bootstrap/template.js.hbs index 166b37b0e1c61..106dbcd9f8ab2 100644 --- a/src/legacy/ui/ui_render/bootstrap/template.js.hbs +++ b/src/legacy/ui/ui_render/bootstrap/template.js.hbs @@ -13,19 +13,7 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { loadingMessage.style.display = 'flex'; window.onload = function () { - var files = [ - '{{dllBundlePath}}/vendors_runtime.bundle.dll.js', - [ - {{#each dllJsChunks}} - '{{this}}', - {{/each}} - '{{regularBundlePath}}/kbn-ui-shared-deps/{{sharedDepsFilename}}', - '{{regularBundlePath}}/commons.bundle.js', - ], - '{{regularBundlePath}}/{{appId}}.bundle.js' - ]; - - var failure = function () { + function failure() { // make subsequent calls to failure() noop failure = function () {}; @@ -40,60 +28,73 @@ if (window.__kbnStrictCsp__ && window.__kbnCspNotEnforced__) { document.body.innerHTML = err.outerHTML; } - function loadStyleSheet(path) { + function loadStyleSheet(url, cb) { var dom = document.createElement('link'); - dom.addEventListener('error', failure); dom.setAttribute('rel', 'stylesheet'); dom.setAttribute('type', 'text/css'); - dom.setAttribute('href', path); - document.head.appendChild(dom); - } - - function createJavascriptElement(path) { - var dom = document.createElement('script'); - - dom.setAttribute('defer', 'defer'); - dom.addEventListener('error', failure); - dom.setAttribute('src', file); - dom.addEventListener('load', next); + dom.setAttribute('href', url); + dom.addEventListener('load', cb); document.head.appendChild(dom); } - function loadJs(file, cb) { + function loadScript(url, cb) { var dom = document.createElement('script'); - dom.setAttribute('async', ''); dom.addEventListener('error', failure); - dom.setAttribute('src', file); + dom.setAttribute('src', url); dom.addEventListener('load', cb); document.head.appendChild(dom); } - function loadJsInParallel(files, cb) { - var pending = files.length; - for (var i = 0; i < files.length; i++) { - loadJs(files[i], function () { + function load(urlSet, cb) { + if (urlSet.deps) { + load({ urls: urlSet.deps }, function () { + load({ urls: urlSet.urls }, cb); + }); + return; + } + + var pending = urlSet.urls.length; + urlSet.urls.forEach(function (url) { + var innerCb = function () { pending = pending - 1; - if (pending === 0) { + if (pending === 0 && typeof cb === 'function') { cb(); } - }) - } - } + } - {{#each styleSheetPaths}} - loadStyleSheet('{{this}}'); - {{/each}} + if (typeof url !== 'string') { + load(url, innerCb); + } else if (url.slice(-4) === '.css') { + loadStyleSheet(url, innerCb); + } else { + loadScript(url, innerCb); + } + }); + } - (function next() { - var file = files.shift(); - if (!file) return; - if (typeof file === 'string') { - loadJs(file, next); - } else { - loadJsInParallel(file, next); - } - }()); + load({ + deps: [ + { + deps: [ + '{{dllBundlePath}}/vendors_runtime.bundle.dll.js' + ], + urls: [ + {{#each dllJsChunks}} + '{{this}}', + {{/each}} + ] + }, + '{{regularBundlePath}}/kbn-ui-shared-deps/{{sharedDepsFilename}}', + '{{regularBundlePath}}/commons.bundle.js', + ], + urls: [ + '{{regularBundlePath}}/{{appId}}.bundle.js', + {{#each styleSheetPaths}} + '{{this}}', + {{/each}}, + ] + }); }; } From de1e2f4ca3e090e163ca25730d5c67b65471ab62 Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 13:55:14 -0700 Subject: [PATCH 47/83] skip flaky suite --- .../test_suites/core_plugins/rendering.ts | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/test/plugin_functional/test_suites/core_plugins/rendering.ts b/test/plugin_functional/test_suites/core_plugins/rendering.ts index 20824f492ccc3..9679636a39d23 100644 --- a/test/plugin_functional/test_suites/core_plugins/rendering.ts +++ b/test/plugin_functional/test_suites/core_plugins/rendering.ts @@ -22,6 +22,16 @@ import expect from '@kbn/expect'; import '../../plugins/core_provider_plugin/types'; import { PluginFunctionalProviderContext } from '../../services'; +declare global { + interface Window { + /** + * We use this global variable to track page history changes to ensure that + * navigation is done without causing a full page reload. + */ + __RENDERING_SESSION__: string[]; + } +} + // eslint-disable-next-line import/no-default-export export default function({ getService, getPageObjects }: PluginFunctionalProviderContext) { const PageObjects = getPageObjects(['common']); @@ -36,10 +46,10 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider await appsMenu.clickLink(title); return browser.execute(() => { if (!('__RENDERING_SESSION__' in window)) { - (window as any).__RENDERING_SESSION__ = []; + window.__RENDERING_SESSION__ = []; } - (window as any).__RENDERING_SESSION__.push(window.location.pathname); + window.__RENDERING_SESSION__.push(window.location.pathname); }); }; const getLegacyMode = () => @@ -52,11 +62,15 @@ export default function({ getService, getPageObjects }: PluginFunctionalProvider return JSON.parse(document.querySelector('kbn-injected-metadata')!.getAttribute('data')!) .legacyMetadata.uiSettings.user; }); - const exists = (selector: string) => testSubjects.exists(selector); - const findLoadingMessage = () => testSubjects.find('kbnLoadingMessage'); - const getRenderingSession = () => browser.execute(() => (window as any).__RENDERING_SESSION__); + const exists = (selector: string) => testSubjects.exists(selector, { timeout: 5000 }); + const findLoadingMessage = () => testSubjects.find('kbnLoadingMessage', 5000); + const getRenderingSession = () => + browser.execute(() => { + return window.__RENDERING_SESSION__; + }); - describe('rendering service', () => { + // Talked to @dover, he aggreed we can skip these tests that are unexpectedly flaky + describe.skip('rendering service', () => { it('renders "core" application', async () => { await navigateTo('/render/core'); From e37229042f3418226b879bbd051a95da0283c6e3 Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 14:03:04 -0700 Subject: [PATCH 48/83] bump From 05bd68191304e0da52bda4467c3571b47f71259c Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 14:59:46 -0700 Subject: [PATCH 49/83] update jest snapshots --- packages/kbn-optimizer/src/optimizer_config.test.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/kbn-optimizer/src/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer_config.test.ts index 5e0c2db0ae97f..7420c3925ea89 100644 --- a/packages/kbn-optimizer/src/optimizer_config.test.ts +++ b/packages/kbn-optimizer/src/optimizer_config.test.ts @@ -95,8 +95,9 @@ describe('OptimizerConfig::parseOptions()', () => { "pluginPaths": Array [], "pluginScanDirs": Array [ /src/plugins, - /plugins, /x-pack/plugins, + /plugins, + -extra, ], "profileWebpack": false, "repoRoot": , @@ -118,8 +119,9 @@ describe('OptimizerConfig::parseOptions()', () => { "pluginPaths": Array [], "pluginScanDirs": Array [ /src/plugins, - /plugins, /x-pack/plugins, + /plugins, + -extra, ], "profileWebpack": false, "repoRoot": , @@ -141,9 +143,10 @@ describe('OptimizerConfig::parseOptions()', () => { "pluginPaths": Array [], "pluginScanDirs": Array [ /src/plugins, - /plugins, /x-pack/plugins, + /plugins, /examples, + -extra, ], "profileWebpack": false, "repoRoot": , @@ -166,6 +169,7 @@ describe('OptimizerConfig::parseOptions()', () => { "pluginScanDirs": Array [ /src/plugins, /plugins, + -extra, ], "profileWebpack": false, "repoRoot": , From 7d11025b2616346b522bf66aabcd948dec4fe8c5 Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 15:03:43 -0700 Subject: [PATCH 50/83] remove hashing from cache key generation --- .../src/get_optimizer_version.ts | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/kbn-optimizer/src/get_optimizer_version.ts b/packages/kbn-optimizer/src/get_optimizer_version.ts index 66dbc3124781c..f027326c52ab7 100644 --- a/packages/kbn-optimizer/src/get_optimizer_version.ts +++ b/packages/kbn-optimizer/src/get_optimizer_version.ts @@ -18,13 +18,14 @@ */ import Path from 'path'; -import { createHash } from 'crypto'; import execa from 'execa'; import { REPO_ROOT } from '@kbn/dev-utils'; + import { getMtimes } from './get_mtimes'; import { getChanges } from './get_changes'; import { OptimizerConfig } from './optimizer_config'; +import { ascending } from './common'; const OPTIMIZER_DIR = Path.dirname(require.resolve('../package.json')); const RELATIVE_DIR = Path.relative(REPO_ROOT, OPTIMIZER_DIR); @@ -47,12 +48,18 @@ export async function getOptimizerVersion(config: OptimizerConfig) { `workerConfig:${JSON.stringify(config.getWorkerConfig('-'))}`, ]; - const mtimes = await getMtimes((await getChanges(OPTIMIZER_DIR)).keys()); - for (const [path, mtime] of mtimes) { - cacheLines.push(`mtime:${path}:${mtime}`); + const filesToMtime: string[] = []; + for (const [path, type] of await getChanges(OPTIMIZER_DIR)) { + if (type === 'deleted') { + cacheLines.push(`deleted:${path}`); + } else { + filesToMtime.push(path); + } + } + + for (const [path, mtime] of await getMtimes(filesToMtime)) { + cacheLines.push(`modified:${path}:${mtime}`); } - return createHash('sha1') - .update(cacheLines.sort((a, b) => a.localeCompare(b)).join('\n')) - .digest('hex'); + return cacheLines.sort(ascending(l => l)).join('\n'); } From cea523e7f93fb19d6aa65b845285cf8096af5405 Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 15:38:03 -0700 Subject: [PATCH 51/83] remove unnecessary non-null assertion --- packages/kbn-optimizer/src/observe_worker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kbn-optimizer/src/observe_worker.ts b/packages/kbn-optimizer/src/observe_worker.ts index 5c303888c5418..d2f81be0a814f 100644 --- a/packages/kbn-optimizer/src/observe_worker.ts +++ b/packages/kbn-optimizer/src/observe_worker.ts @@ -135,8 +135,8 @@ export function observeWorker( type: 'worker started', bundles, }), - observeStdio$(proc.stdout!, 'stdout'), - observeStdio$(proc.stderr!, 'stderr'), + observeStdio$(proc.stdout, 'stdout'), + observeStdio$(proc.stderr, 'stderr'), Rx.fromEvent<[unknown]>(proc, 'message') .pipe( // validate the messages from the process From 262f4abd3fe18f2111399dc0df038cb828a83a0a Mon Sep 17 00:00:00 2001 From: spalger Date: Fri, 7 Feb 2020 17:30:29 -0700 Subject: [PATCH 52/83] improve docs and break up Optimizer#run() --- .../kbn-optimizer/src/common/rxjs_helpers.ts | 19 - packages/kbn-optimizer/src/observe_worker.ts | 6 + packages/kbn-optimizer/src/optimizer.ts | 423 +++++++++++------- packages/kbn-optimizer/src/watcher.ts | 38 +- 4 files changed, 271 insertions(+), 215 deletions(-) diff --git a/packages/kbn-optimizer/src/common/rxjs_helpers.ts b/packages/kbn-optimizer/src/common/rxjs_helpers.ts index a7af91a5971d5..39b01e8e58682 100644 --- a/packages/kbn-optimizer/src/common/rxjs_helpers.ts +++ b/packages/kbn-optimizer/src/common/rxjs_helpers.ts @@ -80,22 +80,3 @@ export const debounceTimeBuffer = (ms: number) => }) ); }); - -/** - * Basically the same as the `scan()` function from RxJS but with the seed - * argument first and the types working properly. - */ -export const scanBetter = ( - seed: T1, - fn: (acc: T1 | T3, item: T2) => T3 -): Operator => { - return pipeClosure(source$ => { - let acc: T1 | T3 = seed; - return source$.pipe( - map(item => { - acc = fn(acc, item); - return acc; - }) - ); - }); -}; diff --git a/packages/kbn-optimizer/src/observe_worker.ts b/packages/kbn-optimizer/src/observe_worker.ts index d2f81be0a814f..7bbcc7a3feb6c 100644 --- a/packages/kbn-optimizer/src/observe_worker.ts +++ b/packages/kbn-optimizer/src/observe_worker.ts @@ -122,6 +122,12 @@ function observeStdio$(stream: Readable, name: WorkerStdio['stream']) { ); } +/** + * Start a worker process with the specified `workerConfig` and + * `bundles` and return an observable of the events related to + * that worker, including the messages sent to us by that worker + * and the status of the process (stdio, started). + */ export function observeWorker( config: OptimizerConfig, workerConfig: WorkerConfig, diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index 835bc6a28723e..598b4d5fe778c 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -20,7 +20,7 @@ import { inspect } from 'util'; import * as Rx from 'rxjs'; -import { map, mergeMap, share } from 'rxjs/operators'; +import { scan, mergeMap, share, distinctUntilChanged } from 'rxjs/operators'; import { observeWorker, WorkerStatus } from './observe_worker'; import { OptimizerConfig } from './optimizer_config'; @@ -30,9 +30,20 @@ import { assignBundlesToWorkers } from './assign_bundles_to_workers'; import { Watcher, ChangesStarted, Changes } from './watcher'; import { getMtimes } from './get_mtimes'; +export interface OptimizerInitializedEvent { + type: 'optimizer initialized'; +} + +export type OptimizerEvent = + | OptimizerInitializedEvent + | ChangesStarted + | Changes + | WorkerMsg + | WorkerStatus; + export interface OptimizerMsg { state: OptimizerState; - event?: ChangesStarted | Changes | WorkerMsg | WorkerStatus; + event?: OptimizerEvent; } export interface OptimizerState { @@ -60,28 +71,10 @@ export type OptimizerNotif = OptimizerStartedWorker; const msToSec = (ms: number) => Math.round(ms / 100) / 10; -const getPhase = (states: CompilerMsg[]): OptimizerState['phase'] => { - const types = states.map(s => s.type); - - if (types.includes('running')) { - return 'running'; - } - - if (types.includes('compiler issue')) { - return 'issue'; - } - - if (types.every(s => s === 'compiler success')) { - return 'success'; - } - - throw new Error(`unable to summarize bundle states: ${JSON.stringify(states)}`); -}; - export class Optimizer { constructor(private readonly config: OptimizerConfig) {} - async getCachedBundles(optimizerVersion: string) { + private async getCachedBundles(optimizerVersion: string) { const eligible = this.config.bundles.filter( // only get the mtimes for files if the bundle was built // with our version of the optimizer and there is a cache key @@ -109,48 +102,236 @@ export class Optimizer { } /** - * Produce an observable that emits bundle objects when they - * should become "online", meaning that the cache on disk is - * no longer valid + * Create an observable that emits change events for offline + * bundles. + * + * Once changes are seen in a bundle that bundles + * files will no longer be watched. + * + * Once changes have been seen in all bundles changeEvent$ + * will complete. + * + * If there are no bundles to watch or we config.watch === false + * the observable completes without sending any notifications. */ - watchBundlesForChanges$(bundles: Iterable) { + private watchBundlesForChanges$(initialBundles: Bundle[], initialStartTime: number) { + if (!this.config.watch || !initialBundles.length) { + return Rx.EMPTY; + } + return Watcher.using(watcher => { - // copy the list of offline bundles - const stillOffline = new Set(bundles); - - // recursively watch for changes in offline bundles until all the - // offline bundles have gone online - const nextBundlesToBringOnline$ = Rx.defer(() => - stillOffline.size ? watcher.getNextChange(stillOffline) : Rx.EMPTY - ).pipe( - mergeMap( - (event): ReturnType => { - if (event.type === 'changes detected') { - return Rx.of(event); - } + /** + * Recursively call watcher.getNextChange$, passing it + * just the bundles that haven't been changed yet until + * all bundles have changed, then exit + */ + const recursiveGetNextChange$ = ( + bundles: Bundle[], + startTime: number + ): ReturnType => + !bundles.length + ? Rx.EMPTY + : watcher.getNextChange$(bundles, startTime).pipe( + mergeMap(event => { + if (event.type === 'changes detected') { + return Rx.of(event); + } + + return Rx.concat( + Rx.of(event), + + recursiveGetNextChange$( + bundles.filter(b => !event.bundles.includes(b)), + Date.now() + ) + ); + }) + ); - for (const bundle of event.bundles) { - stillOffline.delete(bundle); - } + return recursiveGetNextChange$(initialBundles, initialStartTime); + }); + } - return Rx.concat([event], nextBundlesToBringOnline$); - } + /** + * Create a stream of all worker events, these include messages + * from workers and events about the status of workers. To get + * these events we assign the bundles to workers via + * `assignBundlesToWorkers()` and then start a worler for each + * assignment with `observeWorker()`. + * + * Subscribes to `changeEvent$` in order to determine when more + * bundles should be assigned to workers. + * + * Completes when all workers have exitted. If we are running in + * watch mode this observable will never exit. + */ + private runWorkers( + initState: OptimizerState, + changeEvent$: Rx.Observable + ) { + return Rx.concat( + // first batch of bundles are based on how up-to-date the cache is + Rx.of(initState.onlineBundles), + // subsequent batches are defined by changeEvent$ + changeEvent$.pipe(maybeMap(c => (c.type === 'changes' ? c.bundles : undefined))) + ).pipe( + mergeMap(bundles => + Rx.from(assignBundlesToWorkers(bundles, this.config.maxWorkerCount)).pipe( + mergeMap(assignment => + observeWorker( + this.config, + this.config.getWorkerConfig(initState.version), + assignment.bundles + ) + ) ) - ); + ) + ); + } - return nextBundlesToBringOnline$; - }); + /** + * merge a state and some updates into a new optimizer state, apply some + * standard updates related to timing, and wrap it up with an event to + * create an OptimizerMsg + */ + private createOptimizerMsg( + prevState: OptimizerState, + event?: OptimizerEvent, + stateUpdate?: Partial> + ): OptimizerMsg { + // reset start time if we are transitioning into running + const startTime = + (prevState.phase === 'success' || prevState.phase === 'issue') && + (stateUpdate?.phase === 'running' || stateUpdate?.phase === 'reallocating') + ? Date.now() + : prevState.startTime; + + return { + event, + state: { + ...prevState, + ...stateUpdate, + startTime, + durSec: msToSec(Date.now() - startTime), + }, + }; + } + + /** + * calculate the total state, given a set of compiler messages + */ + private getStatePhase(states: CompilerMsg[]) { + const types = states.map(s => s.type); + + if (types.includes('running')) { + return 'running'; + } + + if (types.includes('compiler issue')) { + return 'issue'; + } + + if (types.every(s => s === 'compiler success')) { + return 'success'; + } + + throw new Error(`unable to summarize bundle states: ${JSON.stringify(states)}`); + } + + /** + * Convert a stream of OptimizerEvents into the public stream of + * OptimizerMsgs. The resulting state reflects the total state + * of all bundles and workers. + */ + private summarizeOptimizerEvent$(initMsg: OptimizerMsg, event$: Rx.Observable) { + return event$.pipe( + scan((prevMsg, event) => { + const { state } = prevMsg; + + if (event.type === 'optimizer initialized') { + if (state.onlineBundles.length === 0) { + // all bundles are cached so we transition to success + return this.createOptimizerMsg(state, event, { + phase: 'success', + }); + } + + // no state change necessary + return prevMsg; + } + + if (event.type === 'worker error' || event.type === 'compiler error') { + // unrecoverable error states + const error = new Error(event.errorMsg); + error.stack = event.errorStack; + throw error; + } + + if (event.type === 'worker stdio' || event.type === 'worker started') { + return this.createOptimizerMsg(state, event); + } + + if (event.type === 'changes detected') { + // switch to running early, before workers are started, so that + // base path proxy can prevent requests in the delay between changes + // and workers started + return this.createOptimizerMsg(state, event, { + phase: 'reallocating', + }); + } + + if (event.type === 'changes') { + const onlineBundles: Bundle[] = []; + const offlineBundles: Bundle[] = []; + for (const bundle of this.config.bundles) { + if (state.onlineBundles.includes(bundle) || event.bundles.includes(bundle)) { + onlineBundles.push(bundle); + } else { + offlineBundles.push(bundle); + } + } + + return this.createOptimizerMsg(state, event, { + phase: 'running', + onlineBundles, + offlineBundles, + }); + } + + if ( + event.type === 'compiler issue' || + event.type === 'compiler success' || + event.type === 'running' + ) { + const compilerStates: CompilerMsg[] = [ + ...state.compilerStates.filter(c => c.bundleId !== event.bundleId), + event, + ]; + return this.createOptimizerMsg(state, event, { + phase: this.getStatePhase(compilerStates), + compilerStates, + }); + } + + throw new Error(`unexpected optimizer event ${inspect(event)}`); + }, initMsg), + + // returning the previous message is how we indicate + // that an event should be dropped + distinctUntilChanged() + ); } run() { - return Rx.defer( - async (): Promise => { + // initialize the optimizer by figuring out which bundles are cached, which bundles + const init$ = Rx.defer( + async (): Promise => { const startTime = Date.now(); const version = await getOptimizerVersion(this.config); const offlineBundles = this.config.cache ? await this.getCachedBundles(version) : []; const onlineBundles = this.config.bundles.filter(b => !offlineBundles.includes(b)); - return { + return this.createOptimizerMsg({ phase: 'initialized', version, compilerStates: [], @@ -158,133 +339,31 @@ export class Optimizer { offlineBundles, onlineBundles, startTime, - }; + }); } - ).pipe( + ); + + return init$.pipe( mergeMap( - (initState): Rx.Observable => { - const change$ = this.config.watch - ? this.watchBundlesForChanges$(initState.offlineBundles).pipe(share()) - : Rx.EMPTY; - - const workerMsg$ = Rx.concat( - // first batch is all the workers which weren't initially cached - Rx.of(initState.onlineBundles), - // subsequent batches are defined by our change listener - change$.pipe(maybeMap(c => (c.type === 'changes' ? c.bundles : undefined))) - ).pipe( - mergeMap(bundles => - Rx.from(assignBundlesToWorkers(bundles, this.config.maxWorkerCount)).pipe( - mergeMap(assignment => - observeWorker( - this.config, - this.config.getWorkerConfig(initState.version), - assignment.bundles - ) - ) - ) - ) - ); + (init): Rx.Observable => { + const { state: initState } = init; + + const changeEvent$ = this.watchBundlesForChanges$( + initState.offlineBundles, + initState.startTime + ).pipe(share()); + const workerEvent$ = this.runWorkers(initState, changeEvent$); + + // event to kick off the summarizer + const initEvent: OptimizerInitializedEvent = { + type: 'optimizer initialized', + }; return Rx.concat( - Rx.from([ - { state: initState }, - // emit a success state if there are no online bundles - ...(!initState.onlineBundles.length - ? [{ state: { ...initState, phase: 'success' as const } }] - : []), - ]), - Rx.merge(change$, workerMsg$).pipe( - pipeClosure(event$ => { - let prevState = initState; - - const update = ( - event: NonNullable, - stateChanges?: Partial> - ) => { - // reset start time if we are transitioning into running - const startTime = - (prevState.phase === 'success' || prevState.phase === 'issue') && - (stateChanges?.phase === 'running' || stateChanges?.phase === 'reallocating') - ? Date.now() - : prevState.startTime; - - const next: OptimizerMsg = { - event, - state: { - ...prevState, - ...stateChanges, - startTime, - durSec: msToSec(Date.now() - startTime), - }, - }; - - prevState = next.state; - return next; - }; - - return event$.pipe( - map(event => { - if (event.type === 'worker error' || event.type === 'compiler error') { - // unrecoverable error states - const error = new Error(event.errorMsg); - error.stack = event.errorStack; - throw error; - } - - if (event.type === 'worker stdio' || event.type === 'worker started') { - return update(event); - } - - if (event.type === 'changes detected') { - // switch to running early, before workers are started, so that - // base path proxy can prevent requests in the delay between changes - // and workers started - return update(event, { - phase: 'reallocating', - }); - } - - if (event.type === 'changes') { - const onlineBundles: Bundle[] = []; - const offlineBundles: Bundle[] = []; - for (const bundle of this.config.bundles) { - if ( - prevState.onlineBundles.includes(bundle) || - event.bundles.includes(bundle) - ) { - onlineBundles.push(bundle); - } else { - offlineBundles.push(bundle); - } - } - - return update(event, { - phase: 'running', - onlineBundles, - offlineBundles, - }); - } - - if ( - event.type === 'compiler issue' || - event.type === 'compiler success' || - event.type === 'running' - ) { - const compilerStates: CompilerMsg[] = [ - ...prevState.compilerStates.filter(c => c.bundleId !== event.bundleId), - event, - ]; - return update(event, { - phase: getPhase(compilerStates), - compilerStates, - }); - } - - throw new Error(`unexpected optimizer event ${inspect(event)}`); - }) - ); - }) + Rx.of(init), + this.summarizeOptimizerEvent$( + init, + Rx.merge(Rx.of(initEvent), changeEvent$, workerEvent$) ) ); } diff --git a/packages/kbn-optimizer/src/watcher.ts b/packages/kbn-optimizer/src/watcher.ts index 064a8d259af3e..0ccc05300af9d 100644 --- a/packages/kbn-optimizer/src/watcher.ts +++ b/packages/kbn-optimizer/src/watcher.ts @@ -18,10 +18,10 @@ */ import * as Rx from 'rxjs'; -import { take, tap, debounceTime, map } from 'rxjs/operators'; +import { take, map } from 'rxjs/operators'; import Watchpack from 'watchpack'; -import { pipeClosure, Bundle } from './common'; +import { debounceTimeBuffer, Bundle } from './common'; export interface ChangesStarted { type: 'changes detected'; @@ -32,22 +32,12 @@ export interface Changes { bundles: Bundle[]; } -const debounceTimeBuffer = (time: number) => - pipeClosure((source$: Rx.Observable) => { - const buffer = new Set(); - return source$.pipe( - tap(item => buffer.add(item)), - debounceTime(time), - map(() => { - const items = Array.from(buffer); - buffer.clear(); - return items; - }) - ); - }); - export class Watcher { - // Use watcher as an RxJS Resource so that it is automatically closed + /** + * Use watcher as an RxJS Resource, which is a special type of observable + * that calls unsubscribe on the resource (the Watcher instance in this case) + * when the observable is unsubscribed. + */ static using(fn: (watcher: Watcher) => Rx.Observable) { return Rx.using( () => new Watcher(), @@ -62,7 +52,7 @@ export class Watcher { private readonly change$ = Rx.fromEvent<[string]>(this.watchpack, 'change'); - public getNextChange(bundles: Iterable) { + public getNextChange$(bundles: Iterable, startTime: number) { return Rx.merge( // emit ChangesStarted as soon as we have been triggered this.change$.pipe( @@ -112,17 +102,17 @@ export class Watcher { } } - this.watchpack.watch(watchPaths, [], Date.now()); + this.watchpack.watch(watchPaths, [], startTime); return Rx.EMPTY; }) ); } - close() { - this.watchpack.close(); - } - + /** + * Called automatically by RxJS when Watcher instances + * are used as resources + */ unsubscribe() { - this.close(); + this.watchpack.close(); } } From a3c800bf298de3eeae1b2d0f1e88d0552714b8d6 Mon Sep 17 00:00:00 2001 From: spalger Date: Sat, 8 Feb 2020 09:40:40 -0700 Subject: [PATCH 53/83] remove unused import --- packages/kbn-optimizer/src/optimizer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts index 598b4d5fe778c..e63a97b11028d 100644 --- a/packages/kbn-optimizer/src/optimizer.ts +++ b/packages/kbn-optimizer/src/optimizer.ts @@ -25,7 +25,7 @@ import { scan, mergeMap, share, distinctUntilChanged } from 'rxjs/operators'; import { observeWorker, WorkerStatus } from './observe_worker'; import { OptimizerConfig } from './optimizer_config'; import { getOptimizerVersion } from './get_optimizer_version'; -import { CompilerMsg, WorkerMsg, pipeClosure, Bundle, maybeMap } from './common'; +import { CompilerMsg, WorkerMsg, Bundle, maybeMap } from './common'; import { assignBundlesToWorkers } from './assign_bundles_to_workers'; import { Watcher, ChangesStarted, Changes } from './watcher'; import { getMtimes } from './get_mtimes'; From 9f4cbaba6bfccd35114c817c5e9ae940e153c8d6 Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 10 Feb 2020 13:05:51 -0700 Subject: [PATCH 54/83] refactor kbn/optimizer to break up observable logic, implement more helpful cache invalidation logic with logging --- packages/kbn-optimizer/package.json | 2 + packages/kbn-optimizer/src/cli.ts | 7 +- .../kbn-optimizer/src/common/array_helpers.ts | 11 + packages/kbn-optimizer/src/common/bundle.ts | 14 +- .../kbn-optimizer/src/common/bundle_cache.ts | 12 +- .../kbn-optimizer/src/common/worker_config.ts | 10 +- .../src/get_optimizer_version.ts | 65 --- packages/kbn-optimizer/src/index.ts | 6 +- .../basic_optimization.test.ts | 7 +- .../kbn-optimizer/src/log_optimizer_state.ts | 17 +- packages/kbn-optimizer/src/optimizer.ts | 373 ------------------ .../assign_bundles_to_workers.test.ts | 3 +- .../assign_bundles_to_workers.ts | 2 +- .../src/optimizer/bundle_cache.ts | 139 +++++++ .../kbn-optimizer/src/optimizer/cache_keys.ts | 155 ++++++++ .../src/{ => optimizer}/get_bundles.test.ts | 0 .../src/{ => optimizer}/get_bundles.ts | 3 +- .../src/{ => optimizer}/get_changes.test.ts | 0 .../src/{ => optimizer}/get_changes.ts | 0 .../src/{ => optimizer}/get_mtimes.test.ts | 0 .../src/{ => optimizer}/get_mtimes.ts | 2 +- packages/kbn-optimizer/src/optimizer/index.ts | 26 ++ .../new_platform_plugins.test.ts | 0 .../{ => optimizer}/new_platform_plugins.ts | 0 .../src/{ => optimizer}/observe_worker.ts | 5 +- .../{ => optimizer}/optimizer_config.test.ts | 0 .../src/{ => optimizer}/optimizer_config.ts | 7 +- .../src/optimizer/optimizer_msg.ts | 213 ++++++++++ .../src/optimizer/run_workers.ts | 68 ++++ .../optimizer/watch_bundles_for_changes.ts | 85 ++++ .../src/{ => optimizer}/watcher.ts | 4 +- packages/kbn-optimizer/src/run_optimizer.ts | 72 ++++ .../kbn-optimizer/src/worker/run_compilers.ts | 4 +- .../kbn-optimizer/src/worker/run_worker.ts | 1 + yarn.lock | 86 +++- 35 files changed, 912 insertions(+), 487 deletions(-) delete mode 100644 packages/kbn-optimizer/src/get_optimizer_version.ts delete mode 100644 packages/kbn-optimizer/src/optimizer.ts rename packages/kbn-optimizer/src/{ => optimizer}/assign_bundles_to_workers.test.ts (99%) rename packages/kbn-optimizer/src/{ => optimizer}/assign_bundles_to_workers.ts (98%) create mode 100644 packages/kbn-optimizer/src/optimizer/bundle_cache.ts create mode 100644 packages/kbn-optimizer/src/optimizer/cache_keys.ts rename packages/kbn-optimizer/src/{ => optimizer}/get_bundles.test.ts (100%) rename packages/kbn-optimizer/src/{ => optimizer}/get_bundles.ts (97%) rename packages/kbn-optimizer/src/{ => optimizer}/get_changes.test.ts (100%) rename packages/kbn-optimizer/src/{ => optimizer}/get_changes.ts (100%) rename packages/kbn-optimizer/src/{ => optimizer}/get_mtimes.test.ts (100%) rename packages/kbn-optimizer/src/{ => optimizer}/get_mtimes.ts (97%) create mode 100644 packages/kbn-optimizer/src/optimizer/index.ts rename packages/kbn-optimizer/src/{ => optimizer}/new_platform_plugins.test.ts (100%) rename packages/kbn-optimizer/src/{ => optimizer}/new_platform_plugins.ts (100%) rename packages/kbn-optimizer/src/{ => optimizer}/observe_worker.ts (97%) rename packages/kbn-optimizer/src/{ => optimizer}/optimizer_config.test.ts (100%) rename packages/kbn-optimizer/src/{ => optimizer}/optimizer_config.ts (97%) create mode 100644 packages/kbn-optimizer/src/optimizer/optimizer_msg.ts create mode 100644 packages/kbn-optimizer/src/optimizer/run_workers.ts create mode 100644 packages/kbn-optimizer/src/optimizer/watch_bundles_for_changes.ts rename packages/kbn-optimizer/src/{ => optimizer}/watcher.ts (96%) create mode 100644 packages/kbn-optimizer/src/run_optimizer.ts diff --git a/packages/kbn-optimizer/package.json b/packages/kbn-optimizer/package.json index 4e113eb90405a..e8bb31f1e365d 100644 --- a/packages/kbn-optimizer/package.json +++ b/packages/kbn-optimizer/package.json @@ -25,6 +25,8 @@ "del": "^5.1.0", "file-loader": "^4.2.0", "istanbul-instrumenter-loader": "^3.0.1", + "jest-diff": "^25.1.0", + "json-stable-stringify": "^1.0.1", "loader-utils": "^1.2.3", "node-sass": "^4.13.0", "postcss-loader": "^3.0.0", diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts index 0f41dc6de0c42..1be2df0e45fe9 100644 --- a/packages/kbn-optimizer/src/cli.ts +++ b/packages/kbn-optimizer/src/cli.ts @@ -24,8 +24,8 @@ import Path from 'path'; import { run, REPO_ROOT, createFlagError } from '@kbn/dev-utils'; import { logOptimizerState } from './log_optimizer_state'; -import { OptimizerConfig } from './optimizer_config'; -import { Optimizer } from './optimizer'; +import { OptimizerConfig } from './optimizer'; +import { runOptimizer } from './run_optimizer'; run( async ({ log, flags }) => { @@ -89,8 +89,7 @@ run( inspectWorkers, }); - await new Optimizer(config) - .run() + await runOptimizer(config) .pipe(logOptimizerState(log, config)) .toPromise(); }, diff --git a/packages/kbn-optimizer/src/common/array_helpers.ts b/packages/kbn-optimizer/src/common/array_helpers.ts index 4a236591e2769..a4766e1d37cd2 100644 --- a/packages/kbn-optimizer/src/common/array_helpers.ts +++ b/packages/kbn-optimizer/src/common/array_helpers.ts @@ -78,3 +78,14 @@ export const invert = (fn: (x: T) => x is T2) => (x: T): x is E * Alternate Array#includes() implementation with sane types, functions as a type guard */ export const includes = (array: T[], value: any): value is T => array.includes(value); + +/** + * Ponyfill for Object.fromEntries() + */ +export const entriesToObject = (entries: Array): Record => { + const object: Record = {}; + for (const [key, value] of entries) { + object[key] = value; + } + return object; +}; diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts index f183dd26de28b..75acb9124e99a 100644 --- a/packages/kbn-optimizer/src/common/bundle.ts +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -21,7 +21,7 @@ import Path from 'path'; import { BundleCache } from './bundle_cache'; import { UnknownVals } from './ts_helpers'; -import { includes, ascending } from './array_helpers'; +import { includes, ascending, entriesToObject } from './array_helpers'; export const VALID_BUNDLE_TYPES = ['plugin' as const]; @@ -116,12 +116,12 @@ export class Bundle { * @param mtimes pre-fetched mtimes (ms || undefined) for all referenced files */ createCacheKey(files: string[], mtimes: Map) { - return [ - `bundleSpec:${JSON.stringify(this.toSpec())}`, - ...files.map(p => `path:${p}:${mtimes.get(p)}`), - ] - .sort(ascending(l => l)) - .join('\n'); + return { + spec: this.toSpec(), + mtimes: entriesToObject( + files.map(p => [p, mtimes.get(p)] as const).sort(ascending(e => e[0])) + ), + }; } /** diff --git a/packages/kbn-optimizer/src/common/bundle_cache.ts b/packages/kbn-optimizer/src/common/bundle_cache.ts index bfb690365c39a..c5602cc607b51 100644 --- a/packages/kbn-optimizer/src/common/bundle_cache.ts +++ b/packages/kbn-optimizer/src/common/bundle_cache.ts @@ -21,8 +21,8 @@ import Fs from 'fs'; import Path from 'path'; interface State { - optimizerVersion?: string; - key?: string; + optimizerCacheKey?: unknown; + cacheKey?: unknown; moduleCount?: number; files?: string[]; } @@ -95,11 +95,11 @@ export class BundleCache { return this.get().files; } - public getKey() { - return this.get().key; + public getCacheKeys() { + return this.get().cacheKey; } - public getOptimizerVersion() { - return this.get().optimizerVersion; + public getOptimizerCacheKey() { + return this.get().optimizerCacheKey; } } diff --git a/packages/kbn-optimizer/src/common/worker_config.ts b/packages/kbn-optimizer/src/common/worker_config.ts index 400beec5051b6..c999260872d0f 100644 --- a/packages/kbn-optimizer/src/common/worker_config.ts +++ b/packages/kbn-optimizer/src/common/worker_config.ts @@ -28,7 +28,7 @@ export interface WorkerConfig { readonly cache: boolean; readonly profileWebpack: boolean; readonly browserslistEnv: string; - readonly optimizerVersion: string; + readonly optimizerCacheKey: unknown; } export function parseWorkerConfig(json: string): WorkerConfig { @@ -68,9 +68,9 @@ export function parseWorkerConfig(json: string): WorkerConfig { throw new Error('`profileWebpack` must be a boolean'); } - const optimizerVersion = parsed.optimizerVersion; - if (typeof optimizerVersion !== 'string') { - throw new Error('`optimizerVersion` must be a string'); + const optimizerCacheKey = parsed.optimizerCacheKey; + if (optimizerCacheKey === undefined) { + throw new Error('`optimizerCacheKey` must be defined'); } const browserslistEnv = parsed.browserslistEnv; @@ -84,7 +84,7 @@ export function parseWorkerConfig(json: string): WorkerConfig { watch, dist, profileWebpack, - optimizerVersion, + optimizerCacheKey, browserslistEnv, }; } catch (error) { diff --git a/packages/kbn-optimizer/src/get_optimizer_version.ts b/packages/kbn-optimizer/src/get_optimizer_version.ts deleted file mode 100644 index f027326c52ab7..0000000000000 --- a/packages/kbn-optimizer/src/get_optimizer_version.ts +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import Path from 'path'; - -import execa from 'execa'; -import { REPO_ROOT } from '@kbn/dev-utils'; - -import { getMtimes } from './get_mtimes'; -import { getChanges } from './get_changes'; -import { OptimizerConfig } from './optimizer_config'; -import { ascending } from './common'; - -const OPTIMIZER_DIR = Path.dirname(require.resolve('../package.json')); -const RELATIVE_DIR = Path.relative(REPO_ROOT, OPTIMIZER_DIR); - -async function getLastCommit() { - const { stdout } = await execa( - 'git', - ['log', '-n', '1', '--pretty=format:%H', '--', RELATIVE_DIR], - { - cwd: REPO_ROOT, - } - ); - - return stdout.trim() || undefined; -} - -export async function getOptimizerVersion(config: OptimizerConfig) { - const cacheLines: string[] = [ - `lastCommit:${await getLastCommit()}`, - `workerConfig:${JSON.stringify(config.getWorkerConfig('-'))}`, - ]; - - const filesToMtime: string[] = []; - for (const [path, type] of await getChanges(OPTIMIZER_DIR)) { - if (type === 'deleted') { - cacheLines.push(`deleted:${path}`); - } else { - filesToMtime.push(path); - } - } - - for (const [path, mtime] of await getMtimes(filesToMtime)) { - cacheLines.push(`modified:${path}:${mtime}`); - } - - return cacheLines.sort(ascending(l => l)).join('\n'); -} diff --git a/packages/kbn-optimizer/src/index.ts b/packages/kbn-optimizer/src/index.ts index f0d70db342013..31d2885770c88 100644 --- a/packages/kbn-optimizer/src/index.ts +++ b/packages/kbn-optimizer/src/index.ts @@ -17,7 +17,5 @@ * under the License. */ -export * from './optimizer'; -export * from './optimizer_config'; -export * from './log_optimizer_state'; -export { WorkerStdio } from './observe_worker'; +export { OptimizerConfig, OptimizerMsg } from './optimizer'; +export * from './run_optimizer'; diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index 5fe1b83f556bf..90637797553ee 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -25,7 +25,7 @@ import del from 'del'; import { toArray, tap } from 'rxjs/operators'; import { createAbsolutePathSerializer } from '@kbn/dev-utils'; -import { Optimizer, OptimizerConfig, OptimizerMsg } from '@kbn/optimizer'; +import { runOptimizer, OptimizerConfig, OptimizerMsg } from '@kbn/optimizer'; const TMP_DIR = Path.resolve(__dirname, '../__fixtures__/__tmp__'); const MOCK_REPO_SRC = Path.resolve(__dirname, '../__fixtures__/mock_repo'); @@ -55,10 +55,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { expect(config).toMatchSnapshot('OptimizerConfig'); - const optimizer = new Optimizer(config); - - const msgs = await optimizer - .run() + const msgs = await runOptimizer(config) .pipe( tap(state => { if (state.event?.type === 'worker stdio') { diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index 38675982ffa03..d882bdfc050fc 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -23,8 +23,7 @@ import { ToolingLog } from '@kbn/dev-utils'; import * as Rx from 'rxjs'; import { tap } from 'rxjs/operators'; -import { OptimizerConfig } from './optimizer_config'; -import { OptimizerMsg } from './optimizer'; +import { OptimizerConfig, OptimizerMsg } from './optimizer'; import { CompilerMsg, pipeClosure } from './common'; export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { @@ -45,6 +44,18 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { ); } + if (event?.type === 'bundle not cached') { + log.debug( + `[${event.bundle.id}] bundle not cached because [${event.reason}]${ + event.diff ? `, diff:\n${event.diff}` : '' + }` + ); + } + + if (event?.type === 'bundle cached') { + log.debug(`[${event.bundle.id}] bundle cached`); + } + if (event?.type === 'worker started') { log.info(`worker started for bundles ${event.bundles.map(b => b.id).join(', ')}`); } @@ -58,8 +69,6 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { if (!loggedInit) { loggedInit = true; log.info(`intialized, ${state.offlineBundles.length} bundles cached`); - log.debug(`version: ${state.version}`); - log.debug(`cached: ${state.offlineBundles.map(b => b.id)}`); } return; diff --git a/packages/kbn-optimizer/src/optimizer.ts b/packages/kbn-optimizer/src/optimizer.ts deleted file mode 100644 index e63a97b11028d..0000000000000 --- a/packages/kbn-optimizer/src/optimizer.ts +++ /dev/null @@ -1,373 +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 { inspect } from 'util'; - -import * as Rx from 'rxjs'; -import { scan, mergeMap, share, distinctUntilChanged } from 'rxjs/operators'; - -import { observeWorker, WorkerStatus } from './observe_worker'; -import { OptimizerConfig } from './optimizer_config'; -import { getOptimizerVersion } from './get_optimizer_version'; -import { CompilerMsg, WorkerMsg, Bundle, maybeMap } from './common'; -import { assignBundlesToWorkers } from './assign_bundles_to_workers'; -import { Watcher, ChangesStarted, Changes } from './watcher'; -import { getMtimes } from './get_mtimes'; - -export interface OptimizerInitializedEvent { - type: 'optimizer initialized'; -} - -export type OptimizerEvent = - | OptimizerInitializedEvent - | ChangesStarted - | Changes - | WorkerMsg - | WorkerStatus; - -export interface OptimizerMsg { - state: OptimizerState; - event?: OptimizerEvent; -} - -export interface OptimizerState { - phase: 'initialized' | 'reallocating' | 'success' | 'running' | 'issue'; - version: string; - startTime: number; - durSec: number; - compilerStates: CompilerMsg[]; - onlineBundles: Bundle[]; - offlineBundles: Bundle[]; -} - -export interface OptimizerStartedWorker { - type: 'worker started'; - bundles: Bundle[]; -} - -export interface OptimizerComingOnline { - type: 'bringing bundle online'; - bundle: Bundle; -} - -export { ChangesStarted }; -export type OptimizerNotif = OptimizerStartedWorker; - -const msToSec = (ms: number) => Math.round(ms / 100) / 10; - -export class Optimizer { - constructor(private readonly config: OptimizerConfig) {} - - private async getCachedBundles(optimizerVersion: string) { - const eligible = this.config.bundles.filter( - // only get the mtimes for files if the bundle was built - // with our version of the optimizer and there is a cache key - b => b.cache.getOptimizerVersion() === optimizerVersion && !!b.cache.getKey() - ); - - if (!eligible.length) { - return []; - } - - const mtimes = await getMtimes( - new Set( - eligible.reduce( - (acc: string[], bundle) => [...acc, ...(bundle.cache.getReferencedFiles() || [])], - [] - ) - ) - ); - - return eligible.filter( - bundle => - bundle.cache.getKey() === - bundle.createCacheKey(bundle.cache.getReferencedFiles() || [], mtimes) - ); - } - - /** - * Create an observable that emits change events for offline - * bundles. - * - * Once changes are seen in a bundle that bundles - * files will no longer be watched. - * - * Once changes have been seen in all bundles changeEvent$ - * will complete. - * - * If there are no bundles to watch or we config.watch === false - * the observable completes without sending any notifications. - */ - private watchBundlesForChanges$(initialBundles: Bundle[], initialStartTime: number) { - if (!this.config.watch || !initialBundles.length) { - return Rx.EMPTY; - } - - return Watcher.using(watcher => { - /** - * Recursively call watcher.getNextChange$, passing it - * just the bundles that haven't been changed yet until - * all bundles have changed, then exit - */ - const recursiveGetNextChange$ = ( - bundles: Bundle[], - startTime: number - ): ReturnType => - !bundles.length - ? Rx.EMPTY - : watcher.getNextChange$(bundles, startTime).pipe( - mergeMap(event => { - if (event.type === 'changes detected') { - return Rx.of(event); - } - - return Rx.concat( - Rx.of(event), - - recursiveGetNextChange$( - bundles.filter(b => !event.bundles.includes(b)), - Date.now() - ) - ); - }) - ); - - return recursiveGetNextChange$(initialBundles, initialStartTime); - }); - } - - /** - * Create a stream of all worker events, these include messages - * from workers and events about the status of workers. To get - * these events we assign the bundles to workers via - * `assignBundlesToWorkers()` and then start a worler for each - * assignment with `observeWorker()`. - * - * Subscribes to `changeEvent$` in order to determine when more - * bundles should be assigned to workers. - * - * Completes when all workers have exitted. If we are running in - * watch mode this observable will never exit. - */ - private runWorkers( - initState: OptimizerState, - changeEvent$: Rx.Observable - ) { - return Rx.concat( - // first batch of bundles are based on how up-to-date the cache is - Rx.of(initState.onlineBundles), - // subsequent batches are defined by changeEvent$ - changeEvent$.pipe(maybeMap(c => (c.type === 'changes' ? c.bundles : undefined))) - ).pipe( - mergeMap(bundles => - Rx.from(assignBundlesToWorkers(bundles, this.config.maxWorkerCount)).pipe( - mergeMap(assignment => - observeWorker( - this.config, - this.config.getWorkerConfig(initState.version), - assignment.bundles - ) - ) - ) - ) - ); - } - - /** - * merge a state and some updates into a new optimizer state, apply some - * standard updates related to timing, and wrap it up with an event to - * create an OptimizerMsg - */ - private createOptimizerMsg( - prevState: OptimizerState, - event?: OptimizerEvent, - stateUpdate?: Partial> - ): OptimizerMsg { - // reset start time if we are transitioning into running - const startTime = - (prevState.phase === 'success' || prevState.phase === 'issue') && - (stateUpdate?.phase === 'running' || stateUpdate?.phase === 'reallocating') - ? Date.now() - : prevState.startTime; - - return { - event, - state: { - ...prevState, - ...stateUpdate, - startTime, - durSec: msToSec(Date.now() - startTime), - }, - }; - } - - /** - * calculate the total state, given a set of compiler messages - */ - private getStatePhase(states: CompilerMsg[]) { - const types = states.map(s => s.type); - - if (types.includes('running')) { - return 'running'; - } - - if (types.includes('compiler issue')) { - return 'issue'; - } - - if (types.every(s => s === 'compiler success')) { - return 'success'; - } - - throw new Error(`unable to summarize bundle states: ${JSON.stringify(states)}`); - } - - /** - * Convert a stream of OptimizerEvents into the public stream of - * OptimizerMsgs. The resulting state reflects the total state - * of all bundles and workers. - */ - private summarizeOptimizerEvent$(initMsg: OptimizerMsg, event$: Rx.Observable) { - return event$.pipe( - scan((prevMsg, event) => { - const { state } = prevMsg; - - if (event.type === 'optimizer initialized') { - if (state.onlineBundles.length === 0) { - // all bundles are cached so we transition to success - return this.createOptimizerMsg(state, event, { - phase: 'success', - }); - } - - // no state change necessary - return prevMsg; - } - - if (event.type === 'worker error' || event.type === 'compiler error') { - // unrecoverable error states - const error = new Error(event.errorMsg); - error.stack = event.errorStack; - throw error; - } - - if (event.type === 'worker stdio' || event.type === 'worker started') { - return this.createOptimizerMsg(state, event); - } - - if (event.type === 'changes detected') { - // switch to running early, before workers are started, so that - // base path proxy can prevent requests in the delay between changes - // and workers started - return this.createOptimizerMsg(state, event, { - phase: 'reallocating', - }); - } - - if (event.type === 'changes') { - const onlineBundles: Bundle[] = []; - const offlineBundles: Bundle[] = []; - for (const bundle of this.config.bundles) { - if (state.onlineBundles.includes(bundle) || event.bundles.includes(bundle)) { - onlineBundles.push(bundle); - } else { - offlineBundles.push(bundle); - } - } - - return this.createOptimizerMsg(state, event, { - phase: 'running', - onlineBundles, - offlineBundles, - }); - } - - if ( - event.type === 'compiler issue' || - event.type === 'compiler success' || - event.type === 'running' - ) { - const compilerStates: CompilerMsg[] = [ - ...state.compilerStates.filter(c => c.bundleId !== event.bundleId), - event, - ]; - return this.createOptimizerMsg(state, event, { - phase: this.getStatePhase(compilerStates), - compilerStates, - }); - } - - throw new Error(`unexpected optimizer event ${inspect(event)}`); - }, initMsg), - - // returning the previous message is how we indicate - // that an event should be dropped - distinctUntilChanged() - ); - } - - run() { - // initialize the optimizer by figuring out which bundles are cached, which bundles - const init$ = Rx.defer( - async (): Promise => { - const startTime = Date.now(); - const version = await getOptimizerVersion(this.config); - const offlineBundles = this.config.cache ? await this.getCachedBundles(version) : []; - const onlineBundles = this.config.bundles.filter(b => !offlineBundles.includes(b)); - - return this.createOptimizerMsg({ - phase: 'initialized', - version, - compilerStates: [], - durSec: msToSec(Date.now() - startTime), - offlineBundles, - onlineBundles, - startTime, - }); - } - ); - - return init$.pipe( - mergeMap( - (init): Rx.Observable => { - const { state: initState } = init; - - const changeEvent$ = this.watchBundlesForChanges$( - initState.offlineBundles, - initState.startTime - ).pipe(share()); - const workerEvent$ = this.runWorkers(initState, changeEvent$); - - // event to kick off the summarizer - const initEvent: OptimizerInitializedEvent = { - type: 'optimizer initialized', - }; - - return Rx.concat( - Rx.of(init), - this.summarizeOptimizerEvent$( - init, - Rx.merge(Rx.of(initEvent), changeEvent$, workerEvent$) - ) - ); - } - ) - ); - } -} diff --git a/packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts similarity index 99% rename from packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts rename to packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts index 0d272e9ce6bf0..d18a171c53356 100644 --- a/packages/kbn-optimizer/src/assign_bundles_to_workers.test.ts +++ b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts @@ -17,9 +17,10 @@ * under the License. */ +import { Bundle } from '../common'; + import { getBundles } from './get_bundles'; import { assignBundlesToWorkers, Assignments } from './assign_bundles_to_workers'; -import { Bundle } from './common'; const REPO = '/repo'; const BIG_BUNDLES = 'dqv'.split(''); diff --git a/packages/kbn-optimizer/src/assign_bundles_to_workers.ts b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts similarity index 98% rename from packages/kbn-optimizer/src/assign_bundles_to_workers.ts rename to packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts index a6c88dd2377a3..bf7e4d5b37163 100644 --- a/packages/kbn-optimizer/src/assign_bundles_to_workers.ts +++ b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Bundle, descending, ascending } from './common'; +import { Bundle, descending, ascending } from '../common'; // helper types used inside getWorkerConfigs so we don't have // to calculate moduleCounts over and over diff --git a/packages/kbn-optimizer/src/optimizer/bundle_cache.ts b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts new file mode 100644 index 0000000000000..2cf96346fa40c --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts @@ -0,0 +1,139 @@ +/* + * 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 * as Rx from 'rxjs'; + +import { Bundle } from '../common'; + +import { OptimizerConfig } from './optimizer_config'; +import { getMtimes } from './get_mtimes'; +import { diffCacheKey, OptimizerCacheKey } from './cache_keys'; + +export type BundleCacheEvent = BundleNotCachedEvent | BundleCachedEvent; + +export interface BundleNotCachedEvent { + type: 'bundle not cached'; + reason: + | 'missing optimizer cache key' + | 'optimizer cache key mismatch' + | 'missing cache key' + | 'cache key mismatch'; + diff?: string; + bundle: Bundle; +} + +export interface BundleCachedEvent { + type: 'bundle cached'; + bundle: Bundle; +} + +export function getBundleCacheEvent$( + config: OptimizerConfig, + optimizerCacheKey: OptimizerCacheKey +) { + return new Rx.Observable(subscriber => { + // we only want to get the mtimes for files when the bundle was built + // with our version of the optimizer and there is a cache key so filter + // out some bundles early + const eligible: Bundle[] = []; + + for (const bundle of config.bundles) { + const cachedOptimizerCacheKeys = bundle.cache.getOptimizerCacheKey(); + if (!cachedOptimizerCacheKeys) { + subscriber.next({ + type: 'bundle not cached', + reason: 'missing optimizer cache key', + bundle, + }); + continue; + } + + const optimizerCacheKeyDiff = diffCacheKey(cachedOptimizerCacheKeys, optimizerCacheKey); + if (optimizerCacheKeyDiff !== undefined) { + subscriber.next({ + type: 'bundle not cached', + reason: 'optimizer cache key mismatch', + diff: optimizerCacheKeyDiff, + bundle, + }); + continue; + } + + if (!bundle.cache.getCacheKeys()) { + subscriber.next({ + type: 'bundle not cached', + reason: 'missing cache key', + bundle, + }); + continue; + } + + eligible.push(bundle); + } + + if (!eligible.length) { + subscriber.complete(); + return; + } + + getMtimes( + new Set( + eligible.reduce( + (acc: string[], bundle) => [...acc, ...(bundle.cache.getReferencedFiles() || [])], + [] + ) + ) + ) + .then(mtimes => { + if (subscriber.closed) { + return; + } + + for (const bundle of eligible) { + const diff = diffCacheKey( + bundle.cache.getCacheKeys(), + bundle.createCacheKey(bundle.cache.getReferencedFiles() || [], mtimes) + ); + + if (diff) { + subscriber.next({ + type: 'bundle not cached', + reason: 'cache key mismatch', + diff, + bundle, + }); + continue; + } + + subscriber.next({ + type: 'bundle cached', + bundle, + }); + } + }) + .then( + () => { + subscriber.complete(); + }, + error => { + subscriber.error(error); + } + ); + }); +} diff --git a/packages/kbn-optimizer/src/optimizer/cache_keys.ts b/packages/kbn-optimizer/src/optimizer/cache_keys.ts new file mode 100644 index 0000000000000..e9d7854115685 --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/cache_keys.ts @@ -0,0 +1,155 @@ +/* + * 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 Path from 'path'; + +import Chalk from 'chalk'; +import execa from 'execa'; +import { REPO_ROOT } from '@kbn/dev-utils'; +import stripAnsi from 'strip-ansi'; + +import jestDiff from 'jest-diff'; +import jsonStable from 'json-stable-stringify'; +import { ascending, WorkerConfig } from '../common'; + +import { getMtimes } from './get_mtimes'; +import { getChanges } from './get_changes'; +import { OptimizerConfig } from './optimizer_config'; + +const OPTIMIZER_DIR = Path.dirname(require.resolve('../../package.json')); +const RELATIVE_DIR = Path.relative(REPO_ROOT, OPTIMIZER_DIR); + +export function diffCacheKey(cacheKeyA?: unknown, cacheKeyB?: unknown) { + const a = jsonStable(cacheKeyA); + const b = jsonStable(cacheKeyB); + + if (a === b) { + return; + } + + const diff = jestDiff(cacheKeyA, cacheKeyB); + const diffLines = diff?.split('\n') || []; + + if ( + diffLines.length < 4 || + stripAnsi(diffLines[0]) !== '- Expected' || + stripAnsi(diffLines[1]) !== '+ Received' + ) { + throw new Error(`unexpected diff format: ${diff}`); + } + + const outputLines = [diffLines.shift(), diffLines.shift(), diffLines.shift()]; + + /** + * buffer which contains between 0 and 5 lines from the diff which aren't additions or + * deletions. The first three are the first three lines seen since the buffer was cleared + * and the last two lines are the last two lines seen. + * + * When flushContext() is called we write the first two lines to output, an elipses if there + * are five lines, and then the last two lines. + * + * At the very end we will write the last two lines of context if they're defined + */ + const contextBuffer: string[] = []; + + /** + * Convert a line to an empty line with elipses placed where the text on that line starts + */ + const toElipses = (line: string) => { + return stripAnsi(line).replace(/^(\s*).*/, '$1...'); + }; + + while (diffLines.length) { + const line = diffLines.shift()!; + const plainLine = stripAnsi(line); + if (plainLine.startsWith('+ ') || plainLine.startsWith('- ')) { + // write contextBuffer to the outputLines + if (contextBuffer.length) { + outputLines.push( + ...contextBuffer.slice(0, 2), + ...(contextBuffer.length === 5 + ? [Chalk.dim(toElipses(contextBuffer[2])), ...contextBuffer.slice(3, 5)] + : contextBuffer.slice(2, 4)) + ); + + contextBuffer.length = 0; + } + + // add this line to the outputLines + outputLines.push(line); + } else { + // update the contextBuffer with this line which doesn't represent a change + if (contextBuffer.length === 5) { + contextBuffer[3] = contextBuffer[4]; + contextBuffer[4] = line; + } else { + contextBuffer.push(line); + } + } + } + + if (contextBuffer.length) { + outputLines.push( + ...contextBuffer.slice(0, 2), + ...(contextBuffer.length > 2 ? [Chalk.dim(toElipses(contextBuffer[2]))] : []) + ); + } + + return outputLines.join('\n'); +} + +export interface OptimizerCacheKey { + readonly lastCommit: string | undefined; + readonly workerConfig: WorkerConfig; + readonly deletedPaths: string[]; + readonly modifiedPaths: Record; +} + +async function getLastCommit() { + const { stdout } = await execa( + 'git', + ['log', '-n', '1', '--pretty=format:%H', '--', RELATIVE_DIR], + { + cwd: REPO_ROOT, + } + ); + + return stdout.trim() || undefined; +} + +export async function getOptimizerCacheKey(config: OptimizerConfig) { + const changes = Array.from((await getChanges(OPTIMIZER_DIR)).entries()); + + const cacheKeys: OptimizerCacheKey = { + lastCommit: await getLastCommit(), + workerConfig: config.getWorkerConfig('♻'), + deletedPaths: changes.filter(e => e[1] === 'deleted').map(e => e[0]), + modifiedPaths: {} as Record, + }; + + const modified = changes.filter(e => e[1] === 'modified').map(e => e[0]); + const mtimes = await getMtimes(modified); + for (const [path, mtime] of Array.from(mtimes.entries()).sort(ascending(e => e[0]))) { + if (typeof mtime === 'number') { + cacheKeys.modifiedPaths[path] = mtime; + } + } + + return cacheKeys; +} diff --git a/packages/kbn-optimizer/src/get_bundles.test.ts b/packages/kbn-optimizer/src/optimizer/get_bundles.test.ts similarity index 100% rename from packages/kbn-optimizer/src/get_bundles.test.ts rename to packages/kbn-optimizer/src/optimizer/get_bundles.test.ts diff --git a/packages/kbn-optimizer/src/get_bundles.ts b/packages/kbn-optimizer/src/optimizer/get_bundles.ts similarity index 97% rename from packages/kbn-optimizer/src/get_bundles.ts rename to packages/kbn-optimizer/src/optimizer/get_bundles.ts index a8c919d3daeaa..7b574a40b7617 100644 --- a/packages/kbn-optimizer/src/get_bundles.ts +++ b/packages/kbn-optimizer/src/optimizer/get_bundles.ts @@ -19,8 +19,9 @@ import Path from 'path'; +import { Bundle } from '../common'; + import { NewPlatformPlugin } from './new_platform_plugins'; -import { Bundle } from './common'; export function getBundles(plugins: NewPlatformPlugin[], repoRoot: string) { return plugins diff --git a/packages/kbn-optimizer/src/get_changes.test.ts b/packages/kbn-optimizer/src/optimizer/get_changes.test.ts similarity index 100% rename from packages/kbn-optimizer/src/get_changes.test.ts rename to packages/kbn-optimizer/src/optimizer/get_changes.test.ts diff --git a/packages/kbn-optimizer/src/get_changes.ts b/packages/kbn-optimizer/src/optimizer/get_changes.ts similarity index 100% rename from packages/kbn-optimizer/src/get_changes.ts rename to packages/kbn-optimizer/src/optimizer/get_changes.ts diff --git a/packages/kbn-optimizer/src/get_mtimes.test.ts b/packages/kbn-optimizer/src/optimizer/get_mtimes.test.ts similarity index 100% rename from packages/kbn-optimizer/src/get_mtimes.test.ts rename to packages/kbn-optimizer/src/optimizer/get_mtimes.test.ts diff --git a/packages/kbn-optimizer/src/get_mtimes.ts b/packages/kbn-optimizer/src/optimizer/get_mtimes.ts similarity index 97% rename from packages/kbn-optimizer/src/get_mtimes.ts rename to packages/kbn-optimizer/src/optimizer/get_mtimes.ts index 1993a799cff7b..4efacf7f00dcb 100644 --- a/packages/kbn-optimizer/src/get_mtimes.ts +++ b/packages/kbn-optimizer/src/optimizer/get_mtimes.ts @@ -20,7 +20,7 @@ import Fs from 'fs'; import { promisify } from 'util'; -import { concurrentMap } from './common'; +import { concurrentMap } from '../common'; const statAsync = promisify(Fs.stat); diff --git a/packages/kbn-optimizer/src/optimizer/index.ts b/packages/kbn-optimizer/src/optimizer/index.ts new file mode 100644 index 0000000000000..a549fb156ee61 --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/index.ts @@ -0,0 +1,26 @@ +/* + * 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 * from './optimizer_config'; +export { WorkerStdio } from './observe_worker'; +export * from './optimizer_msg'; +export * from './cache_keys'; +export * from './watch_bundles_for_changes'; +export * from './run_workers'; +export * from './bundle_cache'; diff --git a/packages/kbn-optimizer/src/new_platform_plugins.test.ts b/packages/kbn-optimizer/src/optimizer/new_platform_plugins.test.ts similarity index 100% rename from packages/kbn-optimizer/src/new_platform_plugins.test.ts rename to packages/kbn-optimizer/src/optimizer/new_platform_plugins.test.ts diff --git a/packages/kbn-optimizer/src/new_platform_plugins.ts b/packages/kbn-optimizer/src/optimizer/new_platform_plugins.ts similarity index 100% rename from packages/kbn-optimizer/src/new_platform_plugins.ts rename to packages/kbn-optimizer/src/optimizer/new_platform_plugins.ts diff --git a/packages/kbn-optimizer/src/observe_worker.ts b/packages/kbn-optimizer/src/optimizer/observe_worker.ts similarity index 97% rename from packages/kbn-optimizer/src/observe_worker.ts rename to packages/kbn-optimizer/src/optimizer/observe_worker.ts index 7bbcc7a3feb6c..bfc853e5a6b75 100644 --- a/packages/kbn-optimizer/src/observe_worker.ts +++ b/packages/kbn-optimizer/src/optimizer/observe_worker.ts @@ -24,7 +24,8 @@ import { inspect } from 'util'; import * as Rx from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; -import { isWorkerMsg, WorkerConfig, WorkerMsg, Bundle } from './common'; +import { isWorkerMsg, WorkerConfig, WorkerMsg, Bundle } from '../common'; + import { OptimizerConfig } from './optimizer_config'; export interface WorkerStdio { @@ -75,7 +76,7 @@ function usingWorkerProc( (): ProcResource => { const args = [JSON.stringify(workerConfig), JSON.stringify(bundles.map(b => b.toSpec()))]; - const proc = fork(require.resolve('./worker/run_worker'), args, { + const proc = fork(require.resolve('../worker/run_worker'), args, { stdio: ['ignore', 'pipe', 'pipe', 'ipc'], execArgv: [ ...(inspectFlag && config.inspectWorkers diff --git a/packages/kbn-optimizer/src/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts similarity index 100% rename from packages/kbn-optimizer/src/optimizer_config.test.ts rename to packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts diff --git a/packages/kbn-optimizer/src/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts similarity index 97% rename from packages/kbn-optimizer/src/optimizer_config.ts rename to packages/kbn-optimizer/src/optimizer/optimizer_config.ts index cd1bdd5a64fb1..3467eddd93e48 100644 --- a/packages/kbn-optimizer/src/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts @@ -20,8 +20,9 @@ import Path from 'path'; import Os from 'os'; +import { Bundle, WorkerConfig } from '../common'; + import { findNewPlatformPlugins, NewPlatformPlugin } from './new_platform_plugins'; -import { Bundle, WorkerConfig } from './common'; import { getBundles } from './get_bundles'; interface Options { @@ -157,14 +158,14 @@ export class OptimizerConfig { public readonly profileWebpack: boolean ) {} - getWorkerConfig(optimizerVersion: string): WorkerConfig { + getWorkerConfig(optimizerCacheKey: unknown): WorkerConfig { return { cache: this.cache, dist: this.dist, profileWebpack: this.profileWebpack, repoRoot: this.repoRoot, watch: this.watch, - optimizerVersion, + optimizerCacheKey, browserslistEnv: this.dist ? 'production' : process.env.BROWSERSLIST_ENV || 'dev', }; } diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts b/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts new file mode 100644 index 0000000000000..eb8f25975cc3d --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts @@ -0,0 +1,213 @@ +/* + * 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 { inspect } from 'util'; + +import * as Rx from 'rxjs'; +import { scan, distinctUntilChanged } from 'rxjs/operators'; + +import { WorkerMsg, CompilerMsg, Bundle } from '../common'; + +import { ChangeEvent } from './watcher'; +import { WorkerStatus } from './observe_worker'; +import { BundleCacheEvent } from './bundle_cache'; +import { OptimizerConfig } from './optimizer_config'; + +export interface OptimizerInitializedEvent { + type: 'optimizer initialized'; +} + +export type OptimizerEvent = + | OptimizerInitializedEvent + | ChangeEvent + | WorkerMsg + | WorkerStatus + | BundleCacheEvent; + +export interface OptimizerMsg { + state: OptimizerState; + event?: OptimizerEvent; +} + +export interface OptimizerState { + phase: 'initialized' | 'reallocating' | 'success' | 'running' | 'issue'; + startTime: number; + durSec: number; + compilerStates: CompilerMsg[]; + onlineBundles: Bundle[]; + offlineBundles: Bundle[]; +} + +const msToSec = (ms: number) => Math.round(ms / 100) / 10; + +/** + * merge a state and some updates into a new optimizer state, apply some + * standard updates related to timing, and wrap it up with an event to + * create an OptimizerMsg + */ +export function createOptimizerMsg( + prevState: OptimizerState, + event?: OptimizerEvent, + stateUpdate?: Partial> +): OptimizerMsg { + // reset start time if we are transitioning into running + const startTime = + (prevState.phase === 'success' || prevState.phase === 'issue') && + (stateUpdate?.phase === 'running' || stateUpdate?.phase === 'reallocating') + ? Date.now() + : prevState.startTime; + + return { + event, + state: { + ...prevState, + ...stateUpdate, + startTime, + durSec: msToSec(Date.now() - startTime), + }, + }; +} + +/** + * calculate the total state, given a set of compiler messages + */ +function getStatePhase(states: CompilerMsg[]) { + const types = states.map(s => s.type); + + if (types.includes('running')) { + return 'running'; + } + + if (types.includes('compiler issue')) { + return 'issue'; + } + + if (types.every(s => s === 'compiler success')) { + return 'success'; + } + + throw new Error(`unable to summarize bundle states: ${JSON.stringify(states)}`); +} + +/** + * Convert a stream of OptimizerEvents into the public stream of + * OptimizerMsgs. The resulting state reflects the total state + * of all bundles and workers. + */ +export function summarizeOptimizerEvent$( + config: OptimizerConfig, + initialStartTime: number, + event$: Rx.Observable +) { + return event$.pipe( + scan( + (prevMsg, event) => { + const { state } = prevMsg; + + if (event.type === 'optimizer initialized') { + if (state.onlineBundles.length === 0) { + // all bundles are cached so we transition to success + return createOptimizerMsg(state, event, { + phase: 'success', + }); + } + + // no state change necessary + return prevMsg; + } + + if (event.type === 'worker error' || event.type === 'compiler error') { + // unrecoverable error states + const error = new Error(event.errorMsg); + error.stack = event.errorStack; + throw error; + } + + if (event.type === 'worker stdio' || event.type === 'worker started') { + return createOptimizerMsg(state, event); + } + + if (event.type === 'changes detected') { + // switch to running early, before workers are started, so that + // base path proxy can prevent requests in the delay between changes + // and workers started + return createOptimizerMsg(state, event, { + phase: 'reallocating', + }); + } + + if ( + event.type === 'changes' || + event.type === 'bundle cached' || + event.type === 'bundle not cached' + ) { + const onlineBundles: Bundle[] = [...state.onlineBundles]; + if (event.type === 'changes') { + onlineBundles.push(...event.bundles); + } + if (event.type === 'bundle not cached') { + onlineBundles.push(event.bundle); + } + + const offlineBundles: Bundle[] = []; + for (const bundle of config.bundles) { + if (!onlineBundles.includes(bundle)) { + offlineBundles.push(bundle); + } + } + + return createOptimizerMsg(state, event, { + phase: 'running', + onlineBundles, + offlineBundles, + }); + } + + if ( + event.type === 'compiler issue' || + event.type === 'compiler success' || + event.type === 'running' + ) { + const compilerStates: CompilerMsg[] = [ + ...state.compilerStates.filter(c => c.bundleId !== event.bundleId), + event, + ]; + return createOptimizerMsg(state, event, { + phase: getStatePhase(compilerStates), + compilerStates, + }); + } + + throw new Error(`unexpected optimizer event ${inspect(event)}`); + }, + createOptimizerMsg({ + compilerStates: [], + durSec: 0, + offlineBundles: [], + onlineBundles: [], + phase: 'success', + startTime: initialStartTime, + }) + ), + + // returning the previous message is how we indicate + // that an event should be dropped + distinctUntilChanged() + ); +} diff --git a/packages/kbn-optimizer/src/optimizer/run_workers.ts b/packages/kbn-optimizer/src/optimizer/run_workers.ts new file mode 100644 index 0000000000000..94d850c1ae91e --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/run_workers.ts @@ -0,0 +1,68 @@ +/* + * 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 * as Rx from 'rxjs'; +import { mergeMap, toArray } from 'rxjs/operators'; + +import { maybeMap } from '../common'; + +import { OptimizerConfig } from './optimizer_config'; +import { BundleCacheEvent } from './bundle_cache'; +import { ChangeEvent } from './watcher'; +import { assignBundlesToWorkers } from './assign_bundles_to_workers'; +import { observeWorker } from './observe_worker'; +import { OptimizerCacheKey } from './cache_keys'; + +/** + * Create a stream of all worker events, these include messages + * from workers and events about the status of workers. To get + * these events we assign the bundles to workers via + * `assignBundlesToWorkers()` and then start a worler for each + * assignment with `observeWorker()`. + * + * Subscribes to `changeEvent$` in order to determine when more + * bundles should be assigned to workers. + * + * Completes when all workers have exitted. If we are running in + * watch mode this observable will never exit. + */ +export function runWorkers( + config: OptimizerConfig, + optimizerCacheKey: OptimizerCacheKey, + bundleCache$: Rx.Observable, + changeEvent$: Rx.Observable +) { + return Rx.concat( + // first batch of bundles are based on how up-to-date the cache is + bundleCache$.pipe( + maybeMap(event => (event.type === 'bundle not cached' ? event.bundle : undefined)), + toArray() + ), + // subsequent batches are defined by changeEvent$ + changeEvent$.pipe(maybeMap(c => (c.type === 'changes' ? c.bundles : undefined))) + ).pipe( + mergeMap(bundles => + Rx.from(assignBundlesToWorkers(bundles, config.maxWorkerCount)).pipe( + mergeMap(assignment => + observeWorker(config, config.getWorkerConfig(optimizerCacheKey), assignment.bundles) + ) + ) + ) + ); +} diff --git a/packages/kbn-optimizer/src/optimizer/watch_bundles_for_changes.ts b/packages/kbn-optimizer/src/optimizer/watch_bundles_for_changes.ts new file mode 100644 index 0000000000000..9149c483786fc --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/watch_bundles_for_changes.ts @@ -0,0 +1,85 @@ +/* + * 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 * as Rx from 'rxjs'; +import { mergeMap, toArray } from 'rxjs/operators'; + +import { Bundle, maybeMap } from '../common'; + +import { BundleCacheEvent } from './bundle_cache'; +import { Watcher } from './watcher'; + +/** + * Recursively call watcher.getNextChange$, passing it + * just the bundles that haven't been changed yet until + * all bundles have changed, then exit + */ +function recursiveGetNextChange$( + watcher: Watcher, + bundles: Bundle[], + startTime: number +): ReturnType { + return !bundles.length + ? Rx.EMPTY + : watcher.getNextChange$(bundles, startTime).pipe( + mergeMap(event => { + if (event.type === 'changes detected') { + return Rx.of(event); + } + + return Rx.concat( + Rx.of(event), + + recursiveGetNextChange$( + watcher, + bundles.filter(b => !event.bundles.includes(b)), + Date.now() + ) + ); + }) + ); +} + +/** + * Create an observable that emits change events for offline + * bundles. + * + * Once changes are seen in a bundle that bundles + * files will no longer be watched. + * + * Once changes have been seen in all bundles changeEvent$ + * will complete. + * + * If there are no bundles to watch or we config.watch === false + * the observable completes without sending any notifications. + */ +export function watchBundlesForChanges$( + bundleCacheEvent$: Rx.Observable, + initialStartTime: number +) { + return bundleCacheEvent$.pipe( + maybeMap(event => (event.type === 'bundle cached' ? event.bundle : undefined)), + toArray(), + mergeMap(bundles => + bundles.length + ? Watcher.using(watcher => recursiveGetNextChange$(watcher, bundles, initialStartTime)) + : Rx.EMPTY + ) + ); +} diff --git a/packages/kbn-optimizer/src/watcher.ts b/packages/kbn-optimizer/src/optimizer/watcher.ts similarity index 96% rename from packages/kbn-optimizer/src/watcher.ts rename to packages/kbn-optimizer/src/optimizer/watcher.ts index 0ccc05300af9d..d3ba2640c2dd1 100644 --- a/packages/kbn-optimizer/src/watcher.ts +++ b/packages/kbn-optimizer/src/optimizer/watcher.ts @@ -21,7 +21,7 @@ import * as Rx from 'rxjs'; import { take, map } from 'rxjs/operators'; import Watchpack from 'watchpack'; -import { debounceTimeBuffer, Bundle } from './common'; +import { debounceTimeBuffer, Bundle } from '../common'; export interface ChangesStarted { type: 'changes detected'; @@ -32,6 +32,8 @@ export interface Changes { bundles: Bundle[]; } +export type ChangeEvent = ChangesStarted | Changes; + export class Watcher { /** * Use watcher as an RxJS Resource, which is a special type of observable diff --git a/packages/kbn-optimizer/src/run_optimizer.ts b/packages/kbn-optimizer/src/run_optimizer.ts new file mode 100644 index 0000000000000..9f92756e650a8 --- /dev/null +++ b/packages/kbn-optimizer/src/run_optimizer.ts @@ -0,0 +1,72 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as Rx from 'rxjs'; +import { mergeMap, share, observeOn } from 'rxjs/operators'; + +import { + OptimizerConfig, + OptimizerMsg, + getBundleCacheEvent$, + getOptimizerCacheKey, + watchBundlesForChanges$, + runWorkers, + OptimizerInitializedEvent, + summarizeOptimizerEvent$, +} from './optimizer'; + +export function runOptimizer(config: OptimizerConfig) { + return Rx.defer(async () => ({ + startTime: Date.now(), + cacheKey: await getOptimizerCacheKey(config), + })).pipe( + mergeMap( + (init): Rx.Observable => { + const bundleCacheEvent$ = getBundleCacheEvent$(config, init.cacheKey).pipe( + observeOn(Rx.asyncScheduler), + share() + ); + + // watch the offline bundles for changes, turning them online... + const changeEvent$ = config.watch + ? watchBundlesForChanges$(bundleCacheEvent$, init.startTime).pipe(share()) + : Rx.EMPTY; + + // run workers to build all the online bundles, including the bundles turned online by changeEvent$ + const workerEvent$ = runWorkers(config, init.cacheKey, bundleCacheEvent$, changeEvent$); + + // kick off the event summarizer with an intialized event + const initEvent: OptimizerInitializedEvent = { + type: 'optimizer initialized', + }; + + // all of the events occuring within the optimizer + const event$ = Rx.merge( + Rx.concat(bundleCacheEvent$, Rx.of(initEvent)), + changeEvent$, + workerEvent$ + ); + + // summarize all events into public OptimizerMsg objects, which include states and + // the event which lead to that state + return summarizeOptimizerEvent$(config, init.startTime, event$); + } + ) + ); +} diff --git a/packages/kbn-optimizer/src/worker/run_compilers.ts b/packages/kbn-optimizer/src/worker/run_compilers.ts index 8af5cee03d70a..7dcce8a0fae8d 100644 --- a/packages/kbn-optimizer/src/worker/run_compilers.ts +++ b/packages/kbn-optimizer/src/worker/run_compilers.ts @@ -143,8 +143,8 @@ const observeCompiler = ( ); bundle.cache.set({ - optimizerVersion: workerConfig.optimizerVersion, - key: bundle.createCacheKey(files, mtimes), + optimizerCacheKey: workerConfig.optimizerCacheKey, + cacheKey: bundle.createCacheKey(files, mtimes), moduleCount: normalModules.length, files, }); diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts index 235d5da7f7e99..d6ca2aa94fb1a 100644 --- a/packages/kbn-optimizer/src/worker/run_worker.ts +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -21,6 +21,7 @@ import * as Rx from 'rxjs'; import { mergeMap } from 'rxjs/operators'; import { parseBundles, parseWorkerConfig, WorkerMsg, isWorkerMsg, WorkerMsgs } from '../common'; + import { runCompilers } from './run_compilers'; /** diff --git a/yarn.lock b/yarn.lock index 899b0311fcee9..40bd5736c48f4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2399,6 +2399,16 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" +"@jest/types@^25.1.0": + version "25.1.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.1.0.tgz#b26831916f0d7c381e11dbb5e103a72aed1b4395" + integrity sha512-VpOtt7tCrgvamWZh1reVsGADujKigBUFTi19mlRjqEGsE8qH4r3s+skY33dNdXOwyZIvuftZ5tqdF1IgsMejMA== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + "@jimp/bmp@^0.8.4": version "0.8.4" resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.8.4.tgz#3246e0c6b073b3e2d9b61075ac0146d9124c9277" @@ -4275,6 +4285,11 @@ resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.0.tgz#926f76f7e66f49cc59ad880bb15b030abbf0b66d" integrity sha512-gZ/Rb+MFXF0pXSEQxdRoPMm5jeO3TycjOdvbpbcpHX/B+n9AqaHFe5q6Ga9CsZ7ir/UgIWPfrBzUzn3F19VH/w== +"@types/color-name@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== + "@types/color@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/color/-/color-3.0.0.tgz#40f8a6bf2fd86e969876b339a837d8ff1b0a6e30" @@ -5438,6 +5453,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^15.0.0": + version "15.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.3.tgz#41453a0bc7ab393e995d1f5451455638edbd2baf" + integrity sha512-XCMQRK6kfpNBixHLyHUsGmXrpEmFFxzMrcnSXFMziHd8CoNJo8l16FkHyQq4x+xbM7E2XL83/O78OD8u+iZTdQ== + dependencies: + "@types/yargs-parser" "*" + "@types/zen-observable@^0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.0.tgz#8b63ab7f1aa5321248aad5ac890a485656dcea4d" @@ -6250,6 +6272,14 @@ ansi-styles@^3.2.0: dependencies: color-convert "^1.9.0" +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== + dependencies: + "@types/color-name" "^1.1.1" + color-convert "^2.0.1" + ansi-styles@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" @@ -8782,6 +8812,14 @@ chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^5.2.0" +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" @@ -9411,12 +9449,19 @@ color-convert@^1.9.1: dependencies: color-name "1.1.3" +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + color-name@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@^1.0.0, color-name@^1.1.1: +color-name@^1.0.0, color-name@^1.1.1, color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== @@ -11506,6 +11551,11 @@ diff-sequences@^24.9.0: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== +diff-sequences@^25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.1.0.tgz#fd29a46f1c913fd66c22645dc75bffbe43051f32" + integrity sha512-nFIfVk5B/NStCsJ+zaPO4vYuLjlzQ6uFvPxzYyHlejNZ/UGa7G/n7peOXVrVNvRuyfstt+mZQYGpjxg9Z6N8Kw== + diff@3.5.0, diff@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" @@ -17927,6 +17977,16 @@ jest-diff@^24.0.0: jest-get-type "^24.0.0" pretty-format "^24.0.0" +jest-diff@^25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.1.0.tgz#58b827e63edea1bc80c1de952b80cec9ac50e1ad" + integrity sha512-nepXgajT+h017APJTreSieh4zCqnSHEJ1iT8HDlewu630lSJ4Kjjr9KNzm+kzGwwcpsDE6Snx1GJGzzsefaEHw== + dependencies: + chalk "^3.0.0" + diff-sequences "^25.1.0" + jest-get-type "^25.1.0" + pretty-format "^25.1.0" + jest-docblock@^24.3.0: version "24.3.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.3.0.tgz#b9c32dac70f72e4464520d2ba4aec02ab14db5dd" @@ -17978,6 +18038,11 @@ jest-get-type@^24.9.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== +jest-get-type@^25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.1.0.tgz#1cfe5fc34f148dc3a8a3b7275f6b9ce9e2e8a876" + integrity sha512-yWkBnT+5tMr8ANB6V+OjmrIJufHtCAqI5ic2H40v+tRqxDmE0PGnIiTyvRWFOMtmVHYpwRqyazDbTnhpjsGvLw== + jest-haste-map@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" @@ -23313,6 +23378,16 @@ pretty-format@^24.3.0, pretty-format@^24.9.0: ansi-styles "^3.2.0" react-is "^16.8.4" +pretty-format@^25.1.0: + version "25.1.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.1.0.tgz#ed869bdaec1356fc5ae45de045e2c8ec7b07b0c8" + integrity sha512-46zLRSGLd02Rp+Lhad9zzuNZ+swunitn8zIpfD2B4OPCRLXbM87RJT2aBLBWYOznNUML/2l/ReMyWNC80PJBUQ== + dependencies: + "@jest/types" "^25.1.0" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^16.12.0" + pretty-hrtime@^1.0.0, pretty-hrtime@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -24356,7 +24431,7 @@ react-is@^16.10.2, react-is@^16.9.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.11.0.tgz#b85dfecd48ad1ce469ff558a882ca8e8313928fa" integrity sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw== -react-is@^16.3.1: +react-is@^16.12.0, react-is@^16.3.1: version "16.12.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c" integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q== @@ -28212,6 +28287,13 @@ supports-color@^7.0.0: dependencies: has-flag "^4.0.0" +supports-color@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== + dependencies: + has-flag "^4.0.0" + supports-hyperlinks@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-1.0.1.tgz#71daedf36cc1060ac5100c351bb3da48c29c0ef7" From 6adeb6849e7499771f9e49fd7f4e6a92429f3614 Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 10 Feb 2020 13:07:20 -0700 Subject: [PATCH 55/83] fix tests --- .../kbn-optimizer/src/optimizer/new_platform_plugins.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/src/optimizer/new_platform_plugins.test.ts b/packages/kbn-optimizer/src/optimizer/new_platform_plugins.test.ts index 7d8cc18fc4d6d..eab476e6154b7 100644 --- a/packages/kbn-optimizer/src/optimizer/new_platform_plugins.test.ts +++ b/packages/kbn-optimizer/src/optimizer/new_platform_plugins.test.ts @@ -25,7 +25,7 @@ import { findNewPlatformPlugins } from './new_platform_plugins'; expect.addSnapshotSerializer(createAbsolutePathSerializer()); -const FIXTURES_PATH = Path.resolve(__dirname, './__fixtures__'); +const FIXTURES_PATH = Path.resolve(__dirname, '../__fixtures__'); it('parses kibana.json files of plugins found in pluginDirs', () => { expect( From 85a398a3e87724792a26bb6a2d4aff995af9423a Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 10 Feb 2020 13:43:09 -0700 Subject: [PATCH 56/83] add initializing phase --- .../basic_optimization.test.ts | 6 +++++- .../kbn-optimizer/src/log_optimizer_state.ts | 7 +++++-- .../src/optimizer/optimizer_msg.ts | 18 ++++++------------ 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index 90637797553ee..b1b890fb537d5 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -90,6 +90,9 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { runningStates.length === 2 || runningStates.length === 3 ); + const bundleNotCachedEvents = msgs.filter(msg => msg.event?.type === 'bundle not cached'); + assert('produce two "bundle not cached" events', bundleNotCachedEvents.length === 2); + const successStates = msgs.filter(msg => msg.state.phase === 'success'); assert( 'produce one or two "compiler success" states', @@ -100,7 +103,8 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { msg => msg.state.phase !== 'success' && msg.state.phase !== 'running' && - msg.state.phase !== 'initialized' + msg.state.phase !== 'initialized' && + msg.event?.type !== 'bundle not cached' ); assert('produce zero unexpected states', otherStates.length === 0, otherStates); diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index d882bdfc050fc..aebb5dd87cdb9 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -68,9 +68,12 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { if (state.phase === 'initialized') { if (!loggedInit) { loggedInit = true; - log.info(`intialized, ${state.offlineBundles.length} bundles cached`); + log.info(`initialized, ${state.offlineBundles.length} bundles cached`); } + if (state.onlineBundles.length === 0) { + log.success(`all bundles cached, success after ${state.durSec}`); + } return; } @@ -87,7 +90,7 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { ); } - if (state.phase === 'running') { + if (state.phase === 'running' || state.phase === 'initializing') { return true; } diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts b/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts index eb8f25975cc3d..ff9e52ea6e96d 100644 --- a/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts +++ b/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts @@ -46,7 +46,7 @@ export interface OptimizerMsg { } export interface OptimizerState { - phase: 'initialized' | 'reallocating' | 'success' | 'running' | 'issue'; + phase: 'initializing' | 'initialized' | 'reallocating' | 'success' | 'running' | 'issue'; startTime: number; durSec: number; compilerStates: CompilerMsg[]; @@ -121,15 +121,9 @@ export function summarizeOptimizerEvent$( const { state } = prevMsg; if (event.type === 'optimizer initialized') { - if (state.onlineBundles.length === 0) { - // all bundles are cached so we transition to success - return createOptimizerMsg(state, event, { - phase: 'success', - }); - } - - // no state change necessary - return prevMsg; + return createOptimizerMsg(state, event, { + phase: 'initialized', + }); } if (event.type === 'worker error' || event.type === 'compiler error') { @@ -173,7 +167,7 @@ export function summarizeOptimizerEvent$( } return createOptimizerMsg(state, event, { - phase: 'running', + phase: state.phase === 'initializing' ? 'initializing' : 'running', onlineBundles, offlineBundles, }); @@ -201,7 +195,7 @@ export function summarizeOptimizerEvent$( durSec: 0, offlineBundles: [], onlineBundles: [], - phase: 'success', + phase: 'initializing', startTime: initialStartTime, }) ), From 9546bf7a6cd7163ce82a1088863fd13ba9c95765 Mon Sep 17 00:00:00 2001 From: spalger Date: Mon, 10 Feb 2020 14:45:21 -0700 Subject: [PATCH 57/83] avoid rxjs observable constructor --- .../kbn-optimizer/src/common/rxjs_helpers.ts | 32 ++++++++ .../src/optimizer/bundle_cache.ts | 76 ++++++++----------- 2 files changed, 63 insertions(+), 45 deletions(-) diff --git a/packages/kbn-optimizer/src/common/rxjs_helpers.ts b/packages/kbn-optimizer/src/common/rxjs_helpers.ts index 39b01e8e58682..fc8dc019085f4 100644 --- a/packages/kbn-optimizer/src/common/rxjs_helpers.ts +++ b/packages/kbn-optimizer/src/common/rxjs_helpers.ts @@ -80,3 +80,35 @@ export const debounceTimeBuffer = (ms: number) => }) ); }); + +export const fromAsyncGenerator = (fn: () => AsyncGenerator) => { + return new Rx.Observable(subscriber => { + const iterator = fn(); + + function subToPromise(promise: Promise>) { + promise.then( + result => { + if (subscriber.closed) { + return; + } + + if (result.done) { + subscriber.complete(); + } else { + subscriber.next(result.value); + subToPromise(iterator.next()); + } + }, + error => { + if (subscriber.closed) { + return; + } + + subscriber.error(error); + } + ); + } + + subToPromise(iterator.next()); + }); +}; diff --git a/packages/kbn-optimizer/src/optimizer/bundle_cache.ts b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts index 2cf96346fa40c..f2d0334663040 100644 --- a/packages/kbn-optimizer/src/optimizer/bundle_cache.ts +++ b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts @@ -19,7 +19,7 @@ import * as Rx from 'rxjs'; -import { Bundle } from '../common'; +import { Bundle, fromAsyncGenerator } from '../common'; import { OptimizerConfig } from './optimizer_config'; import { getMtimes } from './get_mtimes'; @@ -47,7 +47,7 @@ export function getBundleCacheEvent$( config: OptimizerConfig, optimizerCacheKey: OptimizerCacheKey ) { - return new Rx.Observable(subscriber => { + return fromAsyncGenerator(async function*() { // we only want to get the mtimes for files when the bundle was built // with our version of the optimizer and there is a cache key so filter // out some bundles early @@ -56,31 +56,31 @@ export function getBundleCacheEvent$( for (const bundle of config.bundles) { const cachedOptimizerCacheKeys = bundle.cache.getOptimizerCacheKey(); if (!cachedOptimizerCacheKeys) { - subscriber.next({ + yield { type: 'bundle not cached', reason: 'missing optimizer cache key', bundle, - }); + }; continue; } const optimizerCacheKeyDiff = diffCacheKey(cachedOptimizerCacheKeys, optimizerCacheKey); if (optimizerCacheKeyDiff !== undefined) { - subscriber.next({ + yield { type: 'bundle not cached', reason: 'optimizer cache key mismatch', diff: optimizerCacheKeyDiff, bundle, - }); + }; continue; } if (!bundle.cache.getCacheKeys()) { - subscriber.next({ + yield { type: 'bundle not cached', reason: 'missing cache key', bundle, - }); + }; continue; } @@ -88,52 +88,38 @@ export function getBundleCacheEvent$( } if (!eligible.length) { - subscriber.complete(); return; } - getMtimes( + const mtimes = await getMtimes( new Set( eligible.reduce( (acc: string[], bundle) => [...acc, ...(bundle.cache.getReferencedFiles() || [])], [] ) ) - ) - .then(mtimes => { - if (subscriber.closed) { - return; - } - - for (const bundle of eligible) { - const diff = diffCacheKey( - bundle.cache.getCacheKeys(), - bundle.createCacheKey(bundle.cache.getReferencedFiles() || [], mtimes) - ); - - if (diff) { - subscriber.next({ - type: 'bundle not cached', - reason: 'cache key mismatch', - diff, - bundle, - }); - continue; - } - - subscriber.next({ - type: 'bundle cached', - bundle, - }); - } - }) - .then( - () => { - subscriber.complete(); - }, - error => { - subscriber.error(error); - } + ); + + for (const bundle of eligible) { + const diff = diffCacheKey( + bundle.cache.getCacheKeys(), + bundle.createCacheKey(bundle.cache.getReferencedFiles() || [], mtimes) ); + + if (diff) { + yield { + type: 'bundle not cached', + reason: 'cache key mismatch', + diff, + bundle, + }; + continue; + } + + yield { + type: 'bundle cached', + bundle, + }; + } }); } From 9636ac02bd1eb4ee7e40befdbbae82c306b919ba Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 08:27:57 -0700 Subject: [PATCH 58/83] remove unnecessary rxjs helper, add tests for bundle cache --- packages/kbn-optimizer/src/common/bundle.ts | 2 +- .../src/common/rxjs_helpers.test.ts | 140 ++++++++++ .../kbn-optimizer/src/common/rxjs_helpers.ts | 47 +--- .../basic_optimization.test.ts | 2 +- .../integration_tests/bundle_cache.test.ts | 260 ++++++++++++++++++ .../src/optimizer/bundle_cache.ts | 51 ++-- 6 files changed, 430 insertions(+), 72 deletions(-) create mode 100644 packages/kbn-optimizer/src/common/rxjs_helpers.test.ts create mode 100644 packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts index 75acb9124e99a..dbaa08547c654 100644 --- a/packages/kbn-optimizer/src/common/bundle.ts +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -115,7 +115,7 @@ export class Bundle { * * @param mtimes pre-fetched mtimes (ms || undefined) for all referenced files */ - createCacheKey(files: string[], mtimes: Map) { + createCacheKey(files: string[], mtimes: Map): unknown { return { spec: this.toSpec(), mtimes: entriesToObject( diff --git a/packages/kbn-optimizer/src/common/rxjs_helpers.test.ts b/packages/kbn-optimizer/src/common/rxjs_helpers.test.ts new file mode 100644 index 0000000000000..72be71e6bf7ec --- /dev/null +++ b/packages/kbn-optimizer/src/common/rxjs_helpers.test.ts @@ -0,0 +1,140 @@ +/* + * 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 * as Rx from 'rxjs'; +import { toArray, map } from 'rxjs/operators'; + +import { pipeClosure, debounceTimeBuffer, maybeMap, maybe } from './rxjs_helpers'; + +jest.useFakeTimers(); + +describe('pipeClosure()', () => { + it('calls closure on each subscription to setup unique state', async () => { + let counter = 0; + + const foo$ = Rx.of(1, 2, 3).pipe( + pipeClosure(source$ => { + const multiplier = ++counter; + return source$.pipe(map(i => i * multiplier)); + }), + toArray() + ); + + await expect(foo$.toPromise()).resolves.toMatchInlineSnapshot(` + Array [ + 1, + 2, + 3, + ] + `); + await expect(foo$.toPromise()).resolves.toMatchInlineSnapshot(` + Array [ + 2, + 4, + 6, + ] + `); + await expect(foo$.toPromise()).resolves.toMatchInlineSnapshot(` + Array [ + 3, + 6, + 9, + ] + `); + }); +}); + +describe('maybe()', () => { + it('filters out undefined values from the stream', async () => { + const foo$ = Rx.of(1, undefined, 2, undefined, 3).pipe(maybe(), toArray()); + + await expect(foo$.toPromise()).resolves.toEqual([1, 2, 3]); + }); +}); + +describe('maybeMap()', () => { + it('calls map fn and filters out undefined values returned', async () => { + const foo$ = Rx.of(1, 2, 3, 4, 5).pipe( + maybeMap(i => (i % 2 ? i : undefined)), + toArray() + ); + + await expect(foo$.toPromise()).resolves.toEqual([1, 3, 5]); + }); +}); + +describe('debounceTimeBuffer()', () => { + beforeEach(() => { + jest.useFakeTimers(); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('buffers items until there is n milliseconds of silence, then flushes buffer to stream', async () => { + const foo$ = new Rx.Subject(); + const dest = new Rx.BehaviorSubject(undefined); + foo$ + .pipe( + debounceTimeBuffer(100), + map(items => items.reduce((sum, n) => sum + n)) + ) + .subscribe(dest); + + foo$.next(1); + expect(dest.getValue()).toBe(undefined); + + // only wait 99 milliseconds before sending the next value + jest.advanceTimersByTime(99); + foo$.next(1); + expect(dest.getValue()).toBe(undefined); + + // only wait 99 milliseconds before sending the next value + jest.advanceTimersByTime(99); + foo$.next(1); + expect(dest.getValue()).toBe(undefined); + + // send the next value after 100 milliseconds and observe that it was forwarded + jest.advanceTimersByTime(100); + foo$.next(1); + expect(dest.getValue()).toBe(3); + + foo$.complete(); + if (!dest.isStopped) { + throw new Error('Expected destination to stop as soon as the source is completed'); + } + }); + + it('clears queue as soon as source completes if source completes before time is up', () => { + const foo$ = new Rx.Subject(); + const dest = new Rx.BehaviorSubject(undefined); + foo$ + .pipe( + debounceTimeBuffer(100), + map(items => items.reduce((sum, n) => sum + n)) + ) + .subscribe(dest); + + foo$.next(1); + expect(dest.getValue()).toBe(undefined); + foo$.complete(); + expect(dest.getValue()).toBe(1); + }); +}); diff --git a/packages/kbn-optimizer/src/common/rxjs_helpers.ts b/packages/kbn-optimizer/src/common/rxjs_helpers.ts index fc8dc019085f4..1114f65bacb19 100644 --- a/packages/kbn-optimizer/src/common/rxjs_helpers.ts +++ b/packages/kbn-optimizer/src/common/rxjs_helpers.ts @@ -27,17 +27,10 @@ type MapFn = (item: T1, index: number) => T2; * Wrap an operator chain in a closure so that is can have some local * state. The `fn` is called each time the final observable is * subscribed so the pipeline/closure is setup for each subscription. - * - * This helper was created to avoid exposing the subscriber when all - * it is needed for is subscribing to an internal obseravble. Using - * `closure()` makes sure that only operators are used so errors - * and subscriptions are managed correctly without worry. */ export const pipeClosure = (fn: Operator): Operator => { return (source: Rx.Observable) => { - return new Rx.Observable(subscriber => { - return fn(source).subscribe(subscriber); - }); + return Rx.defer(() => fn(source)); }; }; @@ -69,46 +62,14 @@ export const maybeMap = (fn: MapFn): Operator(ms: number) => pipeClosure((source$: Rx.Observable) => { - const buffer = new Set(); + const buffer: T[] = []; return source$.pipe( - tap(item => buffer.add(item)), + tap(item => buffer.push(item)), debounceTime(ms), map(() => { const items = Array.from(buffer); - buffer.clear(); + buffer.length = 0; return items; }) ); }); - -export const fromAsyncGenerator = (fn: () => AsyncGenerator) => { - return new Rx.Observable(subscriber => { - const iterator = fn(); - - function subToPromise(promise: Promise>) { - promise.then( - result => { - if (subscriber.closed) { - return; - } - - if (result.done) { - subscriber.complete(); - } else { - subscriber.next(result.value); - subToPromise(iterator.next()); - } - }, - error => { - if (subscriber.closed) { - return; - } - - subscriber.error(error); - } - ); - } - - subToPromise(iterator.next()); - }); -}; diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index b1b890fb537d5..94eae4f0f9878 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -20,9 +20,9 @@ import Path from 'path'; import Fs from 'fs'; import { inspect } from 'util'; + import cpy from 'cpy'; import del from 'del'; - import { toArray, tap } from 'rxjs/operators'; import { createAbsolutePathSerializer } from '@kbn/dev-utils'; import { runOptimizer, OptimizerConfig, OptimizerMsg } from '@kbn/optimizer'; diff --git a/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts b/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts new file mode 100644 index 0000000000000..0237d9ccfd11f --- /dev/null +++ b/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts @@ -0,0 +1,260 @@ +/* + * 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 Path from 'path'; + +import cpy from 'cpy'; +import del from 'del'; +import { toArray } from 'rxjs/operators'; +import { createAbsolutePathSerializer } from '@kbn/dev-utils'; + +import { getMtimes } from '../optimizer/get_mtimes'; +import { OptimizerConfig } from '../optimizer/optimizer_config'; +import { Bundle } from '../common/bundle'; +import { getBundleCacheEvent$ } from '../optimizer/bundle_cache'; + +const TMP_DIR = Path.resolve(__dirname, '../__fixtures__/__tmp__'); +const MOCK_REPO_SRC = Path.resolve(__dirname, '../__fixtures__/mock_repo'); +const MOCK_REPO_DIR = Path.resolve(TMP_DIR, 'mock_repo'); + +expect.addSnapshotSerializer({ + print: () => '', + test: v => v instanceof Bundle, +}); +expect.addSnapshotSerializer(createAbsolutePathSerializer(MOCK_REPO_DIR)); + +beforeEach(async () => { + await del(TMP_DIR); + await cpy('**/*', MOCK_REPO_DIR, { + cwd: MOCK_REPO_SRC, + parents: true, + deep: true, + }); +}); + +afterEach(async () => { + await del(TMP_DIR); +}); + +it('emits "bundle cached" event when everything is updated', async () => { + const config = OptimizerConfig.create({ + repoRoot: MOCK_REPO_DIR, + pluginScanDirs: [], + pluginPaths: [Path.resolve(MOCK_REPO_DIR, 'plugins/foo')], + maxWorkerCount: 1, + }); + const [bundle] = config.bundles; + + const optimizerCacheKey = 'optimizerCacheKey'; + const files = [ + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/ext.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/index.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/lib.ts'), + ]; + const mtimes = await getMtimes(files); + const cacheKey = bundle.createCacheKey(files, mtimes); + + bundle.cache.set({ + cacheKey, + optimizerCacheKey, + files, + moduleCount: files.length, + }); + + const cacheEvents = await getBundleCacheEvent$(config, optimizerCacheKey) + .pipe(toArray()) + .toPromise(); + + expect(cacheEvents).toMatchInlineSnapshot(` + Array [ + Object { + "bundle": , + "type": "bundle cached", + }, + ] + `); +}); + +it('emits "bundle not cached" event when optimizerCacheKey is missing', async () => { + const config = OptimizerConfig.create({ + repoRoot: MOCK_REPO_DIR, + pluginScanDirs: [], + pluginPaths: [Path.resolve(MOCK_REPO_DIR, 'plugins/foo')], + maxWorkerCount: 1, + }); + const [bundle] = config.bundles; + + const optimizerCacheKey = 'optimizerCacheKey'; + const files = [ + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/ext.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/index.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/lib.ts'), + ]; + const mtimes = await getMtimes(files); + const cacheKey = bundle.createCacheKey(files, mtimes); + + bundle.cache.set({ + cacheKey, + optimizerCacheKey: undefined, + files, + moduleCount: files.length, + }); + + const cacheEvents = await getBundleCacheEvent$(config, optimizerCacheKey) + .pipe(toArray()) + .toPromise(); + + expect(cacheEvents).toMatchInlineSnapshot(` + Array [ + Object { + "bundle": , + "reason": "missing optimizer cache key", + "type": "bundle not cached", + }, + ] + `); +}); + +it('emits "bundle not cached" event when optimizerCacheKey is outdated, includes diff', async () => { + const config = OptimizerConfig.create({ + repoRoot: MOCK_REPO_DIR, + pluginScanDirs: [], + pluginPaths: [Path.resolve(MOCK_REPO_DIR, 'plugins/foo')], + maxWorkerCount: 1, + }); + const [bundle] = config.bundles; + + const optimizerCacheKey = 'optimizerCacheKey'; + const files = [ + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/ext.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/index.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/lib.ts'), + ]; + const mtimes = await getMtimes(files); + const cacheKey = bundle.createCacheKey(files, mtimes); + + bundle.cache.set({ + cacheKey, + optimizerCacheKey: 'old', + files, + moduleCount: files.length, + }); + + const cacheEvents = await getBundleCacheEvent$(config, optimizerCacheKey) + .pipe(toArray()) + .toPromise(); + + expect(cacheEvents).toMatchInlineSnapshot(` + Array [ + Object { + "bundle": , + "diff": "- Expected + + Received + + - old + + optimizerCacheKey", + "reason": "optimizer cache key mismatch", + "type": "bundle not cached", + }, + ] + `); +}); + +it('emits "bundle not cached" event when cacheKey is missing', async () => { + const config = OptimizerConfig.create({ + repoRoot: MOCK_REPO_DIR, + pluginScanDirs: [], + pluginPaths: [Path.resolve(MOCK_REPO_DIR, 'plugins/foo')], + maxWorkerCount: 1, + }); + const [bundle] = config.bundles; + + const optimizerCacheKey = 'optimizerCacheKey'; + const files = [ + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/ext.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/index.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/lib.ts'), + ]; + + bundle.cache.set({ + cacheKey: undefined, + optimizerCacheKey, + files, + moduleCount: files.length, + }); + + const cacheEvents = await getBundleCacheEvent$(config, optimizerCacheKey) + .pipe(toArray()) + .toPromise(); + + expect(cacheEvents).toMatchInlineSnapshot(` + Array [ + Object { + "bundle": , + "reason": "missing cache key", + "type": "bundle not cached", + }, + ] + `); +}); + +it('emits "bundle not cached" event when cacheKey is outdated', async () => { + const config = OptimizerConfig.create({ + repoRoot: MOCK_REPO_DIR, + pluginScanDirs: [], + pluginPaths: [Path.resolve(MOCK_REPO_DIR, 'plugins/foo')], + maxWorkerCount: 1, + }); + const [bundle] = config.bundles; + + const optimizerCacheKey = 'optimizerCacheKey'; + const files = [ + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/ext.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/index.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/lib.ts'), + ]; + + bundle.cache.set({ + cacheKey: 'old', + optimizerCacheKey, + files, + moduleCount: files.length, + }); + + jest.spyOn(bundle, 'createCacheKey').mockImplementation(() => 'new'); + + const cacheEvents = await getBundleCacheEvent$(config, optimizerCacheKey) + .pipe(toArray()) + .toPromise(); + + expect(cacheEvents).toMatchInlineSnapshot(` + Array [ + Object { + "bundle": , + "diff": "- Expected + + Received + + - old + + new", + "reason": "cache key mismatch", + "type": "bundle not cached", + }, + ] + `); +}); diff --git a/packages/kbn-optimizer/src/optimizer/bundle_cache.ts b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts index f2d0334663040..06f0f52949f05 100644 --- a/packages/kbn-optimizer/src/optimizer/bundle_cache.ts +++ b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts @@ -18,12 +18,13 @@ */ import * as Rx from 'rxjs'; +import { mergeAll } from 'rxjs/operators'; -import { Bundle, fromAsyncGenerator } from '../common'; +import { Bundle } from '../common'; import { OptimizerConfig } from './optimizer_config'; import { getMtimes } from './get_mtimes'; -import { diffCacheKey, OptimizerCacheKey } from './cache_keys'; +import { diffCacheKey } from './cache_keys'; export type BundleCacheEvent = BundleNotCachedEvent | BundleCachedEvent; @@ -45,81 +46,77 @@ export interface BundleCachedEvent { export function getBundleCacheEvent$( config: OptimizerConfig, - optimizerCacheKey: OptimizerCacheKey -) { - return fromAsyncGenerator(async function*() { - // we only want to get the mtimes for files when the bundle was built - // with our version of the optimizer and there is a cache key so filter - // out some bundles early - const eligible: Bundle[] = []; + optimizerCacheKey: unknown +): Rx.Observable { + return Rx.defer(async () => { + const events: BundleCacheEvent[] = []; + const eligibleBundles: Bundle[] = []; for (const bundle of config.bundles) { const cachedOptimizerCacheKeys = bundle.cache.getOptimizerCacheKey(); if (!cachedOptimizerCacheKeys) { - yield { + events.push({ type: 'bundle not cached', reason: 'missing optimizer cache key', bundle, - }; + }); continue; } const optimizerCacheKeyDiff = diffCacheKey(cachedOptimizerCacheKeys, optimizerCacheKey); if (optimizerCacheKeyDiff !== undefined) { - yield { + events.push({ type: 'bundle not cached', reason: 'optimizer cache key mismatch', diff: optimizerCacheKeyDiff, bundle, - }; + }); continue; } if (!bundle.cache.getCacheKeys()) { - yield { + events.push({ type: 'bundle not cached', reason: 'missing cache key', bundle, - }; + }); continue; } - eligible.push(bundle); - } - - if (!eligible.length) { - return; + eligibleBundles.push(bundle); } const mtimes = await getMtimes( new Set( - eligible.reduce( + eligibleBundles.reduce( (acc: string[], bundle) => [...acc, ...(bundle.cache.getReferencedFiles() || [])], [] ) ) ); - for (const bundle of eligible) { + for (const bundle of eligibleBundles) { const diff = diffCacheKey( bundle.cache.getCacheKeys(), bundle.createCacheKey(bundle.cache.getReferencedFiles() || [], mtimes) ); if (diff) { - yield { + events.push({ type: 'bundle not cached', reason: 'cache key mismatch', diff, bundle, - }; + }); continue; } - yield { + events.push({ type: 'bundle cached', bundle, - }; + }); } - }); + + return events; + }).pipe(mergeAll()); } From 096aac7243ad44e3fef55e0da48ccc256b72bf49 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 09:00:52 -0700 Subject: [PATCH 59/83] update consumers of optimizer --- packages/kbn-optimizer/src/index.ts | 1 + src/cli/cluster/run_kbn_optimizer.ts | 5 ++--- src/dev/build/tasks/build_new_platform_plugins.js | 5 ++--- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/kbn-optimizer/src/index.ts b/packages/kbn-optimizer/src/index.ts index 31d2885770c88..f9fa50fee0b51 100644 --- a/packages/kbn-optimizer/src/index.ts +++ b/packages/kbn-optimizer/src/index.ts @@ -19,3 +19,4 @@ export { OptimizerConfig, OptimizerMsg } from './optimizer'; export * from './run_optimizer'; +export * from './log_optimizer_state'; diff --git a/src/cli/cluster/run_kbn_optimizer.ts b/src/cli/cluster/run_kbn_optimizer.ts index f03861b671dd5..7752d4a45ab65 100644 --- a/src/cli/cluster/run_kbn_optimizer.ts +++ b/src/cli/cluster/run_kbn_optimizer.ts @@ -26,7 +26,7 @@ import { parseLogLevel, REPO_ROOT, } from '@kbn/dev-utils'; -import { OptimizerConfig, Optimizer, logOptimizerState } from '@kbn/optimizer'; +import { runOptimizer, OptimizerConfig, logOptimizerState } from '@kbn/optimizer'; import { LegacyConfig } from '../../core/server/legacy'; @@ -75,6 +75,5 @@ export function runKbnOptimizer(opts: Record, config: LegacyConfig) }, ]); - const optimizer = new Optimizer(optimizerConfig); - return optimizer.run().pipe(logOptimizerState(toolingLog, optimizerConfig)); + return runOptimizer(optimizerConfig).pipe(logOptimizerState(toolingLog, optimizerConfig)); } diff --git a/src/dev/build/tasks/build_new_platform_plugins.js b/src/dev/build/tasks/build_new_platform_plugins.js index 73b916feeb7d9..04b3dde5f9692 100644 --- a/src/dev/build/tasks/build_new_platform_plugins.js +++ b/src/dev/build/tasks/build_new_platform_plugins.js @@ -17,7 +17,7 @@ * under the License. */ -import { Optimizer, OptimizerConfig, logOptimizerState } from '@kbn/optimizer'; +import { runOptimizer, OptimizerConfig, logOptimizerState } from '@kbn/optimizer'; export const BuildNewPlatformPluginsTask = { description: 'Building distributable versions of new platform plugins', @@ -31,8 +31,7 @@ export const BuildNewPlatformPluginsTask = { dist: true, }); - await new Optimizer(optimizerConfig) - .run() + await runOptimizer(optimizerConfig) .pipe(logOptimizerState(log, optimizerConfig)) .toPromise(); }, From 960c2cd342b4dfcdd6d1fdbdc05a09f5f784d08c Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 09:07:27 -0700 Subject: [PATCH 60/83] update readme with new call style --- packages/kbn-optimizer/README.md | 13 ++++++------- .../kbn-optimizer/src/optimizer/optimizer_msg.ts | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/kbn-optimizer/README.md b/packages/kbn-optimizer/README.md index 69cdb959cf323..56591fdd14f2f 100644 --- a/packages/kbn-optimizer/README.md +++ b/packages/kbn-optimizer/README.md @@ -32,11 +32,11 @@ When a bundle is determined to be up-to-date a worker is not started for the bun ## API -To run the optimizer from code, you can import the [`Optimizer`][Optimizer] and [`OptimizerConfig`][OptimizerConfig] classes. Create an [`OptimizerConfig`][OptimizerConfig] instance by calling it's static `create()` method with some options, then pass it to the [`Optimizer`][Optimizer] constructor. Calling `Optimizer#run()` will return an observable of [`OptimizerMsg`][Optimizer] objects, which are summaries of the optimizer state plus an optional `event` property which describes the internal events occuring and may be of use. You can use the [`logOptimizerState()`][LogOptimizerState] helper to write the relevant bits of state to a tooling log or checkout it's implementation to see how the internal events like [`WorkerStdio`][ObserveWorker] and [`WorkerStarted`][ObserveWorker] are used. +To run the optimizer from code, you can import the [`OptimizerConfig`][OptimizerConfig] class and [`runOptimizer`][Optimizer] function. Create an [`OptimizerConfig`][OptimizerConfig] instance by calling it's static `create()` method with some options, then pass it to the [`runOptimizer`][Optimizer] function. `runOptimizer()` returns an observable of [`OptimizerMsg`][Optimizer] objects, which are summaries of the optimizer state plus an optional `event` property which describes the internal events occuring and may be of use. You can use the [`logOptimizerState()`][LogOptimizerState] helper to write the relevant bits of state to a tooling log or checkout it's implementation to see how the internal events like [`WorkerStdio`][ObserveWorker] and [`WorkerStarted`][ObserveWorker] are used. Example: ```ts -import { Optimizer, OptimizerConfig, logOptimizerState } from '@kbn/optimizer'; +import { runOptimizer, OptimizerConfig, logOptimizerState } from '@kbn/optimizer'; import { REPO_ROOT, ToolingLog } from '@kbn/dev-utils'; const log = new ToolingLog({ @@ -51,10 +51,7 @@ const config = OptimizerConfig.create({ dist: true }); -const optimizer = new Optimizer(config); - -await optimizer - .run() +await runOptimizer(config) .pipe(logOptimizerState(log, config)) .toPromise(); ``` @@ -79,8 +76,10 @@ The Optimizer captures all of these messages and produces a stream of [`Optimize Optimizer phases:
+
'initializing'
+
Initial phase, during this state the optimizer is validating caches and determining which builds should be built initially.
'initialized'
-
Initial event emitted by the optimizer once it's don't initializing its internal state.
+
Emitted by the optimizer once it's don't initializing its internal state and determined which bundles are going to be built initially.
'running'
Emitted when any worker is in a running state. To determine which compilers are running, look for BundleState objects with type 'running'.
'issue'
diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts b/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts index ff9e52ea6e96d..5ab84232e44cb 100644 --- a/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts +++ b/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts @@ -46,7 +46,7 @@ export interface OptimizerMsg { } export interface OptimizerState { - phase: 'initializing' | 'initialized' | 'reallocating' | 'success' | 'running' | 'issue'; + phase: 'initializing' | 'initialized' | 'running' | 'issue' | 'success' | 'reallocating'; startTime: number; durSec: number; compilerStates: CompilerMsg[]; From a6ce86aa3037f07acba89d77e72f9ae94a23f90f Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 09:15:27 -0700 Subject: [PATCH 61/83] replace "new platform" with "kibana platform" --- packages/kbn-optimizer/README.md | 12 ++++++------ packages/kbn-optimizer/src/cli.ts | 2 +- packages/kbn-optimizer/src/optimizer/get_bundles.ts | 4 ++-- ...ugins.test.ts => kibana_platform_plugins.test.ts} | 4 ++-- ...latform_plugins.ts => kibana_platform_plugins.ts} | 8 ++++---- .../src/optimizer/optimizer_config.test.ts | 12 ++++++------ .../kbn-optimizer/src/optimizer/optimizer_config.ts | 6 +++--- packages/kbn-optimizer/src/worker/webpack.config.ts | 1 - ...m_plugins.js => build_kibana_platform_plugins.js} | 0 9 files changed, 24 insertions(+), 25 deletions(-) rename packages/kbn-optimizer/src/optimizer/{new_platform_plugins.test.ts => kibana_platform_plugins.test.ts} (95%) rename packages/kbn-optimizer/src/optimizer/{new_platform_plugins.ts => kibana_platform_plugins.ts} (88%) rename scripts/{build_new_platform_plugins.js => build_kibana_platform_plugins.js} (100%) diff --git a/packages/kbn-optimizer/README.md b/packages/kbn-optimizer/README.md index 56591fdd14f2f..bc5c788c8632b 100644 --- a/packages/kbn-optimizer/README.md +++ b/packages/kbn-optimizer/README.md @@ -1,8 +1,8 @@ # @kbn/optimizer -`@kbn/optimizer` is a package for building new platform UI plugins (and hopefully more soon). +`@kbn/optimizer` is a package for building Kibana platform UI plugins (and hopefully more soon). -New Platform plugins with `"ui": true` in their `kibana.json` file will have their `public/index.ts` file (and all of its dependencies) bundled into the `target/public` directory of the plugin. The build output does not need to be updated when other plugins are updated and is included in the distributable without requiring that we ship `@kbn/optimizer` 🎉. +Kibana Platform plugins with `"ui": true` in their `kibana.json` file will have their `public/index.ts` file (and all of its dependencies) bundled into the `target/public` directory of the plugin. The build output does not need to be updated when other plugins are updated and is included in the distributable without requiring that we ship `@kbn/optimizer` 🎉. ## Webpack config @@ -16,7 +16,7 @@ To make front-end code easier to debug the optimizer uses the `BROWSERSLIST_ENV= ## Running the optimizer -The `@kbn/optimizer` is automatically executed from the dev cli, the Kibana build scripts, and in CI. If you're running Kibana locally in some other way you might need to build the plugins manually, which you can do by running `node scripts/build_new_platform_plugins` (pass `--help` for options). +The `@kbn/optimizer` is automatically executed from the dev cli, the Kibana build scripts, and in CI. If you're running Kibana locally in some other way you might need to build the plugins manually, which you can do by running `node scripts/build_kibana_platform_plugins` (pass `--help` for options). ### Worker count @@ -26,7 +26,7 @@ We only limit the number of workers we will start at any given time. If we start ### Caching -Bundles built by the the optimizer include a cache file which describes the information needed to determine if the bundle needs to be rebuilt when the optimizer is restarted. Caching is enabled by default and is very aggressive about invalidating the cache output, but if you need to disable caching you can pass `--no-cache` to `node scripts/build_new_platform_plugins`, or set the `KBN_OPTIMIZER_NO_CACHE` environment variable to anything (env overrides everything). +Bundles built by the the optimizer include a cache file which describes the information needed to determine if the bundle needs to be rebuilt when the optimizer is restarted. Caching is enabled by default and is very aggressive about invalidating the cache output, but if you need to disable caching you can pass `--no-cache` to `node scripts/build_kibana_platform_plugins`, or set the `KBN_OPTIMIZER_NO_CACHE` environment variable to anything (env overrides everything). When a bundle is determined to be up-to-date a worker is not started for the bundle. If running the optimizer with the `--dev/--watch` flag, then all the files referenced by cached bundles are watched for changes. Once a change is detected in any of the files referenced by the built bundle a worker is started. If a file is changed that is referenced by several bundles then workers will be started for each bundle, combining workers together to respect the worker limit. @@ -56,7 +56,7 @@ await runOptimizer(config) .toPromise(); ``` -This is essentially what we're doing in [`script/build_new_platform_plugins`][Cli] and the new [build system task][BuildTask]. +This is essentially what we're doing in [`script/build_kibana_platform_plugins`][Cli] and the new [build system task][BuildTask]. ## Internals @@ -107,4 +107,4 @@ For an example of how to handle these states checkout the [`logOptimizerState()` [OptimizerConfig]: src/optimizer_config.ts [LogOptimizerState]: src/log_optimizer_state.ts [AssignBundlesToWorkers]: src/assign_bundles_to_workers.ts -[BuildTask]: ../../src/dev/build/tasks/build_new_platform_plugins.js \ No newline at end of file +[BuildTask]: ../../src/dev/build/tasks/build_kibana_platform_plugins.js \ No newline at end of file diff --git a/packages/kbn-optimizer/src/cli.ts b/packages/kbn-optimizer/src/cli.ts index 1be2df0e45fe9..dcb4dcd35698d 100644 --- a/packages/kbn-optimizer/src/cli.ts +++ b/packages/kbn-optimizer/src/cli.ts @@ -109,7 +109,7 @@ run( --profile profile the webpack builds and write stats.json files to build outputs --no-cache disable the cache --no-examples don't build the example plugins - --dist build new platform plugins in a way that is suitable for inclusion in the Kibana distributable + --dist create bundles that are suitable for inclusion in the Kibana distributable --scan-dir add a directory to the list of directories scanned for plugins (specify as many times as necessary) --no-inspect-workers when inspecting the parent process, don't inspect the workers `, diff --git a/packages/kbn-optimizer/src/optimizer/get_bundles.ts b/packages/kbn-optimizer/src/optimizer/get_bundles.ts index 7b574a40b7617..7cd7bf15317e0 100644 --- a/packages/kbn-optimizer/src/optimizer/get_bundles.ts +++ b/packages/kbn-optimizer/src/optimizer/get_bundles.ts @@ -21,9 +21,9 @@ import Path from 'path'; import { Bundle } from '../common'; -import { NewPlatformPlugin } from './new_platform_plugins'; +import { KibanaPlatformPlugin } from './kibana_platform_plugins'; -export function getBundles(plugins: NewPlatformPlugin[], repoRoot: string) { +export function getBundles(plugins: KibanaPlatformPlugin[], repoRoot: string) { return plugins .filter(p => p.isUiPlugin) .map( diff --git a/packages/kbn-optimizer/src/optimizer/new_platform_plugins.test.ts b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts similarity index 95% rename from packages/kbn-optimizer/src/optimizer/new_platform_plugins.test.ts rename to packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts index eab476e6154b7..e047b6d1e44cf 100644 --- a/packages/kbn-optimizer/src/optimizer/new_platform_plugins.test.ts +++ b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.test.ts @@ -21,7 +21,7 @@ import Path from 'path'; import { createAbsolutePathSerializer } from '@kbn/dev-utils'; -import { findNewPlatformPlugins } from './new_platform_plugins'; +import { findKibanaPlatformPlugins } from './kibana_platform_plugins'; expect.addSnapshotSerializer(createAbsolutePathSerializer()); @@ -29,7 +29,7 @@ const FIXTURES_PATH = Path.resolve(__dirname, '../__fixtures__'); it('parses kibana.json files of plugins found in pluginDirs', () => { expect( - findNewPlatformPlugins( + findKibanaPlatformPlugins( [Path.resolve(FIXTURES_PATH, 'mock_repo/plugins')], [Path.resolve(FIXTURES_PATH, 'mock_repo/test_plugins/test_baz')] ) diff --git a/packages/kbn-optimizer/src/optimizer/new_platform_plugins.ts b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts similarity index 88% rename from packages/kbn-optimizer/src/optimizer/new_platform_plugins.ts rename to packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts index c4c73412bb639..b7e5e12f46a7f 100644 --- a/packages/kbn-optimizer/src/optimizer/new_platform_plugins.ts +++ b/packages/kbn-optimizer/src/optimizer/kibana_platform_plugins.ts @@ -22,7 +22,7 @@ import Path from 'path'; import globby from 'globby'; import loadJsonFile from 'load-json-file'; -export interface NewPlatformPlugin { +export interface KibanaPlatformPlugin { readonly directory: string; readonly id: string; readonly isUiPlugin: boolean; @@ -31,7 +31,7 @@ export interface NewPlatformPlugin { /** * Helper to find the new platform plugins. */ -export function findNewPlatformPlugins(scanDirs: string[], paths: string[]) { +export function findKibanaPlatformPlugins(scanDirs: string[], paths: string[]) { return globby .sync( Array.from( @@ -44,10 +44,10 @@ export function findNewPlatformPlugins(scanDirs: string[], paths: string[]) { absolute: true, } ) - .map(path => readNewPlatformPlugin(path)); + .map(path => readKibanaPlatformPlugin(path)); } -function readNewPlatformPlugin(manifestPath: string): NewPlatformPlugin { +function readKibanaPlatformPlugin(manifestPath: string): KibanaPlatformPlugin { if (!Path.isAbsolute(manifestPath)) { throw new TypeError('expected new platform manifest path to be absolute'); } diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts b/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts index 7420c3925ea89..d67b957416753 100644 --- a/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts +++ b/packages/kbn-optimizer/src/optimizer/optimizer_config.test.ts @@ -18,7 +18,7 @@ */ jest.mock('./assign_bundles_to_workers.ts'); -jest.mock('./new_platform_plugins.ts'); +jest.mock('./kibana_platform_plugins.ts'); jest.mock('./get_bundles.ts'); import Path from 'path'; @@ -311,8 +311,8 @@ describe('OptimizerConfig::parseOptions()', () => { describe('OptimizerConfig::create()', () => { const assignBundlesToWorkers: jest.Mock = jest.requireMock('./assign_bundles_to_workers.ts') .assignBundlesToWorkers; - const findNewPlatformPlugins: jest.Mock = jest.requireMock('./new_platform_plugins.ts') - .findNewPlatformPlugins; + const findKibanaPlatformPlugins: jest.Mock = jest.requireMock('./kibana_platform_plugins.ts') + .findKibanaPlatformPlugins; const getBundles: jest.Mock = jest.requireMock('./get_bundles.ts').getBundles; beforeEach(() => { @@ -324,7 +324,7 @@ describe('OptimizerConfig::create()', () => { { config: Symbol('worker config 1') }, { config: Symbol('worker config 2') }, ]); - findNewPlatformPlugins.mockReturnValue(Symbol('new platform plugins')); + findKibanaPlatformPlugins.mockReturnValue(Symbol('new platform plugins')); getBundles.mockReturnValue(Symbol('bundles')); jest.spyOn(OptimizerConfig, 'parseOptions').mockImplementation((): any => ({ @@ -340,7 +340,7 @@ describe('OptimizerConfig::create()', () => { })); }); - it('passes parsed options to findNewPlatformPlugins, getBundles, and assignBundlesToWorkers', () => { + it('passes parsed options to findKibanaPlatformPlugins, getBundles, and assignBundlesToWorkers', () => { const config = OptimizerConfig.create({ repoRoot: REPO_ROOT, }); @@ -359,7 +359,7 @@ describe('OptimizerConfig::create()', () => { } `); - expect(findNewPlatformPlugins.mock).toMatchInlineSnapshot(` + expect(findKibanaPlatformPlugins.mock).toMatchInlineSnapshot(` Object { "calls": Array [ Array [ diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_config.ts b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts index 3467eddd93e48..a258e1010fce3 100644 --- a/packages/kbn-optimizer/src/optimizer/optimizer_config.ts +++ b/packages/kbn-optimizer/src/optimizer/optimizer_config.ts @@ -22,7 +22,7 @@ import Os from 'os'; import { Bundle, WorkerConfig } from '../common'; -import { findNewPlatformPlugins, NewPlatformPlugin } from './new_platform_plugins'; +import { findKibanaPlatformPlugins, KibanaPlatformPlugin } from './kibana_platform_plugins'; import { getBundles } from './get_bundles'; interface Options { @@ -130,7 +130,7 @@ export class OptimizerConfig { static create(inputOptions: Options) { const options = OptimizerConfig.parseOptions(inputOptions); - const plugins = findNewPlatformPlugins(options.pluginScanDirs, options.pluginPaths); + const plugins = findKibanaPlatformPlugins(options.pluginScanDirs, options.pluginPaths); const bundles = getBundles(plugins, options.repoRoot); return new OptimizerConfig( @@ -151,7 +151,7 @@ export class OptimizerConfig { public readonly cache: boolean, public readonly watch: boolean, public readonly inspectWorkers: boolean, - public readonly plugins: NewPlatformPlugin[], + public readonly plugins: KibanaPlatformPlugin[], public readonly repoRoot: string, public readonly maxWorkerCount: number, public readonly dist: boolean, diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 69d12bcab0fd8..97ad334f8ed16 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -62,7 +62,6 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) { ? { // When the entry point is loaded, assign it's exported `plugin` // value to a key on the global `__kbnBundles__` object. - // NOTE: Only actually used by new platform plugins library: ['__kbnBundles__', `plugin/${bundle.id}`], libraryExport: 'plugin', } diff --git a/scripts/build_new_platform_plugins.js b/scripts/build_kibana_platform_plugins.js similarity index 100% rename from scripts/build_new_platform_plugins.js rename to scripts/build_kibana_platform_plugins.js From 04a4e82e6c7c57e53c4db8b89fc567e7a7b2acbc Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 09:55:03 -0700 Subject: [PATCH 62/83] fix a couple more renames --- packages/kbn-test/src/functional_tests/tasks.js | 2 +- src/dev/build/build_distributables.js | 4 ++-- ...w_platform_plugins.js => build_kibana_platform_plugins.js} | 4 ++-- src/dev/build/tasks/index.js | 2 +- test/scripts/jenkins_build_kibana.sh | 4 ++-- test/scripts/jenkins_xpack_build_kibana.sh | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) rename src/dev/build/tasks/{build_new_platform_plugins.js => build_kibana_platform_plugins.js} (90%) diff --git a/packages/kbn-test/src/functional_tests/tasks.js b/packages/kbn-test/src/functional_tests/tasks.js index 3408b53d65f4d..8645923a13d30 100644 --- a/packages/kbn-test/src/functional_tests/tasks.js +++ b/packages/kbn-test/src/functional_tests/tasks.js @@ -65,7 +65,7 @@ export async function runTests(options) { log.warning('❗️❗️❗️'); log.warning('❗️❗️❗️'); log.warning( - " Don't forget to use `node scripts/build_new_platform_plugins` to build plugins you plan on testing" + " Don't forget to use `node scripts/build_kibana_platform_plugins` to build plugins you plan on testing" ); log.warning('❗️❗️❗️'); log.warning('❗️❗️❗️'); diff --git a/src/dev/build/build_distributables.js b/src/dev/build/build_distributables.js index 192be0e625a42..c4f9d7f56554c 100644 --- a/src/dev/build/build_distributables.js +++ b/src/dev/build/build_distributables.js @@ -43,7 +43,7 @@ import { DownloadNodeBuildsTask, ExtractNodeBuildsTask, InstallDependenciesTask, - BuildNewPlatformPluginsTask, + BuildKibanaPlatformPluginsTask, OptimizeBuildTask, RemovePackageJsonDepsTask, RemoveWorkspacesTask, @@ -119,7 +119,7 @@ export async function buildDistributables(options) { await run(UpdateLicenseFileTask); await run(RemovePackageJsonDepsTask); await run(TranspileScssTask); - await run(BuildNewPlatformPluginsTask); + await run(BuildKibanaPlatformPluginsTask); await run(OptimizeBuildTask); await run(CleanClientModulesOnDLLTask); await run(CleanTypescriptTask); diff --git a/src/dev/build/tasks/build_new_platform_plugins.js b/src/dev/build/tasks/build_kibana_platform_plugins.js similarity index 90% rename from src/dev/build/tasks/build_new_platform_plugins.js rename to src/dev/build/tasks/build_kibana_platform_plugins.js index 04b3dde5f9692..101d6bd15fc10 100644 --- a/src/dev/build/tasks/build_new_platform_plugins.js +++ b/src/dev/build/tasks/build_kibana_platform_plugins.js @@ -19,8 +19,8 @@ import { runOptimizer, OptimizerConfig, logOptimizerState } from '@kbn/optimizer'; -export const BuildNewPlatformPluginsTask = { - description: 'Building distributable versions of new platform plugins', +export const BuildKibanaPlatformPluginsTask = { + description: 'Building distributable versions of Kibana platform plugins', async run(_, log, build) { const optimizerConfig = OptimizerConfig.create({ repoRoot: build.resolvePath(), diff --git a/src/dev/build/tasks/index.js b/src/dev/build/tasks/index.js index 525632299f650..56e813111279d 100644 --- a/src/dev/build/tasks/index.js +++ b/src/dev/build/tasks/index.js @@ -37,4 +37,4 @@ export * from './transpile_scss_task'; export * from './verify_env_task'; export * from './write_sha_sums_task'; export * from './path_length_task'; -export * from './build_new_platform_plugins'; +export * from './build_kibana_platform_plugins'; diff --git a/test/scripts/jenkins_build_kibana.sh b/test/scripts/jenkins_build_kibana.sh index 938168db687b8..a7c05b6e5802d 100755 --- a/test/scripts/jenkins_build_kibana.sh +++ b/test/scripts/jenkins_build_kibana.sh @@ -2,8 +2,8 @@ source src/dev/ci_setup/setup_env.sh -echo " -> building new platform plugins" -node scripts/build_new_platform_plugins \ +echo " -> building kibana platform plugins" +node scripts/build_kibana_platform_plugins \ --oss \ --scan-dir "$KIBANA_DIR/test/plugin_functional/plugins" \ --verbose; diff --git a/test/scripts/jenkins_xpack_build_kibana.sh b/test/scripts/jenkins_xpack_build_kibana.sh index cb6b031b1ae00..f87d6e1102c45 100755 --- a/test/scripts/jenkins_xpack_build_kibana.sh +++ b/test/scripts/jenkins_xpack_build_kibana.sh @@ -3,8 +3,8 @@ cd "$KIBANA_DIR" source src/dev/ci_setup/setup_env.sh -echo " -> building new platform plugins" -node scripts/build_new_platform_plugins \ +echo " -> building kibana platform plugins" +node scripts/build_kibana_platform_plugins \ --scan-dir "$XPACK_DIR/test/plugin_functional/plugins" \ --verbose; From 045c86e0976e883a51dbf7992174c85f0b83c1df Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 09:57:37 -0700 Subject: [PATCH 63/83] add support for several plain-text file formats --- packages/kbn-optimizer/src/worker/webpack.config.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index 97ad334f8ed16..d1692cfc6c184 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -186,6 +186,12 @@ export function getWebpackConfig(bundle: Bundle, worker: WorkerConfig) { }, }, }, + { + test: /\.(html|md|txt|tmpl)$/, + use: { + loader: 'raw-loader', + }, + }, ], }, From b60c6ad782350ae3bf7c4d3fb5ac06cc9369649e Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 12:31:15 -0700 Subject: [PATCH 64/83] fix naming of OptimizerMsg => OptimizerUpdate, use "store" naming too --- packages/kbn-optimizer/README.md | 4 +- packages/kbn-optimizer/src/common/index.ts | 1 + .../kbn-optimizer/src/common/state_helpers.ts | 69 ++++++ packages/kbn-optimizer/src/index.ts | 2 +- .../kbn-optimizer/src/log_optimizer_state.ts | 14 +- packages/kbn-optimizer/src/optimizer/index.ts | 2 +- .../src/optimizer/optimizer_msg.ts | 207 ------------------ .../src/optimizer/optimizer_reducer.ts | 170 ++++++++++++++ .../src/optimizer/run_workers.ts | 3 +- packages/kbn-optimizer/src/run_optimizer.ts | 72 +++--- 10 files changed, 294 insertions(+), 250 deletions(-) create mode 100644 packages/kbn-optimizer/src/common/state_helpers.ts delete mode 100644 packages/kbn-optimizer/src/optimizer/optimizer_msg.ts create mode 100644 packages/kbn-optimizer/src/optimizer/optimizer_reducer.ts diff --git a/packages/kbn-optimizer/README.md b/packages/kbn-optimizer/README.md index bc5c788c8632b..c7f50c6af8dfd 100644 --- a/packages/kbn-optimizer/README.md +++ b/packages/kbn-optimizer/README.md @@ -32,7 +32,7 @@ When a bundle is determined to be up-to-date a worker is not started for the bun ## API -To run the optimizer from code, you can import the [`OptimizerConfig`][OptimizerConfig] class and [`runOptimizer`][Optimizer] function. Create an [`OptimizerConfig`][OptimizerConfig] instance by calling it's static `create()` method with some options, then pass it to the [`runOptimizer`][Optimizer] function. `runOptimizer()` returns an observable of [`OptimizerMsg`][Optimizer] objects, which are summaries of the optimizer state plus an optional `event` property which describes the internal events occuring and may be of use. You can use the [`logOptimizerState()`][LogOptimizerState] helper to write the relevant bits of state to a tooling log or checkout it's implementation to see how the internal events like [`WorkerStdio`][ObserveWorker] and [`WorkerStarted`][ObserveWorker] are used. +To run the optimizer from code, you can import the [`OptimizerConfig`][OptimizerConfig] class and [`runOptimizer`][Optimizer] function. Create an [`OptimizerConfig`][OptimizerConfig] instance by calling it's static `create()` method with some options, then pass it to the [`runOptimizer`][Optimizer] function. `runOptimizer()` returns an observable of update objects, which are summaries of the optimizer state plus an optional `event` property which describes the internal events occuring and may be of use. You can use the [`logOptimizerState()`][LogOptimizerState] helper to write the relevant bits of state to a tooling log or checkout it's implementation to see how the internal events like [`WorkerStdio`][ObserveWorker] and [`WorkerStarted`][ObserveWorker] are used. Example: ```ts @@ -72,7 +72,7 @@ The [`Bundle`][Bundle] objects which include the details necessary to create a w Each worker communicates state back to the main process by sending [`WorkerMsg`][WorkerMsg] and [`CompilerMsg`][CompilerMsg] objects using IPC. -The Optimizer captures all of these messages and produces a stream of [`OptimizerMsg`][Optimizer] objects. +The Optimizer captures all of these messages and produces a stream of update objects. Optimizer phases:
diff --git a/packages/kbn-optimizer/src/common/index.ts b/packages/kbn-optimizer/src/common/index.ts index 02dd8c3c004ce..398f55bbdf8c2 100644 --- a/packages/kbn-optimizer/src/common/index.ts +++ b/packages/kbn-optimizer/src/common/index.ts @@ -26,3 +26,4 @@ export * from './ts_helpers'; export * from './rxjs_helpers'; export * from './promise_helpers'; export * from './array_helpers'; +export * from './state_helpers'; diff --git a/packages/kbn-optimizer/src/common/state_helpers.ts b/packages/kbn-optimizer/src/common/state_helpers.ts new file mode 100644 index 0000000000000..5a4d44c3adc71 --- /dev/null +++ b/packages/kbn-optimizer/src/common/state_helpers.ts @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as Rx from 'rxjs'; +import { scan, distinctUntilChanged, startWith } from 'rxjs/operators'; + +export interface StoreUpdate { + event?: Event; + state: State; +} + +export type StoreEventType< + Store extends Rx.Observable> +> = Store extends Rx.Observable> ? Event : never; + +export type StoreStateType< + Store extends Rx.Observable> +> = Store extends Rx.Observable> ? State : never; + +export type StoreReducerType>> = ( + prev: StoreStateType, + event: StoreEventType +) => StoreStateType; + +export type Reducer = (prev: State, event: Event) => State; + +/** + * Create a simple store that merges together a series of events into a + * single stream of state updates produced by the reducer function. + */ +export const createStore = ( + event$: Rx.Observable, + initialState: State, + reducer: Reducer +): Rx.Observable> => { + const initUpdate: StoreUpdate = { + state: initialState, + }; + + return event$.pipe( + scan((prev: StoreUpdate, event) => { + const newState = reducer(prev.state, event); + return newState === prev.state + ? prev + : { + event, + state: newState, + }; + }, initUpdate), + distinctUntilChanged(), + startWith(initUpdate) + ); +}; diff --git a/packages/kbn-optimizer/src/index.ts b/packages/kbn-optimizer/src/index.ts index f9fa50fee0b51..48777f1d54aaf 100644 --- a/packages/kbn-optimizer/src/index.ts +++ b/packages/kbn-optimizer/src/index.ts @@ -17,6 +17,6 @@ * under the License. */ -export { OptimizerConfig, OptimizerMsg } from './optimizer'; +export { OptimizerConfig } from './optimizer'; export * from './run_optimizer'; export * from './log_optimizer_state'; diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index aebb5dd87cdb9..e4a515b0ad4f2 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -20,20 +20,20 @@ import { inspect } from 'util'; import { ToolingLog } from '@kbn/dev-utils'; -import * as Rx from 'rxjs'; import { tap } from 'rxjs/operators'; -import { OptimizerConfig, OptimizerMsg } from './optimizer'; +import { OptimizerConfig } from './optimizer'; +import { OptimizerUpdate$ } from './run_optimizer'; import { CompilerMsg, pipeClosure } from './common'; export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { - return pipeClosure((msg$: Rx.Observable) => { + return pipeClosure((update$: OptimizerUpdate$) => { const bundleStates = new Map(); let loggedInit = false; - return msg$.pipe( - tap(msg => { - const { event, state } = msg; + return update$.pipe( + tap(update => { + const { event, state } = update; if (event?.type === 'worker stdio') { const chunk = event.chunk.toString('utf8'); @@ -118,7 +118,7 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { return true; } - throw new Error(`unhandled optimizer message: ${inspect(msg)}`); + throw new Error(`unhandled optimizer message: ${inspect(update)}`); }) ); }); diff --git a/packages/kbn-optimizer/src/optimizer/index.ts b/packages/kbn-optimizer/src/optimizer/index.ts index a549fb156ee61..b7f14cf3c517f 100644 --- a/packages/kbn-optimizer/src/optimizer/index.ts +++ b/packages/kbn-optimizer/src/optimizer/index.ts @@ -19,7 +19,7 @@ export * from './optimizer_config'; export { WorkerStdio } from './observe_worker'; -export * from './optimizer_msg'; +export * from './optimizer_reducer'; export * from './cache_keys'; export * from './watch_bundles_for_changes'; export * from './run_workers'; diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts b/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts deleted file mode 100644 index 5ab84232e44cb..0000000000000 --- a/packages/kbn-optimizer/src/optimizer/optimizer_msg.ts +++ /dev/null @@ -1,207 +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 { inspect } from 'util'; - -import * as Rx from 'rxjs'; -import { scan, distinctUntilChanged } from 'rxjs/operators'; - -import { WorkerMsg, CompilerMsg, Bundle } from '../common'; - -import { ChangeEvent } from './watcher'; -import { WorkerStatus } from './observe_worker'; -import { BundleCacheEvent } from './bundle_cache'; -import { OptimizerConfig } from './optimizer_config'; - -export interface OptimizerInitializedEvent { - type: 'optimizer initialized'; -} - -export type OptimizerEvent = - | OptimizerInitializedEvent - | ChangeEvent - | WorkerMsg - | WorkerStatus - | BundleCacheEvent; - -export interface OptimizerMsg { - state: OptimizerState; - event?: OptimizerEvent; -} - -export interface OptimizerState { - phase: 'initializing' | 'initialized' | 'running' | 'issue' | 'success' | 'reallocating'; - startTime: number; - durSec: number; - compilerStates: CompilerMsg[]; - onlineBundles: Bundle[]; - offlineBundles: Bundle[]; -} - -const msToSec = (ms: number) => Math.round(ms / 100) / 10; - -/** - * merge a state and some updates into a new optimizer state, apply some - * standard updates related to timing, and wrap it up with an event to - * create an OptimizerMsg - */ -export function createOptimizerMsg( - prevState: OptimizerState, - event?: OptimizerEvent, - stateUpdate?: Partial> -): OptimizerMsg { - // reset start time if we are transitioning into running - const startTime = - (prevState.phase === 'success' || prevState.phase === 'issue') && - (stateUpdate?.phase === 'running' || stateUpdate?.phase === 'reallocating') - ? Date.now() - : prevState.startTime; - - return { - event, - state: { - ...prevState, - ...stateUpdate, - startTime, - durSec: msToSec(Date.now() - startTime), - }, - }; -} - -/** - * calculate the total state, given a set of compiler messages - */ -function getStatePhase(states: CompilerMsg[]) { - const types = states.map(s => s.type); - - if (types.includes('running')) { - return 'running'; - } - - if (types.includes('compiler issue')) { - return 'issue'; - } - - if (types.every(s => s === 'compiler success')) { - return 'success'; - } - - throw new Error(`unable to summarize bundle states: ${JSON.stringify(states)}`); -} - -/** - * Convert a stream of OptimizerEvents into the public stream of - * OptimizerMsgs. The resulting state reflects the total state - * of all bundles and workers. - */ -export function summarizeOptimizerEvent$( - config: OptimizerConfig, - initialStartTime: number, - event$: Rx.Observable -) { - return event$.pipe( - scan( - (prevMsg, event) => { - const { state } = prevMsg; - - if (event.type === 'optimizer initialized') { - return createOptimizerMsg(state, event, { - phase: 'initialized', - }); - } - - if (event.type === 'worker error' || event.type === 'compiler error') { - // unrecoverable error states - const error = new Error(event.errorMsg); - error.stack = event.errorStack; - throw error; - } - - if (event.type === 'worker stdio' || event.type === 'worker started') { - return createOptimizerMsg(state, event); - } - - if (event.type === 'changes detected') { - // switch to running early, before workers are started, so that - // base path proxy can prevent requests in the delay between changes - // and workers started - return createOptimizerMsg(state, event, { - phase: 'reallocating', - }); - } - - if ( - event.type === 'changes' || - event.type === 'bundle cached' || - event.type === 'bundle not cached' - ) { - const onlineBundles: Bundle[] = [...state.onlineBundles]; - if (event.type === 'changes') { - onlineBundles.push(...event.bundles); - } - if (event.type === 'bundle not cached') { - onlineBundles.push(event.bundle); - } - - const offlineBundles: Bundle[] = []; - for (const bundle of config.bundles) { - if (!onlineBundles.includes(bundle)) { - offlineBundles.push(bundle); - } - } - - return createOptimizerMsg(state, event, { - phase: state.phase === 'initializing' ? 'initializing' : 'running', - onlineBundles, - offlineBundles, - }); - } - - if ( - event.type === 'compiler issue' || - event.type === 'compiler success' || - event.type === 'running' - ) { - const compilerStates: CompilerMsg[] = [ - ...state.compilerStates.filter(c => c.bundleId !== event.bundleId), - event, - ]; - return createOptimizerMsg(state, event, { - phase: getStatePhase(compilerStates), - compilerStates, - }); - } - - throw new Error(`unexpected optimizer event ${inspect(event)}`); - }, - createOptimizerMsg({ - compilerStates: [], - durSec: 0, - offlineBundles: [], - onlineBundles: [], - phase: 'initializing', - startTime: initialStartTime, - }) - ), - - // returning the previous message is how we indicate - // that an event should be dropped - distinctUntilChanged() - ); -} diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_reducer.ts b/packages/kbn-optimizer/src/optimizer/optimizer_reducer.ts new file mode 100644 index 0000000000000..91b687450f760 --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/optimizer_reducer.ts @@ -0,0 +1,170 @@ +/* + * 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 { inspect } from 'util'; + +import { WorkerMsg, CompilerMsg, Bundle, Reducer } from '../common'; + +import { ChangeEvent } from './watcher'; +import { WorkerStatus } from './observe_worker'; +import { BundleCacheEvent } from './bundle_cache'; +import { OptimizerConfig } from './optimizer_config'; + +export interface OptimizerInitializedEvent { + type: 'optimizer initialized'; +} + +export type OptimizerEvent = + | OptimizerInitializedEvent + | ChangeEvent + | WorkerMsg + | WorkerStatus + | BundleCacheEvent; + +export interface OptimizerState { + phase: 'initializing' | 'initialized' | 'running' | 'issue' | 'success' | 'reallocating'; + startTime: number; + durSec: number; + compilerStates: CompilerMsg[]; + onlineBundles: Bundle[]; + offlineBundles: Bundle[]; +} + +const msToSec = (ms: number) => Math.round(ms / 100) / 10; + +/** + * merge a state and some updates into a new optimizer state, apply some + * standard updates related to timing + */ +function createOptimizerState( + prevState: OptimizerState, + update?: Partial> +): OptimizerState { + // reset start time if we are transitioning into running + const startTime = + (prevState.phase === 'success' || prevState.phase === 'issue') && + (update?.phase === 'running' || update?.phase === 'reallocating') + ? Date.now() + : prevState.startTime; + + return { + ...prevState, + ...update, + startTime, + durSec: msToSec(Date.now() - startTime), + }; +} + +/** + * calculate the total state, given a set of compiler messages + */ +function getStatePhase(states: CompilerMsg[]) { + const types = states.map(s => s.type); + + if (types.includes('running')) { + return 'running'; + } + + if (types.includes('compiler issue')) { + return 'issue'; + } + + if (types.every(s => s === 'compiler success')) { + return 'success'; + } + + throw new Error(`unable to summarize bundle states: ${JSON.stringify(states)}`); +} + +export function createOptimizerReducer( + config: OptimizerConfig +): Reducer { + return (state, event) => { + if (event.type === 'optimizer initialized') { + return createOptimizerState(state, { + phase: 'initialized', + }); + } + + if (event.type === 'worker error' || event.type === 'compiler error') { + // unrecoverable error states + const error = new Error(event.errorMsg); + error.stack = event.errorStack; + throw error; + } + + if (event.type === 'worker stdio' || event.type === 'worker started') { + // same state, but updated to the event is shared externally + return createOptimizerState(state); + } + + if (event.type === 'changes detected') { + // switch to running early, before workers are started, so that + // base path proxy can prevent requests in the delay between changes + // and workers started + return createOptimizerState(state, { + phase: 'reallocating', + }); + } + + if ( + event.type === 'changes' || + event.type === 'bundle cached' || + event.type === 'bundle not cached' + ) { + const onlineBundles: Bundle[] = [...state.onlineBundles]; + if (event.type === 'changes') { + onlineBundles.push(...event.bundles); + } + if (event.type === 'bundle not cached') { + onlineBundles.push(event.bundle); + } + + const offlineBundles: Bundle[] = []; + for (const bundle of config.bundles) { + if (!onlineBundles.includes(bundle)) { + offlineBundles.push(bundle); + } + } + + return createOptimizerState(state, { + phase: state.phase === 'initializing' ? 'initializing' : 'running', + onlineBundles, + offlineBundles, + }); + } + + if ( + event.type === 'compiler issue' || + event.type === 'compiler success' || + event.type === 'running' + ) { + const compilerStates: CompilerMsg[] = [ + ...state.compilerStates.filter(c => c.bundleId !== event.bundleId), + event, + ]; + return createOptimizerState(state, { + phase: getStatePhase(compilerStates), + compilerStates, + }); + } + + throw new Error(`unexpected optimizer event ${inspect(event)}`); + }; +} diff --git a/packages/kbn-optimizer/src/optimizer/run_workers.ts b/packages/kbn-optimizer/src/optimizer/run_workers.ts index 94d850c1ae91e..e91b0d25fd72b 100644 --- a/packages/kbn-optimizer/src/optimizer/run_workers.ts +++ b/packages/kbn-optimizer/src/optimizer/run_workers.ts @@ -27,7 +27,6 @@ import { BundleCacheEvent } from './bundle_cache'; import { ChangeEvent } from './watcher'; import { assignBundlesToWorkers } from './assign_bundles_to_workers'; import { observeWorker } from './observe_worker'; -import { OptimizerCacheKey } from './cache_keys'; /** * Create a stream of all worker events, these include messages @@ -44,7 +43,7 @@ import { OptimizerCacheKey } from './cache_keys'; */ export function runWorkers( config: OptimizerConfig, - optimizerCacheKey: OptimizerCacheKey, + optimizerCacheKey: unknown, bundleCache$: Rx.Observable, changeEvent$: Rx.Observable ) { diff --git a/packages/kbn-optimizer/src/run_optimizer.ts b/packages/kbn-optimizer/src/run_optimizer.ts index 9f92756e650a8..39c40d5ccc418 100644 --- a/packages/kbn-optimizer/src/run_optimizer.ts +++ b/packages/kbn-optimizer/src/run_optimizer.ts @@ -20,53 +20,65 @@ import * as Rx from 'rxjs'; import { mergeMap, share, observeOn } from 'rxjs/operators'; +import { createStore, StoreUpdate } from './common'; + import { OptimizerConfig, - OptimizerMsg, + OptimizerEvent, + OptimizerState, getBundleCacheEvent$, getOptimizerCacheKey, watchBundlesForChanges$, runWorkers, OptimizerInitializedEvent, - summarizeOptimizerEvent$, + createOptimizerReducer, } from './optimizer'; +export type OptimizerUpdate = StoreUpdate; +export type OptimizerUpdate$ = Rx.Observable; + export function runOptimizer(config: OptimizerConfig) { return Rx.defer(async () => ({ startTime: Date.now(), cacheKey: await getOptimizerCacheKey(config), })).pipe( - mergeMap( - (init): Rx.Observable => { - const bundleCacheEvent$ = getBundleCacheEvent$(config, init.cacheKey).pipe( - observeOn(Rx.asyncScheduler), - share() - ); - - // watch the offline bundles for changes, turning them online... - const changeEvent$ = config.watch - ? watchBundlesForChanges$(bundleCacheEvent$, init.startTime).pipe(share()) - : Rx.EMPTY; + mergeMap(({ startTime, cacheKey }) => { + const bundleCacheEvent$ = getBundleCacheEvent$(config, cacheKey).pipe( + observeOn(Rx.asyncScheduler), + share() + ); - // run workers to build all the online bundles, including the bundles turned online by changeEvent$ - const workerEvent$ = runWorkers(config, init.cacheKey, bundleCacheEvent$, changeEvent$); - - // kick off the event summarizer with an intialized event - const initEvent: OptimizerInitializedEvent = { + // initialization completes once all bundle caches have been resolved + const init$ = Rx.concat( + bundleCacheEvent$, + Rx.of({ type: 'optimizer initialized', - }; + }) + ); + + // watch the offline bundles for changes, turning them online... + const changeEvent$ = config.watch + ? watchBundlesForChanges$(bundleCacheEvent$, startTime).pipe(share()) + : Rx.EMPTY; - // all of the events occuring within the optimizer - const event$ = Rx.merge( - Rx.concat(bundleCacheEvent$, Rx.of(initEvent)), - changeEvent$, - workerEvent$ - ); + // run workers to build all the online bundles, including the bundles turned online by changeEvent$ + const workerEvent$ = runWorkers(config, cacheKey, bundleCacheEvent$, changeEvent$); - // summarize all events into public OptimizerMsg objects, which include states and - // the event which lead to that state - return summarizeOptimizerEvent$(config, init.startTime, event$); - } - ) + // create the stream that summarized all the events into state + // objects, which we're calling a store because it's sorta similar to + // the redux store model (events === actions) + return createStore( + Rx.merge(init$, changeEvent$, workerEvent$), + { + phase: 'initializing', + compilerStates: [], + offlineBundles: [], + onlineBundles: [], + startTime, + durSec: 0, + }, + createOptimizerReducer(config) + ); + }) ); } From 8b689f3be08d16fd353152155da5c3f8bc900c14 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 12:38:10 -0700 Subject: [PATCH 65/83] one more OptimizerMsg update --- .../src/integration_tests/basic_optimization.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index 94eae4f0f9878..58b091586d120 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -25,7 +25,7 @@ import cpy from 'cpy'; import del from 'del'; import { toArray, tap } from 'rxjs/operators'; import { createAbsolutePathSerializer } from '@kbn/dev-utils'; -import { runOptimizer, OptimizerConfig, OptimizerMsg } from '@kbn/optimizer'; +import { runOptimizer, OptimizerConfig, OptimizerUpdate } from '@kbn/optimizer'; const TMP_DIR = Path.resolve(__dirname, '../__fixtures__/__tmp__'); const MOCK_REPO_SRC = Path.resolve(__dirname, '../__fixtures__/mock_repo'); @@ -67,7 +67,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { ) .toPromise(); - const assert = (statement: string, truth: boolean, altStates?: OptimizerMsg[]) => { + const assert = (statement: string, truth: boolean, altStates?: OptimizerUpdate[]) => { if (!truth) { throw new Error( `expected optimizer to ${statement}, states: ${inspect(altStates || msgs, { From 6e18553220c7a1c653f4ed1879ebbc52a33e7b26 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 13:06:44 -0700 Subject: [PATCH 66/83] ensure bundles are not cached when cache config is false --- .../integration_tests/bundle_cache.test.ts | 41 +++++++++++++++++++ .../src/optimizer/bundle_cache.ts | 12 +++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts b/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts index 0237d9ccfd11f..1bfd8d3fd073a 100644 --- a/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/bundle_cache.test.ts @@ -91,6 +91,47 @@ it('emits "bundle cached" event when everything is updated', async () => { `); }); +it('emits "bundle not cached" event when cacheKey is up to date but caching is disabled in config', async () => { + const config = OptimizerConfig.create({ + repoRoot: MOCK_REPO_DIR, + pluginScanDirs: [], + pluginPaths: [Path.resolve(MOCK_REPO_DIR, 'plugins/foo')], + maxWorkerCount: 1, + cache: false, + }); + const [bundle] = config.bundles; + + const optimizerCacheKey = 'optimizerCacheKey'; + const files = [ + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/ext.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/index.ts'), + Path.resolve(MOCK_REPO_DIR, 'plugins/foo/public/lib.ts'), + ]; + const mtimes = await getMtimes(files); + const cacheKey = bundle.createCacheKey(files, mtimes); + + bundle.cache.set({ + cacheKey, + optimizerCacheKey, + files, + moduleCount: files.length, + }); + + const cacheEvents = await getBundleCacheEvent$(config, optimizerCacheKey) + .pipe(toArray()) + .toPromise(); + + expect(cacheEvents).toMatchInlineSnapshot(` + Array [ + Object { + "bundle": , + "reason": "cache disabled", + "type": "bundle not cached", + }, + ] + `); +}); + it('emits "bundle not cached" event when optimizerCacheKey is missing', async () => { const config = OptimizerConfig.create({ repoRoot: MOCK_REPO_DIR, diff --git a/packages/kbn-optimizer/src/optimizer/bundle_cache.ts b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts index 06f0f52949f05..1fe59de778363 100644 --- a/packages/kbn-optimizer/src/optimizer/bundle_cache.ts +++ b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts @@ -34,7 +34,8 @@ export interface BundleNotCachedEvent { | 'missing optimizer cache key' | 'optimizer cache key mismatch' | 'missing cache key' - | 'cache key mismatch'; + | 'cache key mismatch' + | 'cache disabled'; diff?: string; bundle: Bundle; } @@ -53,6 +54,15 @@ export function getBundleCacheEvent$( const eligibleBundles: Bundle[] = []; for (const bundle of config.bundles) { + if (!config.cache) { + events.push({ + type: 'bundle not cached', + reason: 'cache disabled', + bundle, + }); + continue; + } + const cachedOptimizerCacheKeys = bundle.cache.getOptimizerCacheKey(); if (!cachedOptimizerCacheKeys) { events.push({ From e77a70a230dcfd8eaf4c5e3187004efd2dce3cad Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 13:53:01 -0700 Subject: [PATCH 67/83] test for initializing states and bundle cache events --- .../src/integration_tests/basic_optimization.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index 58b091586d120..cf4473cbff263 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -78,6 +78,16 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { } }; + const initializingStates = msgs.filter(msg => msg.state.phase === 'initializing'); + assert('produce at least one initializing event', initializingStates.length >= 1); + + const bundleCacheStates = msgs.filter( + msg => + (msg.event?.type === 'bundle cached' || msg.event?.type === 'bundle not cached') && + msg.state.phase === 'initializing' + ); + assert('produce two bundle cache events while initializing', bundleCacheStates.length === 2); + const initializedStates = msgs.filter(msg => msg.state.phase === 'initialized'); assert('produce at least one initialized event', initializedStates.length >= 1); @@ -101,6 +111,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { const otherStates = msgs.filter( msg => + msg.state.phase !== 'initializing' && msg.state.phase !== 'success' && msg.state.phase !== 'running' && msg.state.phase !== 'initialized' && From 5e553b8731b86a1eb259165ed066323986ecc891 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 15:09:19 -0700 Subject: [PATCH 68/83] remove unnecessary timeout change --- .../feature_controls/advanced_settings_spaces.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_spaces.ts b/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_spaces.ts index c780a8efae304..097812c576e92 100644 --- a/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_spaces.ts +++ b/x-pack/test/functional/apps/advanced_settings/feature_controls/advanced_settings_spaces.ts @@ -80,9 +80,7 @@ export default function({ getPageObjects, getService }: FtrProviderContext) { ensureCurrentUrl: false, shouldLoginIfPrompted: false, }); - await testSubjects.existOrFail('managementHome', { - timeout: 10000, - }); + await testSubjects.existOrFail('managementHome'); }); }); }); From 9c47ff0398aad45171005427c08c41196e2c090d Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 16:31:16 -0700 Subject: [PATCH 69/83] Remove unnecessary helpers --- .../src/common/array_helpers.test.ts | 8 +--- .../kbn-optimizer/src/common/array_helpers.ts | 7 ---- packages/kbn-optimizer/src/common/index.ts | 1 - .../src/common/promise_helpers.ts | 39 ------------------- .../kbn-optimizer/src/optimizer/get_mtimes.ts | 38 +++++++++--------- 5 files changed, 19 insertions(+), 74 deletions(-) delete mode 100644 packages/kbn-optimizer/src/common/promise_helpers.ts diff --git a/packages/kbn-optimizer/src/common/array_helpers.test.ts b/packages/kbn-optimizer/src/common/array_helpers.test.ts index 13e0c254ccdaa..9d45217486ee8 100644 --- a/packages/kbn-optimizer/src/common/array_helpers.test.ts +++ b/packages/kbn-optimizer/src/common/array_helpers.test.ts @@ -17,7 +17,7 @@ * under the License. */ -import { ascending, descending, invert } from './array_helpers'; +import { ascending, descending } from './array_helpers'; describe('ascending/descending', () => { interface Item { @@ -110,9 +110,3 @@ describe('ascending/descending', () => { `); }); }); - -describe('invert', () => { - it('inverts a filter function', () => { - expect([1, 2, '3', 4].filter(invert((i): i is number => typeof i === 'number'))).toEqual(['3']); - }); -}); diff --git a/packages/kbn-optimizer/src/common/array_helpers.ts b/packages/kbn-optimizer/src/common/array_helpers.ts index a4766e1d37cd2..740f018d19298 100644 --- a/packages/kbn-optimizer/src/common/array_helpers.ts +++ b/packages/kbn-optimizer/src/common/array_helpers.ts @@ -67,13 +67,6 @@ export const descending = (...getters: Array>): Comparator< return (a, b) => sorter(b, a); }; -/** - * Invert a filter function that has a defined type guard with - * typescript support - */ -export const invert = (fn: (x: T) => x is T2) => (x: T): x is Exclude => - !fn(x); - /** * Alternate Array#includes() implementation with sane types, functions as a type guard */ diff --git a/packages/kbn-optimizer/src/common/index.ts b/packages/kbn-optimizer/src/common/index.ts index 398f55bbdf8c2..975c850251473 100644 --- a/packages/kbn-optimizer/src/common/index.ts +++ b/packages/kbn-optimizer/src/common/index.ts @@ -24,6 +24,5 @@ export * from './worker_messages'; export * from './compiler_messages'; export * from './ts_helpers'; export * from './rxjs_helpers'; -export * from './promise_helpers'; export * from './array_helpers'; export * from './state_helpers'; diff --git a/packages/kbn-optimizer/src/common/promise_helpers.ts b/packages/kbn-optimizer/src/common/promise_helpers.ts deleted file mode 100644 index d0ce3f2762bbe..0000000000000 --- a/packages/kbn-optimizer/src/common/promise_helpers.ts +++ /dev/null @@ -1,39 +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 * as Rx from 'rxjs'; -import { mergeMap, toArray } from 'rxjs/operators'; -import { maybe } from './rxjs_helpers'; - -/** - * Concurrently iterate over an array of items, resolving the promises returned from each call to fn, - * limit concurrency, items are sorted in resolution order so be sure to sort after the fact. - */ -export const concurrentMap = async ( - array: Iterable, - fn: (item: T1) => Promise, - concurrency = 100 -) => - await Rx.from(array) - .pipe( - mergeMap(async item => await fn(item), concurrency), - maybe(), - toArray() - ) - .toPromise(); diff --git a/packages/kbn-optimizer/src/optimizer/get_mtimes.ts b/packages/kbn-optimizer/src/optimizer/get_mtimes.ts index 4efacf7f00dcb..9ac156cb5b8de 100644 --- a/packages/kbn-optimizer/src/optimizer/get_mtimes.ts +++ b/packages/kbn-optimizer/src/optimizer/get_mtimes.ts @@ -18,32 +18,30 @@ */ import Fs from 'fs'; -import { promisify } from 'util'; -import { concurrentMap } from '../common'; +import * as Rx from 'rxjs'; +import { mergeMap, toArray, map, catchError } from 'rxjs/operators'; -const statAsync = promisify(Fs.stat); +const stat$ = Rx.bindNodeCallback(Fs.stat); /** * get mtimes of referenced paths concurrently, limit concurrency to 100 */ export async function getMtimes(paths: Iterable) { - return new Map( - await concurrentMap( - paths, - async path => { - try { - const stat = await statAsync(path); - return [path, stat.mtimeMs] as const; - } catch (error) { - if (error?.code === 'ENOENT') { - return [path, undefined] as const; - } - - throw error; - } - }, - 100 + return await Rx.from(paths) + .pipe( + // map paths to [path, mtimeMs] entries with concurrency of + // 100 at a time, ignoring missing paths + mergeMap( + path => + stat$(path).pipe( + map(stat => [path, stat.mtimeMs] as const), + catchError((error: any) => (error?.code === 'ENOENT' ? Rx.EMPTY : Rx.throwError(error))) + ), + 100 + ), + toArray(), + map(entries => new Map(entries)) ) - ); + .toPromise(); } From 3159b1c61e5385b40e696fb4adb3f410ddcd18f1 Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 16:44:24 -0700 Subject: [PATCH 70/83] Add tests for BundleCache class --- .../src/common/bundle_cache.test.ts | 118 ++++++++++++++++++ .../kbn-optimizer/src/common/bundle_cache.ts | 12 +- .../src/optimizer/bundle_cache.ts | 4 +- 3 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 packages/kbn-optimizer/src/common/bundle_cache.test.ts diff --git a/packages/kbn-optimizer/src/common/bundle_cache.test.ts b/packages/kbn-optimizer/src/common/bundle_cache.test.ts new file mode 100644 index 0000000000000..f6118739045ba --- /dev/null +++ b/packages/kbn-optimizer/src/common/bundle_cache.test.ts @@ -0,0 +1,118 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { BundleCache, State } from './bundle_cache'; + +jest.mock('fs'); +const mockReadFileSync: jest.Mock = jest.requireMock('fs').readFileSync; +const mockMkdirSync: jest.Mock = jest.requireMock('fs').mkdirSync; +const mockWriteFileSync: jest.Mock = jest.requireMock('fs').writeFileSync; + +const SOME_STATE: State = { + cacheKey: 'abc', + files: ['123'], + moduleCount: 123, + optimizerCacheKey: 'abc', +}; + +beforeEach(() => { + jest.clearAllMocks(); +}); + +it(`doesn't complain if files are not on disk`, () => { + const cache = new BundleCache('/foo/bar.json'); + expect(cache.get()).toEqual({}); +}); + +it(`updates files on disk when calling set()`, () => { + const cache = new BundleCache('/foo/bar.json'); + cache.set(SOME_STATE); + expect(mockReadFileSync).not.toHaveBeenCalled(); + expect(mockMkdirSync.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/foo", + Object { + "recursive": true, + }, + ], + ] + `); + expect(mockWriteFileSync.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/foo/bar.json", + "{ + \\"cacheKey\\": \\"abc\\", + \\"files\\": [ + \\"123\\" + ], + \\"moduleCount\\": 123, + \\"optimizerCacheKey\\": \\"abc\\" + }", + ], + ] + `); +}); + +it(`serves updated state from memory`, () => { + const cache = new BundleCache('/foo/bar.json'); + cache.set(SOME_STATE); + jest.clearAllMocks(); + + expect(cache.get()).toEqual(SOME_STATE); + expect(mockReadFileSync).not.toHaveBeenCalled(); + expect(mockMkdirSync).not.toHaveBeenCalled(); + expect(mockWriteFileSync).not.toHaveBeenCalled(); +}); + +it('reads state from disk on get() after refresh()', () => { + const cache = new BundleCache('/foo/bar.json'); + cache.set(SOME_STATE); + cache.refresh(); + jest.clearAllMocks(); + + cache.get(); + expect(mockMkdirSync).not.toHaveBeenCalled(); + expect(mockWriteFileSync).not.toHaveBeenCalled(); + expect(mockReadFileSync.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + "/foo/bar.json", + "utf8", + ], + ] + `); +}); + +it('provides accessors to specific state properties', () => { + const cache = new BundleCache('/foo/bar.json'); + + expect(cache.getModuleCount()).toBe(undefined); + expect(cache.getReferencedFiles()).toEqual(undefined); + expect(cache.getCacheKey()).toEqual(undefined); + expect(cache.getOptimizerCacheKey()).toEqual(undefined); + + cache.set(SOME_STATE); + + expect(cache.getModuleCount()).toBe(123); + expect(cache.getReferencedFiles()).toEqual(['123']); + expect(cache.getCacheKey()).toEqual('abc'); + expect(cache.getOptimizerCacheKey()).toEqual('abc'); +}); diff --git a/packages/kbn-optimizer/src/common/bundle_cache.ts b/packages/kbn-optimizer/src/common/bundle_cache.ts index c5602cc607b51..1dbc7f1d1b6b0 100644 --- a/packages/kbn-optimizer/src/common/bundle_cache.ts +++ b/packages/kbn-optimizer/src/common/bundle_cache.ts @@ -20,7 +20,7 @@ import Fs from 'fs'; import Path from 'path'; -interface State { +export interface State { optimizerCacheKey?: unknown; cacheKey?: unknown; moduleCount?: number; @@ -32,10 +32,6 @@ const DEFAULT_STATE_JSON = JSON.stringify(DEFAULT_STATE); /** * Helper to read and update metadata for bundles. - * - * Currently only tracks the module count of bundles, allowing - * us to assign bundles to workers in a way that ensures an even - * distribution of modules to be built */ export class BundleCache { private state: State | undefined = undefined; @@ -74,10 +70,6 @@ export class BundleCache { return this.state; } - update(updater: (state: State) => State) { - this.set(updater(this.get())); - } - set(updated: State) { this.state = updated; if (this.path) { @@ -95,7 +87,7 @@ export class BundleCache { return this.get().files; } - public getCacheKeys() { + public getCacheKey() { return this.get().cacheKey; } diff --git a/packages/kbn-optimizer/src/optimizer/bundle_cache.ts b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts index 1fe59de778363..55e8e1d3fd084 100644 --- a/packages/kbn-optimizer/src/optimizer/bundle_cache.ts +++ b/packages/kbn-optimizer/src/optimizer/bundle_cache.ts @@ -84,7 +84,7 @@ export function getBundleCacheEvent$( continue; } - if (!bundle.cache.getCacheKeys()) { + if (!bundle.cache.getCacheKey()) { events.push({ type: 'bundle not cached', reason: 'missing cache key', @@ -107,7 +107,7 @@ export function getBundleCacheEvent$( for (const bundle of eligibleBundles) { const diff = diffCacheKey( - bundle.cache.getCacheKeys(), + bundle.cache.getCacheKey(), bundle.createCacheKey(bundle.cache.getReferencedFiles() || [], mtimes) ); From a145e48dac34df7051e6cbaead62758a23e1aa7d Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 17:02:10 -0700 Subject: [PATCH 71/83] Add tests for Bundle class --- .../kbn-optimizer/src/common/bundle.test.ts | 93 ++++++++++++++++++ packages/kbn-optimizer/src/common/bundle.ts | 94 +++++++++---------- 2 files changed, 140 insertions(+), 47 deletions(-) create mode 100644 packages/kbn-optimizer/src/common/bundle.test.ts diff --git a/packages/kbn-optimizer/src/common/bundle.test.ts b/packages/kbn-optimizer/src/common/bundle.test.ts new file mode 100644 index 0000000000000..d7cdee1aa984e --- /dev/null +++ b/packages/kbn-optimizer/src/common/bundle.test.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 { Bundle, BundleSpec, parseBundles } from './bundle'; + +jest.mock('fs'); + +const SPEC: BundleSpec = { + contextDir: '/foo/bar', + entry: 'entry', + id: 'bar', + outputDir: '/foo/bar/target', + sourceRoot: '/foo', + type: 'plugin', +}; + +it('creates cache keys', () => { + const bundle = new Bundle(SPEC); + expect( + bundle.createCacheKey( + ['/foo/bar/a', '/foo/bar/c'], + new Map([ + ['/foo/bar/a', 123], + ['/foo/bar/b', 456], + ['/foo/bar/c', 789], + ]) + ) + ).toMatchInlineSnapshot(` + Object { + "mtimes": Object { + "/foo/bar/a": 123, + "/foo/bar/c": 789, + }, + "spec": Object { + "contextDir": "/foo/bar", + "entry": "entry", + "id": "bar", + "outputDir": "/foo/bar/target", + "sourceRoot": "/foo", + "type": "plugin", + }, + } + `); +}); + +it('provides serializable versions of itself', () => { + const bundle = new Bundle(SPEC); + expect(bundle.toSpec()).toEqual(SPEC); +}); + +it('provides the module count from the cache', () => { + const bundle = new Bundle(SPEC); + expect(bundle.getModuleCount()).toBe(undefined); + bundle.cache.set({ moduleCount: 123 }); + expect(bundle.getModuleCount()).toBe(123); +}); + +it('parses bundles from JSON specs', () => { + const bundles = parseBundles(JSON.stringify([SPEC])); + + expect(bundles).toMatchInlineSnapshot(` + Array [ + Bundle { + "cache": BundleCache { + "path": "/foo/bar/target/.kbn-optimizer-cache", + "state": undefined, + }, + "contextDir": "/foo/bar", + "entry": "entry", + "id": "bar", + "outputDir": "/foo/bar/target", + "sourceRoot": "/foo", + "type": "plugin", + }, + ] + `); +}); diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts index dbaa08547c654..ea3920982f48c 100644 --- a/packages/kbn-optimizer/src/common/bundle.ts +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -23,7 +23,7 @@ import { BundleCache } from './bundle_cache'; import { UnknownVals } from './ts_helpers'; import { includes, ascending, entriesToObject } from './array_helpers'; -export const VALID_BUNDLE_TYPES = ['plugin' as const]; +const VALID_BUNDLE_TYPES = ['plugin' as const]; export interface BundleSpec { readonly type: typeof VALID_BUNDLE_TYPES[0]; @@ -49,51 +49,6 @@ export class Bundle { public readonly cache: BundleCache; - public static parseSpec(spec: UnknownVals) { - if (!(spec && typeof spec === 'object')) { - throw new Error('`bundles[]` must be an object'); - } - - const { type } = spec; - if (!includes(VALID_BUNDLE_TYPES, type)) { - throw new Error('`bundles[]` must have a valid `type`'); - } - - const { id } = spec; - if (!(typeof id === 'string')) { - throw new Error('`bundles[]` must have a string `id` property'); - } - - const { entry } = spec; - if (!(typeof entry === 'string')) { - throw new Error('`bundles[]` must have a string `entry` property'); - } - - const { contextDir } = spec; - if (!(typeof contextDir === 'string' && Path.isAbsolute(contextDir))) { - throw new Error('`bundles[]` must have a string `contextDir` property'); - } - - const { sourceRoot } = spec; - if (!(typeof sourceRoot === 'string' && Path.isAbsolute(sourceRoot))) { - throw new Error('`bundles[]` must have a string `sourceRoot` property'); - } - - const { outputDir } = spec; - if (typeof outputDir !== 'string') { - throw new Error('`bundles[]` must have a string `outputDir` property'); - } - - return new Bundle({ - type, - id, - entry, - contextDir, - sourceRoot, - outputDir, - }); - } - constructor(spec: BundleSpec) { this.type = spec.type; this.id = spec.id; @@ -157,7 +112,52 @@ export function parseBundles(json: string) { throw new Error('must be an array'); } - return specs.map(spec => Bundle.parseSpec(spec)); + return specs.map( + (spec: UnknownVals): Bundle => { + if (!(spec && typeof spec === 'object')) { + throw new Error('`bundles[]` must be an object'); + } + + const { type } = spec; + if (!includes(VALID_BUNDLE_TYPES, type)) { + throw new Error('`bundles[]` must have a valid `type`'); + } + + const { id } = spec; + if (!(typeof id === 'string')) { + throw new Error('`bundles[]` must have a string `id` property'); + } + + const { entry } = spec; + if (!(typeof entry === 'string')) { + throw new Error('`bundles[]` must have a string `entry` property'); + } + + const { contextDir } = spec; + if (!(typeof contextDir === 'string' && Path.isAbsolute(contextDir))) { + throw new Error('`bundles[]` must have an absolute path `contextDir` property'); + } + + const { sourceRoot } = spec; + if (!(typeof sourceRoot === 'string' && Path.isAbsolute(sourceRoot))) { + throw new Error('`bundles[]` must have an absolute path `sourceRoot` property'); + } + + const { outputDir } = spec; + if (!(typeof outputDir === 'string' && Path.isAbsolute(outputDir))) { + throw new Error('`bundles[]` must have an absolute path `outputDir` property'); + } + + return new Bundle({ + type, + id, + entry, + contextDir, + sourceRoot, + outputDir, + }); + } + ); } catch (error) { throw new Error(`unable to parse bundles: ${error.message}`); } From 1a08b22ebfa51b87bfa8d77eca569964247c1f3f Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 17:17:24 -0700 Subject: [PATCH 72/83] test summarizeEvent$ --- .../src/common/event_stream_helpers.test.ts | 69 +++++++++++++++++++ ...ate_helpers.ts => event_stream_helpers.ts} | 33 +++------ packages/kbn-optimizer/src/common/index.ts | 2 +- .../src/optimizer/optimizer_reducer.ts | 4 +- packages/kbn-optimizer/src/run_optimizer.ts | 10 ++- 5 files changed, 86 insertions(+), 32 deletions(-) create mode 100644 packages/kbn-optimizer/src/common/event_stream_helpers.test.ts rename packages/kbn-optimizer/src/common/{state_helpers.ts => event_stream_helpers.ts} (55%) diff --git a/packages/kbn-optimizer/src/common/event_stream_helpers.test.ts b/packages/kbn-optimizer/src/common/event_stream_helpers.test.ts new file mode 100644 index 0000000000000..60982abff2d87 --- /dev/null +++ b/packages/kbn-optimizer/src/common/event_stream_helpers.test.ts @@ -0,0 +1,69 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import * as Rx from 'rxjs'; +import { toArray } from 'rxjs/operators'; + +import { summarizeEvent$ } from './event_stream_helpers'; + +it('emits each state with each event, ignoring events when reducer returns undefined', async () => { + const values = await summarizeEvent$( + Rx.of(1, 2, 3, 4, 5), + { + sum: 0, + }, + (state, event) => { + if (event % 2) { + return { + sum: state.sum + event, + }; + } + } + ) + .pipe(toArray()) + .toPromise(); + + expect(values).toMatchInlineSnapshot(` + Array [ + Object { + "state": Object { + "sum": 0, + }, + }, + Object { + "event": 1, + "state": Object { + "sum": 1, + }, + }, + Object { + "event": 3, + "state": Object { + "sum": 4, + }, + }, + Object { + "event": 5, + "state": Object { + "sum": 9, + }, + }, + ] + `); +}); diff --git a/packages/kbn-optimizer/src/common/state_helpers.ts b/packages/kbn-optimizer/src/common/event_stream_helpers.ts similarity index 55% rename from packages/kbn-optimizer/src/common/state_helpers.ts rename to packages/kbn-optimizer/src/common/event_stream_helpers.ts index 5a4d44c3adc71..9b720bba81114 100644 --- a/packages/kbn-optimizer/src/common/state_helpers.ts +++ b/packages/kbn-optimizer/src/common/event_stream_helpers.ts @@ -20,43 +20,30 @@ import * as Rx from 'rxjs'; import { scan, distinctUntilChanged, startWith } from 'rxjs/operators'; -export interface StoreUpdate { +export interface Update { event?: Event; state: State; } -export type StoreEventType< - Store extends Rx.Observable> -> = Store extends Rx.Observable> ? Event : never; - -export type StoreStateType< - Store extends Rx.Observable> -> = Store extends Rx.Observable> ? State : never; - -export type StoreReducerType>> = ( - prev: StoreStateType, - event: StoreEventType -) => StoreStateType; - -export type Reducer = (prev: State, event: Event) => State; +export type Summarizer = (prev: State, event: Event) => State | undefined; /** - * Create a simple store that merges together a series of events into a - * single stream of state updates produced by the reducer function. + * Transform an event stream into a state update stream which emits + * the events and individual states for each event. */ -export const createStore = ( +export const summarizeEvent$ = ( event$: Rx.Observable, initialState: State, - reducer: Reducer -): Rx.Observable> => { - const initUpdate: StoreUpdate = { + reducer: Summarizer +): Rx.Observable> => { + const initUpdate: Update = { state: initialState, }; return event$.pipe( - scan((prev: StoreUpdate, event) => { + scan((prev: Update, event) => { const newState = reducer(prev.state, event); - return newState === prev.state + return newState === undefined ? prev : { event, diff --git a/packages/kbn-optimizer/src/common/index.ts b/packages/kbn-optimizer/src/common/index.ts index 975c850251473..ea0560f132153 100644 --- a/packages/kbn-optimizer/src/common/index.ts +++ b/packages/kbn-optimizer/src/common/index.ts @@ -25,4 +25,4 @@ export * from './compiler_messages'; export * from './ts_helpers'; export * from './rxjs_helpers'; export * from './array_helpers'; -export * from './state_helpers'; +export * from './event_stream_helpers'; diff --git a/packages/kbn-optimizer/src/optimizer/optimizer_reducer.ts b/packages/kbn-optimizer/src/optimizer/optimizer_reducer.ts index 91b687450f760..c1e6572bd7e75 100644 --- a/packages/kbn-optimizer/src/optimizer/optimizer_reducer.ts +++ b/packages/kbn-optimizer/src/optimizer/optimizer_reducer.ts @@ -19,7 +19,7 @@ import { inspect } from 'util'; -import { WorkerMsg, CompilerMsg, Bundle, Reducer } from '../common'; +import { WorkerMsg, CompilerMsg, Bundle, Summarizer } from '../common'; import { ChangeEvent } from './watcher'; import { WorkerStatus } from './observe_worker'; @@ -94,7 +94,7 @@ function getStatePhase(states: CompilerMsg[]) { export function createOptimizerReducer( config: OptimizerConfig -): Reducer { +): Summarizer { return (state, event) => { if (event.type === 'optimizer initialized') { return createOptimizerState(state, { diff --git a/packages/kbn-optimizer/src/run_optimizer.ts b/packages/kbn-optimizer/src/run_optimizer.ts index 39c40d5ccc418..e6cce8d306e35 100644 --- a/packages/kbn-optimizer/src/run_optimizer.ts +++ b/packages/kbn-optimizer/src/run_optimizer.ts @@ -20,7 +20,7 @@ import * as Rx from 'rxjs'; import { mergeMap, share, observeOn } from 'rxjs/operators'; -import { createStore, StoreUpdate } from './common'; +import { summarizeEvent$, Update } from './common'; import { OptimizerConfig, @@ -34,7 +34,7 @@ import { createOptimizerReducer, } from './optimizer'; -export type OptimizerUpdate = StoreUpdate; +export type OptimizerUpdate = Update; export type OptimizerUpdate$ = Rx.Observable; export function runOptimizer(config: OptimizerConfig) { @@ -64,10 +64,8 @@ export function runOptimizer(config: OptimizerConfig) { // run workers to build all the online bundles, including the bundles turned online by changeEvent$ const workerEvent$ = runWorkers(config, cacheKey, bundleCacheEvent$, changeEvent$); - // create the stream that summarized all the events into state - // objects, which we're calling a store because it's sorta similar to - // the redux store model (events === actions) - return createStore( + // create the stream that summarized all the events into specific states + return summarizeEvent$( Rx.merge(init$, changeEvent$, workerEvent$), { phase: 'initializing', From 8880e0ceecdddabdcab411069390538646fe38af Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 17:59:45 -0700 Subject: [PATCH 73/83] missing paths are no longer listed in mtimes map --- packages/kbn-optimizer/src/optimizer/get_mtimes.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/kbn-optimizer/src/optimizer/get_mtimes.test.ts b/packages/kbn-optimizer/src/optimizer/get_mtimes.test.ts index 68b412c15628d..e1ecd3f1078ad 100644 --- a/packages/kbn-optimizer/src/optimizer/get_mtimes.test.ts +++ b/packages/kbn-optimizer/src/optimizer/get_mtimes.test.ts @@ -40,7 +40,6 @@ it('returns mtimes Map', async () => { .toMatchInlineSnapshot(` Map { "/foo/bar" => 1234, - "/foo/missing" => undefined, "/foo/baz" => 1234, } `); From 0b990af74c2276d64299292ce102286c4863cbfe Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 18:00:20 -0700 Subject: [PATCH 74/83] add tests for optimizer/cache_keys --- .../src/optimizer/cache_keys.test.ts | 178 ++++++++++++++++++ .../kbn-optimizer/src/optimizer/cache_keys.ts | 12 +- 2 files changed, 184 insertions(+), 6 deletions(-) create mode 100644 packages/kbn-optimizer/src/optimizer/cache_keys.test.ts diff --git a/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts b/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts new file mode 100644 index 0000000000000..44234acd897dc --- /dev/null +++ b/packages/kbn-optimizer/src/optimizer/cache_keys.test.ts @@ -0,0 +1,178 @@ +/* + * 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 jestDiff from 'jest-diff'; +import { REPO_ROOT, createAbsolutePathSerializer } from '@kbn/dev-utils'; + +import { reformatJestDiff, getOptimizerCacheKey, diffCacheKey } from './cache_keys'; +import { OptimizerConfig } from './optimizer_config'; + +jest.mock('./get_changes.ts'); +jest.mock('execa'); +expect.addSnapshotSerializer(createAbsolutePathSerializer()); + +jest.requireMock('execa').mockImplementation(async (cmd: string, args: string[], opts: object) => { + expect(cmd).toBe('git'); + expect(args).toEqual([ + 'log', + '-n', + '1', + '--pretty=format:%H', + '--', + expect.stringContaining('kbn-optimizer'), + ]); + expect(opts).toEqual({ + cwd: REPO_ROOT, + }); + + return { + stdout: '', + }; +}); + +jest.requireMock('./get_changes.ts').getChanges.mockImplementation( + async () => + new Map([ + ['/foo/bar/a', 'modified'], + ['/foo/bar/b', 'modified'], + ['/foo/bar/c', 'deleted'], + ]) +); + +describe('getOptimizerCacheKey()', () => { + it('uses latest commit and changes files to create unique value', async () => { + const config = OptimizerConfig.create({ + repoRoot: REPO_ROOT, + }); + + await expect(getOptimizerCacheKey(config)).resolves.toMatchInlineSnapshot(` + Object { + "deletedPaths": Array [ + "/foo/bar/c", + ], + "lastCommit": "", + "modifiedPaths": Object {}, + "workerConfig": Object { + "browserslistEnv": "dev", + "cache": true, + "dist": false, + "optimizerCacheKey": "♻", + "profileWebpack": false, + "repoRoot": , + "watch": false, + }, + } + `); + }); +}); + +describe('diffCacheKey()', () => { + it('returns undefined if values are equal', () => { + expect(diffCacheKey('1', '1')).toBe(undefined); + expect(diffCacheKey(1, 1)).toBe(undefined); + expect(diffCacheKey(['1', '2', { a: 'b' }], ['1', '2', { a: 'b' }])).toBe(undefined); + expect( + diffCacheKey( + { + a: '1', + b: '2', + }, + { + b: '2', + a: '1', + } + ) + ).toBe(undefined); + }); + + it('returns a diff if the values are different', () => { + expect(diffCacheKey(['1', '2', { a: 'b' }], ['1', '2', { b: 'a' }])).toMatchInlineSnapshot(` + "- Expected + + Received + +  Array [ +  \\"1\\", +  \\"2\\", +  Object { + - \\"a\\": \\"b\\", + + \\"b\\": \\"a\\", +  }, +  ]" + `); + expect( + diffCacheKey( + { + a: '1', + b: '1', + }, + { + b: '2', + a: '2', + } + ) + ).toMatchInlineSnapshot(` + "- Expected + + Received + +  Object { + - \\"a\\": \\"1\\", + - \\"b\\": \\"1\\", + + \\"a\\": \\"2\\", + + \\"b\\": \\"2\\", +  }" + `); + }); +}); + +describe('reformatJestDiff()', () => { + it('reformats large jestDiff output to focus on the changed lines', () => { + const diff = jestDiff( + { + a: ['1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1', '1', '1', '1', '1', '1'], + }, + { + b: ['1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '1', '2', '1', '1', '1', '1'], + } + ); + + expect(reformatJestDiff(diff)).toMatchInlineSnapshot(` + "- Expected + + Received + +  Object { + - \\"a\\": Array [ + + \\"b\\": Array [ +  \\"1\\", +  \\"1\\", +  ... +  \\"1\\", +  \\"1\\", + - \\"2\\", +  \\"1\\", +  \\"1\\", +  ... +  \\"1\\", +  \\"1\\", + + \\"2\\", +  \\"1\\", +  \\"1\\", +  ..." + `); + }); +}); diff --git a/packages/kbn-optimizer/src/optimizer/cache_keys.ts b/packages/kbn-optimizer/src/optimizer/cache_keys.ts index e9d7854115685..3529ffa587f16 100644 --- a/packages/kbn-optimizer/src/optimizer/cache_keys.ts +++ b/packages/kbn-optimizer/src/optimizer/cache_keys.ts @@ -35,15 +35,15 @@ import { OptimizerConfig } from './optimizer_config'; const OPTIMIZER_DIR = Path.dirname(require.resolve('../../package.json')); const RELATIVE_DIR = Path.relative(REPO_ROOT, OPTIMIZER_DIR); -export function diffCacheKey(cacheKeyA?: unknown, cacheKeyB?: unknown) { - const a = jsonStable(cacheKeyA); - const b = jsonStable(cacheKeyB); - - if (a === b) { +export function diffCacheKey(expected?: unknown, actual?: unknown) { + if (jsonStable(expected) === jsonStable(actual)) { return; } - const diff = jestDiff(cacheKeyA, cacheKeyB); + return reformatJestDiff(jestDiff(expected, actual)); +} + +export function reformatJestDiff(diff: string | null) { const diffLines = diff?.split('\n') || []; if ( From fdf535c9a6135a044a0f7d8a1c894a929431af0a Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 22:06:28 -0700 Subject: [PATCH 75/83] Add some extra docs --- packages/kbn-optimizer/src/common/bundle.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts index ea3920982f48c..90cdec70ff663 100644 --- a/packages/kbn-optimizer/src/common/bundle.ts +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -40,11 +40,21 @@ export interface BundleSpec { } export class Bundle { + /** Bundle type, only "plugin" is supported for now */ public readonly type: BundleSpec['type']; + /** Unique identifier for this bundle */ public readonly id: BundleSpec['id']; + /** Path, relative to `contextDir`, to the entry file for the Webpack bundle */ public readonly entry: BundleSpec['entry']; + /** + * Absolute path to the root of the bundle context (plugin directory) + * where the entry is resolved relative to and the default output paths + * are relative to + */ public readonly contextDir: BundleSpec['contextDir']; + /** Absolute path to the root of the whole project source, repo root */ public readonly sourceRoot: BundleSpec['sourceRoot']; + /** Absolute path to the output directory for this bundle */ public readonly outputDir: BundleSpec['outputDir']; public readonly cache: BundleCache; From deeaa5ca42914d1028997b026de24e82344b62ea Mon Sep 17 00:00:00 2001 From: spalger Date: Tue, 11 Feb 2020 22:07:32 -0700 Subject: [PATCH 76/83] Remove labeled loop --- .../kbn-optimizer/src/optimizer/watcher.ts | 25 ++++++------------- 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/packages/kbn-optimizer/src/optimizer/watcher.ts b/packages/kbn-optimizer/src/optimizer/watcher.ts index d3ba2640c2dd1..7b344926ccfec 100644 --- a/packages/kbn-optimizer/src/optimizer/watcher.ts +++ b/packages/kbn-optimizer/src/optimizer/watcher.ts @@ -54,7 +54,7 @@ export class Watcher { private readonly change$ = Rx.fromEvent<[string]>(this.watchpack, 'change'); - public getNextChange$(bundles: Iterable, startTime: number) { + public getNextChange$(bundles: Bundle[], startTime: number) { return Rx.merge( // emit ChangesStarted as soon as we have been triggered this.change$.pipe( @@ -72,24 +72,13 @@ export class Watcher { map(event => event[0]), debounceTimeBuffer(1000), map( - (changes): Changes => { - const changedBundles: Bundle[] = []; - - findChangedBundles: for (const bundle of bundles) { + (changes): Changes => ({ + type: 'changes', + bundles: bundles.filter(bundle => { const referencedFiles = bundle.cache.getReferencedFiles(); - for (const change of changes) { - if (referencedFiles?.includes(change)) { - changedBundles.push(bundle); - continue findChangedBundles; - } - } - } - - return { - type: 'changes', - bundles: changedBundles, - }; - } + return changes.some(change => referencedFiles?.includes(change)); + }), + }) ), take(1) ), From c190d782731acc455aa19a32bd9e759cbe5506e1 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 12 Feb 2020 10:14:29 -0700 Subject: [PATCH 77/83] add integration test for kbn-optimizer watcher components --- .../watch_bundles_for_changes.test.ts | 145 ++++++++++++++++++ .../kbn-optimizer/src/optimizer/watcher.ts | 4 +- 2 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts diff --git a/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts b/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts new file mode 100644 index 0000000000000..dec9b93d51b23 --- /dev/null +++ b/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts @@ -0,0 +1,145 @@ +/* + * 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 Path from 'path'; + +import * as Rx from 'rxjs'; +import { createAbsolutePathSerializer } from '@kbn/dev-utils'; +import { map } from 'rxjs/operators'; +import ActualWatchpack from 'watchpack'; + +import { Bundle, ascending } from '../common'; +import { watchBundlesForChanges$ } from '../optimizer/watch_bundles_for_changes'; +import { BundleCacheEvent } from '../optimizer'; + +jest.mock('fs'); +jest.mock('watchpack'); + +const MockWatchPack: jest.MockedClass = jest.requireMock('watchpack'); +const bundleEntryPath = (bundle: Bundle) => `${bundle.contextDir}/${bundle.entry}`; + +const makeTestBundle = (id: string) => { + const bundle = new Bundle({ + type: 'plugin', + id, + contextDir: `/repo/plugins/${id}/public`, + entry: 'index.ts', + outputDir: `/repo/plugins/${id}/target/public`, + sourceRoot: `/repo`, + }); + + bundle.cache.set({ + cacheKey: 'abc', + moduleCount: 1, + optimizerCacheKey: 'abc', + files: [bundleEntryPath(bundle)], + }); + + return bundle; +}; + +const FOO_BUNDLE = makeTestBundle('foo'); +const BAR_BUNDLE = makeTestBundle('bar'); +const BAZ_BUNDLE = makeTestBundle('baz'); +const BOX_BUNDLE = makeTestBundle('box'); +const CAR_BUNDLE = makeTestBundle('car'); +const BUNDLES = [FOO_BUNDLE, BAR_BUNDLE, BAZ_BUNDLE, BOX_BUNDLE, CAR_BUNDLE]; + +const bundleCacheEvent$ = Rx.from(BUNDLES).pipe( + map( + (bundle): BundleCacheEvent => ({ + type: 'bundle cached', + bundle, + }) + ) +); + +beforeEach(async () => { + jest.useFakeTimers(); +}); + +afterEach(async () => { + jest.useRealTimers(); +}); + +it('notifies of changes and completes once all bundles have changed', async () => { + expect.assertions(18); + + const promise = watchBundlesForChanges$(bundleCacheEvent$, Date.now()) + .pipe( + map((event, i) => { + // each time we trigger a change event we get a 'changed detected' event + if (i === 0 || i === 2 || i === 4 || i === 6) { + expect(event).toHaveProperty('type', 'changes detected'); + return; + } + + expect(event).toHaveProperty('type', 'changes'); + // to teach TS what we're doing + if (event.type !== 'changes') { + return; + } + + // first we change foo and bar, and after 1 second get that change comes though + if (i === 1) { + expect(event.bundles).toHaveLength(2); + const [bar, foo] = event.bundles.sort(ascending(b => b.id)); + expect(bar).toHaveProperty('id', 'bar'); + expect(foo).toHaveProperty('id', 'foo'); + } + + // next we change just the baz package and it's represented on its own + if (i === 3) { + expect(event.bundles).toHaveLength(1); + expect(event.bundles[0]).toHaveProperty('id', 'baz'); + } + + // finally we change box and car together + if (i === 5) { + expect(event.bundles).toHaveLength(2); + const [bar, foo] = event.bundles.sort(ascending(b => b.id)); + expect(bar).toHaveProperty('id', 'box'); + expect(foo).toHaveProperty('id', 'car'); + } + }) + ) + .toPromise(); + + expect(MockWatchPack.mock.instances).toHaveLength(1); + const [watcher] = (MockWatchPack.mock.instances as any) as Array>; + expect(watcher.on).toHaveBeenCalledTimes(1); + expect(watcher.on).toHaveBeenCalledWith('change', expect.any(Function)); + const [, changeListener] = watcher.on.mock.calls[0]; + + // foo and bar are changes without 1sec so they are batched + changeListener(bundleEntryPath(FOO_BUNDLE), 'modified'); + jest.advanceTimersByTime(900); + changeListener(bundleEntryPath(BAR_BUNDLE), 'modified'); + jest.advanceTimersByTime(1000); + + // baz is the only change in 1sec so it is on its own + changeListener(bundleEntryPath(BAZ_BUNDLE), 'modified'); + jest.advanceTimersByTime(1000); + + // finish by changing box and car + changeListener(bundleEntryPath(BOX_BUNDLE), 'deleted'); + changeListener(bundleEntryPath(CAR_BUNDLE), 'deleted'); + jest.advanceTimersByTime(1000); + + await expect(promise).resolves.toEqual(undefined); +}); diff --git a/packages/kbn-optimizer/src/optimizer/watcher.ts b/packages/kbn-optimizer/src/optimizer/watcher.ts index 7b344926ccfec..343f391921383 100644 --- a/packages/kbn-optimizer/src/optimizer/watcher.ts +++ b/packages/kbn-optimizer/src/optimizer/watcher.ts @@ -18,7 +18,7 @@ */ import * as Rx from 'rxjs'; -import { take, map } from 'rxjs/operators'; +import { take, map, share } from 'rxjs/operators'; import Watchpack from 'watchpack'; import { debounceTimeBuffer, Bundle } from '../common'; @@ -52,7 +52,7 @@ export class Watcher { ignored: /node_modules\/([^\/]+[\/])*(?!package.json)([^\/]+)$/, }); - private readonly change$ = Rx.fromEvent<[string]>(this.watchpack, 'change'); + private readonly change$ = Rx.fromEvent<[string]>(this.watchpack, 'change').pipe(share()); public getNextChange$(bundles: Bundle[], startTime: number) { return Rx.merge( From e9b4ad0b9c020c375b0ec56ff4da3399e3e0aa09 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 12 Feb 2020 11:00:27 -0700 Subject: [PATCH 78/83] querystring-browser removed --- src/optimize/base_optimizer.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/optimize/base_optimizer.js b/src/optimize/base_optimizer.js index 4002e4a6db95c..a833204eaa0e2 100644 --- a/src/optimize/base_optimizer.js +++ b/src/optimize/base_optimizer.js @@ -397,7 +397,6 @@ export default class BaseOptimizer { alias: { ...this.uiBundles.getAliases(), tinymath: require.resolve('tinymath/lib/tinymath.es5.js'), - querystring: require.resolve('querystring-browser'), }, }, From bfc269f9006f75b5e66e15bdf07f6cb3a1bfb41d Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 12 Feb 2020 11:14:10 -0700 Subject: [PATCH 79/83] tweak logging a smidge, improve info and final message --- packages/kbn-optimizer/src/log_optimizer_state.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index e4a515b0ad4f2..e77392f5cc28f 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -57,7 +57,13 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { } if (event?.type === 'worker started') { - log.info(`worker started for bundles ${event.bundles.map(b => b.id).join(', ')}`); + let moduleCount = 0; + for (const bundle of event.bundles) { + moduleCount += bundle.getModuleCount() ?? NaN; + } + const mcString = isFinite(moduleCount) ? String(moduleCount) : '?'; + const bcString = String(event.bundles.length); + log.info(`starting worker [${bcString} bundles, ${mcString} modules]`); } if (state.phase === 'reallocating') { @@ -113,7 +119,7 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { log.success( config.watch ? `watching for changes in all bundles after ${state.durSec} sec` - : `all bundles compiled successfully after ${state.durSec} sec` + : `${state.compilerStates.length} bundles compiled successfully after ${state.durSec} sec` ); return true; } From 654ad79a037bd408aeecde50b5f315d854e226dd Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 12 Feb 2020 11:18:19 -0700 Subject: [PATCH 80/83] remove unused imports --- .../src/integration_tests/watch_bundles_for_changes.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts b/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts index dec9b93d51b23..c02a857883a98 100644 --- a/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/watch_bundles_for_changes.test.ts @@ -16,10 +16,8 @@ * specific language governing permissions and limitations * under the License. */ -import Path from 'path'; import * as Rx from 'rxjs'; -import { createAbsolutePathSerializer } from '@kbn/dev-utils'; import { map } from 'rxjs/operators'; import ActualWatchpack from 'watchpack'; From a802d020da11173885e5835c195ed579143cb359 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 12 Feb 2020 16:06:51 -0700 Subject: [PATCH 81/83] remove duplication of getModuleCount() method --- .../kbn-optimizer/src/common/bundle.test.ts | 4 +- packages/kbn-optimizer/src/common/bundle.ts | 4 - .../basic_optimization.test.ts | 4 +- .../kbn-optimizer/src/log_optimizer_state.ts | 2 +- .../assign_bundles_to_workers.test.ts | 160 +++++++++--------- .../optimizer/assign_bundles_to_workers.ts | 8 +- 6 files changed, 93 insertions(+), 89 deletions(-) diff --git a/packages/kbn-optimizer/src/common/bundle.test.ts b/packages/kbn-optimizer/src/common/bundle.test.ts index d7cdee1aa984e..ec78a1bdf020e 100644 --- a/packages/kbn-optimizer/src/common/bundle.test.ts +++ b/packages/kbn-optimizer/src/common/bundle.test.ts @@ -66,9 +66,9 @@ it('provides serializable versions of itself', () => { it('provides the module count from the cache', () => { const bundle = new Bundle(SPEC); - expect(bundle.getModuleCount()).toBe(undefined); + expect(bundle.cache.getModuleCount()).toBe(undefined); bundle.cache.set({ moduleCount: 123 }); - expect(bundle.getModuleCount()).toBe(123); + expect(bundle.cache.getModuleCount()).toBe(123); }); it('parses bundles from JSON specs', () => { diff --git a/packages/kbn-optimizer/src/common/bundle.ts b/packages/kbn-optimizer/src/common/bundle.ts index 90cdec70ff663..f1bc0965a46cc 100644 --- a/packages/kbn-optimizer/src/common/bundle.ts +++ b/packages/kbn-optimizer/src/common/bundle.ts @@ -70,10 +70,6 @@ export class Bundle { this.cache = new BundleCache(Path.resolve(this.outputDir, '.kbn-optimizer-cache')); } - getModuleCount() { - return this.cache.getModuleCount(); - } - /** * Calculate the cache key for this bundle based from current * mtime values. diff --git a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts index cf4473cbff263..dda818875db23 100644 --- a/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts +++ b/packages/kbn-optimizer/src/integration_tests/basic_optimization.test.ts @@ -130,7 +130,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { const foo = config.bundles.find(b => b.id === 'foo')!; expect(foo).toBeTruthy(); foo.cache.refresh(); - expect(foo.getModuleCount()).toBe(3); + expect(foo.cache.getModuleCount()).toBe(3); expect(foo.cache.getReferencedFiles()).toMatchInlineSnapshot(` Array [ /plugins/foo/public/ext.ts, @@ -142,7 +142,7 @@ it('builds expected bundles, saves bundle counts to metadata', async () => { const bar = config.bundles.find(b => b.id === 'bar')!; expect(bar).toBeTruthy(); bar.cache.refresh(); - expect(bar.getModuleCount()).toBe(5); + expect(bar.cache.getModuleCount()).toBe(5); expect(bar.cache.getReferencedFiles()).toMatchInlineSnapshot(` Array [ /plugins/foo/public/ext.ts, diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index e77392f5cc28f..8523905db2966 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -59,7 +59,7 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { if (event?.type === 'worker started') { let moduleCount = 0; for (const bundle of event.bundles) { - moduleCount += bundle.getModuleCount() ?? NaN; + moduleCount += bundle.cache.getModuleCount() ?? NaN; } const mcString = isFinite(moduleCount) ? String(moduleCount) : '?'; const bcString = String(event.bundles.length); diff --git a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts index d18a171c53356..dd4d5c294dfc8 100644 --- a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts +++ b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.test.ts @@ -17,40 +17,14 @@ * under the License. */ +jest.mock('fs'); + import { Bundle } from '../common'; -import { getBundles } from './get_bundles'; import { assignBundlesToWorkers, Assignments } from './assign_bundles_to_workers'; -const REPO = '/repo'; -const BIG_BUNDLES = 'dqv'.split(''); -const ALPHABET = 'abcdefghijklmnopqrstuvwxyz'.split(''); -const pluginsWithCounts = (n: number) => - ALPHABET.slice(0, n).map(id => ({ - directory: `/repo/plugins/${id}`, - id, - isUiPlugin: true, - })); - -const pluginsWithoutCounts = (n: number) => - ' ' - .repeat(n) - .split('') - .map((_, i) => `foo${i + 1}`) - .map(id => ({ - directory: `/repo/plugins/${id}`, - id, - isUiPlugin: true, - })); - -jest.spyOn(Bundle.prototype, 'getModuleCount').mockImplementation(function(this: Bundle) { - return ALPHABET.includes(this.id) - ? (ALPHABET.indexOf(this.id) + 1) * (BIG_BUNDLES.includes(this.id) ? 10 : 1) - : undefined; -}); - -const hasModuleCount = (b: Bundle) => b.getModuleCount() !== undefined; -const noModuleCount = (b: Bundle) => b.getModuleCount() === undefined; +const hasModuleCount = (b: Bundle) => b.cache.getModuleCount() !== undefined; +const noModuleCount = (b: Bundle) => b.cache.getModuleCount() === undefined; const summarizeBundles = (w: Assignments) => [ w.moduleCount ? `${w.moduleCount} known modules` : '', @@ -75,144 +49,178 @@ const assertReturnVal = (workers: Assignments[]) => { expect(worker.bundles.filter(noModuleCount).length).toBe(worker.newBundles); expect( - worker.bundles.filter(hasModuleCount).reduce((sum, b) => sum + b.getModuleCount()!, 0) + worker.bundles.filter(hasModuleCount).reduce((sum, b) => sum + b.cache.getModuleCount()!, 0) ).toBe(worker.moduleCount); } }; +const testBundle = (id: string) => + new Bundle({ + contextDir: `/repo/plugin/${id}/public`, + entry: 'index.ts', + id, + outputDir: `/repo/plugins/${id}/target/public`, + sourceRoot: `/repo`, + type: 'plugin', + }); + +const getBundles = ({ + withCounts = 0, + withoutCounts = 0, +}: { + withCounts?: number; + withoutCounts?: number; +}) => { + const bundles: Bundle[] = []; + + for (let i = 1; i <= withCounts; i++) { + const id = `foo${i}`; + const bundle = testBundle(id); + bundle.cache.set({ moduleCount: i % 5 === 0 ? i * 10 : i }); + bundles.push(bundle); + } + + for (let i = 0; i < withoutCounts; i++) { + const id = `bar${i}`; + bundles.push(testBundle(id)); + } + + return bundles; +}; + it('creates less workers if maxWorkersCount is larger than bundle count', () => { - const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(2), REPO), 10); + const workers = assignBundlesToWorkers(getBundles({ withCounts: 2 }), 10); assertReturnVal(workers); expect(workers.length).toBe(2); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (1 known modules) => a", - "worker 1 (2 known modules) => b", + "worker 0 (1 known modules) => foo1", + "worker 1 (2 known modules) => foo2", ] `); }); it('assigns unknown plugin counts as evenly as possible', () => { - const workers = assignBundlesToWorkers(getBundles(pluginsWithoutCounts(10), REPO), 3); + const workers = assignBundlesToWorkers(getBundles({ withoutCounts: 10 }), 3); assertReturnVal(workers); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (4 new bundles) => foo9,foo6,foo3,foo1", - "worker 1 (3 new bundles) => foo8,foo5,foo2", - "worker 2 (3 new bundles) => foo7,foo4,foo10", + "worker 0 (4 new bundles) => bar9,bar6,bar3,bar0", + "worker 1 (3 new bundles) => bar8,bar5,bar2", + "worker 2 (3 new bundles) => bar7,bar4,bar1", ] `); }); it('distributes bundles without module counts evenly after assigning modules with known counts evenly', () => { - const bundles = getBundles([...pluginsWithCounts(16), ...pluginsWithoutCounts(10)], REPO); + const bundles = getBundles({ withCounts: 16, withoutCounts: 10 }); const workers = assignBundlesToWorkers(bundles, 4); assertReturnVal(workers); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (42 known modules, 3 new bundles) => n,m,h,g,foo9,foo5,foo10", - "worker 1 (43 known modules, 3 new bundles) => o,l,i,f,a,foo8,foo4,foo1", - "worker 2 (43 known modules, 2 new bundles) => d,c,foo7,foo3", - "worker 3 (44 known modules, 2 new bundles) => p,k,j,e,b,foo6,foo2", + "worker 0 (78 known modules, 3 new bundles) => foo5,foo11,foo8,foo6,foo2,foo1,bar9,bar5,bar1", + "worker 1 (78 known modules, 3 new bundles) => foo16,foo14,foo13,foo12,foo9,foo7,foo4,foo3,bar8,bar4,bar0", + "worker 2 (100 known modules, 2 new bundles) => foo10,bar7,bar3", + "worker 3 (150 known modules, 2 new bundles) => foo15,bar6,bar2", ] `); }); it('distributes 2 bundles to workers evenly', () => { - const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(2), REPO), 4); + const workers = assignBundlesToWorkers(getBundles({ withCounts: 2 }), 4); assertReturnVal(workers); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (1 known modules) => a", - "worker 1 (2 known modules) => b", + "worker 0 (1 known modules) => foo1", + "worker 1 (2 known modules) => foo2", ] `); }); it('distributes 5 bundles to workers evenly', () => { - const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(5), REPO), 4); + const workers = assignBundlesToWorkers(getBundles({ withCounts: 5 }), 4); assertReturnVal(workers); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (3 known modules) => b,a", - "worker 1 (3 known modules) => c", - "worker 2 (5 known modules) => e", - "worker 3 (40 known modules) => d", + "worker 0 (3 known modules) => foo2,foo1", + "worker 1 (3 known modules) => foo3", + "worker 2 (4 known modules) => foo4", + "worker 3 (50 known modules) => foo5", ] `); }); it('distributes 10 bundles to workers evenly', () => { - const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(10), REPO), 4); + const workers = assignBundlesToWorkers(getBundles({ withCounts: 10 }), 4); assertReturnVal(workers); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (16 known modules) => h,g,a", - "worker 1 (17 known modules) => i,f,b", - "worker 2 (18 known modules) => j,e,c", - "worker 3 (40 known modules) => d", + "worker 0 (20 known modules) => foo9,foo6,foo4,foo1", + "worker 1 (20 known modules) => foo8,foo7,foo3,foo2", + "worker 2 (50 known modules) => foo5", + "worker 3 (100 known modules) => foo10", ] `); }); it('distributes 15 bundles to workers evenly', () => { - const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(15), REPO), 4); + const workers = assignBundlesToWorkers(getBundles({ withCounts: 15 }), 4); assertReturnVal(workers); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (38 known modules) => m,l,g,f", - "worker 1 (39 known modules) => n,k,h,e,a", - "worker 2 (39 known modules) => o,j,i,c,b", - "worker 3 (40 known modules) => d", + "worker 0 (70 known modules) => foo14,foo13,foo12,foo11,foo9,foo6,foo4,foo1", + "worker 1 (70 known modules) => foo5,foo8,foo7,foo3,foo2", + "worker 2 (100 known modules) => foo10", + "worker 3 (150 known modules) => foo15", ] `); }); it('distributes 20 bundles to workers evenly', () => { - const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(20), REPO), 4); + const workers = assignBundlesToWorkers(getBundles({ withCounts: 20 }), 4); assertReturnVal(workers); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (76 known modules) => d,m,j,h,e", - "worker 1 (76 known modules) => s,r,n,l,g,f", - "worker 2 (77 known modules) => t,p,o,k,i,c,b,a", - "worker 3 (170 known modules) => q", + "worker 0 (153 known modules) => foo15,foo3", + "worker 1 (153 known modules) => foo10,foo16,foo13,foo11,foo7,foo6", + "worker 2 (154 known modules) => foo5,foo19,foo18,foo17,foo14,foo12,foo9,foo8,foo4,foo2,foo1", + "worker 3 (200 known modules) => foo20", ] `); }); it('distributes 25 bundles to workers evenly', () => { - const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(25), REPO), 4); + const workers = assignBundlesToWorkers(getBundles({ withCounts: 25 }), 4); assertReturnVal(workers); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (161 known modules) => d,w,t,r,o,m,k,i,f,e,a", - "worker 1 (161 known modules) => y,x,u,s,p,n,l,j,h,g,c,b", - "worker 2 (170 known modules) => q", - "worker 3 (220 known modules) => v", + "worker 0 (250 known modules) => foo20,foo17,foo13,foo9,foo8,foo2,foo1", + "worker 1 (250 known modules) => foo15,foo23,foo22,foo18,foo16,foo11,foo7,foo3", + "worker 2 (250 known modules) => foo10,foo5,foo24,foo21,foo19,foo14,foo12,foo6,foo4", + "worker 3 (250 known modules) => foo25", ] `); }); it('distributes 30 bundles to workers evenly', () => { - const workers = assignBundlesToWorkers(getBundles(pluginsWithCounts(30), REPO), 4); + const workers = assignBundlesToWorkers(getBundles({ withCounts: 30 }), 4); assertReturnVal(workers); expect(readConfigs(workers)).toMatchInlineSnapshot(` Array [ - "worker 0 (172 known modules) => z,y,w,t,r,o,m,k,i,g,e", - "worker 1 (173 known modules) => q,b,a", - "worker 2 (173 known modules) => d,x,u,s,p,n,l,j,h,f,c", - "worker 3 (220 known modules) => v", + "worker 0 (352 known modules) => foo30,foo22,foo14,foo11,foo4,foo1", + "worker 1 (352 known modules) => foo15,foo10,foo28,foo24,foo19,foo16,foo9,foo6", + "worker 2 (353 known modules) => foo20,foo5,foo29,foo23,foo21,foo13,foo12,foo3,foo2", + "worker 3 (353 known modules) => foo25,foo27,foo26,foo18,foo17,foo8,foo7", ] `); }); diff --git a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts index bf7e4d5b37163..001783b167c7a 100644 --- a/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts +++ b/packages/kbn-optimizer/src/optimizer/assign_bundles_to_workers.ts @@ -30,7 +30,7 @@ export interface Assignments { /** assign a wrapped bundle to a worker */ const assignBundle = (worker: Assignments, bundle: Bundle) => { - const moduleCount = bundle.getModuleCount(); + const moduleCount = bundle.cache.getModuleCount(); if (moduleCount !== undefined) { worker.moduleCount += moduleCount; } else { @@ -70,15 +70,15 @@ export function assignBundlesToWorkers(bundles: Bundle[], maxWorkerCount: number * counts and sort them by [moduleCount, id] */ const bundlesWithCountsDesc = bundles - .filter(b => b.getModuleCount() !== undefined) + .filter(b => b.cache.getModuleCount() !== undefined) .sort( descending( - b => b.getModuleCount(), + b => b.cache.getModuleCount(), b => b.id ) ); const bundlesWithoutModuleCounts = bundles - .filter(b => b.getModuleCount() === undefined) + .filter(b => b.cache.getModuleCount() === undefined) .sort(descending(b => b.id)); /** From 7986dbed2b9abc9f841a19b9a3aedc8777999579 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 12 Feb 2020 16:07:43 -0700 Subject: [PATCH 82/83] move type annotation that validates things --- packages/kbn-optimizer/src/common/event_stream_helpers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kbn-optimizer/src/common/event_stream_helpers.ts b/packages/kbn-optimizer/src/common/event_stream_helpers.ts index 9b720bba81114..c1585f79ede6e 100644 --- a/packages/kbn-optimizer/src/common/event_stream_helpers.ts +++ b/packages/kbn-optimizer/src/common/event_stream_helpers.ts @@ -35,13 +35,13 @@ export const summarizeEvent$ = ( event$: Rx.Observable, initialState: State, reducer: Summarizer -): Rx.Observable> => { +) => { const initUpdate: Update = { state: initialState, }; return event$.pipe( - scan((prev: Update, event) => { + scan((prev, event): Update => { const newState = reducer(prev.state, event); return newState === undefined ? prev From b6390e745359ddd7f0184d6241727369511c30e7 Mon Sep 17 00:00:00 2001 From: spalger Date: Wed, 12 Feb 2020 16:16:36 -0700 Subject: [PATCH 83/83] clear up the build completion message --- packages/kbn-optimizer/src/log_optimizer_state.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/kbn-optimizer/src/log_optimizer_state.ts b/packages/kbn-optimizer/src/log_optimizer_state.ts index 8523905db2966..1ee4e47bfd9ee 100644 --- a/packages/kbn-optimizer/src/log_optimizer_state.ts +++ b/packages/kbn-optimizer/src/log_optimizer_state.ts @@ -29,6 +29,7 @@ import { CompilerMsg, pipeClosure } from './common'; export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { return pipeClosure((update$: OptimizerUpdate$) => { const bundleStates = new Map(); + const bundlesThatWereBuilt = new Set(); let loggedInit = false; return update$.pipe( @@ -90,6 +91,10 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { continue; } + if (type === 'running') { + bundlesThatWereBuilt.add(id); + } + bundleStates.set(id, type); log.debug( `[${id}] state = "${type}"${type !== 'running' ? ` after ${state.durSec} sec` : ''}` @@ -116,10 +121,11 @@ export function logOptimizerState(log: ToolingLog, config: OptimizerConfig) { } if (state.phase === 'success') { + const buildCount = bundlesThatWereBuilt.size; + bundlesThatWereBuilt.clear(); log.success( - config.watch - ? `watching for changes in all bundles after ${state.durSec} sec` - : `${state.compilerStates.length} bundles compiled successfully after ${state.durSec} sec` + `${buildCount} bundles compiled successfully after ${state.durSec} sec` + + (config.watch ? ', watching for changes' : '') ); return true; }