From 01a9b36a1e682a3db7d868b6750ddd78ed8b0e61 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sun, 13 May 2018 22:35:05 +0200 Subject: [PATCH 01/54] feat(Logging api): add logging api --- packages/stryker-api/logging.ts | 4 +++ packages/stryker-api/package-lock.json | 7 +++-- packages/stryker-api/src/logging/Logger.ts | 15 ++++++++++ .../stryker-api/src/logging/LoggerFactory.ts | 30 +++++++++++++++++++ .../src/logging/LoggerFactoryMethod.ts | 12 ++++++++ packages/stryker-api/src/logging/getLogger.ts | 6 ++++ 6 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 packages/stryker-api/logging.ts create mode 100644 packages/stryker-api/src/logging/Logger.ts create mode 100644 packages/stryker-api/src/logging/LoggerFactory.ts create mode 100644 packages/stryker-api/src/logging/LoggerFactoryMethod.ts create mode 100644 packages/stryker-api/src/logging/getLogger.ts diff --git a/packages/stryker-api/logging.ts b/packages/stryker-api/logging.ts new file mode 100644 index 0000000000..f7ea628c1b --- /dev/null +++ b/packages/stryker-api/logging.ts @@ -0,0 +1,4 @@ +export { default as LoggerFactory } from './src/logging/LoggerFactory'; +export { default as Logger } from './src/logging/Logger'; +export { default as LoggerFactoryMethod } from './src/logging/LoggerFactoryMethod'; +export { default as getLogger } from './src/logging/getLogger'; \ No newline at end of file diff --git a/packages/stryker-api/package-lock.json b/packages/stryker-api/package-lock.json index 984b3a5b7b..66a0bd3f0b 100644 --- a/packages/stryker-api/package-lock.json +++ b/packages/stryker-api/package-lock.json @@ -1,11 +1,14 @@ { - "requires": true, + "name": "stryker-api", + "version": "0.17.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "surrial": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/surrial/-/surrial-0.1.3.tgz", - "integrity": "sha512-Iqfqc9luWn/4r9gHxe3XifYQaVne09TP2hMFQwXSRw4WpfMjNZkZQQjFSzatvrw+MgynEuOZlsB24m0zHNVEBA==" + "integrity": "sha512-Iqfqc9luWn/4r9gHxe3XifYQaVne09TP2hMFQwXSRw4WpfMjNZkZQQjFSzatvrw+MgynEuOZlsB24m0zHNVEBA==", + "dev": true }, "tslib": { "version": "1.9.0", diff --git a/packages/stryker-api/src/logging/Logger.ts b/packages/stryker-api/src/logging/Logger.ts new file mode 100644 index 0000000000..029def6ebc --- /dev/null +++ b/packages/stryker-api/src/logging/Logger.ts @@ -0,0 +1,15 @@ +export default interface Logger { + isTraceEnabled(): boolean; + isDebugEnabled(): boolean; + isInfoEnabled(): boolean; + isWarnEnabled(): boolean; + isErrorEnabled(): boolean; + isFatalEnabled(): boolean; + + trace(message: string, ...args: any[]): void; + debug(message: string, ...args: any[]): void; + info(message: string, ...args: any[]): void; + warn(message: string, ...args: any[]): void; + error(message: string, ...args: any[]): void; + fatal(message: string, ...args: any[]): void; +} \ No newline at end of file diff --git a/packages/stryker-api/src/logging/LoggerFactory.ts b/packages/stryker-api/src/logging/LoggerFactory.ts new file mode 100644 index 0000000000..80178f882b --- /dev/null +++ b/packages/stryker-api/src/logging/LoggerFactory.ts @@ -0,0 +1,30 @@ +import LoggerFactoryMethod from './LoggerFactoryMethod'; +import Logger from './Logger'; + +const noopLogger: Logger = { + isTraceEnabled(): boolean { return false; }, + isDebugEnabled(): boolean { return false; }, + isInfoEnabled(): boolean { return false; }, + isWarnEnabled(): boolean { return false; }, + isErrorEnabled(): boolean { return false; }, + isFatalEnabled(): boolean { return false; }, + trace(): void { }, + debug(): void { }, + info(): void { }, + warn(): void { }, + error(): void { }, + fatal(): void { } +}; + +let implementation: LoggerFactoryMethod = () => noopLogger; + +export default class LoggerFactory { + + static setLogImplementation(implementation: LoggerFactoryMethod) { + this.getLogger = implementation; + } + + static getLogger: LoggerFactoryMethod = (categoryName?: string) => { + return implementation(categoryName); + } +} \ No newline at end of file diff --git a/packages/stryker-api/src/logging/LoggerFactoryMethod.ts b/packages/stryker-api/src/logging/LoggerFactoryMethod.ts new file mode 100644 index 0000000000..5bb9a43651 --- /dev/null +++ b/packages/stryker-api/src/logging/LoggerFactoryMethod.ts @@ -0,0 +1,12 @@ +import Logger from './Logger'; + +/** + * Get a logger instance. Instance is cached on categoryName level. + * + * @param {String} [categoryName] name of category to log to. + * @returns {Logger} instance of logger for the category + * @static + */ +export default interface LoggerFactoryMethod { + (categoryName?: string): Logger; +} \ No newline at end of file diff --git a/packages/stryker-api/src/logging/getLogger.ts b/packages/stryker-api/src/logging/getLogger.ts new file mode 100644 index 0000000000..fbd602e2aa --- /dev/null +++ b/packages/stryker-api/src/logging/getLogger.ts @@ -0,0 +1,6 @@ +import LoggerFactory from './LoggerFactory'; +import LoggerFactoryMethod from './LoggerFactoryMethod'; + +const getLogger: LoggerFactoryMethod = LoggerFactory.getLogger; + +export default getLogger; \ No newline at end of file From 187855ed8b0ca29bb922636bfc91cbf472ff96ba Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 15 May 2018 13:51:17 +0200 Subject: [PATCH 02/54] feat(logging-api): first usage of logging api --- package-lock.json | 65 - package.json | 1 - .../stryker-api/src/logging/LoggerFactory.ts | 6 +- .../package-lock.json | 332 +++- .../stryker-babel-transpiler/package.json | 3 +- .../src/BabelConfigReader.ts | 3 +- .../src/BabelTranspiler.ts | 2 - .../test/unit/BabelConfigReaderSpec.ts | 2 +- .../stryker-html-reporter/package-lock.json | 298 ++-- packages/stryker-html-reporter/package.json | 1 - .../stryker-html-reporter/src/HtmlReporter.ts | 5 +- .../test/helpers/log4jsMock.ts | 2 +- .../stryker-jasmine-runner/package-lock.json | 14 +- packages/stryker-jasmine-runner/package.json | 5 +- packages/stryker-jasmine/package-lock.json | 26 + packages/stryker-jasmine/package.json | 3 +- .../package-lock.json | 93 +- .../stryker-javascript-mutator/package.json | 1 - .../src/JavaScriptMutator.ts | 3 +- .../test/helpers/LogMock.ts | 2 +- .../test/helpers/initSinon.ts | 2 +- .../stryker-karma-runner/package-lock.json | 898 +++++++--- packages/stryker-karma-runner/package.json | 2 +- .../src/KarmaConfigReader.ts | 10 +- .../src/KarmaTestRunner.ts | 6 +- .../test/unit/KarmaConfigReaderSpec.ts | 2 +- .../stryker-mocha-framework/package-lock.json | 105 +- packages/stryker-mocha-framework/package.json | 4 +- .../stryker-mocha-runner/package-lock.json | 57 +- packages/stryker-mocha-runner/package.json | 1 - .../src/MochaConfigEditor.ts | 2 - .../src/MochaOptionsLoader.ts | 2 +- .../src/MochaTestRunner.ts | 3 +- .../src/StrykerMochaReporter.ts | 2 +- .../test/helpers/mockHelpers.ts | 4 +- .../test/unit/MochaOptionsLoaderSpec.ts | 2 +- .../test/unit/MochaTestRunnerSpec.ts | 2 +- .../package-lock.json | 5 + .../package.json | 3 +- packages/stryker-typescript/package-lock.json | 111 +- packages/stryker-typescript/package.json | 1 - .../src/TypescriptConfigEditor.ts | 3 +- .../src/TypescriptTranspiler.ts | 2 - .../transpiler/TranspilingLanguageService.ts | 2 +- .../test/helpers/producers.ts | 4 +- .../test/integration/allowJS.it.ts | 6 - .../test/integration/ownDogFoodSpec.ts | 6 - .../test/integration/sampleSpec.ts | 6 - .../test/integration/useHeaderFile.ts | 6 - .../test/unit/TypescriptConfigEditorSpec.ts | 2 +- .../test/unit/TypescriptTranspilerSpec.ts | 8 - .../package-lock.json | 697 ++++++-- .../stryker-webpack-transpiler/package.json | 1 - .../src/WebpackTranspiler.ts | 2 - .../src/compiler/ConfigLoader.ts | 2 +- .../test/helpers/sinonInit.ts | 2 +- .../test/unit/WebpackTranspilerSpec.ts | 8 - packages/stryker/package-lock.json | 1538 ++++++++++++++++- packages/stryker/package.json | 2 +- packages/stryker/src/ConfigReader.ts | 6 +- packages/stryker/src/ConfigValidator.ts | 5 +- packages/stryker/src/MutantTestMatcher.ts | 2 +- packages/stryker/src/PluginLoader.ts | 2 +- packages/stryker/src/ReporterOrchestrator.ts | 2 +- packages/stryker/src/Sandbox.ts | 2 +- packages/stryker/src/SandboxPool.ts | 2 +- packages/stryker/src/ScoreResultCalculator.ts | 2 +- packages/stryker/src/Stryker.ts | 15 +- packages/stryker/src/StrykerCli.ts | 19 +- .../stryker/src/TestFrameworkOrchestrator.ts | 2 +- .../src/child-proxy/ChildProcessProxy.ts | 14 +- .../child-proxy/ChildProcessProxyWorker.ts | 16 +- .../src/child-proxy/messageProtocol.ts | 12 +- packages/stryker/src/initializer/NpmClient.ts | 2 +- .../src/initializer/StrykerConfigWriter.ts | 2 +- .../src/initializer/StrykerInitializer.ts | 2 +- .../stryker/src/input/InputFileCollection.ts | 2 +- .../stryker/src/input/InputFileResolver.ts | 2 +- .../IsolatedTestRunnerAdapter.ts | 2 +- .../IsolatedTestRunnerAdapterWorker.ts | 8 +- .../src/isolated-runner/TimeoutDecorator.ts | 2 +- packages/stryker/src/mutators/ES5Mutator.ts | 2 +- .../src/process/InitialTestExecutor.ts | 2 +- .../src/reporters/BroadcastReporter.ts | 2 +- .../src/reporters/ClearTextReporter.ts | 2 +- .../src/reporters/DashboardReporter.ts | 2 +- .../src/reporters/EventRecorderReporter.ts | 2 +- .../DashboardReporterClient.ts | 2 +- .../stryker/src/transpiler/SourceMapper.ts | 2 +- packages/stryker/src/utils/LogConfigurator.ts | 57 + .../stryker/src/utils/StrykerTempFolder.ts | 2 +- packages/stryker/src/utils/TempFolder.ts | 2 +- .../helpers/{log4jsMock.ts => logMock.ts} | 6 +- packages/stryker/test/helpers/producers.ts | 4 +- .../config-reader/ConfigReaderSpec.ts | 4 +- .../ResilientTestRunnerFactorySpec.ts | 4 +- .../stryker/test/unit/ConfigValidatorSpec.ts | 67 +- .../test/unit/MutantTestMatcherSpec.ts | 4 +- .../stryker/test/unit/PluginLoaderSpec.ts | 4 +- packages/stryker/test/unit/SandboxSpec.ts | 4 +- .../test/unit/ScoreResultCalculatorSpec.ts | 4 +- packages/stryker/test/unit/StrykerSpec.ts | 9 +- .../unit/TestFrameworkOrchestratorSpec.ts | 4 +- .../child-proxy/ChildProcessWorkerSpec.ts | 8 +- .../initializer/StrykerInitializerSpec.ts | 4 +- .../test/unit/input/InputFileResolverSpec.ts | 8 +- .../unit/process/InitialTestExecutorSpec.ts | 4 +- .../unit/reporters/BroadcastReporterSpec.ts | 4 +- .../unit/reporters/DashboardReporterSpec.ts | 4 +- .../reporters/EventRecorderReporterSpec.ts | 2 +- .../DashboardReporterClientSpec.ts | 4 +- 111 files changed, 3511 insertions(+), 1229 deletions(-) create mode 100644 packages/stryker-jasmine/package-lock.json create mode 100644 packages/stryker-mutator-specification/package-lock.json create mode 100644 packages/stryker/src/utils/LogConfigurator.ts rename packages/stryker/test/helpers/{log4jsMock.ts => logMock.ts} (52%) diff --git a/package-lock.json b/package-lock.json index 29de79430c..c98d9ff098 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,16 +73,6 @@ "integrity": "sha512-Wk41MVdF+cHBfVXj/ufUHJeO3BlIQr1McbHZANErMykaCWeDSZbH5erGjNBw2/3UlRdSxZbLfSuQTzFmPOYFsA==", "dev": true }, - "@types/body-parser": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz", - "integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==", - "dev": true, - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, "@types/chai": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.1.3.tgz", @@ -98,15 +88,6 @@ "@types/chai": "*" } }, - "@types/connect": { - "version": "3.4.32", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", - "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, "@types/escodegen": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/@types/escodegen/-/escodegen-0.0.6.tgz", @@ -143,27 +124,6 @@ "@types/node": "*" } }, - "@types/express": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.11.1.tgz", - "integrity": "sha512-ttWle8cnPA5rAelauSWeWJimtY2RsUf2aspYZs7xPHiWgOlPn6nnUfBMtrkcnjFJuIHJF4gNOdVvpLK2Zmvh6g==", - "dev": true, - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.11.1.tgz", - "integrity": "sha512-EehCl3tpuqiM8RUb+0255M8PhhSwTtLfmO7zBBdv0ay/VTd/zmrqDfQdZFsa5z/PVMbH2yCMZPXsnrImpATyIw==", - "dev": true, - "requires": { - "@types/events": "*", - "@types/node": "*" - } - }, "@types/glob": { "version": "5.0.35", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz", @@ -197,21 +157,6 @@ "integrity": "sha512-WD2vUOKfBBVHxWUV9iMR9RMfpuf8HquxWeAq2yqGVL7Nc4JW2+sQama0pREMqzNI3Tutj0PyxYUJwuoxxvX+xA==", "dev": true }, - "@types/log4js": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/log4js/-/log4js-0.0.32.tgz", - "integrity": "sha1-wVYhz6lvkuxrDPtJCWvdI82JPHw=", - "dev": true, - "requires": { - "@types/express": "*" - } - }, - "@types/mime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", - "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==", - "dev": true - }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -270,16 +215,6 @@ "integrity": "sha512-UBYHWph6P3tutkbXpW6XYg9ZPbTKjw/YC2hGG1/GEvWwTbvezBUv3h+mmUFw79T3RFPnmedpiXdOBbXX+4l0jg==", "dev": true }, - "@types/serve-static": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz", - "integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==", - "dev": true, - "requires": { - "@types/express-serve-static-core": "*", - "@types/mime": "*" - } - }, "@types/sinon": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-4.3.3.tgz", diff --git a/package.json b/package.json index 239b5498f3..d0ad9fe080 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "@types/istanbul": "^0.4.29", "@types/karma": "^1.7.2", "@types/lodash": "^4.14.108", - "@types/log4js": "0.0.32", "@types/mkdirp": "^0.5.2", "@types/mocha": "^2.2.44", "@types/mz": "0.0.32", diff --git a/packages/stryker-api/src/logging/LoggerFactory.ts b/packages/stryker-api/src/logging/LoggerFactory.ts index 80178f882b..0f3fc55966 100644 --- a/packages/stryker-api/src/logging/LoggerFactory.ts +++ b/packages/stryker-api/src/logging/LoggerFactory.ts @@ -16,15 +16,15 @@ const noopLogger: Logger = { fatal(): void { } }; -let implementation: LoggerFactoryMethod = () => noopLogger; +let logImplementation: LoggerFactoryMethod = () => noopLogger; export default class LoggerFactory { static setLogImplementation(implementation: LoggerFactoryMethod) { - this.getLogger = implementation; + logImplementation = implementation; } static getLogger: LoggerFactoryMethod = (categoryName?: string) => { - return implementation(categoryName); + return logImplementation(categoryName); } } \ No newline at end of file diff --git a/packages/stryker-babel-transpiler/package-lock.json b/packages/stryker-babel-transpiler/package-lock.json index 2f140ea1fd..49c444a8f3 100644 --- a/packages/stryker-babel-transpiler/package-lock.json +++ b/packages/stryker-babel-transpiler/package-lock.json @@ -1,11 +1,14 @@ { - "requires": true, + "name": "stryker-babel-transpiler", + "version": "0.5.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@types/babel-core": { "version": "6.25.3", "resolved": "https://registry.npmjs.org/@types/babel-core/-/babel-core-6.25.3.tgz", "integrity": "sha512-OlUjfM+Qv+XwcaucEiekBIhfAYe4q4ruvQZZcCkOtQZ27Hykxm1LLY2s0mE6LtP9XQt6x+TUvS70KW2e8Mz0ZA==", + "dev": true, "requires": { "@types/babel-generator": "*", "@types/babel-template": "*", @@ -18,6 +21,7 @@ "version": "6.25.1", "resolved": "https://registry.npmjs.org/@types/babel-generator/-/babel-generator-6.25.1.tgz", "integrity": "sha512-nKNz9Ch4WP2TFZjQROhxqqS2SCk0OoDzGazJI6S+2sGgW9P7N4o3vluZAXFuPEnRqtz2A0vrrkK3tjQktxIlRw==", + "dev": true, "requires": { "@types/babel-types": "*" } @@ -26,6 +30,7 @@ "version": "6.25.0", "resolved": "https://registry.npmjs.org/@types/babel-template/-/babel-template-6.25.0.tgz", "integrity": "sha512-TtyfVlrprX92xSuKa8D//7vFz5kBJODBw5IQ1hQXehqO+me26vt1fyNxOZyXhUq2a7jRyT72V8p68IyH4NEZNA==", + "dev": true, "requires": { "@types/babel-types": "*", "@types/babylon": "*" @@ -35,6 +40,7 @@ "version": "6.25.3", "resolved": "https://registry.npmjs.org/@types/babel-traverse/-/babel-traverse-6.25.3.tgz", "integrity": "sha512-4FaulWyA7nrXPkzoukL2VmSpxCnBZwc+MgwZqO30gtHCrtaUXnoxymdYfxzf3CZN80zjtrVzKfLlZ7FPYvrhQQ==", + "dev": true, "requires": { "@types/babel-types": "*" } @@ -42,12 +48,14 @@ "@types/babel-types": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.2.tgz", - "integrity": "sha512-ylggu8DwwxT6mk3jVoJeohWAePWMNWEYm06MSoJ19kwp3hT9eY2Z4NNZn3oevzgFmClgNQ2GQF500hPDvNsGHg==" + "integrity": "sha512-ylggu8DwwxT6mk3jVoJeohWAePWMNWEYm06MSoJ19kwp3hT9eY2Z4NNZn3oevzgFmClgNQ2GQF500hPDvNsGHg==", + "dev": true }, "@types/babylon": { "version": "6.16.2", "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.2.tgz", "integrity": "sha512-+Jty46mPaWe1VAyZbfvgJM4BAdklLWxrT5tc/RjvCgLrtk6gzRY6AOnoWFv4p6hVxhJshDdr2hGVn56alBp97Q==", + "dev": true, "requires": { "@types/babel-types": "*" } @@ -55,12 +63,14 @@ "@types/events": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", - "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==" + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", + "dev": true }, "@types/glob": { "version": "5.0.35", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.35.tgz", "integrity": "sha512-wc+VveszMLyMWFvXLkloixT4n0harUIVZjnpzztaZ0nKLuul7Z32iMt2fUFGAaZ4y1XWjFRMtCI5ewvyh4aIeg==", + "dev": true, "requires": { "@types/events": "*", "@types/minimatch": "*", @@ -70,12 +80,14 @@ "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true }, "@types/node": { "version": "10.0.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.0.8.tgz", - "integrity": "sha512-MFFKFv2X4iZy/NFl1m1E8uwE1CR96SGwJjgHma09PLtqOWoj3nqeJHMG+P/EuJGVLvC2I6MdQRQsr4TcRduIow==" + "integrity": "sha512-MFFKFv2X4iZy/NFl1m1E8uwE1CR96SGwJjgHma09PLtqOWoj3nqeJHMG+P/EuJGVLvC2I6MdQRQsr4TcRduIow==", + "dev": true }, "ansi-regex": { "version": "2.1.1", @@ -91,6 +103,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, "optional": true, "requires": { "micromatch": "^2.1.5", @@ -101,6 +114,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, "optional": true, "requires": { "arr-flatten": "^1.0.1" @@ -110,24 +124,28 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, "optional": true }, "array-unique": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true, "optional": true }, "async-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true, "optional": true }, "babel-cli": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-cli/-/babel-cli-6.26.0.tgz", "integrity": "sha1-UCq1SHTX24itALiHoGODzgPQAvE=", + "dev": true, "requires": { "babel-core": "^6.26.0", "babel-polyfill": "^6.26.0", @@ -201,6 +219,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, "requires": { "babel-helper-hoist-variables": "^6.24.1", "babel-runtime": "^6.22.0", @@ -212,6 +231,7 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, "requires": { "babel-helper-function-name": "^6.24.1", "babel-runtime": "^6.26.0", @@ -223,6 +243,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, "requires": { "babel-helper-get-function-arity": "^6.24.1", "babel-runtime": "^6.22.0", @@ -235,6 +256,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, "requires": { "babel-runtime": "^6.22.0", "babel-types": "^6.24.1" @@ -244,6 +266,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, "requires": { "babel-runtime": "^6.22.0", "babel-types": "^6.24.1" @@ -253,6 +276,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, "requires": { "babel-runtime": "^6.22.0", "babel-types": "^6.24.1" @@ -262,6 +286,7 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, "requires": { "babel-runtime": "^6.26.0", "babel-types": "^6.26.0", @@ -272,6 +297,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, "requires": { "babel-helper-optimise-call-expression": "^6.24.1", "babel-messages": "^6.23.0", @@ -302,6 +328,7 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -310,6 +337,7 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -318,6 +346,7 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -326,6 +355,7 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, "requires": { "babel-runtime": "^6.26.0", "babel-template": "^6.26.0", @@ -338,6 +368,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, "requires": { "babel-helper-define-map": "^6.24.1", "babel-helper-function-name": "^6.24.1", @@ -354,6 +385,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, "requires": { "babel-runtime": "^6.22.0", "babel-template": "^6.24.1" @@ -363,6 +395,7 @@ "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -371,6 +404,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, "requires": { "babel-runtime": "^6.22.0", "babel-types": "^6.24.1" @@ -380,6 +414,7 @@ "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -388,6 +423,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, "requires": { "babel-helper-function-name": "^6.24.1", "babel-runtime": "^6.22.0", @@ -398,6 +434,7 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -406,6 +443,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, "requires": { "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1", "babel-runtime": "^6.22.0", @@ -416,6 +454,7 @@ "version": "6.26.2", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz", "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==", + "dev": true, "requires": { "babel-plugin-transform-strict-mode": "^6.24.1", "babel-runtime": "^6.26.0", @@ -427,6 +466,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, "requires": { "babel-helper-hoist-variables": "^6.24.1", "babel-runtime": "^6.22.0", @@ -437,6 +477,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, "requires": { "babel-plugin-transform-es2015-modules-amd": "^6.24.1", "babel-runtime": "^6.22.0", @@ -447,6 +488,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, "requires": { "babel-helper-replace-supers": "^6.24.1", "babel-runtime": "^6.22.0" @@ -456,6 +498,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, "requires": { "babel-helper-call-delegate": "^6.24.1", "babel-helper-get-function-arity": "^6.24.1", @@ -469,6 +512,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, "requires": { "babel-runtime": "^6.22.0", "babel-types": "^6.24.1" @@ -478,6 +522,7 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -486,6 +531,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, "requires": { "babel-helper-regex": "^6.24.1", "babel-runtime": "^6.22.0", @@ -496,6 +542,7 @@ "version": "6.22.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -504,6 +551,7 @@ "version": "6.23.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, "requires": { "babel-runtime": "^6.22.0" } @@ -512,6 +560,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, "requires": { "babel-helper-regex": "^6.24.1", "babel-runtime": "^6.22.0", @@ -522,6 +571,7 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, "requires": { "regenerator-transform": "^0.10.0" } @@ -530,6 +580,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, "requires": { "babel-runtime": "^6.22.0", "babel-types": "^6.24.1" @@ -539,6 +590,7 @@ "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", + "dev": true, "requires": { "babel-runtime": "^6.26.0", "core-js": "^2.5.0", @@ -548,7 +600,8 @@ "regenerator-runtime": { "version": "0.10.5", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", - "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true } } }, @@ -556,6 +609,7 @@ "version": "6.24.1", "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "dev": true, "requires": { "babel-plugin-check-es2015-constants": "^6.22.0", "babel-plugin-transform-es2015-arrow-functions": "^6.22.0", @@ -659,6 +713,7 @@ "version": "1.11.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "dev": true, "optional": true }, "brace-expansion": { @@ -674,6 +729,7 @@ "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, "optional": true, "requires": { "expand-range": "^1.8.1", @@ -697,6 +753,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, "optional": true, "requires": { "anymatch": "^1.3.0", @@ -713,7 +770,8 @@ "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", - "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" + "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true }, "concat-map": { "version": "0.0.1", @@ -733,12 +791,9 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "date-format": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", - "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true, + "optional": true }, "debug": { "version": "2.6.9", @@ -770,6 +825,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, "optional": true, "requires": { "is-posix-bracket": "^0.1.0" @@ -779,6 +835,7 @@ "version": "1.8.2", "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, "optional": true, "requires": { "fill-range": "^2.1.0" @@ -788,6 +845,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, "optional": true, "requires": { "is-extglob": "^1.0.0" @@ -797,12 +855,14 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true, "optional": true }, "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, "optional": true, "requires": { "is-number": "^2.1.0", @@ -816,12 +876,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, "optional": true }, "for-own": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, "optional": true, "requires": { "for-in": "^1.0.1" @@ -830,17 +892,20 @@ "fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", - "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==" + "integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==", + "dev": true }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.3.tgz", "integrity": "sha512-X+57O5YkDTiEQGiw8i7wYc2nQgweIekqkepI8Q3y4wVlurgBt2SuwxTeYUYMZIGpLZH3r/TsMjczCMXE5ZOt7Q==", + "dev": true, "optional": true, "requires": { "nan": "^2.9.2", @@ -850,20 +915,24 @@ "abbrev": { "version": "1.1.1", "bundled": true, + "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "dev": true }, "aproba": { "version": "1.2.0", "bundled": true, + "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", "bundled": true, + "dev": true, "optional": true, "requires": { "delegates": "^1.0.0", @@ -872,11 +941,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -885,28 +956,34 @@ "chownr": { "version": "1.0.1", "bundled": true, + "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "dev": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "core-util-is": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "debug": { "version": "2.6.9", "bundled": true, + "dev": true, "optional": true, "requires": { "ms": "2.0.0" @@ -915,21 +992,25 @@ "deep-extend": { "version": "0.4.2", "bundled": true, + "dev": true, "optional": true }, "delegates": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", "bundled": true, + "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", "bundled": true, + "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -938,11 +1019,13 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "gauge": { "version": "2.7.4", "bundled": true, + "dev": true, "optional": true, "requires": { "aproba": "^1.0.3", @@ -958,6 +1041,7 @@ "glob": { "version": "7.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -971,11 +1055,13 @@ "has-unicode": { "version": "2.0.1", "bundled": true, + "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", "bundled": true, + "dev": true, "optional": true, "requires": { "safer-buffer": "^2.1.0" @@ -984,6 +1070,7 @@ "ignore-walk": { "version": "3.0.1", "bundled": true, + "dev": true, "optional": true, "requires": { "minimatch": "^3.0.4" @@ -992,6 +1079,7 @@ "inflight": { "version": "1.0.6", "bundled": true, + "dev": true, "optional": true, "requires": { "once": "^1.3.0", @@ -1000,16 +1088,19 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "dev": true }, "ini": { "version": "1.3.5", "bundled": true, + "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1017,22 +1108,26 @@ "isarray": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", "bundled": true, + "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, + "dev": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -1041,6 +1136,7 @@ "minizlib": { "version": "1.1.0", "bundled": true, + "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -1049,6 +1145,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "dev": true, "requires": { "minimist": "0.0.8" } @@ -1056,11 +1153,13 @@ "ms": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "needle": { "version": "2.2.0", "bundled": true, + "dev": true, "optional": true, "requires": { "debug": "^2.1.2", @@ -1071,6 +1170,7 @@ "node-pre-gyp": { "version": "0.9.1", "bundled": true, + "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -1088,6 +1188,7 @@ "nopt": { "version": "4.0.1", "bundled": true, + "dev": true, "optional": true, "requires": { "abbrev": "1", @@ -1097,11 +1198,13 @@ "npm-bundled": { "version": "1.0.3", "bundled": true, + "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", "bundled": true, + "dev": true, "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -1111,6 +1214,7 @@ "npmlog": { "version": "4.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -1121,16 +1225,19 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "object-assign": { "version": "4.1.1", "bundled": true, + "dev": true, "optional": true }, "once": { "version": "1.4.0", "bundled": true, + "dev": true, "requires": { "wrappy": "1" } @@ -1138,16 +1245,19 @@ "os-homedir": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "osenv": { "version": "0.1.5", "bundled": true, + "dev": true, "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -1157,16 +1267,19 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, + "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "rc": { "version": "1.2.6", "bundled": true, + "dev": true, "optional": true, "requires": { "deep-extend": "~0.4.0", @@ -1178,6 +1291,7 @@ "minimist": { "version": "1.2.0", "bundled": true, + "dev": true, "optional": true } } @@ -1185,6 +1299,7 @@ "readable-stream": { "version": "2.3.6", "bundled": true, + "dev": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -1199,6 +1314,7 @@ "rimraf": { "version": "2.6.2", "bundled": true, + "dev": true, "optional": true, "requires": { "glob": "^7.0.5" @@ -1206,36 +1322,43 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true + "bundled": true, + "dev": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, + "dev": true, "optional": true }, "sax": { "version": "1.2.4", "bundled": true, + "dev": true, "optional": true }, "semver": { "version": "5.5.0", "bundled": true, + "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", "bundled": true, + "dev": true, "optional": true }, "string-width": { "version": "1.0.2", "bundled": true, + "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1245,6 +1368,7 @@ "string_decoder": { "version": "1.1.1", "bundled": true, + "dev": true, "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -1253,6 +1377,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1260,11 +1385,13 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, + "dev": true, "optional": true }, "tar": { "version": "4.4.1", "bundled": true, + "dev": true, "optional": true, "requires": { "chownr": "^1.0.1", @@ -1279,11 +1406,13 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "string-width": "^1.0.2" @@ -1291,11 +1420,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "dev": true }, "yallist": { "version": "3.0.2", - "bundled": true + "bundled": true, + "dev": true } } }, @@ -1303,6 +1434,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1316,6 +1448,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, "optional": true, "requires": { "glob-parent": "^2.0.0", @@ -1326,6 +1459,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, "requires": { "is-glob": "^2.0.0" } @@ -1338,7 +1472,8 @@ "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true }, "has-ansi": { "version": "2.0.0", @@ -1361,6 +1496,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1369,7 +1505,8 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "invariant": { "version": "2.2.4", @@ -1383,6 +1520,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, "optional": true, "requires": { "binary-extensions": "^1.0.0" @@ -1391,18 +1529,21 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true, "optional": true }, "is-equal-shallow": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, "optional": true, "requires": { "is-primitive": "^2.0.0" @@ -1412,12 +1553,14 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, "optional": true }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true }, "is-finite": { "version": "1.0.2", @@ -1431,6 +1574,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, "requires": { "is-extglob": "^1.0.0" } @@ -1439,6 +1583,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, "optional": true, "requires": { "kind-of": "^3.0.2" @@ -1448,23 +1593,27 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true, "optional": true }, "is-primitive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true, "optional": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, "optional": true, "requires": { "isarray": "1.0.0" @@ -1489,6 +1638,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -1498,16 +1648,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, - "log4js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-1.1.1.tgz", - "integrity": "sha1-wh0px2BAieTyVYM+f5SzRh3h/0M=", - "requires": { - "debug": "^2.2.0", - "semver": "^5.3.0", - "streamroller": "^0.4.0" - } - }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", @@ -1520,12 +1660,14 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "dev": true, "optional": true }, "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, "optional": true, "requires": { "arr-diff": "^2.0.0", @@ -1573,12 +1715,14 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "dev": true, "optional": true }, "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -1591,12 +1735,14 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true }, "object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, "optional": true, "requires": { "for-own": "^0.1.4", @@ -1607,6 +1753,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -1625,6 +1772,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-1.1.2.tgz", "integrity": "sha1-0KM+7+YaIF+suQCS6CZZjVJFznY=", + "dev": true, "requires": { "graceful-fs": "^4.1.4", "mkdirp": "^0.5.1", @@ -1635,6 +1783,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, "optional": true, "requires": { "glob-base": "^0.3.0", @@ -1652,6 +1801,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true, "optional": true }, "private": { @@ -1663,12 +1813,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true, "optional": true }, "randomatic": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", + "dev": true, "optional": true, "requires": { "is-number": "^4.0.0", @@ -1680,12 +1832,14 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, "optional": true }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true, "optional": true } } @@ -1694,6 +1848,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -1709,6 +1864,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, "optional": true, "requires": { "graceful-fs": "^4.1.2", @@ -1720,7 +1876,8 @@ "regenerate": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", - "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==" + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", + "dev": true }, "regenerator-runtime": { "version": "0.11.1", @@ -1731,6 +1888,7 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, "requires": { "babel-runtime": "^6.18.0", "babel-types": "^6.19.0", @@ -1741,6 +1899,7 @@ "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, "optional": true, "requires": { "is-equal-shallow": "^0.1.3" @@ -1750,6 +1909,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, "requires": { "regenerate": "^1.2.1", "regjsgen": "^0.2.0", @@ -1759,12 +1919,14 @@ "regjsgen": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true }, "regjsparser": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, "requires": { "jsesc": "~0.5.0" }, @@ -1772,24 +1934,28 @@ "jsesc": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true } } }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true }, "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, "optional": true }, "repeating": { @@ -1803,17 +1969,14 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "set-immediate-shim": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true, "optional": true }, "slash": { @@ -1834,49 +1997,11 @@ "source-map": "^0.5.6" } }, - "streamroller": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.4.1.tgz", - "integrity": "sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8=", - "requires": { - "date-format": "^0.0.0", - "debug": "^0.7.2", - "mkdirp": "^0.5.1", - "readable-stream": "^1.1.7" - }, - "dependencies": { - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -1890,6 +2015,15 @@ "ansi-regex": "^2.0.0" } }, + "stryker-api": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.17.0.tgz", + "integrity": "sha512-CJKAx+D8ztmXtnORk0bKfrccIbeAOXcKZ2pQpevvj7SFZJKlF8PRQy8lkgP5kvTK/sKidQp84kHjiqyRvf634A==", + "dev": true, + "requires": { + "tslib": "^1.6.0" + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", @@ -1905,21 +2039,30 @@ "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" }, + "tslib": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "dev": true + }, "user-home": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=" + "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", + "dev": true }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true, "optional": true }, "v8flags": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "dev": true, "requires": { "user-home": "^1.1.1" } @@ -1927,7 +2070,8 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true } } } diff --git a/packages/stryker-babel-transpiler/package.json b/packages/stryker-babel-transpiler/package.json index 1a5a9df356..ab64eb239d 100644 --- a/packages/stryker-babel-transpiler/package.json +++ b/packages/stryker-babel-transpiler/package.json @@ -45,7 +45,6 @@ "license": "Apache-2.0", "dependencies": { "babel-core": "6.26.3", - "log4js": "^1.1.1", "minimatch": "^3.0.4" }, "devDependencies": { @@ -66,4 +65,4 @@ "babelrcFile": ".babelrc", "coverageAnalysis": "off" } -} \ No newline at end of file +} diff --git a/packages/stryker-babel-transpiler/src/BabelConfigReader.ts b/packages/stryker-babel-transpiler/src/BabelConfigReader.ts index a102bbc3ef..2ac3035f29 100644 --- a/packages/stryker-babel-transpiler/src/BabelConfigReader.ts +++ b/packages/stryker-babel-transpiler/src/BabelConfigReader.ts @@ -2,13 +2,12 @@ import * as fs from 'fs'; import * as path from 'path'; import { Config } from 'stryker-api/config'; import { CONFIG_KEY_FILE, CONFIG_KEY_OPTIONS } from './helpers/keys'; -import { getLogger, setGlobalLogLevel } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; export default class BabelConfigReader { private readonly log = getLogger(BabelConfigReader.name); public readConfig(config: Config): babel.TransformOptions { - setGlobalLogLevel(config.logLevel); const babelConfig: babel.TransformOptions = config[CONFIG_KEY_OPTIONS] || this.getConfigFile(config) || {}; this.log.debug(`babel config is: ${JSON.stringify(babelConfig, null, 2)}`); return babelConfig; diff --git a/packages/stryker-babel-transpiler/src/BabelTranspiler.ts b/packages/stryker-babel-transpiler/src/BabelTranspiler.ts index fd411f142a..79e958d82a 100644 --- a/packages/stryker-babel-transpiler/src/BabelTranspiler.ts +++ b/packages/stryker-babel-transpiler/src/BabelTranspiler.ts @@ -5,7 +5,6 @@ import * as path from 'path'; import BabelConfigReader from './BabelConfigReader'; import { CONFIG_KEY_FILE } from './helpers/keys'; import { toJSFileName } from './helpers/helpers'; -import { setGlobalLogLevel } from 'log4js'; const KNOWN_EXTENSIONS = Object.freeze([ '.es6', @@ -21,7 +20,6 @@ class BabelTranspiler implements Transpiler { private projectRoot: string; public constructor(options: TranspilerOptions) { - setGlobalLogLevel(options.config.logLevel); this.babelOptions = new BabelConfigReader().readConfig(options.config); this.projectRoot = this.determineProjectRoot(options); if (options.produceSourceMaps) { diff --git a/packages/stryker-babel-transpiler/test/unit/BabelConfigReaderSpec.ts b/packages/stryker-babel-transpiler/test/unit/BabelConfigReaderSpec.ts index 6b92e557ef..d9fdbdf8c4 100644 --- a/packages/stryker-babel-transpiler/test/unit/BabelConfigReaderSpec.ts +++ b/packages/stryker-babel-transpiler/test/unit/BabelConfigReaderSpec.ts @@ -2,7 +2,7 @@ import BabelConfigReader from '../../src/BabelConfigReader'; import { Config } from 'stryker-api/config'; import { expect } from 'chai'; import * as fs from 'fs'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; import * as sinon from 'sinon'; import * as path from 'path'; diff --git a/packages/stryker-html-reporter/package-lock.json b/packages/stryker-html-reporter/package-lock.json index 5b7aeb4d25..e2fe05878c 100644 --- a/packages/stryker-html-reporter/package-lock.json +++ b/packages/stryker-html-reporter/package-lock.json @@ -1,16 +1,20 @@ { - "requires": true, + "name": "stryker-html-reporter", + "version": "0.14.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@types/file-url": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/file-url/-/file-url-2.0.0.tgz", - "integrity": "sha512-9YqUM3izkmwtCbq6ANdcHJiU2mpDvPm3WuHOcJ5ZouHw7CoYcyY/KvZm6dmYTIurfrRsmBIvHr6y1jpBjDd4Jg==" + "integrity": "sha512-9YqUM3izkmwtCbq6ANdcHJiU2mpDvPm3WuHOcJ5ZouHw7CoYcyY/KvZm6dmYTIurfrRsmBIvHr6y1jpBjDd4Jg==", + "dev": true }, "@types/jsdom": { "version": "11.0.4", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-11.0.4.tgz", "integrity": "sha512-lthMj4kw7Fzs3LjBhQ0+1faAfDrN9GFJZO5Nf/xO7fppFfxqnnQdNR28n0xMGXsx8fTHOPliE1NTkAW1bVLpYw==", + "dev": true, "requires": { "@types/node": "*", "@types/tough-cookie": "*", @@ -20,27 +24,32 @@ "@types/node": { "version": "8.10.14", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.14.tgz", - "integrity": "sha512-TKQqQIaYNO+8MrOsFgobkt3fbMzkfXhBFKcg20Nip5Omptw1HOY/IEvYiFtMwIbr7Me/Y2H/JO+TgNUMJ9NGjA==" + "integrity": "sha512-TKQqQIaYNO+8MrOsFgobkt3fbMzkfXhBFKcg20Nip5Omptw1HOY/IEvYiFtMwIbr7Me/Y2H/JO+TgNUMJ9NGjA==", + "dev": true }, "@types/tough-cookie": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha512-MDQLxNFRLasqS4UlkWMSACMKeSm1x4Q3TxzUC7KQUsh6RK1ZrQ0VEyE3yzXcBu+K8ejVj4wuX32eUG02yNp+YQ==" + "integrity": "sha512-MDQLxNFRLasqS4UlkWMSACMKeSm1x4Q3TxzUC7KQUsh6RK1ZrQ0VEyE3yzXcBu+K8ejVj4wuX32eUG02yNp+YQ==", + "dev": true }, "abab": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", - "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=" + "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=", + "dev": true }, "acorn": { "version": "4.0.13", "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "dev": true }, "acorn-globals": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", + "dev": true, "requires": { "acorn": "^4.0.4" } @@ -49,6 +58,7 @@ "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, "requires": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", @@ -64,32 +74,38 @@ "array-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true }, "asn1": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true }, "aws4": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", + "dev": true }, "balanced-match": { "version": "1.0.0", @@ -100,6 +116,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, "optional": true, "requires": { "tweetnacl": "^0.14.3" @@ -109,6 +126,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, "requires": { "hoek": "4.x.x" } @@ -116,7 +134,8 @@ "bootstrap": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.1.tgz", - "integrity": "sha512-SpiDSOcbg4J/PjVSt4ny5eY6j74VbVSjROY4Fb/WIUXBV9cnb5luyR4KnPvNoXuGnBK1T+nJIWqRsvU3yP8Mcg==" + "integrity": "sha512-SpiDSOcbg4J/PjVSt4ny5eY6j74VbVSjROY4Fb/WIUXBV9cnb5luyR4KnPvNoXuGnBK1T+nJIWqRsvU3yP8Mcg==", + "dev": true }, "brace-expansion": { "version": "1.1.11", @@ -130,17 +149,20 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true }, "combined-stream": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -153,17 +175,20 @@ "content-type-parser": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", - "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==" + "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==", + "dev": true }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "cryptiles": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, "requires": { "boom": "5.x.x" }, @@ -172,6 +197,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, "requires": { "hoek": "4.x.x" } @@ -181,12 +207,14 @@ "cssom": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz", - "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=" + "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs=", + "dev": true }, "cssstyle": { "version": "0.2.37", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=", + "dev": true, "requires": { "cssom": "0.3.x" } @@ -195,37 +223,28 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, "requires": { "assert-plus": "^1.0.0" } }, - "date-format": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", - "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, "optional": true, "requires": { "jsbn": "~0.1.0" @@ -235,6 +254,7 @@ "version": "1.9.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz", "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", + "dev": true, "requires": { "esprima": "^3.1.3", "estraverse": "^4.2.0", @@ -246,42 +266,50 @@ "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true }, "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true }, "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true }, "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true }, "file-url": { "version": "2.0.2", @@ -291,12 +319,14 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true }, "form-data": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "1.0.6", @@ -312,6 +342,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -332,12 +363,14 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true }, "har-validator": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, "requires": { "ajv": "^5.1.0", "har-schema": "^2.0.0" @@ -347,6 +380,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, "requires": { "boom": "4.x.x", "cryptiles": "3.x.x", @@ -357,17 +391,20 @@ "highlight.js": { "version": "9.12.0", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz", - "integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4=" + "integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4=", + "dev": true }, "hoek": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true }, "html-encoding-sniffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, "requires": { "whatwg-encoding": "^1.0.1" } @@ -376,6 +413,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -385,7 +423,8 @@ "iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true }, "inflight": { "version": "1.0.6", @@ -404,33 +443,33 @@ "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true }, "jquery": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", - "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" + "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==", + "dev": true }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, "optional": true }, "jsdom": { "version": "9.12.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", "integrity": "sha1-6MVG//ywbADUgzyoRBD+1/igl9Q=", + "dev": true, "requires": { "abab": "^1.0.3", "acorn": "^4.0.4", @@ -456,29 +495,34 @@ "parse5": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", - "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=" + "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=", + "dev": true } } }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -490,6 +534,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, "requires": { "prelude-ls": "~1.1.2", "type-check": "~0.3.2" @@ -500,25 +545,17 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, - "log4js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-1.1.1.tgz", - "integrity": "sha1-wh0px2BAieTyVYM+f5SzRh3h/0M=", - "requires": { - "debug": "^2.2.0", - "semver": "^5.3.0", - "streamroller": "^0.4.0" - } - }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true }, "mime-types": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, "requires": { "mime-db": "~1.33.0" } @@ -544,11 +581,6 @@ "minimist": "0.0.8" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, "mz": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", @@ -562,12 +594,14 @@ "nwmatcher": { "version": "1.4.4", "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", - "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==" + "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==", + "dev": true }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true }, "object-assign": { "version": "4.1.1", @@ -586,6 +620,7 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, "requires": { "deep-is": "~0.1.3", "fast-levenshtein": "~2.0.4", @@ -599,6 +634,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "dev": true, "requires": { "@types/node": "*" } @@ -611,43 +647,38 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true }, "popper.js": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.3.tgz", - "integrity": "sha1-FDj5jQRqz3tNeM1QK/QYrGTU8JU=" + "integrity": "sha1-FDj5jQRqz3tNeM1QK/QYrGTU8JU=", + "dev": true }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true }, "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true }, "request": { "version": "2.85.0", "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.6.0", @@ -684,22 +715,20 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true }, "sntp": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, "requires": { "hoek": "4.x.x" } @@ -708,12 +737,14 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, "optional": true }, "sshpk": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", + "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -725,38 +756,26 @@ "tweetnacl": "~0.14.0" } }, - "streamroller": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.4.1.tgz", - "integrity": "sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8=", - "requires": { - "date-format": "^0.0.0", - "debug": "^0.7.2", - "mkdirp": "^0.5.1", - "readable-stream": "^1.1.7" - }, - "dependencies": { - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" - } - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "stryker-api": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.17.0.tgz", + "integrity": "sha512-CJKAx+D8ztmXtnORk0bKfrccIbeAOXcKZ2pQpevvj7SFZJKlF8PRQy8lkgP5kvTK/sKidQp84kHjiqyRvf634A==", + "dev": true, + "requires": { + "tslib": "^1.6.0" + } }, "symbol-tree": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", - "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=" + "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=", + "dev": true }, "thenify": { "version": "3.3.0", @@ -778,6 +797,7 @@ "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, "requires": { "punycode": "^1.4.1" } @@ -785,12 +805,20 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true + }, + "tslib": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "dev": true }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -799,12 +827,14 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, "optional": true }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, "requires": { "prelude-ls": "~1.1.2" } @@ -817,12 +847,14 @@ "uuid": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "dev": true }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -832,12 +864,14 @@ "webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true }, "whatwg-encoding": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz", "integrity": "sha512-jLBwwKUhi8WtBfsMQlL4bUUcT8sMkAtQinscJAe/M4KHCkHuUJAF6vuB0tueNIw4c8ziO6AkRmgY+jL3a0iiPw==", + "dev": true, "requires": { "iconv-lite": "0.4.19" } @@ -846,6 +880,7 @@ "version": "4.8.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", "integrity": "sha1-0pgaqRSMHgCkHFphMRZqtGg7vMA=", + "dev": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -854,14 +889,16 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true } } }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true }, "wrappy": { "version": "1.0.2", @@ -871,7 +908,8 @@ "xml-name-validator": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", - "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=" + "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=", + "dev": true } } } diff --git a/packages/stryker-html-reporter/package.json b/packages/stryker-html-reporter/package.json index 29a5534606..4609744b03 100644 --- a/packages/stryker-html-reporter/package.json +++ b/packages/stryker-html-reporter/package.json @@ -38,7 +38,6 @@ "dependencies": { "file-url": "^2.0.0", "lodash": "^4.13.1", - "log4js": "^1.0.1", "mkdirp": "^0.5.1", "mz": "^2.5.0", "rimraf": "^2.6.1", diff --git a/packages/stryker-html-reporter/src/HtmlReporter.ts b/packages/stryker-html-reporter/src/HtmlReporter.ts index 78e9808a64..73aba313f5 100644 --- a/packages/stryker-html-reporter/src/HtmlReporter.ts +++ b/packages/stryker-html-reporter/src/HtmlReporter.ts @@ -1,4 +1,4 @@ -import * as log4js from 'log4js'; +import * as logging from 'stryker-api/logging'; import fileUrl = require('file-url'); import * as path from 'path'; import { Config } from 'stryker-api/config'; @@ -7,7 +7,7 @@ import * as util from './util'; import * as templates from './templates'; import Breadcrumb from './Breadcrumb'; -const log = log4js.getLogger('HtmlReporter'); +const log = logging.getLogger('HtmlReporter'); const DEFAULT_BASE_FOLDER = path.normalize('reports/mutation/html'); export const RESOURCES_DIR_NAME = 'strykerResources'; @@ -20,7 +20,6 @@ export default class HtmlReporter implements Reporter { private scoreResult: ScoreResult; constructor(private options: Config) { - log4js.setGlobalLogLevel(options.logLevel || 'info'); } onAllSourceFilesRead(files: SourceFile[]) { diff --git a/packages/stryker-html-reporter/test/helpers/log4jsMock.ts b/packages/stryker-html-reporter/test/helpers/log4jsMock.ts index dabc9f146a..2e1a7080fb 100644 --- a/packages/stryker-html-reporter/test/helpers/log4jsMock.ts +++ b/packages/stryker-html-reporter/test/helpers/log4jsMock.ts @@ -1,4 +1,4 @@ -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; import * as sinon from 'sinon'; let logger = { diff --git a/packages/stryker-jasmine-runner/package-lock.json b/packages/stryker-jasmine-runner/package-lock.json index ead3b6a478..a42803668d 100644 --- a/packages/stryker-jasmine-runner/package-lock.json +++ b/packages/stryker-jasmine-runner/package-lock.json @@ -1,19 +1,29 @@ { - "requires": true, + "name": "stryker-jasmine-runner", + "version": "0.0.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "stryker-api": { "version": "0.16.1", "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.16.1.tgz", "integrity": "sha1-bhP1ocSPZGjmuPG716LfhiKCwT4=", + "dev": true, "requires": { "tslib": "^1.6.0" } }, + "stryker-jasmine": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/stryker-jasmine/-/stryker-jasmine-0.8.4.tgz", + "integrity": "sha512-25W2S3eCaN62p41GY+pbsp+3Ny7gS1oQfI1bX2LtWoFly6Iyi23C4EjrngQx+8gU0pZ05Of8t3LSMGQKibQk6Q==", + "dev": true + }, "tslib": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", - "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==" + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "dev": true } } } diff --git a/packages/stryker-jasmine-runner/package.json b/packages/stryker-jasmine-runner/package.json index f823b3cf81..d6206e5016 100644 --- a/packages/stryker-jasmine-runner/package.json +++ b/packages/stryker-jasmine-runner/package.json @@ -47,5 +47,6 @@ "initStrykerConfig": { "jasmineConfigFile": "spec/support/jasmine.json" }, - "contributors": [] -} \ No newline at end of file + "contributors": [], + "dependencies": {} +} diff --git a/packages/stryker-jasmine/package-lock.json b/packages/stryker-jasmine/package-lock.json new file mode 100644 index 0000000000..f8ec4b7cb3 --- /dev/null +++ b/packages/stryker-jasmine/package-lock.json @@ -0,0 +1,26 @@ +{ + "name": "stryker-jasmine", + "version": "0.8.4", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "stryker-api": { + "version": "0.17.0", + "dev": true, + "requires": { + "tslib": "^1.6.0" + }, + "dependencies": { + "surrial": { + "version": "0.1.3", + "bundled": true + }, + "tslib": { + "version": "1.9.0", + "bundled": true, + "dev": true + } + } + } + } +} diff --git a/packages/stryker-jasmine/package.json b/packages/stryker-jasmine/package.json index a03aadcfac..f920095783 100644 --- a/packages/stryker-jasmine/package.json +++ b/packages/stryker-jasmine/package.json @@ -36,5 +36,6 @@ "devDependencies": { "stryker-api": "^0.17.0" }, - "contributors": [] + "contributors": [], + "dependencies": {} } diff --git a/packages/stryker-javascript-mutator/package-lock.json b/packages/stryker-javascript-mutator/package-lock.json index 6585b3f69b..e6a5ccfaac 100644 --- a/packages/stryker-javascript-mutator/package-lock.json +++ b/packages/stryker-javascript-mutator/package-lock.json @@ -1,11 +1,14 @@ { - "requires": true, + "name": "stryker-javascript-mutator", + "version": "0.7.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@types/babel-generator": { "version": "6.25.1", "resolved": "https://registry.npmjs.org/@types/babel-generator/-/babel-generator-6.25.1.tgz", "integrity": "sha512-nKNz9Ch4WP2TFZjQROhxqqS2SCk0OoDzGazJI6S+2sGgW9P7N4o3vluZAXFuPEnRqtz2A0vrrkK3tjQktxIlRw==", + "dev": true, "requires": { "@types/babel-types": "*" } @@ -13,12 +16,14 @@ "@types/babel-types": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.2.tgz", - "integrity": "sha512-ylggu8DwwxT6mk3jVoJeohWAePWMNWEYm06MSoJ19kwp3hT9eY2Z4NNZn3oevzgFmClgNQ2GQF500hPDvNsGHg==" + "integrity": "sha512-ylggu8DwwxT6mk3jVoJeohWAePWMNWEYm06MSoJ19kwp3hT9eY2Z4NNZn3oevzgFmClgNQ2GQF500hPDvNsGHg==", + "dev": true }, "@types/babylon": { "version": "6.16.2", "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.2.tgz", "integrity": "sha512-+Jty46mPaWe1VAyZbfvgJM4BAdklLWxrT5tc/RjvCgLrtk6gzRY6AOnoWFv4p6hVxhJshDdr2hGVn56alBp97Q==", + "dev": true, "requires": { "@types/babel-types": "*" } @@ -209,16 +214,6 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.6.tgz", "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==" }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "date-format": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", - "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=" - }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -267,11 +262,6 @@ "os-tmpdir": "^1.0.1" } }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, "invariant": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", @@ -288,11 +278,6 @@ "number-is-nan": "^1.0.0" } }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, "js-tokens": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", @@ -313,16 +298,6 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, - "log4js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-1.1.1.tgz", - "integrity": "sha1-wh0px2BAieTyVYM+f5SzRh3h/0M=", - "requires": { - "debug": "^2.2.0", - "semver": "^5.3.0", - "streamroller": "^0.4.0" - } - }, "loose-envify": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", @@ -382,17 +357,6 @@ "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==" }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", @@ -406,11 +370,6 @@ "is-finite": "^1.0.0" } }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - }, "slash": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", @@ -429,29 +388,6 @@ "source-map": "^0.5.6" } }, - "streamroller": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.4.1.tgz", - "integrity": "sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8=", - "requires": { - "date-format": "^0.0.0", - "debug": "^0.7.2", - "mkdirp": "^0.5.1", - "readable-stream": "^1.1.7" - }, - "dependencies": { - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" - } - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", @@ -460,6 +396,21 @@ "ansi-regex": "^2.0.0" } }, + "stryker-api": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.17.0.tgz", + "integrity": "sha512-CJKAx+D8ztmXtnORk0bKfrccIbeAOXcKZ2pQpevvj7SFZJKlF8PRQy8lkgP5kvTK/sKidQp84kHjiqyRvf634A==", + "dev": true, + "requires": { + "tslib": "^1.6.0" + } + }, + "stryker-mutator-specification": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/stryker-mutator-specification/-/stryker-mutator-specification-0.3.0.tgz", + "integrity": "sha512-8uNnV8Pr2XuoXZNQeUa7RdtNJ6yHzjrgPau+pTO9xiMGM1Q0uYEifYkOoZffB7NdximYu1FIsVCT76pJKmORug==", + "dev": true + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", diff --git a/packages/stryker-javascript-mutator/package.json b/packages/stryker-javascript-mutator/package.json index 57d9dac8c1..bf0b6549d5 100644 --- a/packages/stryker-javascript-mutator/package.json +++ b/packages/stryker-javascript-mutator/package.json @@ -41,7 +41,6 @@ "babel-generator": "^6.26.0", "babylon": "^6.18.0", "lodash": "^4.17.4", - "log4js": "^1.1.1", "tslib": "^1.8.0" }, "devDependencies": { diff --git a/packages/stryker-javascript-mutator/src/JavaScriptMutator.ts b/packages/stryker-javascript-mutator/src/JavaScriptMutator.ts index 05133f2caa..0ea67694fd 100644 --- a/packages/stryker-javascript-mutator/src/JavaScriptMutator.ts +++ b/packages/stryker-javascript-mutator/src/JavaScriptMutator.ts @@ -1,5 +1,5 @@ import * as babel from 'babel-core'; -import { getLogger, setGlobalLogLevel } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { Mutator, Mutant } from 'stryker-api/mutant'; import { File } from 'stryker-api/core'; import { Config } from 'stryker-api/config'; @@ -16,7 +16,6 @@ export default class JavaScriptMutator implements Mutator { private log = getLogger(JavaScriptMutator.name); constructor(config: Config, private mutators: NodeMutator[] = defaultMutators()) { - setGlobalLogLevel(config.logLevel); } public mutate(inputFiles: File[]): Mutant[] { diff --git a/packages/stryker-javascript-mutator/test/helpers/LogMock.ts b/packages/stryker-javascript-mutator/test/helpers/LogMock.ts index 2b4ba4c148..ee5962d251 100644 --- a/packages/stryker-javascript-mutator/test/helpers/LogMock.ts +++ b/packages/stryker-javascript-mutator/test/helpers/LogMock.ts @@ -1,4 +1,4 @@ -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { SinonStub } from 'sinon'; export default class LogMock implements Mock { diff --git a/packages/stryker-javascript-mutator/test/helpers/initSinon.ts b/packages/stryker-javascript-mutator/test/helpers/initSinon.ts index 750d76a76c..f94e4da3c2 100644 --- a/packages/stryker-javascript-mutator/test/helpers/initSinon.ts +++ b/packages/stryker-javascript-mutator/test/helpers/initSinon.ts @@ -1,5 +1,5 @@ import * as sinon from 'sinon'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; import LogMock from './LogMock'; beforeEach(() => { diff --git a/packages/stryker-karma-runner/package-lock.json b/packages/stryker-karma-runner/package-lock.json index 894394da35..e19d6b941a 100644 --- a/packages/stryker-karma-runner/package-lock.json +++ b/packages/stryker-karma-runner/package-lock.json @@ -1,11 +1,82 @@ { - "requires": true, + "name": "stryker-karma-runner", + "version": "0.15.0", "lockfileVersion": 1, + "requires": true, "dependencies": { + "@types/body-parser": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.0.tgz", + "integrity": "sha512-a2+YeUjPkztKJu5aIF2yArYFQQp8d51wZ7DavSHjFuY1mqVgidGyzEQ41JIVNy82fXj8yPgy2vJmfIywgESW6w==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", + "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/events": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz", + "integrity": "sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA==", + "dev": true + }, + "@types/express": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.11.1.tgz", + "integrity": "sha512-ttWle8cnPA5rAelauSWeWJimtY2RsUf2aspYZs7xPHiWgOlPn6nnUfBMtrkcnjFJuIHJF4gNOdVvpLK2Zmvh6g==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.11.1.tgz", + "integrity": "sha512-EehCl3tpuqiM8RUb+0255M8PhhSwTtLfmO7zBBdv0ay/VTd/zmrqDfQdZFsa5z/PVMbH2yCMZPXsnrImpATyIw==", + "dev": true, + "requires": { + "@types/events": "*", + "@types/node": "*" + } + }, + "@types/mime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", + "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==", + "dev": true + }, + "@types/node": { + "version": "10.0.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.0.9.tgz", + "integrity": "sha512-ekJ3mXJcJP+Nn5kC6eCmWPND/fHx/Ga12Lz0IJgTfGz1ge7OCIR5xcDY5tcYgnyM1kWsVDRH2bguxkGcNj39AQ==", + "dev": true + }, + "@types/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-/BZ4QRLpH/bNYgZgwhKEh+5AsboDBcUdlBYgzoLX0fpj3Y2gp6EApyOlM3bK53wQS/OE1SrdSYBAbux2D1528Q==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, "accepts": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", + "dev": true, "requires": { "mime-types": "~2.1.18", "negotiator": "0.6.1" @@ -15,17 +86,20 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz", "integrity": "sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=", + "dev": true, "optional": true }, "after": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", - "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=" + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true }, "agent-base": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz", "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=", + "dev": true, "requires": { "extend": "~3.0.0", "semver": "~5.0.1" @@ -34,7 +108,8 @@ "semver": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz", - "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=" + "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=", + "dev": true } } }, @@ -42,6 +117,7 @@ "version": "5.5.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "dev": true, "requires": { "co": "^4.6.0", "fast-deep-equal": "^1.0.0", @@ -53,6 +129,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.2.tgz", "integrity": "sha512-l9mCs6LbydtHqRniRwYkKdqxVa6XMz3Vw1fh+2gJaaVgTM6Jk3o8RccAKWKtlhT1US5sWrFh+KKxsVUALURSIA==", + "dev": true, "optional": true, "requires": { "bitsyntax": "~0.0.4", @@ -66,12 +143,14 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true, "optional": true }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -84,6 +163,7 @@ "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true, "optional": true } } @@ -91,18 +171,21 @@ "ansi-regex": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, "optional": true }, "anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, "requires": { "micromatch": "^2.1.5", "normalize-path": "^2.0.0" @@ -112,6 +195,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, "requires": { "arr-flatten": "^1.0.1" } @@ -119,43 +203,51 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true }, "array-slice": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", - "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=" + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true }, "array-unique": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true }, "arraybuffer.slice": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", - "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==" + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true }, "asn1": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true }, "ast-types": { "version": "0.11.3", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.3.tgz", "integrity": "sha512-XA5o5dsNw8MhyW0Q7MWXJWc4oOzZKbdsEJq45h7c8q/d9DwWZ5F2ugUc1PuMLPGsUnphCt/cNDHu8JeBbxf1qA==", + "dev": true, "optional": true }, "async": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/async/-/async-2.1.5.tgz", "integrity": "sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw=", + "dev": true, "optional": true, "requires": { "lodash": "^4.14.0" @@ -164,32 +256,38 @@ "async-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true }, "async-limiter": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", - "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==", + "dev": true }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true }, "aws4": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", + "dev": true }, "axios": { "version": "0.15.3", "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz", "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", + "dev": true, "optional": true, "requires": { "follow-redirects": "1.0.0" @@ -199,6 +297,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "dev": true, "optional": true, "requires": { "debug": "^2.2.0" @@ -209,27 +308,32 @@ "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=" + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base64-arraybuffer": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", - "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=" + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true }, "base64id": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", - "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=" + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true }, "bcrypt-pbkdf": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, "optional": true, "requires": { "tweetnacl": "^0.14.3" @@ -239,6 +343,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, "requires": { "callsite": "1.0.0" } @@ -246,12 +351,14 @@ "binary-extensions": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=" + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "dev": true }, "bitsyntax": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.0.4.tgz", "integrity": "sha1-6xDMb4K4xJDj6FaY8H6D1G4MuoI=", + "dev": true, "optional": true, "requires": { "buffer-more-ints": "0.0.2" @@ -261,6 +368,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", + "dev": true, "optional": true, "requires": { "readable-stream": "~2.0.5" @@ -270,12 +378,14 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true, "optional": true }, "readable-stream": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "dev": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -290,6 +400,7 @@ "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true, "optional": true } } @@ -297,17 +408,20 @@ "blob": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz", - "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=" + "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=", + "dev": true }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true }, "body-parser": { "version": "1.18.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "dev": true, "requires": { "bytes": "3.0.0", "content-type": "~1.0.4", @@ -325,6 +439,7 @@ "version": "4.3.1", "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "dev": true, "requires": { "hoek": "4.x.x" } @@ -333,6 +448,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -342,6 +458,7 @@ "version": "1.8.5", "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, "requires": { "expand-range": "^1.8.1", "preserve": "^0.2.0", @@ -351,12 +468,14 @@ "buffer-more-ints": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz", - "integrity": "sha1-JrOIXRD6E9t/wBquOquHAZngEkw=" + "integrity": "sha1-JrOIXRD6E9t/wBquOquHAZngEkw=", + "dev": true }, "buildmail": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/buildmail/-/buildmail-4.0.1.tgz", "integrity": "sha1-h393OLeHKYccmhBeO4N9K+EaenI=", + "dev": true, "optional": true, "requires": { "addressparser": "1.0.1", @@ -371,22 +490,26 @@ "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", - "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=" + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, "optional": true, "requires": { "ansi-styles": "^2.2.1", @@ -400,6 +523,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, "requires": { "anymatch": "^1.3.0", "async-each": "^1.0.0", @@ -415,22 +539,26 @@ "circular-json": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.4.tgz", - "integrity": "sha512-vnJA8KS0BfOihugYEUkLRcnmq21FbuivbxgzDLXNs3zIk4KllV4Mx4UuTzBXht9F00C7QfD1YqMXg1zP6EXpig==" + "integrity": "sha512-vnJA8KS0BfOihugYEUkLRcnmq21FbuivbxgzDLXNs3zIk4KllV4Mx4UuTzBXht9F00C7QfD1YqMXg1zP6EXpig==", + "dev": true }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true }, "colors": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/colors/-/colors-1.2.5.tgz", - "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==" + "integrity": "sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==", + "dev": true }, "combine-lists": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz", "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=", + "dev": true, "requires": { "lodash": "^4.5.0" } @@ -439,6 +567,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -447,32 +576,38 @@ "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", + "dev": true, "optional": true }, "component-bind": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", - "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=" + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true }, "component-inherit": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", - "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=" + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concat-stream": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, "requires": { "inherits": "^2.0.3", "readable-stream": "^2.2.2", @@ -483,6 +618,7 @@ "version": "3.6.6", "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", "integrity": "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ=", + "dev": true, "requires": { "debug": "2.6.9", "finalhandler": "1.1.0", @@ -493,27 +629,32 @@ "content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true }, "cookie": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true }, "core-js": { "version": "2.5.6", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.6.tgz", - "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==" + "integrity": "sha512-lQUVfQi0aLix2xpyjrrJEvfuYCqPc/HwmTKsC/VNf8q0zsjX7SQZtp4+oRONN5Tsur9GDETPjj+Ub2iDiGZfSQ==", + "dev": true }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "cryptiles": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "dev": true, "requires": { "boom": "5.x.x" }, @@ -522,6 +663,7 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "dev": true, "requires": { "hoek": "4.x.x" } @@ -531,12 +673,14 @@ "custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", - "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=" + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -545,17 +689,20 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", + "dev": true, "optional": true }, "date-format": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", - "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=" + "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=", + "dev": true }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -564,12 +711,14 @@ "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true, "optional": true }, "degenerator": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "dev": true, "optional": true, "requires": { "ast-types": "0.x.x", @@ -580,22 +729,26 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true }, "di": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", - "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=" + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true }, "dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, "requires": { "custom-event": "~1.0.0", "ent": "~2.2.0", @@ -607,12 +760,14 @@ "version": "2.1.0-0", "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", + "dev": true, "optional": true }, "ecc-jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, "optional": true, "requires": { "jsbn": "~0.1.0" @@ -621,17 +776,20 @@ "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true }, "encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true }, "engine.io": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.5.tgz", "integrity": "sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA==", + "dev": true, "requires": { "accepts": "~1.3.4", "base64id": "1.0.0", @@ -646,6 +804,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -656,6 +815,7 @@ "version": "3.1.6", "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.6.tgz", "integrity": "sha512-hnuHsFluXnsKOndS4Hv6SvUrgdYx1pk2NqfaDMW+GWdgfU3+/V25Cj7I8a0x92idSpa5PIhJRKxPvp9mnoLsfg==", + "dev": true, "requires": { "component-emitter": "1.2.1", "component-inherit": "0.0.3", @@ -674,6 +834,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -684,6 +845,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "dev": true, "requires": { "after": "0.8.2", "arraybuffer.slice": "~0.0.7", @@ -695,28 +857,33 @@ "ent": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", - "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true }, "es6-promise": { "version": "4.2.4", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", - "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", + "dev": true }, "escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, "optional": true }, "escodegen": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.1.tgz", "integrity": "sha512-6hTjO1NAWkHnDk3OqQ4YrCuwwmGHL9S3nPlzBOUG/R44rda3wLNrfvQ5fkSGjyhHFKM7ALPKcKGrwvCLe0lC7Q==", + "dev": true, "optional": true, "requires": { "esprima": "^3.1.3", @@ -729,29 +896,34 @@ "esprima": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true }, "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true, "optional": true }, "esutils": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true, "optional": true }, "eventemitter3": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz", - "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==" + "integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==", + "dev": true }, "expand-braces": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz", "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=", + "dev": true, "requires": { "array-slice": "^0.2.3", "array-unique": "^0.2.1", @@ -762,6 +934,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz", "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=", + "dev": true, "requires": { "expand-range": "^0.1.0" } @@ -770,6 +943,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz", "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=", + "dev": true, "requires": { "is-number": "^0.1.1", "repeat-string": "^0.2.2" @@ -778,12 +952,14 @@ "is-number": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz", - "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=" + "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=", + "dev": true }, "repeat-string": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz", - "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=" + "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=", + "dev": true } } }, @@ -791,6 +967,7 @@ "version": "0.1.5", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, "requires": { "is-posix-bracket": "^0.1.0" } @@ -799,6 +976,7 @@ "version": "1.8.2", "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, "requires": { "fill-range": "^2.1.0" } @@ -806,12 +984,14 @@ "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true }, "extglob": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, "requires": { "is-extglob": "^1.0.0" } @@ -820,6 +1000,7 @@ "version": "1.6.6", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.6.tgz", "integrity": "sha1-EpDt6NINCHK0Kf0/NRyhKOxe+Fw=", + "dev": true, "requires": { "concat-stream": "1.6.0", "debug": "2.6.9", @@ -831,6 +1012,7 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "dev": true, "requires": { "minimist": "0.0.8" } @@ -840,28 +1022,33 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true }, "fast-deep-equal": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true, "optional": true }, "fd-slicer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.0.1.tgz", "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", + "dev": true, "requires": { "pend": "~1.2.0" } @@ -870,17 +1057,20 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, "optional": true }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true }, "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, "requires": { "is-number": "^2.1.0", "isobject": "^2.0.0", @@ -893,6 +1083,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "dev": true, "requires": { "debug": "2.6.9", "encodeurl": "~1.0.1", @@ -906,7 +1097,8 @@ "statuses": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true } } }, @@ -914,6 +1106,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.4.1.tgz", "integrity": "sha512-uxYePVPogtya1ktGnAAXOacnbIuRMB4dkvqeNz2qTtTQsuzSfbDolV+wMMKxAmCx0bLgAKLbBOkjItMbbkR1vg==", + "dev": true, "requires": { "debug": "^3.1.0" }, @@ -922,6 +1115,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -931,12 +1125,14 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true }, "for-own": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, "requires": { "for-in": "^1.0.1" } @@ -944,12 +1140,14 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true }, "form-data": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "1.0.6", @@ -960,6 +1158,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "jsonfile": "^2.1.0", @@ -969,12 +1168,14 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.3.tgz", "integrity": "sha512-X+57O5YkDTiEQGiw8i7wYc2nQgweIekqkepI8Q3y4wVlurgBt2SuwxTeYUYMZIGpLZH3r/TsMjczCMXE5ZOt7Q==", + "dev": true, "optional": true, "requires": { "nan": "^2.9.2", @@ -984,20 +1185,24 @@ "abbrev": { "version": "1.1.1", "bundled": true, + "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "dev": true }, "aproba": { "version": "1.2.0", "bundled": true, + "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", "bundled": true, + "dev": true, "optional": true, "requires": { "delegates": "^1.0.0", @@ -1006,11 +1211,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1019,28 +1226,34 @@ "chownr": { "version": "1.0.1", "bundled": true, + "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "dev": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "core-util-is": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "debug": { "version": "2.6.9", "bundled": true, + "dev": true, "optional": true, "requires": { "ms": "2.0.0" @@ -1049,21 +1262,25 @@ "deep-extend": { "version": "0.4.2", "bundled": true, + "dev": true, "optional": true }, "delegates": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", "bundled": true, + "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", "bundled": true, + "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -1072,11 +1289,13 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "gauge": { "version": "2.7.4", "bundled": true, + "dev": true, "optional": true, "requires": { "aproba": "^1.0.3", @@ -1092,6 +1311,7 @@ "glob": { "version": "7.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -1105,11 +1325,13 @@ "has-unicode": { "version": "2.0.1", "bundled": true, + "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", "bundled": true, + "dev": true, "optional": true, "requires": { "safer-buffer": "^2.1.0" @@ -1118,6 +1340,7 @@ "ignore-walk": { "version": "3.0.1", "bundled": true, + "dev": true, "optional": true, "requires": { "minimatch": "^3.0.4" @@ -1126,6 +1349,7 @@ "inflight": { "version": "1.0.6", "bundled": true, + "dev": true, "optional": true, "requires": { "once": "^1.3.0", @@ -1134,16 +1358,19 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "dev": true }, "ini": { "version": "1.3.5", "bundled": true, + "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1151,22 +1378,26 @@ "isarray": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", "bundled": true, + "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, + "dev": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -1175,6 +1406,7 @@ "minizlib": { "version": "1.1.0", "bundled": true, + "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -1183,6 +1415,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "dev": true, "requires": { "minimist": "0.0.8" } @@ -1190,11 +1423,13 @@ "ms": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "needle": { "version": "2.2.0", "bundled": true, + "dev": true, "optional": true, "requires": { "debug": "^2.1.2", @@ -1205,6 +1440,7 @@ "node-pre-gyp": { "version": "0.9.1", "bundled": true, + "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -1222,6 +1458,7 @@ "nopt": { "version": "4.0.1", "bundled": true, + "dev": true, "optional": true, "requires": { "abbrev": "1", @@ -1231,11 +1468,13 @@ "npm-bundled": { "version": "1.0.3", "bundled": true, + "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", "bundled": true, + "dev": true, "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -1245,6 +1484,7 @@ "npmlog": { "version": "4.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -1255,16 +1495,19 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "object-assign": { "version": "4.1.1", "bundled": true, + "dev": true, "optional": true }, "once": { "version": "1.4.0", "bundled": true, + "dev": true, "requires": { "wrappy": "1" } @@ -1272,16 +1515,19 @@ "os-homedir": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "osenv": { "version": "0.1.5", "bundled": true, + "dev": true, "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -1291,16 +1537,19 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, + "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "rc": { "version": "1.2.6", "bundled": true, + "dev": true, "optional": true, "requires": { "deep-extend": "~0.4.0", @@ -1312,6 +1561,7 @@ "minimist": { "version": "1.2.0", "bundled": true, + "dev": true, "optional": true } } @@ -1319,6 +1569,7 @@ "readable-stream": { "version": "2.3.6", "bundled": true, + "dev": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -1333,6 +1584,7 @@ "rimraf": { "version": "2.6.2", "bundled": true, + "dev": true, "optional": true, "requires": { "glob": "^7.0.5" @@ -1340,36 +1592,43 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true + "bundled": true, + "dev": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, + "dev": true, "optional": true }, "sax": { "version": "1.2.4", "bundled": true, + "dev": true, "optional": true }, "semver": { "version": "5.5.0", "bundled": true, + "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", "bundled": true, + "dev": true, "optional": true }, "string-width": { "version": "1.0.2", "bundled": true, + "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1379,6 +1638,7 @@ "string_decoder": { "version": "1.1.1", "bundled": true, + "dev": true, "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -1387,6 +1647,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1394,11 +1655,13 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, + "dev": true, "optional": true }, "tar": { "version": "4.4.1", "bundled": true, + "dev": true, "optional": true, "requires": { "chownr": "^1.0.1", @@ -1413,11 +1676,13 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "string-width": "^1.0.2" @@ -1425,11 +1690,13 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "dev": true }, "yallist": { "version": "3.0.2", - "bundled": true + "bundled": true, + "dev": true } } }, @@ -1437,6 +1704,7 @@ "version": "0.3.10", "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, "optional": true, "requires": { "readable-stream": "1.1.x", @@ -1447,12 +1715,14 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true, "optional": true }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -1465,6 +1735,7 @@ "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true, "optional": true } } @@ -1473,12 +1744,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true, "optional": true }, "generate-object-property": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, "optional": true, "requires": { "is-property": "^1.0.0" @@ -1488,6 +1761,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.1.tgz", "integrity": "sha512-7aelVrYqCLuVjq2kEKRTH8fXPTC0xKTkM+G7UlFkEwCXY3sFbSxvY375JoFowOAYbkaU47SrBvOefUlLZZ+6QA==", + "dev": true, "optional": true, "requires": { "data-uri-to-buffer": "1", @@ -1502,6 +1776,7 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -1510,6 +1785,7 @@ "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1523,6 +1799,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, "requires": { "glob-parent": "^2.0.0", "is-glob": "^2.0.0" @@ -1532,6 +1809,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, "requires": { "is-glob": "^2.0.0" } @@ -1539,17 +1817,20 @@ "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true }, "har-validator": { "version": "5.0.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "dev": true, "requires": { "ajv": "^5.1.0", "har-schema": "^2.0.0" @@ -1559,6 +1840,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, "optional": true, "requires": { "ansi-regex": "^2.0.0" @@ -1568,6 +1850,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.2.tgz", "integrity": "sha1-6D26SfC5vk0CbSc2U1DZ8D9Uvpg=", + "dev": true, "requires": { "isarray": "2.0.1" }, @@ -1575,19 +1858,22 @@ "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true } } }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=" + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true }, "hasha": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", "integrity": "sha1-eNfL/B5tZjA/55g3NlmEUXsvbuE=", + "dev": true, "requires": { "is-stream": "^1.0.1", "pinkie-promise": "^2.0.0" @@ -1597,6 +1883,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "dev": true, "requires": { "boom": "4.x.x", "cryptiles": "3.x.x", @@ -1608,6 +1895,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz", "integrity": "sha1-ttJJdVQ3wZEII2d5nTupoPI7Ix4=", + "dev": true, "optional": true, "requires": { "lodash": "^4.0.0", @@ -1617,12 +1905,14 @@ "hoek": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==", + "dev": true }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, "requires": { "depd": "~1.1.2", "inherits": "2.0.3", @@ -1634,6 +1924,7 @@ "version": "1.17.0", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz", "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==", + "dev": true, "requires": { "eventemitter3": "^3.0.0", "follow-redirects": "^1.0.0", @@ -1644,6 +1935,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-1.0.0.tgz", "integrity": "sha1-zBzjjkU7+YSg93AtLdWcc9CBKEo=", + "dev": true, "requires": { "agent-base": "2", "debug": "2", @@ -1654,6 +1946,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -1664,6 +1957,7 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", + "dev": true, "requires": { "httpreq": ">=0.4.22", "underscore": "~1.7.0" @@ -1672,12 +1966,14 @@ "httpreq": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", - "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=" + "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=", + "dev": true }, "https-proxy-agent": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz", "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=", + "dev": true, "requires": { "agent-base": "2", "debug": "2", @@ -1687,23 +1983,27 @@ "iconv-lite": { "version": "0.4.19", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", - "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true }, "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true }, "inflection": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.10.0.tgz", "integrity": "sha1-W//LEZetPoEFD44X4hZoCH7p6y8=", + "dev": true, "optional": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1712,18 +2012,21 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "ip": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/ip/-/ip-1.0.1.tgz", "integrity": "sha1-x+NWzeoiWucbNtcPLnGpK6TkJZA=", + "dev": true, "optional": true }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, "requires": { "binary-extensions": "^1.0.0" } @@ -1731,17 +2034,20 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, "is-dotfile": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true }, "is-equal-shallow": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, "requires": { "is-primitive": "^2.0.0" } @@ -1749,17 +2055,20 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true }, "is-extglob": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true }, "is-glob": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, "requires": { "is-extglob": "^1.0.0" } @@ -1768,12 +2077,14 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "dev": true, "optional": true }, "is-my-json-valid": { "version": "2.17.2", "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "dev": true, "optional": true, "requires": { "generate-function": "^2.0.0", @@ -1787,6 +2098,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, "requires": { "kind-of": "^3.0.2" } @@ -1794,48 +2106,57 @@ "is-posix-bracket": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true }, "is-primitive": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true }, "is-property": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true, "optional": true }, "is-stream": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "isbinaryfile": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", - "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=" + "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", + "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "isobject": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, "requires": { "isarray": "1.0.0" } @@ -1843,38 +2164,45 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true }, "jasmine-core": { "version": "2.99.1", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.99.1.tgz", - "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=" + "integrity": "sha1-5kAN8ea1bhMLYcS80JPap/boyhU=", + "dev": true }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, "optional": true }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true }, "jsonfile": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", "integrity": "sha1-NzaitCi4e72gzIO1P6PWM6NcKug=", + "dev": true, "requires": { "graceful-fs": "^4.1.6" } @@ -1883,12 +2211,14 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true, "optional": true }, "jsprim": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -1900,6 +2230,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/karma/-/karma-2.0.2.tgz", "integrity": "sha1-TS25QChQpmVR+nhLAWT7CCTtjEs=", + "dev": true, "requires": { "bluebird": "^3.3.0", "body-parser": "^1.16.1", @@ -1934,6 +2265,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -1942,6 +2274,7 @@ "version": "2.5.3", "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.5.3.tgz", "integrity": "sha512-YL/qpTxYtK0iWWbuKCrevDZz5lh+OjyHHD+mICqpjnYGKdNRBvPeh/1uYjkKUemT1CSO4wwLOwphWMpKAnD9kw==", + "dev": true, "requires": { "amqplib": "^0.5.2", "axios": "^0.15.3", @@ -1963,12 +2296,14 @@ "karma-jasmine": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.2.tgz", - "integrity": "sha1-OU8rJf+0pkS5rabyLUQ+L9CIhsM=" + "integrity": "sha1-OU8rJf+0pkS5rabyLUQ+L9CIhsM=", + "dev": true }, "karma-phantomjs-launcher": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/karma-phantomjs-launcher/-/karma-phantomjs-launcher-1.0.4.tgz", "integrity": "sha1-0jyjSAG9qYY60xjju0vUBisTrNI=", + "dev": true, "requires": { "lodash": "^4.0.1", "phantomjs-prebuilt": "^2.1.7" @@ -1977,12 +2312,14 @@ "kew": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz", - "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=" + "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", + "dev": true }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -1991,6 +2328,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, "requires": { "graceful-fs": "^4.1.9" } @@ -1999,6 +2337,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, "optional": true, "requires": { "prelude-ls": "~1.1.2", @@ -2008,12 +2347,14 @@ "libbase64": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", - "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=" + "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=", + "dev": true }, "libmime": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", + "dev": true, "requires": { "iconv-lite": "0.4.15", "libbase64": "0.1.0", @@ -2023,80 +2364,28 @@ "iconv-lite": { "version": "0.4.15", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", - "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=", + "dev": true } } }, "libqp": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", - "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=" + "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=", + "dev": true }, "lodash": { "version": "4.17.10", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, - "log4js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-1.1.1.tgz", - "integrity": "sha1-wh0px2BAieTyVYM+f5SzRh3h/0M=", - "requires": { - "debug": "^2.2.0", - "semver": "^5.3.0", - "streamroller": "^0.4.0" - }, - "dependencies": { - "date-format": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", - "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "streamroller": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.4.1.tgz", - "integrity": "sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8=", - "requires": { - "date-format": "^0.0.0", - "debug": "^0.7.2", - "mkdirp": "^0.5.1", - "readable-stream": "^1.1.7" - }, - "dependencies": { - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" - } - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==", + "dev": true }, "loggly": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/loggly/-/loggly-1.1.1.tgz", "integrity": "sha1-Cg/B0/o6XsRP3HuJe+uipGlc6+4=", + "dev": true, "optional": true, "requires": { "json-stringify-safe": "5.0.x", @@ -2108,18 +2397,21 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true, "optional": true }, "aws-sign2": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true, "optional": true }, "boom": { "version": "2.10.1", "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, "requires": { "hoek": "2.x.x" } @@ -2128,12 +2420,14 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true, "optional": true }, "cryptiles": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, "optional": true, "requires": { "boom": "2.x.x" @@ -2143,6 +2437,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", + "dev": true, "optional": true, "requires": { "asynckit": "^0.4.0", @@ -2154,6 +2449,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, "optional": true, "requires": { "chalk": "^1.1.1", @@ -2166,6 +2462,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, "optional": true, "requires": { "boom": "2.x.x", @@ -2177,12 +2474,14 @@ "hoek": { "version": "2.16.3", "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", - "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true }, "http-signature": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, "optional": true, "requires": { "assert-plus": "^0.2.0", @@ -2194,18 +2493,21 @@ "version": "1.4.8", "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "dev": true, "optional": true }, "qs": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", + "dev": true, "optional": true }, "request": { "version": "2.75.0", "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", + "dev": true, "optional": true, "requires": { "aws-sign2": "~0.6.0", @@ -2235,6 +2537,7 @@ "version": "1.0.9", "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, "optional": true, "requires": { "hoek": "2.x.x" @@ -2244,6 +2547,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true, "optional": true } } @@ -2252,12 +2556,14 @@ "version": "2.6.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.5.tgz", "integrity": "sha1-5W1jVBSO3o13B7WNFDIg/QjfD9U=", + "dev": true, "optional": true }, "mailcomposer": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-4.0.1.tgz", "integrity": "sha1-DhxEsqB890DuF9wUm6AJ8Zyt/rQ=", + "dev": true, "optional": true, "requires": { "buildmail": "4.0.1", @@ -2268,6 +2574,7 @@ "version": "0.7.15", "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.7.15.tgz", "integrity": "sha1-7jZqINrGTDwVwD1sGz4O15UlKrs=", + "dev": true, "optional": true, "requires": { "async": "~2.1.2", @@ -2285,6 +2592,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, "optional": true, "requires": { "ms": "0.7.1" @@ -2294,6 +2602,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, "optional": true, "requires": { "asynckit": "^0.4.0", @@ -2305,6 +2614,7 @@ "version": "0.7.1", "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true, "optional": true } } @@ -2312,17 +2622,20 @@ "math-random": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.1.tgz", - "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=" + "integrity": "sha1-izqsWIuKZuSXXjzepn97sylgH6w=", + "dev": true }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true }, "micromatch": { "version": "2.3.11", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, "requires": { "arr-diff": "^2.0.0", "array-unique": "^0.2.1", @@ -2342,17 +2655,20 @@ "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true }, "mime-db": { "version": "1.33.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==", + "dev": true }, "mime-types": { "version": "2.1.18", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "dev": true, "requires": { "mime-db": "~1.33.0" } @@ -2361,6 +2677,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2368,12 +2685,14 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, "requires": { "minimist": "0.0.8" } @@ -2381,29 +2700,34 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true }, "nan": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "dev": true, "optional": true }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=", + "dev": true }, "netmask": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", + "dev": true, "optional": true }, "nodemailer": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-2.7.2.tgz", "integrity": "sha1-8kLmSa7q45tsftdA73sGHEBNMPk=", + "dev": true, "optional": true, "requires": { "libmime": "3.0.0", @@ -2419,12 +2743,14 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true, "optional": true }, "socks": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz", "integrity": "sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE=", + "dev": true, "optional": true, "requires": { "ip": "^1.1.2", @@ -2437,6 +2763,7 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz", "integrity": "sha1-6W+vuQNYVglH5WkBfZfmBzilCoY=", + "dev": true, "optional": true, "requires": { "nodemailer-shared": "1.1.0", @@ -2446,12 +2773,14 @@ "nodemailer-fetch": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", - "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=" + "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=", + "dev": true }, "nodemailer-shared": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", + "dev": true, "requires": { "nodemailer-fetch": "1.6.0" } @@ -2460,6 +2789,7 @@ "version": "2.8.2", "resolved": "https://registry.npmjs.org/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz", "integrity": "sha1-LrlNbPhXgLG0clzoU7nL1ejajHI=", + "dev": true, "optional": true, "requires": { "nodemailer-shared": "1.1.0", @@ -2471,6 +2801,7 @@ "version": "2.7.2", "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz", "integrity": "sha1-A9ccdjFPFKx9vHvwM6am0W1n+3c=", + "dev": true, "optional": true, "requires": { "nodemailer-shared": "1.1.0", @@ -2481,12 +2812,14 @@ "nodemailer-wellknown": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", - "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=" + "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=", + "dev": true }, "normalize-path": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -2494,17 +2827,20 @@ "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true }, "object-component": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", - "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=" + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true }, "object.omit": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, "requires": { "for-own": "^0.1.4", "is-extendable": "^0.1.1" @@ -2514,6 +2850,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, "requires": { "ee-first": "1.1.1" } @@ -2522,6 +2859,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -2530,6 +2868,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, "requires": { "minimist": "~0.0.1", "wordwrap": "~0.0.2" @@ -2538,7 +2877,8 @@ "wordwrap": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true } } }, @@ -2546,6 +2886,7 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, "optional": true, "requires": { "deep-is": "~0.1.3", @@ -2559,12 +2900,14 @@ "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true }, "pac-proxy-agent": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz", "integrity": "sha512-QBELCWyLYPgE2Gj+4wUEiMscHrQ8nRPBzYItQNOHWavwBt25ohZHQC4qnd5IszdVVrFbLsQ+dPkm6eqdjJAmwQ==", + "dev": true, "optional": true, "requires": { "agent-base": "2", @@ -2582,6 +2925,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-2.0.0.tgz", "integrity": "sha1-mbiNLxk/ve78HJpSnB8yYKtSd80=", + "dev": true, "optional": true, "requires": { "co": "~3.0.6", @@ -2595,6 +2939,7 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/co/-/co-3.0.6.tgz", "integrity": "sha1-FEXyJsXrlWE45oyawwFn6n0ua9o=", + "dev": true, "optional": true } } @@ -2603,6 +2948,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, "requires": { "glob-base": "^0.3.0", "is-dotfile": "^1.0.0", @@ -2614,6 +2960,7 @@ "version": "0.0.5", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, "requires": { "better-assert": "~1.0.0" } @@ -2622,6 +2969,7 @@ "version": "0.0.5", "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, "requires": { "better-assert": "~1.0.0" } @@ -2629,17 +2977,20 @@ "parseurl": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=", + "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "path-proxy": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz", "integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=", + "dev": true, "optional": true, "requires": { "inflection": "~1.3.0" @@ -2649,6 +3000,7 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz", "integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4=", + "dev": true, "optional": true } } @@ -2656,17 +3008,20 @@ "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true }, "phantomjs-prebuilt": { "version": "2.1.16", "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.16.tgz", "integrity": "sha1-79ISpKOWbTZHaE6ouniFSb4q7+8=", + "dev": true, "requires": { "es6-promise": "^4.0.3", "extract-zip": "^1.6.5", @@ -2682,12 +3037,14 @@ "pinkie": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true }, "pinkie-promise": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, "requires": { "pinkie": "^2.0.0" } @@ -2695,27 +3052,32 @@ "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true }, "preserve": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true }, "progress": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=" + "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", + "dev": true }, "proxy-agent": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-2.0.0.tgz", "integrity": "sha1-V+tTR6qAXXTsaByyVknbo5yTNJk=", + "dev": true, "optional": true, "requires": { "agent-base": "2", @@ -2731,28 +3093,33 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true }, "q": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=", + "dev": true, "optional": true }, "qjobs": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", - "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==" + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true }, "qs": { "version": "6.5.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", + "dev": true }, "randomatic": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz", "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==", + "dev": true, "requires": { "is-number": "^4.0.0", "kind-of": "^6.0.0", @@ -2762,24 +3129,28 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true } } }, "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=", + "dev": true }, "raw-body": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "dev": true, "requires": { "bytes": "3.0.0", "http-errors": "1.6.2", @@ -2790,12 +3161,14 @@ "depd": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=", + "dev": true }, "http-errors": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "dev": true, "requires": { "depd": "1.1.1", "inherits": "2.0.3", @@ -2806,7 +3179,8 @@ "setprototypeof": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=", + "dev": true } } }, @@ -2814,6 +3188,7 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -2828,6 +3203,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "minimatch": "^3.0.2", @@ -2839,6 +3215,7 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "dev": true, "optional": true, "requires": { "double-ended-queue": "^2.1.0-0", @@ -2850,18 +3227,21 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.5.tgz", "integrity": "sha512-foGF8u6MXGFF++1TZVC6icGXuMYPftKXt1FBT2vrfU9ZATNtZJ8duRC5d1lEfE8hyVe3jhelHGB91oB7I6qLsA==", + "dev": true, "optional": true }, "redis-parser": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", + "dev": true, "optional": true }, "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, "requires": { "is-equal-shallow": "^0.1.3" } @@ -2869,22 +3249,26 @@ "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true }, "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true }, "request": { "version": "2.85.0", "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.6.0", @@ -2914,6 +3298,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", "integrity": "sha1-XTa7V5YcZzqlt4jbyBQf3yO0Tgg=", + "dev": true, "requires": { "throttleit": "^1.0.0" } @@ -2922,6 +3307,7 @@ "version": "1.13.0", "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", + "dev": true, "optional": true, "requires": { "extend": "^3.0.0", @@ -2933,12 +3319,14 @@ "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, "requires": { "glob": "^7.0.5" } @@ -2946,27 +3334,32 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true }, "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true }, "set-immediate-shim": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true }, "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true }, "slack-node": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/slack-node/-/slack-node-0.2.0.tgz", "integrity": "sha1-3kuN3aqLeT9h29KTgQT9q/N9+jA=", + "dev": true, "optional": true, "requires": { "requestretry": "^1.2.2" @@ -2975,12 +3368,14 @@ "smart-buffer": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", - "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=" + "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=", + "dev": true }, "smtp-connection": { "version": "2.12.0", "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", + "dev": true, "requires": { "httpntlm": "1.6.1", "nodemailer-shared": "1.1.0" @@ -2990,6 +3385,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "dev": true, "requires": { "hoek": "4.x.x" } @@ -2998,6 +3394,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", + "dev": true, "requires": { "debug": "~2.6.6", "engine.io": "~3.1.0", @@ -3009,12 +3406,14 @@ "socket.io-adapter": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.1.tgz", - "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=" + "integrity": "sha1-KoBeihTWNyEk3ZFZrUUC+MsH8Gs=", + "dev": true }, "socket.io-client": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", + "dev": true, "requires": { "backo2": "1.0.2", "base64-arraybuffer": "0.1.5", @@ -3035,6 +3434,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.3.tgz", "integrity": "sha512-g0a2HPqLguqAczs3dMECuA1RgoGFPyvDqcbaDEdCWY9g59kdUAz3YRmaJBNKXflrHNwB7Q12Gkf/0CZXfdHR7g==", + "dev": true, "requires": { "component-emitter": "1.2.1", "debug": "~3.1.0", @@ -3046,6 +3446,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -3053,7 +3454,8 @@ "isarray": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", - "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=" + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true } } }, @@ -3061,6 +3463,7 @@ "version": "1.1.10", "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=", + "dev": true, "requires": { "ip": "^1.1.4", "smart-buffer": "^1.0.13" @@ -3069,7 +3472,8 @@ "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true } } }, @@ -3077,6 +3481,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz", "integrity": "sha512-sFtmYqdUK5dAMh85H0LEVFUCO7OhJJe1/z2x/Z6mxp3s7/QPf1RkZmpZy+BpuU0bEjcV9npqKjq9Y3kwFUjnxw==", + "dev": true, "requires": { "agent-base": "2", "extend": "3", @@ -3086,12 +3491,14 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true }, "sshpk": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", + "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -3106,12 +3513,14 @@ "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true }, "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "dev": true, "requires": { "date-format": "^1.2.0", "debug": "^3.1.0", @@ -3123,6 +3532,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -3133,6 +3543,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -3140,44 +3551,66 @@ "stringstream": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, "optional": true, "requires": { "ansi-regex": "^2.0.0" } }, + "stryker-api": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.17.0.tgz", + "integrity": "sha512-CJKAx+D8ztmXtnORk0bKfrccIbeAOXcKZ2pQpevvj7SFZJKlF8PRQy8lkgP5kvTK/sKidQp84kHjiqyRvf634A==", + "dev": true, + "requires": { + "tslib": "^1.6.0" + } + }, + "stryker-jasmine": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/stryker-jasmine/-/stryker-jasmine-0.8.4.tgz", + "integrity": "sha512-25W2S3eCaN62p41GY+pbsp+3Ny7gS1oQfI1bX2LtWoFly6Iyi23C4EjrngQx+8gU0pZ05Of8t3LSMGQKibQk6Q==", + "dev": true + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, "optional": true }, "throttleit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", - "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=" + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "dev": true }, "thunkify": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", + "dev": true, "optional": true }, "timespan": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=", + "dev": true, "optional": true }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, "requires": { "os-tmpdir": "~1.0.2" } @@ -3185,12 +3618,14 @@ "to-array": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", - "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=" + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true }, "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, "requires": { "punycode": "^1.4.1" } @@ -3204,12 +3639,14 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz", "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc=", + "dev": true, "optional": true }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -3218,12 +3655,14 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, "optional": true }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, "requires": { "prelude-ls": "~1.1.2" } @@ -3232,6 +3671,7 @@ "version": "1.6.16", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", + "dev": true, "requires": { "media-typer": "0.3.0", "mime-types": "~2.1.18" @@ -3240,27 +3680,32 @@ "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true }, "ultron": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", - "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true }, "underscore": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", + "dev": true }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true }, "useragent": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz", "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=", + "dev": true, "requires": { "lru-cache": "2.2.x", "tmp": "0.0.x" @@ -3269,35 +3714,41 @@ "lru-cache": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz", - "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=" + "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=", + "dev": true } } }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true }, "uuid": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "dev": true }, "uws": { "version": "9.14.0", "resolved": "https://registry.npmjs.org/uws/-/uws-9.14.0.tgz", "integrity": "sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg==", + "dev": true, "optional": true }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -3307,18 +3758,21 @@ "void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true }, "when": { "version": "3.7.8", "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "dev": true, "optional": true }, "which": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -3327,17 +3781,20 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true, "optional": true }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "ws": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, "requires": { "async-limiter": "~1.0.0", "safe-buffer": "~5.1.0", @@ -3347,24 +3804,28 @@ "xmlhttprequest-ssl": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", - "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true }, "xregexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true, "optional": true }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true, "optional": true }, "yauzl": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz", "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", + "dev": true, "requires": { "fd-slicer": "~1.0.1" } @@ -3372,7 +3833,8 @@ "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true } } } diff --git a/packages/stryker-karma-runner/package.json b/packages/stryker-karma-runner/package.json index 8dc9c58110..7636fbc587 100644 --- a/packages/stryker-karma-runner/package.json +++ b/packages/stryker-karma-runner/package.json @@ -35,6 +35,7 @@ "stryker-api": ">=0.15.0 <0.18.0" }, "devDependencies": { + "@types/express": "^4.11.1", "jasmine-core": "^2.4.1", "karma": "^2.0.0", "karma-jasmine": "^1.1.2", @@ -43,7 +44,6 @@ "stryker-jasmine": "^0.8.4" }, "dependencies": { - "log4js": "^1.0.1", "tslib": "^1.6.1" }, "contributors": [ diff --git a/packages/stryker-karma-runner/src/KarmaConfigReader.ts b/packages/stryker-karma-runner/src/KarmaConfigReader.ts index acbbe60f14..ee2cdf79ef 100644 --- a/packages/stryker-karma-runner/src/KarmaConfigReader.ts +++ b/packages/stryker-karma-runner/src/KarmaConfigReader.ts @@ -1,4 +1,4 @@ -import * as log4js from 'log4js'; +import * as logging from 'stryker-api/logging'; import * as path from 'path'; import * as karma from 'karma'; import { requireModule } from './utils'; @@ -7,13 +7,13 @@ const karmaConfigReaderLocation = 'karma/lib/config'; export default class KarmaConfigReader { - private readonly log: log4js.Logger; + private readonly log: logging.Logger; constructor(private karmaConfigFile: string | undefined) { if (this.karmaConfigFile) { this.karmaConfigFile = path.resolve(this.karmaConfigFile); } - this.log = log4js.getLogger('KarmaConfigReader'); + this.log = logging.getLogger('KarmaConfigReader'); } read(): karma.ConfigOptions | null { @@ -60,9 +60,9 @@ export default class KarmaConfigReader { class Config implements karma.ConfigOptions { [key: string]: any - + autoWatch: boolean = false; - + readonly LOG_DISABLE = 'OFF'; readonly LOG_ERROR = 'ERROR'; readonly LOG_WARN = 'WARN'; diff --git a/packages/stryker-karma-runner/src/KarmaTestRunner.ts b/packages/stryker-karma-runner/src/KarmaTestRunner.ts index 712678f757..019fa0de00 100644 --- a/packages/stryker-karma-runner/src/KarmaTestRunner.ts +++ b/packages/stryker-karma-runner/src/KarmaTestRunner.ts @@ -1,11 +1,10 @@ -import * as log4js from 'log4js'; +import * as logging from 'stryker-api/logging'; import { TestRunner, TestResult, TestStatus, RunStatus, RunResult, RunnerOptions, CoverageCollection, CoveragePerTestResult } from 'stryker-api/test_runner'; import * as karma from 'karma'; import * as rawCoverageReporter from './RawCoverageReporter'; import { KARMA_CONFIG, KARMA_CONFIG_FILE } from './configKeys'; import TestHooksMiddleware, { TEST_HOOKS_FILE_NAME } from './TestHooksMiddleware'; import { touchSync } from './utils'; -import { setGlobalLogLevel } from 'log4js'; import KarmaConfigReader from './KarmaConfigReader'; export interface ConfigOptions extends karma.ConfigOptions { @@ -48,7 +47,7 @@ function defaultOptions(): Readonly { export default class KarmaTestRunner implements TestRunner { - private log = log4js.getLogger(KarmaTestRunner.name); + private log = logging.getLogger(KarmaTestRunner.name); private server: karma.Server; private serverStartedPromise: Promise; private currentTestResults: TestResult[]; @@ -58,7 +57,6 @@ export default class KarmaTestRunner implements TestRunner { private readonly testHooksMiddleware = new TestHooksMiddleware(); constructor(private options: RunnerOptions) { - setGlobalLogLevel(options.strykerOptions.logLevel || 'info'); let karmaConfig = this.readConfig(options); karmaConfig = this.configureTestRunner(karmaConfig); karmaConfig = this.configureCoverageIfEnabled(karmaConfig); diff --git a/packages/stryker-karma-runner/test/unit/KarmaConfigReaderSpec.ts b/packages/stryker-karma-runner/test/unit/KarmaConfigReaderSpec.ts index 5ae03198bd..f196ff5e32 100644 --- a/packages/stryker-karma-runner/test/unit/KarmaConfigReaderSpec.ts +++ b/packages/stryker-karma-runner/test/unit/KarmaConfigReaderSpec.ts @@ -1,6 +1,6 @@ import * as sinon from 'sinon'; import { expect } from 'chai'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; const cfg: { parseConfig: sinon.SinonStub } = require('karma/lib/config'); import KarmaConfigReader from '../../src/KarmaConfigReader'; import LoggerStub from '../helpers/LoggerStub'; diff --git a/packages/stryker-mocha-framework/package-lock.json b/packages/stryker-mocha-framework/package-lock.json index 0ce8ae95d9..ef9f347575 100644 --- a/packages/stryker-mocha-framework/package-lock.json +++ b/packages/stryker-mocha-framework/package-lock.json @@ -1,106 +1,23 @@ { - "requires": true, + "name": "stryker-mocha-framework", + "version": "0.10.0", "lockfileVersion": 1, + "requires": true, "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "date-format": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", - "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "log4js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-1.1.1.tgz", - "integrity": "sha1-wh0px2BAieTyVYM+f5SzRh3h/0M=", - "requires": { - "debug": "^2.2.0", - "semver": "^5.3.0", - "streamroller": "^0.4.0" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "stryker-api": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.17.0.tgz", + "integrity": "sha512-CJKAx+D8ztmXtnORk0bKfrccIbeAOXcKZ2pQpevvj7SFZJKlF8PRQy8lkgP5kvTK/sKidQp84kHjiqyRvf634A==", + "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "tslib": "^1.6.0" } }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - }, - "streamroller": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.4.1.tgz", - "integrity": "sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8=", - "requires": { - "date-format": "^0.0.0", - "debug": "^0.7.2", - "mkdirp": "^0.5.1", - "readable-stream": "^1.1.7" - }, - "dependencies": { - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" - } - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - }, "tslib": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", - "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==" + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "dev": true } } } diff --git a/packages/stryker-mocha-framework/package.json b/packages/stryker-mocha-framework/package.json index 4ac188533b..95edf31f09 100644 --- a/packages/stryker-mocha-framework/package.json +++ b/packages/stryker-mocha-framework/package.json @@ -36,9 +36,7 @@ ], "homepage": "https://github.com/stryker-mutator/stryker/tree/master/packages/stryker-mocha-framework#readme", "license": "Apache-2.0", - "dependencies": { - "log4js": "^1.1.1" - }, + "dependencies": {}, "devDependencies": { "stryker-api": "^0.17.0", "tslib": "^1.5.0" diff --git a/packages/stryker-mocha-runner/package-lock.json b/packages/stryker-mocha-runner/package-lock.json index 7b694a884b..a9f6980b0a 100644 --- a/packages/stryker-mocha-runner/package-lock.json +++ b/packages/stryker-mocha-runner/package-lock.json @@ -1,11 +1,14 @@ { - "requires": true, + "name": "stryker-mocha-runner", + "version": "0.12.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@types/multimatch": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@types/multimatch/-/multimatch-2.1.2.tgz", - "integrity": "sha512-2WC+kyYTb1HATEVdVuBerAx+iHnGl8xlnOEjhi791BI94pxtWMk322gVLrvBArogrB229MfIDX2n1G1KglbGMg==" + "integrity": "sha512-2WC+kyYTb1HATEVdVuBerAx+iHnGl8xlnOEjhi791BI94pxtWMk322gVLrvBArogrB229MfIDX2n1G1KglbGMg==", + "dev": true }, "array-differ": { "version": "1.0.0", @@ -52,17 +55,20 @@ "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "date-format": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", - "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=" + "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=", + "dev": true }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -70,17 +76,20 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true }, "log4js": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/log4js/-/log4js-1.1.1.tgz", "integrity": "sha1-wh0px2BAieTyVYM+f5SzRh3h/0M=", + "dev": true, "requires": { "debug": "^2.2.0", "semver": "^5.3.0", @@ -98,12 +107,14 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true }, "mkdirp": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, "requires": { "minimist": "0.0.8" } @@ -111,7 +122,8 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true }, "multimatch": { "version": "2.1.0", @@ -128,6 +140,7 @@ "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -138,12 +151,14 @@ "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true }, "streamroller": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.4.1.tgz", "integrity": "sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8=", + "dev": true, "requires": { "date-format": "^0.0.0", "debug": "^0.7.2", @@ -154,14 +169,34 @@ "debug": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", + "dev": true } } }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "stryker-api": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.17.0.tgz", + "integrity": "sha512-CJKAx+D8ztmXtnORk0bKfrccIbeAOXcKZ2pQpevvj7SFZJKlF8PRQy8lkgP5kvTK/sKidQp84kHjiqyRvf634A==", + "dev": true, + "requires": { + "tslib": "^1.6.0" + } + }, + "stryker-mocha-framework": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/stryker-mocha-framework/-/stryker-mocha-framework-0.10.0.tgz", + "integrity": "sha512-VRHi7H4HVvzmoUvQyKm20XZyMDey4OEbdLMsN1bCv5YG8NKDhafxgQiiDBCHQphzcwt2XYRELeZHlVgwYoqrFQ==", + "dev": true, + "requires": { + "log4js": "^1.1.1" + } }, "tslib": { "version": "1.9.0", diff --git a/packages/stryker-mocha-runner/package.json b/packages/stryker-mocha-runner/package.json index 8a08cce1f7..741e492343 100644 --- a/packages/stryker-mocha-runner/package.json +++ b/packages/stryker-mocha-runner/package.json @@ -35,7 +35,6 @@ }, "homepage": "https://github.com/stryker-mutator/stryker/tree/master/packages/stryker-mocha-runner#readme", "dependencies": { - "log4js": "^1.1.1", "multimatch": "^2.1.0", "tslib": "^1.5.0" }, diff --git a/packages/stryker-mocha-runner/src/MochaConfigEditor.ts b/packages/stryker-mocha-runner/src/MochaConfigEditor.ts index ce09a6f54e..a5f9c7ece6 100644 --- a/packages/stryker-mocha-runner/src/MochaConfigEditor.ts +++ b/packages/stryker-mocha-runner/src/MochaConfigEditor.ts @@ -1,11 +1,9 @@ import { ConfigEditor, Config } from 'stryker-api/config'; import { mochaOptionsKey } from './MochaRunnerOptions'; import MochaOptionsLoader from './MochaOptionsLoader'; -import { setGlobalLogLevel } from 'log4js'; export default class MochaConfigEditor implements ConfigEditor { edit(config: Config): void { - setGlobalLogLevel(config.logLevel || 'info'); config[mochaOptionsKey] = new MochaOptionsLoader().load(config); } } \ No newline at end of file diff --git a/packages/stryker-mocha-runner/src/MochaOptionsLoader.ts b/packages/stryker-mocha-runner/src/MochaOptionsLoader.ts index 0e9097e515..78e2f82598 100644 --- a/packages/stryker-mocha-runner/src/MochaOptionsLoader.ts +++ b/packages/stryker-mocha-runner/src/MochaOptionsLoader.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import * as fs from 'fs'; import { StrykerOptions } from 'stryker-api/core'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import MochaRunnerOptions, { mochaOptionsKey } from './MochaRunnerOptions'; export default class MochaOptionsLoader { diff --git a/packages/stryker-mocha-runner/src/MochaTestRunner.ts b/packages/stryker-mocha-runner/src/MochaTestRunner.ts index 4ac8dd3c65..371ab13ec6 100644 --- a/packages/stryker-mocha-runner/src/MochaTestRunner.ts +++ b/packages/stryker-mocha-runner/src/MochaTestRunner.ts @@ -1,4 +1,4 @@ -import { getLogger, setGlobalLogLevel } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import * as path from 'path'; import { TestRunner, RunResult, RunStatus, RunnerOptions } from 'stryker-api/test_runner'; import LibWrapper from './LibWrapper'; @@ -16,7 +16,6 @@ export default class MochaTestRunner implements TestRunner { private mochaRunnerOptions: MochaRunnerOptions; constructor(runnerOptions: RunnerOptions) { - setGlobalLogLevel(runnerOptions.strykerOptions.logLevel || 'info'); this.mochaRunnerOptions = runnerOptions.strykerOptions[mochaOptionsKey]; this.allFileNames = runnerOptions.fileNames; this.additionalRequires(); diff --git a/packages/stryker-mocha-runner/src/StrykerMochaReporter.ts b/packages/stryker-mocha-runner/src/StrykerMochaReporter.ts index c7fa9e54cf..3cb7a4a980 100644 --- a/packages/stryker-mocha-runner/src/StrykerMochaReporter.ts +++ b/packages/stryker-mocha-runner/src/StrykerMochaReporter.ts @@ -1,5 +1,5 @@ import { RunResult, RunStatus, TestStatus } from 'stryker-api/test_runner'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; import Timer from './Timer'; const log = log4js.getLogger('StrykerMochaReporter'); diff --git a/packages/stryker-mocha-runner/test/helpers/mockHelpers.ts b/packages/stryker-mocha-runner/test/helpers/mockHelpers.ts index 6ef8b41ce5..0018ccc696 100644 --- a/packages/stryker-mocha-runner/test/helpers/mockHelpers.ts +++ b/packages/stryker-mocha-runner/test/helpers/mockHelpers.ts @@ -1,5 +1,5 @@ import * as sinon from 'sinon'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { RunnerOptions } from 'stryker-api/test_runner'; export type Mock = { @@ -13,8 +13,6 @@ export function mock(constructorFn: { new(...args: any[]): T; }): Mock { export function logger(): Mock { return { - setLevel: sinon.stub(), - isLevelEnabled: sinon.stub(), trace: sinon.stub(), isTraceEnabled: sinon.stub(), debug: sinon.stub(), diff --git a/packages/stryker-mocha-runner/test/unit/MochaOptionsLoaderSpec.ts b/packages/stryker-mocha-runner/test/unit/MochaOptionsLoaderSpec.ts index 503a6c83f1..857ce7efe6 100644 --- a/packages/stryker-mocha-runner/test/unit/MochaOptionsLoaderSpec.ts +++ b/packages/stryker-mocha-runner/test/unit/MochaOptionsLoaderSpec.ts @@ -3,7 +3,7 @@ import * as fs from 'fs'; import { Config } from 'stryker-api/config'; import MochaOptionsLoader from '../../src/MochaOptionsLoader'; import { expect } from 'chai'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; import MochaRunnerOptions from '../../src/MochaRunnerOptions'; import { logger, Mock } from '../helpers/mockHelpers'; diff --git a/packages/stryker-mocha-runner/test/unit/MochaTestRunnerSpec.ts b/packages/stryker-mocha-runner/test/unit/MochaTestRunnerSpec.ts index f14ee8b0fb..063cdf8a66 100644 --- a/packages/stryker-mocha-runner/test/unit/MochaTestRunnerSpec.ts +++ b/packages/stryker-mocha-runner/test/unit/MochaTestRunnerSpec.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import { EventEmitter } from 'events'; import * as Mocha from 'mocha'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; import { expect } from 'chai'; import { RunOptions } from 'stryker-api/test_runner'; import MochaTestRunner from '../../src/MochaTestRunner'; diff --git a/packages/stryker-mutator-specification/package-lock.json b/packages/stryker-mutator-specification/package-lock.json new file mode 100644 index 0000000000..05f41519b2 --- /dev/null +++ b/packages/stryker-mutator-specification/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "stryker-mutator-specification", + "version": "0.3.0", + "lockfileVersion": 1 +} diff --git a/packages/stryker-mutator-specification/package.json b/packages/stryker-mutator-specification/package.json index e2c09d3733..4d1acf6148 100644 --- a/packages/stryker-mutator-specification/package.json +++ b/packages/stryker-mutator-specification/package.json @@ -23,5 +23,6 @@ "node": ">=6" }, "homepage": "https://github.com/stryker-mutator/stryker/tree/master/packages/stryker-javascript-mutator#readme", - "license": "Apache-2.0" + "license": "Apache-2.0", + "dependencies": {} } diff --git a/packages/stryker-typescript/package-lock.json b/packages/stryker-typescript/package-lock.json index 7d1b1e588b..7a27c1eda1 100644 --- a/packages/stryker-typescript/package-lock.json +++ b/packages/stryker-typescript/package-lock.json @@ -1,16 +1,20 @@ { - "requires": true, + "name": "stryker-typescript", + "version": "0.11.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@types/lodash": { "version": "4.14.108", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.108.tgz", - "integrity": "sha512-WD2vUOKfBBVHxWUV9iMR9RMfpuf8HquxWeAq2yqGVL7Nc4JW2+sQama0pREMqzNI3Tutj0PyxYUJwuoxxvX+xA==" + "integrity": "sha512-WD2vUOKfBBVHxWUV9iMR9RMfpuf8HquxWeAq2yqGVL7Nc4JW2+sQama0pREMqzNI3Tutj0PyxYUJwuoxxvX+xA==", + "dev": true }, "@types/lodash.flatmap": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/@types/lodash.flatmap/-/lodash.flatmap-4.5.3.tgz", "integrity": "sha512-0+aQVPOiJgcYoo87AyUW12HxbOL+ApPAAVpwzzMJgyEYu8dev8OPLT6tp7FKLK4F3wlfcAqwdiYT+0R4xe9aiQ==", + "dev": true, "requires": { "@types/lodash": "*" } @@ -18,112 +22,39 @@ "@types/semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "date-format": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", - "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==", + "dev": true }, "lodash.flatmap": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.flatmap/-/lodash.flatmap-4.5.0.tgz", "integrity": "sha1-74y/QI9uSCaGYzRTBcaswLd4cC4=" }, - "log4js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-1.1.1.tgz", - "integrity": "sha1-wh0px2BAieTyVYM+f5SzRh3h/0M=", - "requires": { - "debug": "^2.2.0", - "semver": "^5.3.0", - "streamroller": "^0.4.0" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, "semver": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" }, - "streamroller": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.4.1.tgz", - "integrity": "sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8=", + "stryker-api": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.17.0.tgz", + "integrity": "sha512-CJKAx+D8ztmXtnORk0bKfrccIbeAOXcKZ2pQpevvj7SFZJKlF8PRQy8lkgP5kvTK/sKidQp84kHjiqyRvf634A==", + "dev": true, "requires": { - "date-format": "^0.0.0", - "debug": "^0.7.2", - "mkdirp": "^0.5.1", - "readable-stream": "^1.1.7" - }, - "dependencies": { - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" - } + "tslib": "^1.6.0" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "stryker-mutator-specification": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/stryker-mutator-specification/-/stryker-mutator-specification-0.3.0.tgz", + "integrity": "sha512-8uNnV8Pr2XuoXZNQeUa7RdtNJ6yHzjrgPau+pTO9xiMGM1Q0uYEifYkOoZffB7NdximYu1FIsVCT76pJKmORug==", + "dev": true }, "surrial": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/surrial/-/surrial-0.1.3.tgz", - "integrity": "sha512-Iqfqc9luWn/4r9gHxe3XifYQaVne09TP2hMFQwXSRw4WpfMjNZkZQQjFSzatvrw+MgynEuOZlsB24m0zHNVEBA==" + "integrity": "sha512-Iqfqc9luWn/4r9gHxe3XifYQaVne09TP2hMFQwXSRw4WpfMjNZkZQQjFSzatvrw+MgynEuOZlsB24m0zHNVEBA==", + "dev": true }, "tslib": { "version": "1.9.0", diff --git a/packages/stryker-typescript/package.json b/packages/stryker-typescript/package.json index ace1a1ea9d..8127f92e4a 100644 --- a/packages/stryker-typescript/package.json +++ b/packages/stryker-typescript/package.json @@ -38,7 +38,6 @@ "license": "Apache-2.0", "dependencies": { "lodash.flatmap": "^4.5.0", - "log4js": "^1.1.1", "semver": "^5.4.1", "tslib": "^1.5.0" }, diff --git a/packages/stryker-typescript/src/TypescriptConfigEditor.ts b/packages/stryker-typescript/src/TypescriptConfigEditor.ts index 61fc68b289..345c9fb9a1 100644 --- a/packages/stryker-typescript/src/TypescriptConfigEditor.ts +++ b/packages/stryker-typescript/src/TypescriptConfigEditor.ts @@ -1,7 +1,7 @@ import * as os from 'os'; import * as path from 'path'; import * as ts from 'typescript'; -import { getLogger, setGlobalLogLevel } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { ConfigEditor, Config } from 'stryker-api/config'; import { CONFIG_KEY_FILE, CONFIG_KEY } from './helpers/keys'; import * as fs from 'fs'; @@ -20,7 +20,6 @@ export default class TypescriptConfigEditor implements ConfigEditor { private log = getLogger(TypescriptConfigEditor.name); edit(strykerConfig: Config, host: ts.ParseConfigHost = ts.sys) { - setGlobalLogLevel(strykerConfig.logLevel); this.loadTSConfig(strykerConfig, host); } diff --git a/packages/stryker-typescript/src/TypescriptTranspiler.ts b/packages/stryker-typescript/src/TypescriptTranspiler.ts index 610dfc4e8e..d0a4e9a9e3 100644 --- a/packages/stryker-typescript/src/TypescriptTranspiler.ts +++ b/packages/stryker-typescript/src/TypescriptTranspiler.ts @@ -5,7 +5,6 @@ import { Transpiler, TranspilerOptions } from 'stryker-api/transpile'; import { File } from 'stryker-api/core'; import { getTSConfig, getProjectDirectory, guardTypescriptVersion, isHeaderFile } from './helpers/tsHelpers'; import TranspilingLanguageService from './transpiler/TranspilingLanguageService'; -import { setGlobalLogLevel } from 'log4js'; import TranspileFilter from './transpiler/TranspileFilter'; export default class TypescriptTranspiler implements Transpiler { @@ -16,7 +15,6 @@ export default class TypescriptTranspiler implements Transpiler { constructor(options: TranspilerOptions) { guardTypescriptVersion(); - setGlobalLogLevel(options.config.logLevel); this.config = options.config; this.produceSourceMaps = options.produceSourceMaps; this.filter = TranspileFilter.create(this.config); diff --git a/packages/stryker-typescript/src/transpiler/TranspilingLanguageService.ts b/packages/stryker-typescript/src/transpiler/TranspilingLanguageService.ts index 8f80c5759f..80ea868731 100644 --- a/packages/stryker-typescript/src/transpiler/TranspilingLanguageService.ts +++ b/packages/stryker-typescript/src/transpiler/TranspilingLanguageService.ts @@ -2,7 +2,7 @@ import * as os from 'os'; import * as path from 'path'; import * as fs from 'fs'; import * as ts from 'typescript'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import flatMap = require('lodash.flatmap'); import ScriptFile from './ScriptFile'; import { normalizeFileFromTypescript, isJavaScriptFile, isMapFile, normalizeFileForTypescript } from '../helpers/tsHelpers'; diff --git a/packages/stryker-typescript/test/helpers/producers.ts b/packages/stryker-typescript/test/helpers/producers.ts index 81a1f50b48..2991148acd 100644 --- a/packages/stryker-typescript/test/helpers/producers.ts +++ b/packages/stryker-typescript/test/helpers/producers.ts @@ -1,5 +1,5 @@ import * as sinon from 'sinon'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; export type Mock = { [P in keyof T]: sinon.SinonStub; @@ -13,8 +13,6 @@ export function mock(constructorFn: Constructor): Mock { export const logger = (): Mock => { return { - setLevel: sinon.stub(), - isLevelEnabled: sinon.stub(), isTraceEnabled: sinon.stub(), isDebugEnabled: sinon.stub(), isInfoEnabled: sinon.stub(), diff --git a/packages/stryker-typescript/test/integration/allowJS.it.ts b/packages/stryker-typescript/test/integration/allowJS.it.ts index efd61f2528..232c06c11d 100644 --- a/packages/stryker-typescript/test/integration/allowJS.it.ts +++ b/packages/stryker-typescript/test/integration/allowJS.it.ts @@ -2,7 +2,6 @@ import * as path from 'path'; import * as fs from 'fs'; import { Config } from 'stryker-api/config'; import TypescriptConfigEditor from '../../src/TypescriptConfigEditor'; -import { setGlobalLogLevel } from 'log4js'; import { File } from 'stryker-api/core'; import { CONFIG_KEY } from '../../src/helpers/keys'; import TypescriptTranspiler from '../../src/TypescriptTranspiler'; @@ -15,7 +14,6 @@ describe('AllowJS integration', function () { let inputFiles: File[]; beforeEach(() => { - setGlobalLogLevel('error'); const configEditor = new TypescriptConfigEditor(); config = new Config(); config.set({ @@ -24,10 +22,6 @@ describe('AllowJS integration', function () { configEditor.edit(config); inputFiles = config[CONFIG_KEY].fileNames.map((fileName: string) => new File(fileName, fs.readFileSync(fileName, 'utf8'))); }); - - afterEach(() => { - setGlobalLogLevel('trace'); - }); it('should be able to transpile source code', async () => { const transpiler = new TypescriptTranspiler({ config, produceSourceMaps: false }); diff --git a/packages/stryker-typescript/test/integration/ownDogFoodSpec.ts b/packages/stryker-typescript/test/integration/ownDogFoodSpec.ts index 6d9c75cc4b..6bd3286b8c 100644 --- a/packages/stryker-typescript/test/integration/ownDogFoodSpec.ts +++ b/packages/stryker-typescript/test/integration/ownDogFoodSpec.ts @@ -5,7 +5,6 @@ import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; import TypescriptConfigEditor from '../../src/TypescriptConfigEditor'; import TypescriptTranspiler from '../../src/TypescriptTranspiler'; -import { setGlobalLogLevel } from 'log4js'; import { CONFIG_KEY } from '../../src/helpers/keys'; describe('stryker-typescript', function () { @@ -15,7 +14,6 @@ describe('stryker-typescript', function () { let inputFiles: File[]; beforeEach(() => { - setGlobalLogLevel('error'); const configEditor = new TypescriptConfigEditor(); config = new Config(); config.set({ @@ -25,10 +23,6 @@ describe('stryker-typescript', function () { inputFiles = config[CONFIG_KEY].fileNames.map((fileName: string) => new File(fileName, fs.readFileSync(fileName, 'utf8'))); }); - afterEach(() => { - setGlobalLogLevel('trace'); - }); - it('should be able to transpile itself', async () => { const transpiler = new TypescriptTranspiler({ config, produceSourceMaps: true }); const outputFiles = await transpiler.transpile(inputFiles); diff --git a/packages/stryker-typescript/test/integration/sampleSpec.ts b/packages/stryker-typescript/test/integration/sampleSpec.ts index 4845e6986f..5d6c98faaa 100644 --- a/packages/stryker-typescript/test/integration/sampleSpec.ts +++ b/packages/stryker-typescript/test/integration/sampleSpec.ts @@ -7,7 +7,6 @@ import { File } from 'stryker-api/core'; import TypescriptConfigEditor from '../../src/TypescriptConfigEditor'; import TypescriptMutator from '../../src/TypescriptMutator'; import TypescriptTranspiler from '../../src/TypescriptTranspiler'; -import { setGlobalLogLevel } from 'log4js'; import { CONFIG_KEY } from '../../src/helpers/keys'; describe('Sample integration', function () { @@ -17,7 +16,6 @@ describe('Sample integration', function () { let inputFiles: File[]; beforeEach(() => { - setGlobalLogLevel('error'); const configEditor = new TypescriptConfigEditor(); config = new Config(); config.set({ @@ -27,10 +25,6 @@ describe('Sample integration', function () { inputFiles = config[CONFIG_KEY].fileNames.map((fileName: string) => new File(fileName, fs.readFileSync(fileName, 'utf8'))); }); - afterEach(() => { - setGlobalLogLevel('trace'); - }); - it('should be able to generate mutants', () => { // Generate mutants const mutator = new TypescriptMutator(config); diff --git a/packages/stryker-typescript/test/integration/useHeaderFile.ts b/packages/stryker-typescript/test/integration/useHeaderFile.ts index 74aac8cb0b..dbe8fdba2c 100644 --- a/packages/stryker-typescript/test/integration/useHeaderFile.ts +++ b/packages/stryker-typescript/test/integration/useHeaderFile.ts @@ -5,7 +5,6 @@ import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; import TypescriptConfigEditor from '../../src/TypescriptConfigEditor'; import TypescriptTranspiler from '../../src/TypescriptTranspiler'; -import { setGlobalLogLevel } from 'log4js'; import { CONFIG_KEY } from '../../src/helpers/keys'; describe('Use header file integration', function () { @@ -14,7 +13,6 @@ describe('Use header file integration', function () { let inputFiles: File[]; beforeEach(() => { - setGlobalLogLevel('error'); const configEditor = new TypescriptConfigEditor(); config = new Config(); config.set({ @@ -24,10 +22,6 @@ describe('Use header file integration', function () { inputFiles = config[CONFIG_KEY].fileNames.map((fileName: string) => new File(fileName, fs.readFileSync(fileName, 'utf8'))); }); - afterEach(() => { - setGlobalLogLevel('trace'); - }); - it('should be able to transpile source code', async () => { const transpiler = new TypescriptTranspiler({ config, produceSourceMaps: false }); const outputFiles = await transpiler.transpile(inputFiles); diff --git a/packages/stryker-typescript/test/unit/TypescriptConfigEditorSpec.ts b/packages/stryker-typescript/test/unit/TypescriptConfigEditorSpec.ts index 21bb17161b..8a9d726433 100644 --- a/packages/stryker-typescript/test/unit/TypescriptConfigEditorSpec.ts +++ b/packages/stryker-typescript/test/unit/TypescriptConfigEditorSpec.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; import * as ts from 'typescript'; import { expect } from 'chai'; import { SinonStub, match } from 'sinon'; diff --git a/packages/stryker-typescript/test/unit/TypescriptTranspilerSpec.ts b/packages/stryker-typescript/test/unit/TypescriptTranspilerSpec.ts index 2913684571..1a0ace81f1 100644 --- a/packages/stryker-typescript/test/unit/TypescriptTranspilerSpec.ts +++ b/packages/stryker-typescript/test/unit/TypescriptTranspilerSpec.ts @@ -1,5 +1,4 @@ import TranspilingLanguageService, * as transpilingLanguageService from '../../src/transpiler/TranspilingLanguageService'; -import * as log4js from 'log4js'; import { expect } from 'chai'; import { Mock, mock } from '../helpers/producers'; import TypescriptTranspiler from '../../src/TypescriptTranspiler'; @@ -24,13 +23,6 @@ describe('TypescriptTranspiler', () => { transpileFilterMock.isIncluded = sandbox.stub(); sandbox.stub(TranspileFilter, 'create').returns(transpileFilterMock); sandbox.stub(transpilingLanguageService, 'default').returns(languageService); - sandbox.stub(log4js, 'setGlobalLogLevel'); - }); - - it('set global log level', () => { - config.logLevel = 'foobar'; - sut = new TypescriptTranspiler({ config, produceSourceMaps: true }); - expect(log4js.setGlobalLogLevel).calledWith('foobar'); }); describe('transpile', () => { diff --git a/packages/stryker-webpack-transpiler/package-lock.json b/packages/stryker-webpack-transpiler/package-lock.json index 2b7257a2df..3758fde169 100644 --- a/packages/stryker-webpack-transpiler/package-lock.json +++ b/packages/stryker-webpack-transpiler/package-lock.json @@ -1,11 +1,14 @@ { - "requires": true, + "name": "stryker-webpack-transpiler", + "version": "0.4.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@types/memory-fs": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@types/memory-fs/-/memory-fs-0.3.0.tgz", "integrity": "sha1-hHWWqU+aloii40L0AX/MAFDo4to=", + "dev": true, "requires": { "@types/node": "*" } @@ -13,17 +16,20 @@ "@types/node": { "version": "10.0.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.0.8.tgz", - "integrity": "sha512-MFFKFv2X4iZy/NFl1m1E8uwE1CR96SGwJjgHma09PLtqOWoj3nqeJHMG+P/EuJGVLvC2I6MdQRQsr4TcRduIow==" + "integrity": "sha512-MFFKFv2X4iZy/NFl1m1E8uwE1CR96SGwJjgHma09PLtqOWoj3nqeJHMG+P/EuJGVLvC2I6MdQRQsr4TcRduIow==", + "dev": true }, "@types/tapable": { "version": "0.2.5", "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-0.2.5.tgz", - "integrity": "sha512-dEoVvo/I9QFomyhY+4Q6Qk+I+dhG59TYceZgC6Q0mCifVPErx6Y83PNTKGDS5e9h9Eti6q0S2mm16BU6iQK+3w==" + "integrity": "sha512-dEoVvo/I9QFomyhY+4Q6Qk+I+dhG59TYceZgC6Q0mCifVPErx6Y83PNTKGDS5e9h9Eti6q0S2mm16BU6iQK+3w==", + "dev": true }, "@types/uglify-js": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.0.2.tgz", "integrity": "sha512-o8hU2+4xsyGC27Vujoklvxl88Ew5zmJuTBYMX1Uro2rYUt4HEFJKL6fuq8aGykvS+ssIsIzerWWP2DRxonownQ==", + "dev": true, "requires": { "source-map": "^0.6.1" } @@ -32,6 +38,7 @@ "version": "3.8.12", "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-3.8.12.tgz", "integrity": "sha512-Q8ro/vCAyE8piwBvRgzeerrVkGy3XBmK2O2bk5g+NBHDqR0R2qZGwpBsz+js5mBH9PvvenQCojqB9nZC9Gz4MQ==", + "dev": true, "requires": { "@types/node": "*", "@types/tapable": "^0", @@ -43,6 +50,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.3.1.tgz", "integrity": "sha512-WJKy500MK6cM5LNcOjKlLHnYtTU5PcmL06iXErYriA90GLn7W/EzIyknZRx0Bj3W6FjYKTPkHADdE3GM0ZJk1Q==", + "dev": true, "requires": { "@webassemblyjs/helper-wasm-bytecode": "1.3.1", "@webassemblyjs/wast-parser": "1.3.1", @@ -52,17 +60,20 @@ "@webassemblyjs/floating-point-hex-parser": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.3.1.tgz", - "integrity": "sha512-8kCRyt0bQSnZD67UQfDTONO0jD7HCxmNUUJfT9OnVok0RWYs/AnpS83kfHtQjHucRMyx2d+YlsJWkdhXdLobqA==" + "integrity": "sha512-8kCRyt0bQSnZD67UQfDTONO0jD7HCxmNUUJfT9OnVok0RWYs/AnpS83kfHtQjHucRMyx2d+YlsJWkdhXdLobqA==", + "dev": true }, "@webassemblyjs/helper-buffer": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.3.1.tgz", - "integrity": "sha512-xIcxcfkBrrivLauyXJ57i/ArPy+kFgZjMDrxm4pSUBG2VtwwYKjOZAyjf4qsM4JbP5vRuRzMD2gp+a9WMyC3PA==" + "integrity": "sha512-xIcxcfkBrrivLauyXJ57i/ArPy+kFgZjMDrxm4pSUBG2VtwwYKjOZAyjf4qsM4JbP5vRuRzMD2gp+a9WMyC3PA==", + "dev": true }, "@webassemblyjs/helper-code-frame": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.3.1.tgz", "integrity": "sha512-X305tLl7qeTixYz0/Y0Xu+bcNizJLfHUZ1iTiVtorDkh5mLrIZ8hLkkM2oYNSq/oaoW6gpHDrHRfYZItExTeeQ==", + "dev": true, "requires": { "@webassemblyjs/wast-printer": "1.3.1" } @@ -70,17 +81,20 @@ "@webassemblyjs/helper-fsm": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.3.1.tgz", - "integrity": "sha512-Be1G8ZDTP1T+vXaVMraXY8+SoJnOVNarRkByrM83PHjW+vqUwubwYPpA4U2NBTz4WG19vYpfsUccCZwOPiyK+Q==" + "integrity": "sha512-Be1G8ZDTP1T+vXaVMraXY8+SoJnOVNarRkByrM83PHjW+vqUwubwYPpA4U2NBTz4WG19vYpfsUccCZwOPiyK+Q==", + "dev": true }, "@webassemblyjs/helper-wasm-bytecode": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.3.1.tgz", - "integrity": "sha512-rOIjy/Cmd+hspim9B/c7dUqhW8AyKsRceVcQtWljIvFSitx9rsL5m73NGaGFUVAEaMDvvEzYczehjwbrHPz4KA==" + "integrity": "sha512-rOIjy/Cmd+hspim9B/c7dUqhW8AyKsRceVcQtWljIvFSitx9rsL5m73NGaGFUVAEaMDvvEzYczehjwbrHPz4KA==", + "dev": true }, "@webassemblyjs/helper-wasm-section": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.3.1.tgz", "integrity": "sha512-mDBlDsrsl1Y7LGEdmlTzdDwr/SCe2l9ZsQZ1GYXird71jlU/0djs5ZXfxyufd1G3wO+yuxW997m50Patk4s1fA==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1", "@webassemblyjs/helper-buffer": "1.3.1", @@ -92,6 +106,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.3.1.tgz", "integrity": "sha512-CgkWUXRINTGs/+Swp8COvwOk5Ci4spv1MKDdGfRecyFiLGs7wYm/p4fgRQWzBEFaotEP/ftPa9O6BFykrwghzw==", + "dev": true, "requires": { "leb": "^0.3.0" } @@ -100,6 +115,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/validation/-/validation-1.3.1.tgz", "integrity": "sha512-afp32tgDVwW53lQc58PtIBifyZf3qGzRpl9r+8SNHzPOe6lBamjK1RWEA83YHwvu7qk6uBV7IAeUC7BgdxPtsA==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1" } @@ -108,6 +124,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.3.1.tgz", "integrity": "sha512-0T75tHKR0dIDiO3oqBZmo+2McJy5FkgSL2AIP3rJvqrDFaJ19jCrC5KLqGbqo3ZicdY9x9Xdc9zaY2A1TCkAiw==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1", "@webassemblyjs/helper-buffer": "1.3.1", @@ -124,6 +141,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -134,6 +152,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.3.1.tgz", "integrity": "sha512-iYgQ3UJpsKiJnXerHulT//JpJAHuLavqMPEtUiRnSh0r/WvZh8pNtYBaN2v64+d9yTtu9aMlJmlKi6uz1j5FFg==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1", "@webassemblyjs/helper-wasm-bytecode": "1.3.1", @@ -144,6 +163,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.3.1.tgz", "integrity": "sha512-Eqi1he5VuGxMYKGhrBU+UxUhIwTDlnuvJmwrad3k4dD2UQpqu3HedRndGdJTQ68xj2GqDCdE6QiLzjytSN4KVQ==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1", "@webassemblyjs/helper-buffer": "1.3.1", @@ -155,6 +175,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.3.1.tgz", "integrity": "sha512-euRnqP/bky9DGbXf5Nqvtmc5soOM7xkvwI2H+LSP88NAFkcGMPEnrAP4UbsFAH+ESnS4kAW6wL5UyzjWBiiTbA==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1", "@webassemblyjs/helper-wasm-bytecode": "1.3.1", @@ -167,6 +188,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.3.1.tgz", "integrity": "sha512-lM7Kwsp1mqqL3jq1kXKeoT8Z/cXvPQ2kWBNg19nZXbL1eLgr+4qRi83WvQU45+5+uIovigtBw/WU0nLLev7LGA==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1", "@webassemblyjs/floating-point-hex-parser": "1.3.1", @@ -180,6 +202,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.3.1.tgz", "integrity": "sha512-V2SMByzsrTT2wGQOjm/3ctCiy8mdYOSLDk+EkOpNHVZWB9ISJc+gZWzniTgihih03UWqqNa1S/0XpyVz7ZEYSQ==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1", "@webassemblyjs/wast-parser": "1.3.1", @@ -189,12 +212,14 @@ "acorn": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.5.3.tgz", - "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==" + "integrity": "sha512-jd5MkIUlbbmb07nXH0DT3y7rDVtkzDi4XZOUVWAer8ajmF/DTSSbl5oNFyDOl/OXA33Bl79+ypHhl2pN20VeOQ==", + "dev": true }, "acorn-dynamic-import": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz", "integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==", + "dev": true, "requires": { "acorn": "^5.0.0" } @@ -203,6 +228,7 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.0.tgz", "integrity": "sha512-VDUX1oSajablmiyFyED9L1DFndg0P9h7p1F+NO8FkIzei6EPrR6Zu1n18rd5P8PqaSRd/FrWv3G1TVBqpM83gA==", + "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -213,12 +239,14 @@ "ajv-keywords": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.2.0.tgz", - "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=" + "integrity": "sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=", + "dev": true }, "anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, "requires": { "micromatch": "^3.1.4", "normalize-path": "^2.1.1" @@ -227,32 +255,38 @@ "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true }, "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true }, "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true }, "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true }, "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true }, "asn1.js": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, "requires": { "bn.js": "^4.0.0", "inherits": "^2.0.1", @@ -263,6 +297,7 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", + "dev": true, "requires": { "util": "0.10.3" } @@ -270,27 +305,32 @@ "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true }, "async-each": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true }, "atob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=" + "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", + "dev": true }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, "requires": { "cache-base": "^1.0.1", "class-utils": "^0.3.5", @@ -305,6 +345,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -313,6 +354,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -321,6 +363,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -329,6 +372,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -340,32 +384,38 @@ "base64-js": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz", - "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==" + "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==", + "dev": true }, "big.js": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" + "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==", + "dev": true }, "binary-extensions": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", - "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=" + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "dev": true }, "bluebird": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true }, "bn.js": { "version": "4.11.8", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", - "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -375,6 +425,7 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", @@ -392,6 +443,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -401,12 +453,14 @@ "brorand": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true }, "browserify-aes": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, "requires": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -420,6 +474,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, "requires": { "browserify-aes": "^1.0.4", "browserify-des": "^1.0.0", @@ -430,6 +485,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.1.tgz", "integrity": "sha512-zy0Cobe3hhgpiOM32Tj7KQ3Vl91m0njwsjzZQK1L+JDf11dzP9qIvjreVinsvXrgfjhStXwUWAEpB9D7Gwmayw==", + "dev": true, "requires": { "cipher-base": "^1.0.1", "des.js": "^1.0.0", @@ -440,6 +496,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, "requires": { "bn.js": "^4.1.0", "randombytes": "^2.0.1" @@ -449,6 +506,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, "requires": { "bn.js": "^4.1.1", "browserify-rsa": "^4.0.0", @@ -463,6 +521,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, "requires": { "pako": "~1.0.5" } @@ -471,6 +530,7 @@ "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -480,22 +540,26 @@ "buffer-from": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz", - "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==" + "integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==", + "dev": true }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true }, "builtin-status-codes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true }, "cacache": { "version": "10.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.4.tgz", "integrity": "sha512-Dph0MzuH+rTQzGPNT9fAnrPmMmjKfST6trxJeK7NQuHRaVw24VzPRWTmg9MpcwOVQZO0E1FBICUlFeNaKPIfHA==", + "dev": true, "requires": { "bluebird": "^3.5.1", "chownr": "^1.0.1", @@ -516,6 +580,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, "requires": { "collection-visit": "^1.0.0", "component-emitter": "^1.2.1", @@ -532,6 +597,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.3.tgz", "integrity": "sha512-zW8iXYZtXMx4kux/nuZVXjkLP+CyIK5Al5FHnj1OgTKGZfp4Oy6/ymtMSKFv3GD8DviEmUPmJg9eFdJ/JzudMg==", + "dev": true, "requires": { "anymatch": "^2.0.0", "async-each": "^1.0.0", @@ -550,17 +616,20 @@ "chownr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" + "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=", + "dev": true }, "chrome-trace-event": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-0.1.3.tgz", - "integrity": "sha512-sjndyZHrrWiu4RY7AkHgjn80GfAM2ZSzUkZLV/Js59Ldmh6JDThf0SUmOHU53rFu2rVxxfCzJ30Ukcfch3Gb/A==" + "integrity": "sha512-sjndyZHrrWiu4RY7AkHgjn80GfAM2ZSzUkZLV/Js59Ldmh6JDThf0SUmOHU53rFu2rVxxfCzJ30Ukcfch3Gb/A==", + "dev": true }, "cipher-base": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -570,6 +639,7 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, "requires": { "arr-union": "^3.1.0", "define-property": "^0.2.5", @@ -581,6 +651,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -591,6 +662,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" @@ -599,27 +671,32 @@ "commander": { "version": "2.13.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz", - "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==" + "integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA==", + "dev": true }, "commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true }, "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, "concat-stream": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, "requires": { "buffer-from": "^1.0.0", "inherits": "^2.0.3", @@ -631,6 +708,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "dev": true, "requires": { "date-now": "^0.1.4" } @@ -638,12 +716,14 @@ "constants-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true }, "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, "requires": { "aproba": "^1.1.1", "fs-write-stream-atomic": "^1.0.8", @@ -656,7 +736,8 @@ "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -667,6 +748,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, "requires": { "bn.js": "^4.1.0", "elliptic": "^6.0.0" @@ -676,6 +758,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, "requires": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -688,6 +771,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, "requires": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -701,6 +785,7 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, "requires": { "browserify-cipher": "^1.0.0", "browserify-sign": "^4.0.0", @@ -718,22 +803,20 @@ "cyclist": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" - }, - "date-format": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", - "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=" + "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=", + "dev": true }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" + "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "dev": true }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -741,12 +824,14 @@ "decode-uri-component": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -756,6 +841,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -764,6 +850,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -772,6 +859,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -784,6 +872,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", + "dev": true, "requires": { "inherits": "^2.0.1", "minimalistic-assert": "^1.0.0" @@ -793,6 +882,7 @@ "version": "5.0.3", "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, "requires": { "bn.js": "^4.1.0", "miller-rabin": "^4.0.0", @@ -802,12 +892,14 @@ "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", - "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true }, "duplexify": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", + "dev": true, "requires": { "end-of-stream": "^1.0.0", "inherits": "^2.0.1", @@ -819,6 +911,7 @@ "version": "6.4.0", "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", + "dev": true, "requires": { "bn.js": "^4.4.0", "brorand": "^1.0.1", @@ -832,12 +925,14 @@ "emojis-list": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, "requires": { "once": "^1.4.0" } @@ -864,6 +959,7 @@ "version": "3.7.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, "requires": { "esrecurse": "^4.1.0", "estraverse": "^4.1.1" @@ -873,6 +969,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, "requires": { "estraverse": "^4.1.0" } @@ -880,17 +977,20 @@ "estraverse": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true }, "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true }, "evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, "requires": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -900,6 +1000,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", @@ -914,6 +1015,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -922,6 +1024,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -932,6 +1035,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -941,6 +1045,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, "requires": { "is-plain-object": "^2.0.4" } @@ -951,6 +1056,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, "requires": { "array-unique": "^0.3.2", "define-property": "^1.0.0", @@ -966,6 +1072,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -974,6 +1081,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -982,6 +1090,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -990,6 +1099,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -998,6 +1108,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -1009,17 +1120,20 @@ "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true }, "fast-json-stable-stringify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", @@ -1031,6 +1145,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -1041,6 +1156,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", + "dev": true, "requires": { "commondir": "^1.0.1", "make-dir": "^1.0.0", @@ -1051,6 +1167,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, "requires": { "locate-path": "^2.0.0" } @@ -1059,6 +1176,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "dev": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.4" @@ -1067,12 +1185,14 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, "requires": { "map-cache": "^0.2.2" } @@ -1081,6 +1201,7 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, "requires": { "inherits": "^2.0.1", "readable-stream": "^2.0.0" @@ -1090,6 +1211,7 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "iferr": "^0.1.5", @@ -1100,12 +1222,14 @@ "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true }, "fsevents": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.3.tgz", "integrity": "sha512-X+57O5YkDTiEQGiw8i7wYc2nQgweIekqkepI8Q3y4wVlurgBt2SuwxTeYUYMZIGpLZH3r/TsMjczCMXE5ZOt7Q==", + "dev": true, "optional": true, "requires": { "nan": "^2.9.2", @@ -1115,20 +1239,24 @@ "abbrev": { "version": "1.1.1", "bundled": true, + "dev": true, "optional": true }, "ansi-regex": { "version": "2.1.1", - "bundled": true + "bundled": true, + "dev": true }, "aproba": { "version": "1.2.0", "bundled": true, + "dev": true, "optional": true }, "are-we-there-yet": { "version": "1.1.4", "bundled": true, + "dev": true, "optional": true, "requires": { "delegates": "^1.0.0", @@ -1137,11 +1265,13 @@ }, "balanced-match": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1150,28 +1280,34 @@ "chownr": { "version": "1.0.1", "bundled": true, + "dev": true, "optional": true }, "code-point-at": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "dev": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "core-util-is": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "debug": { "version": "2.6.9", "bundled": true, + "dev": true, "optional": true, "requires": { "ms": "2.0.0" @@ -1180,21 +1316,25 @@ "deep-extend": { "version": "0.4.2", "bundled": true, + "dev": true, "optional": true }, "delegates": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "detect-libc": { "version": "1.0.3", "bundled": true, + "dev": true, "optional": true }, "fs-minipass": { "version": "1.2.5", "bundled": true, + "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -1203,11 +1343,13 @@ "fs.realpath": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "gauge": { "version": "2.7.4", "bundled": true, + "dev": true, "optional": true, "requires": { "aproba": "^1.0.3", @@ -1223,6 +1365,7 @@ "glob": { "version": "7.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "fs.realpath": "^1.0.0", @@ -1236,11 +1379,13 @@ "has-unicode": { "version": "2.0.1", "bundled": true, + "dev": true, "optional": true }, "iconv-lite": { "version": "0.4.21", "bundled": true, + "dev": true, "optional": true, "requires": { "safer-buffer": "^2.1.0" @@ -1249,6 +1394,7 @@ "ignore-walk": { "version": "3.0.1", "bundled": true, + "dev": true, "optional": true, "requires": { "minimatch": "^3.0.4" @@ -1257,6 +1403,7 @@ "inflight": { "version": "1.0.6", "bundled": true, + "dev": true, "optional": true, "requires": { "once": "^1.3.0", @@ -1265,16 +1412,19 @@ }, "inherits": { "version": "2.0.3", - "bundled": true + "bundled": true, + "dev": true }, "ini": { "version": "1.3.5", "bundled": true, + "dev": true, "optional": true }, "is-fullwidth-code-point": { "version": "1.0.0", "bundled": true, + "dev": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1282,22 +1432,26 @@ "isarray": { "version": "1.0.0", "bundled": true, + "dev": true, "optional": true }, "minimatch": { "version": "3.0.4", "bundled": true, + "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { "version": "0.0.8", - "bundled": true + "bundled": true, + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, + "dev": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -1306,6 +1460,7 @@ "minizlib": { "version": "1.1.0", "bundled": true, + "dev": true, "optional": true, "requires": { "minipass": "^2.2.1" @@ -1314,6 +1469,7 @@ "mkdirp": { "version": "0.5.1", "bundled": true, + "dev": true, "requires": { "minimist": "0.0.8" } @@ -1321,11 +1477,13 @@ "ms": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "needle": { "version": "2.2.0", "bundled": true, + "dev": true, "optional": true, "requires": { "debug": "^2.1.2", @@ -1336,6 +1494,7 @@ "node-pre-gyp": { "version": "0.9.1", "bundled": true, + "dev": true, "optional": true, "requires": { "detect-libc": "^1.0.2", @@ -1353,6 +1512,7 @@ "nopt": { "version": "4.0.1", "bundled": true, + "dev": true, "optional": true, "requires": { "abbrev": "1", @@ -1362,11 +1522,13 @@ "npm-bundled": { "version": "1.0.3", "bundled": true, + "dev": true, "optional": true }, "npm-packlist": { "version": "1.1.10", "bundled": true, + "dev": true, "optional": true, "requires": { "ignore-walk": "^3.0.1", @@ -1376,6 +1538,7 @@ "npmlog": { "version": "4.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "are-we-there-yet": "~1.1.2", @@ -1386,16 +1549,19 @@ }, "number-is-nan": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "object-assign": { "version": "4.1.1", "bundled": true, + "dev": true, "optional": true }, "once": { "version": "1.4.0", "bundled": true, + "dev": true, "requires": { "wrappy": "1" } @@ -1403,16 +1569,19 @@ "os-homedir": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "os-tmpdir": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "osenv": { "version": "0.1.5", "bundled": true, + "dev": true, "optional": true, "requires": { "os-homedir": "^1.0.0", @@ -1422,16 +1591,19 @@ "path-is-absolute": { "version": "1.0.1", "bundled": true, + "dev": true, "optional": true }, "process-nextick-args": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "rc": { "version": "1.2.6", "bundled": true, + "dev": true, "optional": true, "requires": { "deep-extend": "~0.4.0", @@ -1443,6 +1615,7 @@ "minimist": { "version": "1.2.0", "bundled": true, + "dev": true, "optional": true } } @@ -1450,6 +1623,7 @@ "readable-stream": { "version": "2.3.6", "bundled": true, + "dev": true, "optional": true, "requires": { "core-util-is": "~1.0.0", @@ -1464,6 +1638,7 @@ "rimraf": { "version": "2.6.2", "bundled": true, + "dev": true, "optional": true, "requires": { "glob": "^7.0.5" @@ -1471,36 +1646,43 @@ }, "safe-buffer": { "version": "5.1.1", - "bundled": true + "bundled": true, + "dev": true }, "safer-buffer": { "version": "2.1.2", "bundled": true, + "dev": true, "optional": true }, "sax": { "version": "1.2.4", "bundled": true, + "dev": true, "optional": true }, "semver": { "version": "5.5.0", "bundled": true, + "dev": true, "optional": true }, "set-blocking": { "version": "2.0.0", "bundled": true, + "dev": true, "optional": true }, "signal-exit": { "version": "3.0.2", "bundled": true, + "dev": true, "optional": true }, "string-width": { "version": "1.0.2", "bundled": true, + "dev": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1510,6 +1692,7 @@ "string_decoder": { "version": "1.1.1", "bundled": true, + "dev": true, "optional": true, "requires": { "safe-buffer": "~5.1.0" @@ -1518,6 +1701,7 @@ "strip-ansi": { "version": "3.0.1", "bundled": true, + "dev": true, "requires": { "ansi-regex": "^2.0.0" } @@ -1525,11 +1709,13 @@ "strip-json-comments": { "version": "2.0.1", "bundled": true, + "dev": true, "optional": true }, "tar": { "version": "4.4.1", "bundled": true, + "dev": true, "optional": true, "requires": { "chownr": "^1.0.1", @@ -1544,11 +1730,13 @@ "util-deprecate": { "version": "1.0.2", "bundled": true, + "dev": true, "optional": true }, "wide-align": { "version": "1.1.2", "bundled": true, + "dev": true, "optional": true, "requires": { "string-width": "^1.0.2" @@ -1556,23 +1744,27 @@ }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "dev": true }, "yallist": { "version": "3.0.2", - "bundled": true + "bundled": true, + "dev": true } } }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -1586,6 +1778,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, "requires": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" @@ -1595,6 +1788,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, "requires": { "is-extglob": "^2.1.0" } @@ -1610,6 +1804,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, "requires": { "get-value": "^2.0.6", "has-values": "^1.0.0", @@ -1620,6 +1815,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" @@ -1629,6 +1825,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -1639,6 +1836,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -1648,6 +1846,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", + "dev": true, "requires": { "inherits": "^2.0.3", "minimalistic-assert": "^1.0.0" @@ -1657,6 +1856,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, "requires": { "hash.js": "^1.0.3", "minimalistic-assert": "^1.0.0", @@ -1666,32 +1866,38 @@ "https-browserify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", - "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true }, "ieee754": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.11.tgz", - "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==" + "integrity": "sha512-VhDzCKN7K8ufStx/CLj5/PDTMgph+qwN5Pkd5i0sGnVwk56zJ0lkT8Qzi1xqWLS0Wp29DgDtNeS7v8/wMoZeHg==", + "dev": true }, "iferr": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true }, "indexof": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -1706,6 +1912,7 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -1714,6 +1921,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -1724,6 +1932,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, "requires": { "binary-extensions": "^1.0.0" } @@ -1731,12 +1940,14 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true }, "is-data-descriptor": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -1745,6 +1956,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -1755,6 +1967,7 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", @@ -1764,24 +1977,28 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true } } }, "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true }, "is-glob": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -1790,6 +2007,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -1798,6 +2016,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -1808,6 +2027,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-2.0.0.tgz", "integrity": "sha512-OTiixgpZAT1M4NHgS5IguFp/Vz2VI3U7Goh4/HA1adtwyLtSBrxYlcSYkhpAE07s4fKEcjrFxyvtQBND4vFQyQ==", + "dev": true, "requires": { "is-number": "^4.0.0" }, @@ -1815,7 +2035,8 @@ "is-number": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true } } }, @@ -1823,6 +2044,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, "requires": { "isobject": "^3.0.1" } @@ -1830,7 +2052,8 @@ "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true }, "isarray": { "version": "1.0.0", @@ -1840,37 +2063,44 @@ "isobject": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true }, "json-schema-traverse": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true }, "json5": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true }, "leb": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/leb/-/leb-0.3.0.tgz", - "integrity": "sha1-Mr7p+tFoMo1q6oUi2DP0GA7tHaM=" + "integrity": "sha1-Mr7p+tFoMo1q6oUi2DP0GA7tHaM=", + "dev": true }, "loader-runner": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", - "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=" + "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=", + "dev": true }, "loader-utils": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", + "dev": true, "requires": { "big.js": "^3.1.3", "emojis-list": "^2.0.0", @@ -1881,6 +2111,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, "requires": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" @@ -1891,25 +2122,17 @@ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, - "log4js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-1.1.1.tgz", - "integrity": "sha1-wh0px2BAieTyVYM+f5SzRh3h/0M=", - "requires": { - "debug": "^2.2.0", - "semver": "^5.3.0", - "streamroller": "^0.4.0" - } - }, "long": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/long/-/long-3.2.0.tgz", - "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=" + "integrity": "sha1-2CG3E4yhy1gcFymQ7xTbIAtcR0s=", + "dev": true }, "lru-cache": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "dev": true, "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" @@ -1919,6 +2142,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, "requires": { "pify": "^3.0.0" } @@ -1926,12 +2150,14 @@ "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true }, "map-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, "requires": { "object-visit": "^1.0.0" } @@ -1940,6 +2166,7 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz", "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=", + "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -1958,6 +2185,7 @@ "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -1978,6 +2206,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, "requires": { "bn.js": "^4.0.0", "brorand": "^1.0.1" @@ -1986,17 +2215,20 @@ "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true }, "minimalistic-crypto-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -2004,12 +2236,14 @@ "minimist": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true }, "mississippi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-2.0.0.tgz", "integrity": "sha512-zHo8v+otD1J10j/tC+VNoGK9keCuByhKovAvdn74dmxJl9+mWHnx6EMsDN4lgRoMI/eYo2nchAxniIbUPb5onw==", + "dev": true, "requires": { "concat-stream": "^1.5.0", "duplexify": "^3.4.2", @@ -2027,6 +2261,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -2036,6 +2271,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, "requires": { "is-plain-object": "^2.0.4" } @@ -2046,6 +2282,7 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, "requires": { "minimist": "0.0.8" } @@ -2054,6 +2291,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, "requires": { "aproba": "^1.1.1", "copy-concurrently": "^1.0.0", @@ -2066,18 +2304,21 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true }, "nan": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==", + "dev": true, "optional": true }, "nanomatch": { "version": "1.2.9", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.9.tgz", "integrity": "sha512-n8R9bS8yQ6eSXaV6jHUpKzD8gLsin02w1HSFiegwrs9E098Ylhw5jdyKPaYqvHknHaSCKTPp7C8dGCQ0q9koXA==", + "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -2096,12 +2337,14 @@ "neo-async": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz", - "integrity": "sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA==" + "integrity": "sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA==", + "dev": true }, "node-libs-browser": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.1.0.tgz", "integrity": "sha512-5AzFzdoIMb89hBGMZglEegffzgRg+ZFoUmisQ8HI4j1KDdpx13J0taNp2y9xPbur6W61gepGDDotGBVQ7mfUCg==", + "dev": true, "requires": { "assert": "^1.1.1", "browserify-zlib": "^0.2.0", @@ -2131,7 +2374,8 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true } } }, @@ -2139,6 +2383,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, "requires": { "remove-trailing-separator": "^1.0.1" } @@ -2147,6 +2392,7 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -2157,6 +2403,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -2165,6 +2412,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -2175,6 +2423,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, "requires": { "isobject": "^3.0.0" } @@ -2183,6 +2432,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, "requires": { "isobject": "^3.0.1" } @@ -2191,6 +2441,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, "requires": { "wrappy": "1" } @@ -2198,12 +2449,14 @@ "os-browserify": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", - "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true }, "p-limit": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "dev": true, "requires": { "p-try": "^1.0.0" } @@ -2212,6 +2465,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, "requires": { "p-limit": "^1.1.0" } @@ -2219,17 +2473,20 @@ "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true }, "pako": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz", - "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==" + "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==", + "dev": true }, "parallel-transform": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", + "dev": true, "requires": { "cyclist": "~0.2.2", "inherits": "^2.0.3", @@ -2240,6 +2497,7 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.1.tgz", "integrity": "sha512-KPx7flKXg775zZpnp9SxJlz00gTd4BmJ2yJufSc44gMCRrRQ7NSzAcSJQfifuOLgW6bEi+ftrALtsgALeB2Adw==", + "dev": true, "requires": { "asn1.js": "^4.0.0", "browserify-aes": "^1.0.0", @@ -2251,32 +2509,38 @@ "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true }, "path-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=" + "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=", + "dev": true }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true }, "pbkdf2": { "version": "3.0.16", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.16.tgz", "integrity": "sha512-y4CXP3thSxqf7c0qmOF+9UeOTrifiVTIM+u7NWlq+PRsHbr7r7dpCmvzrZxa96JJUNi0Y5w9VqG5ZNeCVMoDcA==", + "dev": true, "requires": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -2288,12 +2552,14 @@ "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, "requires": { "find-up": "^2.1.0" } @@ -2301,12 +2567,14 @@ "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true }, "process-nextick-args": { "version": "2.0.0", @@ -2316,7 +2584,8 @@ "promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true }, "prr": { "version": "1.0.1", @@ -2326,12 +2595,14 @@ "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true }, "public-encrypt": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.2.tgz", "integrity": "sha512-4kJ5Esocg8X3h8YgJsKAuoesBgB7mqH3eowiDzMUPKiRDDE7E/BqqZD1hnTByIaAFiwAw246YEltSq7tdrOH0Q==", + "dev": true, "requires": { "bn.js": "^4.1.0", "browserify-rsa": "^4.0.0", @@ -2344,6 +2615,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, "requires": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -2353,6 +2625,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.0.tgz", "integrity": "sha512-UWi0klDoq8xtVzlMRgENV9F7iCTZExaJQSQL187UXsxpk9NnrKGqTqqUNYAKGOzucSOxs2+jUnRNI+rLviPhJg==", + "dev": true, "requires": { "duplexify": "^3.6.0", "inherits": "^2.0.3", @@ -2362,22 +2635,26 @@ "punycode": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.0.tgz", - "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=" + "integrity": "sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0=", + "dev": true }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true }, "querystring-es3": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true }, "randombytes": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz", "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==", + "dev": true, "requires": { "safe-buffer": "^5.1.0" } @@ -2386,6 +2663,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, "requires": { "randombytes": "^2.0.5", "safe-buffer": "^5.1.0" @@ -2394,7 +2672,8 @@ "raw-loader": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", - "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=" + "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=", + "dev": true }, "readable-stream": { "version": "2.3.6", @@ -2414,6 +2693,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, "requires": { "graceful-fs": "^4.1.2", "minimatch": "^3.0.2", @@ -2425,6 +2705,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" @@ -2433,32 +2714,38 @@ "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true }, "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true }, "repeat-string": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true }, "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true }, "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, "requires": { "glob": "^7.0.5" } @@ -2467,6 +2754,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -2476,6 +2764,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, "requires": { "aproba": "^1.1.1" } @@ -2489,6 +2778,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, "requires": { "ret": "~0.1.10" } @@ -2497,30 +2787,29 @@ "version": "0.4.5", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz", "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==", + "dev": true, "requires": { "ajv": "^6.1.0", "ajv-keywords": "^3.1.0" } }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - }, "serialize-javascript": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-1.5.0.tgz", - "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==" + "integrity": "sha512-Ga8c8NjAAp46Br4+0oZ2WxJCwIzwP60Gq1YPgU+39PiTVxyed/iKE/zyZI6+UlVYH5Q4PaQdHhcegIFPZTUfoQ==", + "dev": true }, "set-immediate-shim": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true }, "set-value": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -2532,6 +2821,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -2541,12 +2831,14 @@ "setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true }, "sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, "requires": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -2556,6 +2848,7 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, "requires": { "base": "^0.11.1", "debug": "^2.2.0", @@ -2571,6 +2864,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -2579,6 +2873,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -2586,7 +2881,8 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true } } }, @@ -2594,6 +2890,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, "requires": { "define-property": "^1.0.0", "isobject": "^3.0.0", @@ -2604,6 +2901,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -2612,6 +2910,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -2620,6 +2919,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -2628,6 +2928,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -2640,6 +2941,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, "requires": { "kind-of": "^3.2.0" }, @@ -2648,6 +2950,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -2657,17 +2960,20 @@ "source-list-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==" + "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==", + "dev": true }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true }, "source-map-resolve": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, "requires": { "atob": "^2.1.1", "decode-uri-component": "^0.2.0", @@ -2679,12 +2985,14 @@ "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, "requires": { "extend-shallow": "^3.0.0" } @@ -2693,6 +3001,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.3.0.tgz", "integrity": "sha512-XRSIPqLij52MtgoQavH/x/dU1qVKtWUAAZeOHsR9c2Ddi4XerFy3mc1alf+dLJKl9EUIm/Ht+EowFkTUOA6GAQ==", + "dev": true, "requires": { "safe-buffer": "^5.1.1" } @@ -2701,6 +3010,7 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -2710,6 +3020,7 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -2720,6 +3031,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", + "dev": true, "requires": { "inherits": "~2.0.1", "readable-stream": "^2.0.2" @@ -2729,6 +3041,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.2.tgz", "integrity": "sha512-mc1dbFhGBxvTM3bIWmAAINbqiuAk9TATcfIQC8P+/+HJefgaiTlMn2dHvkX8qlI12KeYKSQ1Ua9RrIqrn1VPoA==", + "dev": true, "requires": { "end-of-stream": "^1.1.0", "stream-shift": "^1.0.0" @@ -2738,6 +3051,7 @@ "version": "2.8.2", "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.2.tgz", "integrity": "sha512-QllfrBhqF1DPcz46WxKTs6Mz1Bpc+8Qm6vbqOpVav5odAXwbyzwnEczoWqtxrsmlO+cJqtPrp/8gWKWjaKLLlA==", + "dev": true, "requires": { "builtin-status-codes": "^3.0.0", "inherits": "^2.0.1", @@ -2749,46 +3063,8 @@ "stream-shift": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" - }, - "streamroller": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.4.1.tgz", - "integrity": "sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8=", - "requires": { - "date-format": "^0.0.0", - "debug": "^0.7.2", - "mkdirp": "^0.5.1", - "readable-stream": "^1.1.7" - }, - "dependencies": { - "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true }, "string_decoder": { "version": "1.1.1", @@ -2798,6 +3074,15 @@ "safe-buffer": "~5.1.0" } }, + "stryker-api": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.17.0.tgz", + "integrity": "sha512-CJKAx+D8ztmXtnORk0bKfrccIbeAOXcKZ2pQpevvj7SFZJKlF8PRQy8lkgP5kvTK/sKidQp84kHjiqyRvf634A==", + "dev": true, + "requires": { + "tslib": "^1.6.0" + } + }, "tapable": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.0.0.tgz", @@ -2807,6 +3092,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", + "dev": true, "requires": { "readable-stream": "^2.1.5", "xtend": "~4.0.1" @@ -2816,6 +3102,7 @@ "version": "2.0.10", "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz", "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==", + "dev": true, "requires": { "setimmediate": "^1.0.4" } @@ -2823,12 +3110,14 @@ "to-arraybuffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -2837,6 +3126,7 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -2847,6 +3137,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, "requires": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", @@ -2858,25 +3149,35 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, "requires": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" } }, + "tslib": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", + "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==", + "dev": true + }, "tty-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true }, "uglify-es": { "version": "3.3.9", "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz", "integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==", + "dev": true, "requires": { "commander": "~2.13.0", "source-map": "~0.6.1" @@ -2886,6 +3187,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.2.5.tgz", "integrity": "sha512-hIQJ1yxAPhEA2yW/i7Fr+SXZVMp+VEI3d42RTHBgQd2yhp/1UdBcR3QEWPV5ahBxlqQDMEMTuTEvDHSFINfwSw==", + "dev": true, "requires": { "cacache": "^10.0.4", "find-cache-dir": "^1.0.0", @@ -2901,6 +3203,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", @@ -2912,6 +3215,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -2920,6 +3224,7 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -2933,6 +3238,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", + "dev": true, "requires": { "unique-slug": "^2.0.0" } @@ -2941,6 +3247,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", + "dev": true, "requires": { "imurmurhash": "^0.1.4" } @@ -2949,6 +3256,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, "requires": { "has-value": "^0.3.1", "isobject": "^3.0.0" @@ -2958,6 +3266,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, "requires": { "get-value": "^2.0.3", "has-values": "^0.1.4", @@ -2968,6 +3277,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, "requires": { "isarray": "1.0.0" } @@ -2977,19 +3287,22 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true } } }, "upath": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/upath/-/upath-1.0.5.tgz", - "integrity": "sha512-qbKn90aDQ0YEwvXoLqj0oiuUYroLX2lVHZ+b+xwjozFasAOC4GneDq5+OaIG5Zj+jFmbz/uO+f7a9qxjktJQww==" + "integrity": "sha512-qbKn90aDQ0YEwvXoLqj0oiuUYroLX2lVHZ+b+xwjozFasAOC4GneDq5+OaIG5Zj+jFmbz/uO+f7a9qxjktJQww==", + "dev": true }, "uri-js": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.1.tgz", "integrity": "sha512-jpKCA3HjsBfSDOEgxRDAxQCNyHfCPSbq57PqCkd3gAyBuPb3IWxw54EHncqESznIdqSetHfw3D7ylThu2Kcc9A==", + "dev": true, "requires": { "punycode": "^2.1.0" } @@ -2997,12 +3310,14 @@ "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true }, "url": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, "requires": { "punycode": "1.3.2", "querystring": "0.2.0" @@ -3011,7 +3326,8 @@ "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true } } }, @@ -3019,6 +3335,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/use/-/use-3.1.0.tgz", "integrity": "sha512-6UJEQM/L+mzC3ZJNM56Q4DFGLX/evKGRg15UJHGB9X5j5Z3AFbgZvjUh2yq/UJUY4U5dh7Fal++XbNg1uzpRAw==", + "dev": true, "requires": { "kind-of": "^6.0.2" } @@ -3027,6 +3344,7 @@ "version": "0.10.3", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, "requires": { "inherits": "2.0.1" }, @@ -3034,7 +3352,8 @@ "inherits": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true } } }, @@ -3047,6 +3366,7 @@ "version": "0.0.4", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", + "dev": true, "requires": { "indexof": "0.0.1" } @@ -3055,6 +3375,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, "requires": { "chokidar": "^2.0.2", "graceful-fs": "^4.1.2", @@ -3065,6 +3386,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/webassemblyjs/-/webassemblyjs-1.3.1.tgz", "integrity": "sha512-jaqGpR+MLye6fzxKTiv0/TPEm6ma7ypef76JlQVk9E1z5M2N6EXNrsMOuh7P6aXUVFHJSioRp4N9QOFpcWfIVA==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1", "@webassemblyjs/validation": "1.3.1", @@ -3077,6 +3399,7 @@ "version": "4.8.1", "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.8.1.tgz", "integrity": "sha512-xkxthzaVR298HmvmrjBCjiCmgzWnBnvBlgPzuvqmxWSh8QImrPvCCmr482YIx7ixWkTtQj1aMRz+cjoNPUsGEQ==", + "dev": true, "requires": { "@webassemblyjs/ast": "1.3.1", "@webassemblyjs/wasm-edit": "1.3.1", @@ -3106,6 +3429,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.1.0.tgz", "integrity": "sha512-aqYp18kPphgoO5c/+NaUvEeACtZjMESmDChuD3NBciVpah3XpMEU9VAAtIaB1BsfJWWTSdv8Vv1m3T0aRk2dUw==", + "dev": true, "requires": { "source-list-map": "^2.0.0", "source-map": "~0.6.1" @@ -3115,6 +3439,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.6.0.tgz", "integrity": "sha512-6w+3tHbM87WnSWnENBUvA2pxJPLhQUg5LKwUQHq3r+XPhIM+Gh2R5ycbwPCyuGbNg+lPgdcnQUhuC02kJCvffQ==", + "dev": true, "requires": { "errno": "~0.1.7" } @@ -3122,22 +3447,26 @@ "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, "xtend": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true }, "y18n": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true } } } diff --git a/packages/stryker-webpack-transpiler/package.json b/packages/stryker-webpack-transpiler/package.json index 3bd0df38d5..4a126cdc79 100644 --- a/packages/stryker-webpack-transpiler/package.json +++ b/packages/stryker-webpack-transpiler/package.json @@ -51,7 +51,6 @@ "dependencies": { "enhanced-resolve": "^4.0.0-beta.4", "lodash": "^4.17.4", - "log4js": "^1.1.0", "memory-fs": "^0.4.1" }, "initStrykerConfig": { diff --git a/packages/stryker-webpack-transpiler/src/WebpackTranspiler.ts b/packages/stryker-webpack-transpiler/src/WebpackTranspiler.ts index 2cea691517..d645c553e4 100644 --- a/packages/stryker-webpack-transpiler/src/WebpackTranspiler.ts +++ b/packages/stryker-webpack-transpiler/src/WebpackTranspiler.ts @@ -2,7 +2,6 @@ import { TranspilerOptions, Transpiler } from 'stryker-api/transpile'; import { File } from 'stryker-api/core'; import WebpackCompiler from './compiler/WebpackCompiler'; import ConfigLoader from './compiler/ConfigLoader'; -import { setGlobalLogLevel } from 'log4js'; const DEFAULT_STRYKER_WEBPACK_CONFIG = Object.freeze({ configFile: undefined, silent: true, context: process.cwd() }); @@ -11,7 +10,6 @@ export default class WebpackTranspiler implements Transpiler { private webpackCompiler: WebpackCompiler; public constructor(options: TranspilerOptions) { - setGlobalLogLevel(options.config.logLevel); if (options.produceSourceMaps) { throw new Error(`Invalid \`coverageAnalysis\` "${options.config.coverageAnalysis}" is not supported by the stryker-webpack-transpiler (yet). It is not able to produce source maps yet. Please set it "coverageAnalysis" to "off".`); } diff --git a/packages/stryker-webpack-transpiler/src/compiler/ConfigLoader.ts b/packages/stryker-webpack-transpiler/src/compiler/ConfigLoader.ts index b21c43a14d..e1a208d44e 100644 --- a/packages/stryker-webpack-transpiler/src/compiler/ConfigLoader.ts +++ b/packages/stryker-webpack-transpiler/src/compiler/ConfigLoader.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import * as fs from 'fs'; import { Configuration } from 'webpack'; import { StrykerWebpackConfig } from '../WebpackTranspiler'; -import { getLogger, Logger } from 'log4js'; +import { getLogger, Logger } from 'stryker-api/logging'; import { isFunction } from 'lodash'; const PROGRESS_PLUGIN_NAME = 'ProgressPlugin'; diff --git a/packages/stryker-webpack-transpiler/test/helpers/sinonInit.ts b/packages/stryker-webpack-transpiler/test/helpers/sinonInit.ts index 5148e8d332..f4e5baea1f 100644 --- a/packages/stryker-webpack-transpiler/test/helpers/sinonInit.ts +++ b/packages/stryker-webpack-transpiler/test/helpers/sinonInit.ts @@ -1,5 +1,5 @@ import * as sinon from 'sinon'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; beforeEach(() => { global.sandbox = sinon.sandbox.create(); diff --git a/packages/stryker-webpack-transpiler/test/unit/WebpackTranspilerSpec.ts b/packages/stryker-webpack-transpiler/test/unit/WebpackTranspilerSpec.ts index f827e3e044..d13c2b706a 100644 --- a/packages/stryker-webpack-transpiler/test/unit/WebpackTranspilerSpec.ts +++ b/packages/stryker-webpack-transpiler/test/unit/WebpackTranspilerSpec.ts @@ -6,7 +6,6 @@ import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; import { expect } from 'chai'; import { Configuration } from 'webpack'; -import * as log4js from 'log4js'; describe('WebpackTranspiler', () => { let webpackTranspiler: WebpackTranspiler; @@ -27,7 +26,6 @@ describe('WebpackTranspiler', () => { configLoaderStub = createMockInstance(ConfigLoader); configLoaderStub.load.returns(webpackConfig); - sandbox.stub(log4js, 'setGlobalLogLevel'); sandbox.stub(configLoaderModule, 'default').returns(configLoaderStub); sandbox.stub(webpackCompilerModule, 'default').returns(webpackCompilerStub); @@ -48,12 +46,6 @@ describe('WebpackTranspiler', () => { expect(configLoaderStub.load).calledWith(createStrykerWebpackConfig()); }); - it('should set global log level when compiler is called', () => { - config.logLevel = 'foobar level'; - new WebpackTranspiler({ config, produceSourceMaps: false }); - expect(log4js.setGlobalLogLevel).calledWith('foobar level'); - }); - it('should throw an error if `produceSourceMaps` is `true`', () => { expect(() => new WebpackTranspiler({ config, produceSourceMaps: true })).throws('Invalid `coverageAnalysis` "perTest" is not supported by the stryker-webpack-transpiler (yet). It is not able to produce source maps yet. Please set it "coverageAnalysis" to "off"'); }); diff --git a/packages/stryker/package-lock.json b/packages/stryker/package-lock.json index 66147cbe9f..a42b610c26 100644 --- a/packages/stryker/package-lock.json +++ b/packages/stryker/package-lock.json @@ -170,6 +170,45 @@ "@types/node": "*" } }, + "addressparser": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz", + "integrity": "sha1-R6++GiqSYhkdtoOOT9HTm0CCF0Y=", + "optional": true + }, + "agent-base": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.0.tgz", + "integrity": "sha512-c+R/U5X+2zz2+UCrCFv6odQzJdoqI+YecuhnAJLa1zYaMc13zPfwMwZrr91Pd1DYNo/yPRbiM4WVf9whgwFsIg==", + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "optional": true, + "requires": { + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" + } + }, + "amqplib": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.2.tgz", + "integrity": "sha512-l9mCs6LbydtHqRniRwYkKdqxVa6XMz3Vw1fh+2gJaaVgTM6Jk3o8RccAKWKtlhT1US5sWrFh+KKxsVUALURSIA==", + "optional": true, + "requires": { + "bitsyntax": "~0.0.4", + "bluebird": "^3.4.6", + "buffer-more-ints": "0.0.2", + "readable-stream": "1.x >=1.1.9", + "safe-buffer": "^5.0.1" + } + }, "ansi-escapes": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", @@ -193,6 +232,59 @@ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "optional": true + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "ast-types": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.3.tgz", + "integrity": "sha512-XA5o5dsNw8MhyW0Q7MWXJWc4oOzZKbdsEJq45h7c8q/d9DwWZ5F2ugUc1PuMLPGsUnphCt/cNDHu8JeBbxf1qA==", + "optional": true + }, + "async": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.0.tgz", + "integrity": "sha512-xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==", + "optional": true, + "requires": { + "lodash": "^4.14.0" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "optional": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "optional": true + }, + "aws4": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", + "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==", + "optional": true + }, + "axios": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz", + "integrity": "sha1-LJ1jiy4ZGgjqHWzJiOrda6W9wFM=", + "optional": true, + "requires": { + "follow-redirects": "1.0.0" + } + }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -328,6 +420,70 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bitsyntax": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/bitsyntax/-/bitsyntax-0.0.4.tgz", + "integrity": "sha1-6xDMb4K4xJDj6FaY8H6D1G4MuoI=", + "optional": true, + "requires": { + "buffer-more-ints": "0.0.2" + } + }, + "bl": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", + "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", + "optional": true, + "requires": { + "readable-stream": "~2.0.5" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "optional": true + }, + "readable-stream": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", + "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" + } + } + } + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "optional": true + }, + "boom": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", + "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "optional": true, + "requires": { + "hoek": "4.x.x" + } + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -337,6 +493,38 @@ "concat-map": "0.0.1" } }, + "buffer-more-ints": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/buffer-more-ints/-/buffer-more-ints-0.0.2.tgz", + "integrity": "sha1-JrOIXRD6E9t/wBquOquHAZngEkw=" + }, + "buildmail": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/buildmail/-/buildmail-4.0.1.tgz", + "integrity": "sha1-h393OLeHKYccmhBeO4N9K+EaenI=", + "optional": true, + "requires": { + "addressparser": "1.0.1", + "libbase64": "0.1.0", + "libmime": "3.0.0", + "libqp": "1.1.0", + "nodemailer-fetch": "1.6.0", + "nodemailer-shared": "1.1.0", + "punycode": "1.4.1" + } + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "optional": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "optional": true + }, "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", @@ -352,6 +540,11 @@ "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" }, + "circular-json": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.5.4.tgz", + "integrity": "sha512-vnJA8KS0BfOihugYEUkLRcnmq21FbuivbxgzDLXNs3zIk4KllV4Mx4UuTzBXht9F00C7QfD1YqMXg1zP6EXpig==" + }, "cli-cursor": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", @@ -365,6 +558,12 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "optional": true + }, "color-convert": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", @@ -378,6 +577,14 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, + "combined-stream": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", + "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", + "requires": { + "delayed-stream": "~1.0.0" + } + }, "commander": { "version": "2.15.1", "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", @@ -398,10 +605,45 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, + "cryptiles": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", + "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", + "optional": true, + "requires": { + "boom": "5.x.x" + }, + "dependencies": { + "boom": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", + "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", + "optional": true, + "requires": { + "hoek": "4.x.x" + } + } + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-uri-to-buffer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", + "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", + "optional": true + }, "date-format": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/date-format/-/date-format-0.0.0.tgz", - "integrity": "sha1-CSBoY6sHDrRZrOpVQsvYVrEZZrM=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-1.2.0.tgz", + "integrity": "sha1-YV6CjiM90aubua4JUODOzPpuytg=" }, "debug": { "version": "2.6.9", @@ -416,6 +658,36 @@ "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" }, + "degenerator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", + "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "optional": true, + "requires": { + "ast-types": "0.x.x", + "escodegen": "1.x.x", + "esprima": "3.x.x" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "optional": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "optional": true + }, "detect-indent": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", @@ -424,6 +696,34 @@ "repeating": "^2.0.0" } }, + "double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=", + "optional": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "optional": true, + "requires": { + "jsbn": "~0.1.0" + } + }, + "es6-promise": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", + "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==" + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "requires": { + "es6-promise": "^4.0.3" + } + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -463,6 +763,11 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + }, "external-editor": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", @@ -473,6 +778,23 @@ "tmp": "^0.0.33" } }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=", + "optional": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "optional": true + }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", @@ -486,11 +808,129 @@ "escape-string-regexp": "^1.0.5" } }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "follow-redirects": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz", + "integrity": "sha1-jjQpjL0uF28lTv/sdaHHjMhJ/Tc=", + "optional": true, + "requires": { + "debug": "^2.2.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "optional": true + }, + "form-data": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", + "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "1.0.6", + "mime-types": "^2.1.12" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "optional": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + } + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "optional": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "optional": true, + "requires": { + "is-property": "^1.0.0" + } + }, + "get-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.1.tgz", + "integrity": "sha512-7aelVrYqCLuVjq2kEKRTH8fXPTC0xKTkM+G7UlFkEwCXY3sFbSxvY375JoFowOAYbkaU47SrBvOefUlLZZ+6QA==", + "optional": true, + "requires": { + "data-uri-to-buffer": "1", + "debug": "2", + "extend": "3", + "file-uri-to-path": "1", + "ftp": "~0.3.10", + "readable-stream": "2" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "optional": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", @@ -509,6 +949,22 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "optional": true + }, + "har-validator": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", + "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "optional": true, + "requires": { + "ajv": "^5.1.0", + "har-schema": "^2.0.0" + } + }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -529,6 +985,115 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "hawk": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", + "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", + "optional": true, + "requires": { + "boom": "4.x.x", + "cryptiles": "3.x.x", + "hoek": "4.x.x", + "sntp": "2.x.x" + } + }, + "hipchat-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hipchat-notifier/-/hipchat-notifier-1.1.0.tgz", + "integrity": "sha1-ttJJdVQ3wZEII2d5nTupoPI7Ix4=", + "optional": true, + "requires": { + "lodash": "^4.0.0", + "request": "^2.0.0" + } + }, + "hoek": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", + "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "optional": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "httpntlm": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", + "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", + "requires": { + "httpreq": ">=0.4.22", + "underscore": "~1.7.0" + }, + "dependencies": { + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" + } + } + }, + "httpreq": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", + "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=" + }, + "https-proxy-agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", + "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "requires": { + "agent-base": "^4.1.0", + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", @@ -537,6 +1102,12 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", + "optional": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -589,6 +1160,11 @@ "loose-envify": "^1.0.0" } }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" + }, "is-finite": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", @@ -602,15 +1178,59 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" }, + "is-my-ip-valid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", + "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "optional": true + }, + "is-my-json-valid": { + "version": "2.17.2", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz", + "integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==", + "optional": true, + "requires": { + "generate-function": "^2.0.0", + "generate-object-property": "^1.1.0", + "is-my-ip-valid": "^1.0.0", + "jsonpointer": "^4.0.0", + "xtend": "^4.0.0" + } + }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "optional": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "optional": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "optional": true + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "optional": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "optional": true }, "istanbul-lib-coverage": { "version": "1.2.0", @@ -636,11 +1256,52 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "optional": true + }, "jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "optional": true + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "optional": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "optional": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -650,19 +1311,261 @@ "type-check": "~0.3.2" } }, + "libbase64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz", + "integrity": "sha1-YjUag5VjrF/1vSbxL2Dpgwu3UeY=" + }, + "libmime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz", + "integrity": "sha1-UaGp50SOy9Ms2lRCFnW7IbwJPaY=", + "requires": { + "iconv-lite": "0.4.15", + "libbase64": "0.1.0", + "libqp": "1.1.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz", + "integrity": "sha1-/iZaIYrGpXz+hUkn6dBMGYJe3es=" + } + } + }, + "libqp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz", + "integrity": "sha1-9ebgatdLeU+1tbZpiL9yjvHe2+g=" + }, "lodash": { "version": "4.17.10", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" }, "log4js": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-2.6.1.tgz", + "integrity": "sha512-BOoWTr8gxJ9XRkQr/f68KUciHR6qnLESgbXuoD7VAhtu/aMq5kD1WD7IFMMaKjCDKLUHsjwT3V2cw34ENiJKig==", + "requires": { + "amqplib": "^0.5.2", + "axios": "^0.15.3", + "circular-json": "^0.5.4", + "date-format": "^1.2.0", + "debug": "^3.1.0", + "hipchat-notifier": "^1.1.0", + "loggly": "^1.1.0", + "mailgun-js": "^0.18.0", + "nodemailer": "^2.5.0", + "redis": "^2.7.1", + "semver": "^5.5.0", + "slack-node": "~0.2.0", + "streamroller": "0.7.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "loggly": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/log4js/-/log4js-1.1.1.tgz", - "integrity": "sha1-wh0px2BAieTyVYM+f5SzRh3h/0M=", + "resolved": "https://registry.npmjs.org/loggly/-/loggly-1.1.1.tgz", + "integrity": "sha1-Cg/B0/o6XsRP3HuJe+uipGlc6+4=", + "optional": true, "requires": { - "debug": "^2.2.0", - "semver": "^5.3.0", - "streamroller": "^0.4.0" + "json-stringify-safe": "5.0.x", + "request": "2.75.x", + "timespan": "2.3.x" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "optional": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "optional": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "optional": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "optional": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "requires": { + "hoek": "2.x.x" + } + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "optional": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "optional": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "optional": true, + "requires": { + "boom": "2.x.x" + } + }, + "form-data": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.0.0.tgz", + "integrity": "sha1-bwrrrcxdoWwT4ezBETfYX5uIOyU=", + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.11" + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "optional": true, + "requires": { + "chalk": "^1.1.1", + "commander": "^2.9.0", + "is-my-json-valid": "^2.12.4", + "pinkie-promise": "^2.0.0" + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "optional": true, + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=" + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "optional": true, + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "optional": true + }, + "qs": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz", + "integrity": "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4=", + "optional": true + }, + "request": { + "version": "2.75.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.75.0.tgz", + "integrity": "sha1-0rgmiihtoT6qXQGt9dGMyQ9lfZM=", + "optional": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "bl": "~1.1.2", + "caseless": "~0.11.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.0.0", + "har-validator": "~2.0.6", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "node-uuid": "~1.4.7", + "oauth-sign": "~0.8.1", + "qs": "~6.2.0", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "~0.4.1" + } + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "optional": true, + "requires": { + "hoek": "2.x.x" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "optional": true + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "optional": true + } } }, "loose-envify": { @@ -673,6 +1576,67 @@ "js-tokens": "^3.0.0" } }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "optional": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "mailcomposer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-4.0.1.tgz", + "integrity": "sha1-DhxEsqB890DuF9wUm6AJ8Zyt/rQ=", + "optional": true, + "requires": { + "buildmail": "4.0.1", + "libmime": "3.0.0" + } + }, + "mailgun-js": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.18.0.tgz", + "integrity": "sha512-o0P6jjZlx5CQj12tvVgDTbgjTqVN0+5h6/6P1+3c6xmozVKBwniQ6Qt3MkCSF0+ueVTbobAfWyGpWRZMJu8t1g==", + "optional": true, + "requires": { + "async": "~2.6.0", + "debug": "~3.1.0", + "form-data": "~2.3.0", + "inflection": "~1.12.0", + "is-stream": "^1.1.0", + "path-proxy": "~1.0.0", + "promisify-call": "^2.0.2", + "proxy-agent": "~3.0.0", + "tsscmp": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "mime-db": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", + "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + }, + "mime-types": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", + "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "requires": { + "mime-db": "~1.33.0" + } + }, "mimic-fn": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", @@ -719,11 +1683,100 @@ "thenify-all": "^1.0.0" } }, + "netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", + "optional": true + }, + "nodemailer": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-2.7.2.tgz", + "integrity": "sha1-8kLmSa7q45tsftdA73sGHEBNMPk=", + "optional": true, + "requires": { + "libmime": "3.0.0", + "mailcomposer": "4.0.1", + "nodemailer-direct-transport": "3.3.2", + "nodemailer-shared": "1.1.0", + "nodemailer-smtp-pool": "2.8.2", + "nodemailer-smtp-transport": "2.7.2", + "socks": "1.1.9" + }, + "dependencies": { + "socks": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz", + "integrity": "sha1-Yo1+TQSRJDVEWsC25Fk3bLPm1pE=", + "optional": true, + "requires": { + "ip": "^1.1.2", + "smart-buffer": "^1.0.4" + } + } + } + }, + "nodemailer-direct-transport": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz", + "integrity": "sha1-6W+vuQNYVglH5WkBfZfmBzilCoY=", + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-fetch": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", + "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=" + }, + "nodemailer-shared": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", + "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", + "requires": { + "nodemailer-fetch": "1.6.0" + } + }, + "nodemailer-smtp-pool": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz", + "integrity": "sha1-LrlNbPhXgLG0clzoU7nL1ejajHI=", + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "nodemailer-wellknown": "0.1.10", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-smtp-transport": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz", + "integrity": "sha1-A9ccdjFPFKx9vHvwM6am0W1n+3c=", + "optional": true, + "requires": { + "nodemailer-shared": "1.1.0", + "nodemailer-wellknown": "0.1.10", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-wellknown": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz", + "integrity": "sha1-WG24EB2zDLRDjrVGc3pBqtDPE9U=" + }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "optional": true + }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -763,11 +1816,89 @@ "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" }, + "pac-proxy-agent": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-2.0.2.tgz", + "integrity": "sha512-cDNAN1Ehjbf5EHkNY5qnRhGPUCp6SnpyVof5fRzN800QV1Y2OkzbH9rmjZkbBRa8igof903yOnjIl6z0SlAhxA==", + "optional": true, + "requires": { + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "get-uri": "^2.0.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "pac-resolver": "^3.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "pac-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", + "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", + "optional": true, + "requires": { + "co": "^4.6.0", + "degenerator": "^1.0.4", + "ip": "^1.1.5", + "netmask": "^1.0.6", + "thunkify": "^2.1.2" + } + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, + "path-proxy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz", + "integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=", + "optional": true, + "requires": { + "inflection": "~1.3.0" + }, + "dependencies": { + "inflection": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz", + "integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4=", + "optional": true + } + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "optional": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "optional": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "optional": true, + "requires": { + "pinkie": "^2.0.0" + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -778,15 +1909,94 @@ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.12.1.tgz", "integrity": "sha1-wa0g6APndJ+vkFpAnSNn4Gu+cyU=" }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "optional": true + }, "progress": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" }, + "promisify-call": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/promisify-call/-/promisify-call-2.0.4.tgz", + "integrity": "sha1-1IwtRWUszM1SgB3ey9UzptS9X7o=", + "optional": true, + "requires": { + "with-callback": "^1.0.2" + } + }, + "proxy-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.0.0.tgz", + "integrity": "sha512-g6n6vnk8fRf705ShN+FEXFG/SDJaW++lSs0d9KaJh4uBWW/wi7en4Cpo5VYQW3SZzAE121lhB/KLQrbURoubZw==", + "optional": true, + "requires": { + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "pac-proxy-agent": "^2.0.1", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "optional": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "optional": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "optional": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "optional": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "optional": true + }, + "raw-body": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", + "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "optional": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.1", @@ -794,6 +2004,29 @@ "string_decoder": "~0.10.x" } }, + "redis": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", + "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "optional": true, + "requires": { + "double-ended-queue": "^2.1.0-0", + "redis-commands": "^1.2.0", + "redis-parser": "^2.6.0" + } + }, + "redis-commands": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.5.tgz", + "integrity": "sha512-foGF8u6MXGFF++1TZVC6icGXuMYPftKXt1FBT2vrfU9ZATNtZJ8duRC5d1lEfE8hyVe3jhelHGB91oB7I6qLsA==", + "optional": true + }, + "redis-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=", + "optional": true + }, "regenerator-runtime": { "version": "0.11.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", @@ -807,6 +2040,48 @@ "is-finite": "^1.0.0" } }, + "request": { + "version": "2.85.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", + "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "optional": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.6.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.1", + "forever-agent": "~0.6.1", + "form-data": "~2.3.1", + "har-validator": "~5.0.3", + "hawk": "~6.0.2", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.17", + "oauth-sign": "~0.8.2", + "performance-now": "^2.1.0", + "qs": "~6.5.1", + "safe-buffer": "^5.1.1", + "stringstream": "~0.0.5", + "tough-cookie": "~2.3.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.1.0" + } + }, + "requestretry": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", + "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", + "optional": true, + "requires": { + "extend": "^3.0.0", + "lodash": "^4.15.0", + "request": "^2.74.0", + "when": "^3.7.7" + } + }, "restore-cursor": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", @@ -840,6 +2115,11 @@ "tslib": "^1.9.0" } }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -850,31 +2130,144 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "optional": true + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" }, + "slack-node": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/slack-node/-/slack-node-0.2.0.tgz", + "integrity": "sha1-3kuN3aqLeT9h29KTgQT9q/N9+jA=", + "optional": true, + "requires": { + "requestretry": "^1.2.2" + } + }, + "smart-buffer": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz", + "integrity": "sha1-fxFLW2X6s+KjWqd1uxLw0cZJvxY=" + }, + "smtp-connection": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", + "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", + "requires": { + "httpntlm": "1.6.1", + "nodemailer-shared": "1.1.0" + } + }, + "sntp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", + "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", + "optional": true, + "requires": { + "hoek": "4.x.x" + } + }, + "socks": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.10.tgz", + "integrity": "sha1-W4t/x8jzQcU+0FbpKbe/Tei6e1o=", + "requires": { + "ip": "^1.1.4", + "smart-buffer": "^1.0.13" + } + }, + "socks-proxy-agent": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-3.0.1.tgz", + "integrity": "sha512-ZwEDymm204mTzvdqyUqOdovVr2YRd2NYskrYrF2LXyZ9qDiMAoFESGK8CRphiO7rtbo2Y757k2Nia3x2hGtalA==", + "requires": { + "agent-base": "^4.1.0", + "socks": "^1.1.10" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" }, + "sshpk": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.1.tgz", + "integrity": "sha1-Ew9Zde3a2WPx1W+SuaxsUfqfg+s=", + "optional": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "optional": true + }, "streamroller": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.4.1.tgz", - "integrity": "sha1-1DW9WXQ3Or2b2QaDWVEwhRBswF8=", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", + "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", "requires": { - "date-format": "^0.0.0", - "debug": "^0.7.2", + "date-format": "^1.2.0", + "debug": "^3.1.0", "mkdirp": "^0.5.1", - "readable-stream": "^1.1.7" + "readable-stream": "^2.3.0" }, "dependencies": { "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } } } }, @@ -890,7 +2283,14 @@ "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "optional": true + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "optional": true }, "strip-ansi": { "version": "4.0.0", @@ -939,6 +2339,18 @@ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" }, + "thunkify": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", + "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", + "optional": true + }, + "timespan": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/timespan/-/timespan-2.3.0.tgz", + "integrity": "sha1-SQLOBAvRPYRcj1myfp1ZutbzmSk=", + "optional": true + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -952,6 +2364,15 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "optional": true, + "requires": { + "punycode": "^1.4.1" + } + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -962,11 +2383,32 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz", "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==" }, + "tsscmp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz", + "integrity": "sha1-fcSjOvcVgatDN9qR2FylQn69mpc=", + "optional": true + }, "tunnel": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.4.tgz", "integrity": "sha1-LTeFoVjBdMmhbcLARuxfxfF0IhM=" }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "optional": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "optional": true + }, "type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -989,6 +2431,46 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "optional": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I=", + "optional": true + }, + "with-callback": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/with-callback/-/with-callback-1.0.2.tgz", + "integrity": "sha1-oJYpuakgAo1yFAT7Q1vc/1yRvCE=", + "optional": true + }, "wordwrap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", @@ -998,6 +2480,24 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "optional": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "optional": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "optional": true } } } diff --git a/packages/stryker/package.json b/packages/stryker/package.json index a17e8321d6..07f8cbd93c 100644 --- a/packages/stryker/package.json +++ b/packages/stryker/package.json @@ -61,7 +61,7 @@ "inquirer": "^5.2.0", "istanbul-lib-instrument": "^1.9.2", "lodash": "^4.17.4", - "log4js": "^1.1.0", + "log4js": "^2.6.1", "mkdirp": "^0.5.1", "mz": "^2.6.0", "prettier": "^1.6.1", diff --git a/packages/stryker/src/ConfigReader.ts b/packages/stryker/src/ConfigReader.ts index 8afd4d8e28..fc0ce25bb8 100644 --- a/packages/stryker/src/ConfigReader.ts +++ b/packages/stryker/src/ConfigReader.ts @@ -1,9 +1,10 @@ import { Config } from 'stryker-api/config'; import { StrykerOptions } from 'stryker-api/core'; import * as fs from 'mz/fs'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; import * as path from 'path'; import * as _ from 'lodash'; +import StrykerError from './utils/StrykerError'; export const CONFIG_SYNTAX_HELP = ' module.exports = function(config) {\n' + ' config.set({\n' + @@ -25,8 +26,7 @@ export default class ConfigReader { try { configModule(config); } catch (e) { - this.log.fatal('Error in config file!\n', e); - process.exit(1); + throw new StrykerError('Error in config file!', e); } // merge the config from config file and cliOptions (precedence) diff --git a/packages/stryker/src/ConfigValidator.ts b/packages/stryker/src/ConfigValidator.ts index a5c836217e..3b844d200c 100644 --- a/packages/stryker/src/ConfigValidator.ts +++ b/packages/stryker/src/ConfigValidator.ts @@ -1,7 +1,8 @@ import { TestFramework } from 'stryker-api/test_framework'; import { MutatorDescriptor, MutationScoreThresholds } from 'stryker-api/core'; import { Config } from 'stryker-api/config'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; +import StrykerError from './utils/StrykerError'; export default class ConfigValidator { @@ -101,7 +102,7 @@ export default class ConfigValidator { private crashIfNeeded() { if (!this.isValid) { - process.exit(1); + throw new StrykerError('Stryker could not recover from this configuration error, see fatal log message(s) above.'); } } diff --git a/packages/stryker/src/MutantTestMatcher.ts b/packages/stryker/src/MutantTestMatcher.ts index de0fa9778e..956d63c3d1 100644 --- a/packages/stryker/src/MutantTestMatcher.ts +++ b/packages/stryker/src/MutantTestMatcher.ts @@ -1,5 +1,5 @@ import * as _ from 'lodash'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { RunResult, CoverageCollection, StatementMap, CoveragePerTestResult, CoverageResult } from 'stryker-api/test_runner'; import { StrykerOptions, File } from 'stryker-api/core'; import { MatchedMutant } from 'stryker-api/report'; diff --git a/packages/stryker/src/PluginLoader.ts b/packages/stryker/src/PluginLoader.ts index 2678877aec..9efc457bc9 100644 --- a/packages/stryker/src/PluginLoader.ts +++ b/packages/stryker/src/PluginLoader.ts @@ -1,6 +1,6 @@ import * as fs from 'mz/fs'; import * as path from 'path'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import * as _ from 'lodash'; import { importModule } from './utils/fileUtils'; diff --git a/packages/stryker/src/ReporterOrchestrator.ts b/packages/stryker/src/ReporterOrchestrator.ts index 85c3ddb0b4..ae32b03619 100644 --- a/packages/stryker/src/ReporterOrchestrator.ts +++ b/packages/stryker/src/ReporterOrchestrator.ts @@ -8,7 +8,7 @@ import EventRecorderReporter from './reporters/EventRecorderReporter'; import BroadcastReporter, { NamedReporter } from './reporters/BroadcastReporter'; import DashboardReporter from './reporters/DashboardReporter'; import StrictReporter from './reporters/StrictReporter'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; function registerDefaultReporters() { ReporterFactory.instance().register('progress-append-only', ProgressAppendOnlyReporter); diff --git a/packages/stryker/src/Sandbox.ts b/packages/stryker/src/Sandbox.ts index 11976437af..4f1439cb10 100644 --- a/packages/stryker/src/Sandbox.ts +++ b/packages/stryker/src/Sandbox.ts @@ -1,6 +1,6 @@ import { Config } from 'stryker-api/config'; import * as path from 'path'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import * as mkdirp from 'mkdirp'; import { RunResult } from 'stryker-api/test_runner'; import { File } from 'stryker-api/core'; diff --git a/packages/stryker/src/SandboxPool.ts b/packages/stryker/src/SandboxPool.ts index ec9286c411..30b45673f8 100644 --- a/packages/stryker/src/SandboxPool.ts +++ b/packages/stryker/src/SandboxPool.ts @@ -1,4 +1,4 @@ -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import * as os from 'os'; import { Observable, range } from 'rxjs'; import { flatMap } from 'rxjs/operators'; diff --git a/packages/stryker/src/ScoreResultCalculator.ts b/packages/stryker/src/ScoreResultCalculator.ts index 748e845ed7..010577c520 100644 --- a/packages/stryker/src/ScoreResultCalculator.ts +++ b/packages/stryker/src/ScoreResultCalculator.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import * as _ from 'lodash'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { MutationScoreThresholds } from 'stryker-api/core'; import { MutantResult, MutantStatus, ScoreResult } from 'stryker-api/report'; import { freezeRecursively, setExitCode } from './utils/objectUtils'; diff --git a/packages/stryker/src/Stryker.ts b/packages/stryker/src/Stryker.ts index d8fc1c7b61..6ddb850793 100644 --- a/packages/stryker/src/Stryker.ts +++ b/packages/stryker/src/Stryker.ts @@ -1,3 +1,4 @@ +import { getLogger, Logger } from 'stryker-api/logging'; import { Config, ConfigEditorFactory } from 'stryker-api/config'; import { StrykerOptions, MutatorDescriptor } from 'stryker-api/core'; import { MutantResult } from 'stryker-api/report'; @@ -13,13 +14,13 @@ import ScoreResultCalculator from './ScoreResultCalculator'; import ConfigValidator from './ConfigValidator'; import { freezeRecursively, isPromise } from './utils/objectUtils'; import { TempFolder } from './utils/TempFolder'; -import * as log4js from 'log4js'; import Timer from './utils/Timer'; import StrictReporter from './reporters/StrictReporter'; import MutatorFacade from './MutatorFacade'; import InitialTestExecutor, { InitialTestRunResult } from './process/InitialTestExecutor'; import MutationTestExecutor from './process/MutationTestExecutor'; import InputFileCollection from './input/InputFileCollection'; +import LogConfigurator from './utils/LogConfigurator'; export default class Stryker { @@ -27,7 +28,7 @@ export default class Stryker { private timer = new Timer(); private reporter: StrictReporter; private testFramework: TestFramework | null; - private readonly log = log4js.getLogger(Stryker.name); + private readonly log: Logger; /** * The Stryker mutation tester. @@ -35,12 +36,14 @@ export default class Stryker { * @param {Object} [options] - Optional options. */ constructor(options: StrykerOptions) { + LogConfigurator.forMaster(options.logLevel); + this.log = getLogger(Stryker.name); let configReader = new ConfigReader(options); this.config = configReader.readConfig(); - this.setGlobalLogLevel(); // logLevel could be changed + LogConfigurator.forMaster(this.config.logLevel); // logLevel could be changed this.loadPlugins(); this.applyConfigEditors(); - this.setGlobalLogLevel(); // logLevel could be changed + LogConfigurator.forMaster(this.config.logLevel); // logLevel could be changed this.freezeConfig(); this.reporter = new ReporterOrchestrator(this.config).createBroadcastReporter(); this.testFramework = new TestFrameworkOrchestrator(this.config).determineTestFramework(); @@ -146,10 +149,6 @@ export default class Stryker { this.log.info('Done in %s.', this.timer.humanReadableElapsed()); } - private setGlobalLogLevel() { - log4js.setGlobalLogLevel(this.config.logLevel); - } - private reportScore(mutantResults: MutantResult[]) { const calculator = new ScoreResultCalculator(); const score = calculator.calculate(mutantResults); diff --git a/packages/stryker/src/StrykerCli.ts b/packages/stryker/src/StrykerCli.ts index 017e84bec0..27f184c04b 100644 --- a/packages/stryker/src/StrykerCli.ts +++ b/packages/stryker/src/StrykerCli.ts @@ -2,12 +2,11 @@ import * as program from 'commander'; import { CONFIG_SYNTAX_HELP } from './ConfigReader'; import Stryker from './Stryker'; import StrykerInitializer from './initializer/StrykerInitializer'; -import { getLogger, setGlobalLogLevel } from 'log4js'; - +import { getLogger } from 'stryker-api/logging'; +import LogConfigurator from './utils/LogConfigurator'; export default class StrykerCli { - private readonly log = getLogger(StrykerCli.name); private command: string = ''; private strykerConfig: string | null = null; @@ -23,7 +22,7 @@ export default class StrykerCli { .usage(' [options] [stryker.conf.js]') .description(`Possible commands: run: Run mutation testing - init: Initalize Stryker for your project + init: Initialize Stryker for your project Optional location to the stryker.conf.js file as last argument. That file should export a function which accepts a "config" object\n${CONFIG_SYNTAX_HELP}`) .arguments(' [stryker.conf.js]') @@ -49,8 +48,8 @@ export default class StrykerCli { .option('--logLevel ', 'Set the log4js log level. Possible values: fatal, error, warn, info, debug, trace, all and off. Default is "info"') .parse(this.argv); - setGlobalLogLevel(program['logLevel'] || 'info'); - + LogConfigurator.forMaster(program['logLevel']); + const log = getLogger(StrykerCli.name); // Cleanup commander state delete program['options']; delete program['rawArgs']; @@ -68,10 +67,6 @@ export default class StrykerCli { program['configFile'] = this.strykerConfig; } - if (program['logLevel']) { - setGlobalLogLevel(program['logLevel']); - } - const commands: { [cmd: string]: () => Promise } = { init: () => new StrykerInitializer().initialize(), run: () => new Stryker(program).runMutationTest() @@ -79,12 +74,12 @@ export default class StrykerCli { if (Object.keys(commands).indexOf(this.command) >= 0) { commands[this.command]().catch(err => { - this.log.error(`an error occurred`, err); + log.error(`an error occurred`, err); process.exitCode = 1; process.kill(process.pid, 'SIGINT'); }); } else { - this.log.error('Unknown command: "%s", supported commands: [%s], or use `stryker --help`.', this.command, Object.keys(commands)); + log.error('Unknown command: "%s", supported commands: [%s], or use `stryker --help`.', this.command, Object.keys(commands)); } } } diff --git a/packages/stryker/src/TestFrameworkOrchestrator.ts b/packages/stryker/src/TestFrameworkOrchestrator.ts index f9b9bdb73d..26846384b5 100644 --- a/packages/stryker/src/TestFrameworkOrchestrator.ts +++ b/packages/stryker/src/TestFrameworkOrchestrator.ts @@ -1,6 +1,6 @@ import { TestFrameworkFactory, TestFramework } from 'stryker-api/test_framework'; import { StrykerOptions } from 'stryker-api/core'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; export default class TestFrameworkOrchestrator { private readonly log = getLogger(TestFrameworkOrchestrator.name); diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index 3f254c2a43..874572bbcc 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -3,7 +3,7 @@ import { File } from 'stryker-api/core'; import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol'; import { serialize, deserialize } from '../utils/objectUtils'; import Task from '../utils/Task'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; export type ChildProxy = { [K in keyof T]: (...args: any[]) => Promise; @@ -14,6 +14,7 @@ export default class ChildProcessProxy { private worker: ChildProcess; private initTask: Task; + private disposeTask: Task; private workerTasks: Task[] = []; private log = getLogger(ChildProcessProxy.name); @@ -85,6 +86,9 @@ export default class ChildProcessProxy { case ParentMessageKind.Rejection: this.workerTasks[message.correlationId].reject(new Error(message.error)); break; + case ParentMessageKind.DisposeCompleted: + this.disposeTask.resolve(undefined); + break; default: this.logUnidentifiedMessage(message); break; @@ -92,8 +96,12 @@ export default class ChildProcessProxy { }); } - public dispose() { - this.worker.kill(); + public dispose(): Promise { + this.disposeTask = new Task(); + this.send({ kind: WorkerMessageKind.Dispose }); + return this.disposeTask.promise + .then(() => this.worker.kill()) + .catch(() => this.worker.kill()); } private logUnidentifiedMessage(message: never) { diff --git a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts index db74f4e19e..47ad8ba46b 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts @@ -1,16 +1,19 @@ -import { setGlobalLogLevel, getLogger } from 'log4js'; +import { getLogger, Logger } from 'stryker-api/logging'; import { File } from 'stryker-api/core'; import { serialize, deserialize, errorToString } from '../utils/objectUtils'; import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol'; import PluginLoader from '../PluginLoader'; +import LogConfigurator from '../utils/LogConfigurator'; export default class ChildProcessProxyWorker { - private log = getLogger(ChildProcessProxyWorker.name); + private readonly log: Logger; realSubject: any; constructor() { + LogConfigurator.forWorker(); + this.log = getLogger(ChildProcessProxyWorker.name); this.listenToParent(); } @@ -26,7 +29,6 @@ export default class ChildProcessProxyWorker { const message = deserialize(serializedMessage, [File]); switch (message.kind) { case WorkerMessageKind.Init: - setGlobalLogLevel(message.logLevel); new PluginLoader(message.plugins).load(); const RealSubjectClass = require(message.requirePath).default; this.realSubject = new RealSubjectClass(...message.constructorArgs); @@ -50,6 +52,14 @@ export default class ChildProcessProxyWorker { }); this.removeAnyAdditionalMessageListeners(handler); break; + case WorkerMessageKind.Dispose: + const sendCompleted = () => { + this.send({ kind: ParentMessageKind.DisposeCompleted }); + }; + LogConfigurator.shutdown() + .then(sendCompleted) + .catch(sendCompleted); + break; } }; process.on('message', handler); diff --git a/packages/stryker/src/child-proxy/messageProtocol.ts b/packages/stryker/src/child-proxy/messageProtocol.ts index 980aba168b..1b2b3b4155 100644 --- a/packages/stryker/src/child-proxy/messageProtocol.ts +++ b/packages/stryker/src/child-proxy/messageProtocol.ts @@ -1,16 +1,18 @@ export enum WorkerMessageKind { 'Init', - 'Work' + 'Work', + 'Dispose' } export enum ParentMessageKind { 'Initialized', 'Result', - 'Rejection' + 'Rejection', + 'DisposeCompleted' } -export type WorkerMessage = InitMessage | WorkMessage; -export type ParentMessage = WorkResult | { kind: ParentMessageKind.Initialized} | RejectionResult; +export type WorkerMessage = InitMessage | WorkMessage | { kind: WorkerMessageKind.Dispose }; +export type ParentMessage = WorkResult | { kind: ParentMessageKind.Initialized | ParentMessageKind.DisposeCompleted } | RejectionResult; // Make this an unlikely command line argument // (prevents incidental start of child process) @@ -41,4 +43,4 @@ export interface WorkMessage { kind: WorkerMessageKind.Work; args: any[]; methodName: string; -} \ No newline at end of file +} diff --git a/packages/stryker/src/initializer/NpmClient.ts b/packages/stryker/src/initializer/NpmClient.ts index bb41404ad6..a182f206fa 100644 --- a/packages/stryker/src/initializer/NpmClient.ts +++ b/packages/stryker/src/initializer/NpmClient.ts @@ -1,6 +1,6 @@ import { RestClient, IRestResponse } from 'typed-rest-client/RestClient'; import PromptOption from './PromptOption'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { errorToString } from '../utils/objectUtils'; interface NpmSearchPackageInfo { diff --git a/packages/stryker/src/initializer/StrykerConfigWriter.ts b/packages/stryker/src/initializer/StrykerConfigWriter.ts index 465803ebb4..c5281c4f05 100644 --- a/packages/stryker/src/initializer/StrykerConfigWriter.ts +++ b/packages/stryker/src/initializer/StrykerConfigWriter.ts @@ -1,6 +1,6 @@ import * as fs from 'mz/fs'; import * as _ from 'lodash'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { StrykerOptions } from 'stryker-api/core'; import PromptOption from './PromptOption'; import { format } from 'prettier'; diff --git a/packages/stryker/src/initializer/StrykerInitializer.ts b/packages/stryker/src/initializer/StrykerInitializer.ts index c0eed01366..3663600a7f 100644 --- a/packages/stryker/src/initializer/StrykerInitializer.ts +++ b/packages/stryker/src/initializer/StrykerInitializer.ts @@ -2,7 +2,7 @@ import * as child from 'child_process'; import { StrykerInquirer } from './StrykerInquirer'; import NpmClient from './NpmClient'; import PromptOption from './PromptOption'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { filterEmpty } from '../utils/objectUtils'; import StrykerConfigWriter from './StrykerConfigWriter'; diff --git a/packages/stryker/src/input/InputFileCollection.ts b/packages/stryker/src/input/InputFileCollection.ts index c5ca416cc9..2eb13a2a84 100644 --- a/packages/stryker/src/input/InputFileCollection.ts +++ b/packages/stryker/src/input/InputFileCollection.ts @@ -1,5 +1,5 @@ import { File } from 'stryker-api/core'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { normalizeWhiteSpaces } from '../utils/objectUtils'; export default class InputFileCollection { diff --git a/packages/stryker/src/input/InputFileResolver.ts b/packages/stryker/src/input/InputFileResolver.ts index a15ec8dfeb..e53f9b06bf 100644 --- a/packages/stryker/src/input/InputFileResolver.ts +++ b/packages/stryker/src/input/InputFileResolver.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import * as fs from 'mz/fs'; import { exec } from 'mz/child_process'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { File } from 'stryker-api/core'; import { glob } from '../utils/fileUtils'; import StrictReporter from '../reporters/StrictReporter'; diff --git a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts index e1ab9796db..f2bb79d596 100644 --- a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts +++ b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts @@ -1,5 +1,5 @@ import { EventEmitter } from 'events'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import * as _ from 'lodash'; import { fork, ChildProcess } from 'child_process'; import { TestRunner, RunResult, RunOptions } from 'stryker-api/test_runner'; diff --git a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts index 50d2d66d7d..8f49b4bcd4 100644 --- a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts +++ b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts @@ -1,15 +1,18 @@ import { AdapterMessage, RunMessage, StartMessage, WorkerMessage, InitDoneMessage } from './MessageProtocol'; import { TestRunner, RunStatus, TestRunnerFactory, RunResult } from 'stryker-api/test_runner'; import PluginLoader from '../PluginLoader'; -import { getLogger } from 'log4js'; +import { getLogger, Logger } from 'stryker-api/logging'; import { deserialize, errorToString } from '../utils/objectUtils'; +import LogConfigurator from '../utils/LogConfigurator'; class IsolatedTestRunnerAdapterWorker { - private readonly log = getLogger(IsolatedTestRunnerAdapterWorker.name); + private readonly log: Logger; private underlyingTestRunner: TestRunner; constructor() { + LogConfigurator.forWorker(); + this.log = getLogger(IsolatedTestRunnerAdapterWorker.name); this.handlePromiseRejections(); this.listenToMessages(); } @@ -86,6 +89,7 @@ class IsolatedTestRunnerAdapterWorker { if (this.underlyingTestRunner.dispose) { await this.underlyingTestRunner.dispose(); } + await LogConfigurator.shutdown(); this.sendDisposeDone(); } diff --git a/packages/stryker/src/isolated-runner/TimeoutDecorator.ts b/packages/stryker/src/isolated-runner/TimeoutDecorator.ts index 7bcc666d03..d72f044c86 100644 --- a/packages/stryker/src/isolated-runner/TimeoutDecorator.ts +++ b/packages/stryker/src/isolated-runner/TimeoutDecorator.ts @@ -2,7 +2,7 @@ import { RunOptions, RunResult, RunStatus } from 'stryker-api/test_runner'; import { isPromise } from '../utils/objectUtils'; import Task from '../utils/Task'; import TestRunnerDecorator from './TestRunnerDecorator'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; const MAX_WAIT_FOR_DISPOSE = 2500; diff --git a/packages/stryker/src/mutators/ES5Mutator.ts b/packages/stryker/src/mutators/ES5Mutator.ts index 61ebf2d21b..a3ad8ea8e2 100644 --- a/packages/stryker/src/mutators/ES5Mutator.ts +++ b/packages/stryker/src/mutators/ES5Mutator.ts @@ -1,5 +1,5 @@ import * as _ from 'lodash'; -import { Logger, getLogger } from 'log4js'; +import { Logger, getLogger } from 'stryker-api/logging'; import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; import { Mutator, Mutant } from 'stryker-api/mutant'; diff --git a/packages/stryker/src/process/InitialTestExecutor.ts b/packages/stryker/src/process/InitialTestExecutor.ts index 887914f5b8..22f135fa53 100644 --- a/packages/stryker/src/process/InitialTestExecutor.ts +++ b/packages/stryker/src/process/InitialTestExecutor.ts @@ -5,7 +5,7 @@ import { Config } from 'stryker-api/config'; import { TranspilerOptions, Transpiler } from 'stryker-api/transpile'; import { File } from 'stryker-api/core'; import TranspilerFacade from '../transpiler/TranspilerFacade'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import Sandbox from '../Sandbox'; import Timer from '../utils/Timer'; import CoverageInstrumenterTranspiler, { CoverageMapsByFile } from '../transpiler/CoverageInstrumenterTranspiler'; diff --git a/packages/stryker/src/reporters/BroadcastReporter.ts b/packages/stryker/src/reporters/BroadcastReporter.ts index 59d8220ee9..b52993adc5 100644 --- a/packages/stryker/src/reporters/BroadcastReporter.ts +++ b/packages/stryker/src/reporters/BroadcastReporter.ts @@ -1,5 +1,5 @@ import { Reporter, SourceFile, MutantResult, MatchedMutant, ScoreResult } from 'stryker-api/report'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { isPromise } from '../utils/objectUtils'; import StrictReporter from './StrictReporter'; diff --git a/packages/stryker/src/reporters/ClearTextReporter.ts b/packages/stryker/src/reporters/ClearTextReporter.ts index 19115a0ddf..1d0ee6c45e 100644 --- a/packages/stryker/src/reporters/ClearTextReporter.ts +++ b/packages/stryker/src/reporters/ClearTextReporter.ts @@ -1,5 +1,5 @@ import chalk from 'chalk'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { Reporter, MutantResult, MutantStatus, ScoreResult } from 'stryker-api/report'; import { Config } from 'stryker-api/config'; import ClearTextScoreTable from './ClearTextScoreTable'; diff --git a/packages/stryker/src/reporters/DashboardReporter.ts b/packages/stryker/src/reporters/DashboardReporter.ts index f118e97421..e1fde7ea4b 100644 --- a/packages/stryker/src/reporters/DashboardReporter.ts +++ b/packages/stryker/src/reporters/DashboardReporter.ts @@ -1,7 +1,7 @@ import {Reporter, ScoreResult} from 'stryker-api/report'; import DashboardReporterClient from './dashboard-reporter/DashboardReporterClient'; import {getEnvironmentVariable} from '../utils/objectUtils'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { StrykerOptions } from 'stryker-api/core'; export default class DashboardReporter implements Reporter { diff --git a/packages/stryker/src/reporters/EventRecorderReporter.ts b/packages/stryker/src/reporters/EventRecorderReporter.ts index a6295b19a6..4a3ffe59e8 100644 --- a/packages/stryker/src/reporters/EventRecorderReporter.ts +++ b/packages/stryker/src/reporters/EventRecorderReporter.ts @@ -1,4 +1,4 @@ -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import * as path from 'path'; import * as fs from 'mz/fs'; import { StrykerOptions } from 'stryker-api/core'; diff --git a/packages/stryker/src/reporters/dashboard-reporter/DashboardReporterClient.ts b/packages/stryker/src/reporters/dashboard-reporter/DashboardReporterClient.ts index 95c9781847..4d4a011417 100644 --- a/packages/stryker/src/reporters/dashboard-reporter/DashboardReporterClient.ts +++ b/packages/stryker/src/reporters/dashboard-reporter/DashboardReporterClient.ts @@ -1,4 +1,4 @@ -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { HttpClient } from 'typed-rest-client/HttpClient'; import { errorToString } from '../../utils/objectUtils'; diff --git a/packages/stryker/src/transpiler/SourceMapper.ts b/packages/stryker/src/transpiler/SourceMapper.ts index 739a535eb7..c16e18a540 100644 --- a/packages/stryker/src/transpiler/SourceMapper.ts +++ b/packages/stryker/src/transpiler/SourceMapper.ts @@ -3,7 +3,7 @@ import { SourceMapConsumer, RawSourceMap } from 'source-map'; import { File, Location, Position } from 'stryker-api/core'; import { Config } from 'stryker-api/config'; import { base64Decode } from '../utils/objectUtils'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import StrykerError from '../utils/StrykerError'; const SOURCE_MAP_URL_REGEX = /\/\/\s*#\s*sourceMappingURL=(.*)/g; diff --git a/packages/stryker/src/utils/LogConfigurator.ts b/packages/stryker/src/utils/LogConfigurator.ts new file mode 100644 index 0000000000..06773a644d --- /dev/null +++ b/packages/stryker/src/utils/LogConfigurator.ts @@ -0,0 +1,57 @@ +import * as log4js from 'log4js'; +import { LoggerFactory } from 'stryker-api/logging'; + +let notConfigured = true; + +export default class LogConfigurator { + + static setImplementation(): void { + LoggerFactory.setLogImplementation(log4js.getLogger); + } + + static forMaster(logLevel = 'info') { + const layout: log4js.PatternLayout = { + type: 'pattern', + pattern: '%[%r (%z) %p %c%] %m' + }; + this.setImplementation(); + if (notConfigured) { + log4js.configure({ + appenders: { + console: { type: 'stdout', layout }, + file: { type: 'file', filename: 'application.log', layout }, + filteredConsole: { type: 'logLevelFilter', appender: 'console', level: logLevel }, + server: { type: 'multiprocess', mode: 'master', appender: 'file' } + }, + categories: { + default: { appenders: ['filteredConsole', 'file'], level: 'trace' } + }, + }); + notConfigured = false; + } + } + + static forWorker() { + this.setImplementation(); + log4js.configure({ + appenders: { + server: { type: 'multiprocess', mode: 'worker' } + }, + categories: { + default: { appenders: ['server'], level: 'trace' } + }, + }); + } + + static shutdown(): Promise { + return new Promise((res, rej) => { + log4js.shutdown(err => { + if (err) { + rej(err); + } else { + res(); + } + }); + }; + } +} \ No newline at end of file diff --git a/packages/stryker/src/utils/StrykerTempFolder.ts b/packages/stryker/src/utils/StrykerTempFolder.ts index dfc880600b..4561b1ff5b 100644 --- a/packages/stryker/src/utils/StrykerTempFolder.ts +++ b/packages/stryker/src/utils/StrykerTempFolder.ts @@ -1,7 +1,7 @@ import * as fs from 'mz/fs'; import * as path from 'path'; import * as mkdirp from 'mkdirp'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { deleteDir } from './fileUtils'; let baseTempFolder = path.join(process.cwd(), '.stryker-tmp'); diff --git a/packages/stryker/src/utils/TempFolder.ts b/packages/stryker/src/utils/TempFolder.ts index ee13d3eb2a..560d5837fc 100644 --- a/packages/stryker/src/utils/TempFolder.ts +++ b/packages/stryker/src/utils/TempFolder.ts @@ -1,7 +1,7 @@ import * as fs from 'mz/fs'; import * as path from 'path'; import * as mkdirp from 'mkdirp'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { deleteDir } from './fileUtils'; diff --git a/packages/stryker/test/helpers/log4jsMock.ts b/packages/stryker/test/helpers/logMock.ts similarity index 52% rename from packages/stryker/test/helpers/log4jsMock.ts rename to packages/stryker/test/helpers/logMock.ts index b9ef04786d..c236d55207 100644 --- a/packages/stryker/test/helpers/log4jsMock.ts +++ b/packages/stryker/test/helpers/logMock.ts @@ -1,11 +1,11 @@ -import * as log4js from 'log4js'; +import * as logging from 'stryker-api/logging'; import { logger, Mock } from './producers'; -let log: Mock; +let log: Mock; beforeEach(() => { log = logger(); - sandbox.stub(log4js, 'getLogger').returns(log); + sandbox.stub(logging, 'getLogger').returns(log); }); export default function currentLogMock() { diff --git a/packages/stryker/test/helpers/producers.ts b/packages/stryker/test/helpers/producers.ts index 9097e8f005..202d008e8a 100644 --- a/packages/stryker/test/helpers/producers.ts +++ b/packages/stryker/test/helpers/producers.ts @@ -1,6 +1,7 @@ import { TestResult, TestStatus, RunResult, RunStatus } from 'stryker-api/test_runner'; import { Mutant } from 'stryker-api/mutant'; import { Config } from 'stryker-api/config'; +import { Logger } from 'stryker-api/logging'; import * as sinon from 'sinon'; import { TestFramework, TestSelection } from 'stryker-api/test_framework'; import { MutantStatus, MatchedMutant, MutantResult, Reporter, ScoreResult } from 'stryker-api/report'; @@ -8,7 +9,6 @@ import { MutationScoreThresholds, File, Location } from 'stryker-api/core'; import TestableMutant from '../../src/TestableMutant'; import SourceFile from '../../src/SourceFile'; import TranspiledMutant from '../../src/TranspiledMutant'; -import { Logger } from 'log4js'; import { FileCoverageData } from 'istanbul-lib-coverage'; import { CoverageMaps } from '../../src/transpiler/CoverageInstrumenterTranspiler'; import { MappedLocation } from '../../src/transpiler/SourceMapper'; @@ -80,8 +80,6 @@ export const mutant = factoryMethod(() => ({ export const logger = (): Mock => { return { - setLevel: sinon.stub(), - isLevelEnabled: sinon.stub(), isTraceEnabled: sinon.stub(), isDebugEnabled: sinon.stub(), isInfoEnabled: sinon.stub(), diff --git a/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts b/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts index 9a1092b756..d12a85c37a 100644 --- a/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts +++ b/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts @@ -1,8 +1,8 @@ import { expect } from 'chai'; -import * as log4js from 'log4js'; +import * as log4js from 'stryker-api/logging'; import ConfigReader from '../../../src/ConfigReader'; import { Config } from 'stryker-api/config'; -import currentLogMock from '../../helpers/log4jsMock'; +import currentLogMock from '../../helpers/logMock'; import { Mock } from '../../helpers/producers'; describe('ConfigReader', () => { diff --git a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts index c06559c7af..1b9cad373f 100644 --- a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts +++ b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts @@ -1,11 +1,11 @@ import * as path from 'path'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { expect } from 'chai'; import { RunResult, RunStatus } from 'stryker-api/test_runner'; import ResilientTestRunnerFactory from '../../../src/isolated-runner/ResilientTestRunnerFactory'; import IsolatedRunnerOptions from '../../../src/isolated-runner/IsolatedRunnerOptions'; import TestRunnerDecorator from '../../../src/isolated-runner/TestRunnerDecorator'; -import currentLogMock from '../../helpers/log4jsMock'; +import currentLogMock from '../../helpers/logMock'; import { Mock } from '../../helpers/producers'; function sleep(ms: number) { diff --git a/packages/stryker/test/unit/ConfigValidatorSpec.ts b/packages/stryker/test/unit/ConfigValidatorSpec.ts index 84ae867cdd..02670ce36d 100644 --- a/packages/stryker/test/unit/ConfigValidatorSpec.ts +++ b/packages/stryker/test/unit/ConfigValidatorSpec.ts @@ -1,16 +1,15 @@ import { expect } from 'chai'; import * as sinon from 'sinon'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { Config } from 'stryker-api/config'; import ConfigValidator from './../../src/ConfigValidator'; -import currentLogMock from '../helpers/log4jsMock'; +import currentLogMock from '../helpers/logMock'; import { testFramework, Mock } from '../helpers/producers'; describe('ConfigValidator', () => { let config: Config; let sandbox: sinon.SinonSandbox; - let exitStub: sinon.SinonStub; let sut: ConfigValidator; let log: Mock; @@ -22,7 +21,6 @@ describe('ConfigValidator', () => { log = currentLogMock(); config = new Config(); sandbox = sinon.createSandbox(); - exitStub = sandbox.stub(process, 'exit'); }); afterEach(() => { @@ -32,15 +30,13 @@ describe('ConfigValidator', () => { it('should validate with default config', () => { sut = new ConfigValidator(config, testFramework()); sut.validate(); - expect(exitStub).not.called; expect(log.fatal).not.called; }); it('should be invalid with coverageAnalysis "perTest" without a testFramework', () => { config.coverageAnalysis = 'perTest'; sut = new ConfigValidator(config, null); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Configured coverage analysis "perTest" requires there to be a testFramework configured. Either configure a testFramework or set coverageAnalysis to "all" or "off".'); }); @@ -50,8 +46,7 @@ describe('ConfigValidator', () => { config.thresholds.high = -1; config.thresholds.low = 101; sut = new ConfigValidator(config, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('`thresholds.high` is lower than `thresholds.low` (-1 < 101)'); expect(log.fatal).calledWith('Value "-1" is invalid for `thresholds.high`. Expected a number between 0 and 100'); expect(log.fatal).calledWith('Value "101" is invalid for `thresholds.low`. Expected a number between 0 and 100'); @@ -61,8 +56,7 @@ describe('ConfigValidator', () => { (config.thresholds.high as any) = null; config.thresholds.low = 101; sut = new ConfigValidator(config, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "null" is invalid for `thresholds.high`. Expected a number between 0 and 100'); }); }); @@ -72,34 +66,30 @@ describe('ConfigValidator', () => { config.transpilers.push('a second transpiler'); config.coverageAnalysis = 'all'; sut = new ConfigValidator(config, testFramework()); - sut.validate(); + actValidationError(); expect(log.fatal).calledWith('Value "all" for `coverageAnalysis` is invalid with multiple transpilers' + ' (configured transpilers: a transpiler, a second transpiler). Please report this to the Stryker team' + ' if you whish this feature to be implemented'); - expect(exitStub).calledWith(1); }); it('should be invalid with invalid logLevel', () => { config.logLevel = 'thisTestPasses'; sut = new ConfigValidator(config, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "thisTestPasses" is invalid for `logLevel`. Expected one of the following: "fatal", "error", "warn", "info", "debug", "trace", "all", "off"'); }); it('should be invalid with nonnumeric timeoutMs', () => { let brokenConfig = breakConfig(config, 'timeoutMs', 'break'); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "break" is invalid for `timeoutMs`. Expected a number'); }); it('should be invalid with nonnumeric timeoutFactor', () => { let brokenConfig = breakConfig(config, 'timeoutFactor', 'break'); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "break" is invalid for `timeoutFactor`. Expected a number'); }); @@ -107,16 +97,14 @@ describe('ConfigValidator', () => { it('should be invalid with non-array plugins', () => { let brokenConfig = breakConfig(config, 'plugins', 'stryker-typescript'); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "stryker-typescript" is invalid for `plugins`. Expected an array'); }); it('should be invalid with non-string array elements', () => { let brokenConfig = breakConfig(config, 'plugins', ['stryker-jest', 0]); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "0" is an invalid element of `plugins`. Expected a string'); }); }); @@ -125,8 +113,7 @@ describe('ConfigValidator', () => { it('should be invalid with non-string mutator', () => { let brokenConfig = breakConfig(config, 'mutator', 0); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "0" is invalid for `mutator`. Expected either a string or an object'); }); @@ -138,7 +125,6 @@ describe('ConfigValidator', () => { }); sut = new ConfigValidator(validConfig, testFramework()); sut.validate(); - expect(exitStub).not.called; expect(log.fatal).not.called; }); @@ -148,8 +134,7 @@ describe('ConfigValidator', () => { excludedMutations: [] }); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "0" is invalid for `mutator.name`. Expected a string'); }); @@ -159,8 +144,7 @@ describe('ConfigValidator', () => { excludedMutations: 'BooleanSubstitution' }); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "BooleanSubstitution" is invalid for `mutator.excludedMutations`. Expected an array'); }); @@ -170,8 +154,7 @@ describe('ConfigValidator', () => { excludedMutations: ['BooleanSubstitution', 0] }); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "0" is an invalid element of `mutator.excludedMutations`. Expected a string'); }); }); @@ -181,8 +164,7 @@ describe('ConfigValidator', () => { it('should be invalid with non-array reporter', () => { let brokenConfig = breakConfig(config, 'reporter', 'stryker-typescript'); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "stryker-typescript" is invalid for `reporter`. Expected an array'); }); @@ -192,8 +174,7 @@ describe('ConfigValidator', () => { 0 ]); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "0" is an invalid element of `reporter`. Expected a string'); }); }); @@ -202,8 +183,7 @@ describe('ConfigValidator', () => { it('should be invalid with non-array transpilers', () => { let brokenConfig = breakConfig(config, 'transpilers', 'stryker-typescript'); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "stryker-typescript" is invalid for `transpilers`. Expected an array'); }); @@ -213,8 +193,7 @@ describe('ConfigValidator', () => { 0 ]); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "0" is an invalid element of `transpilers`. Expected a string'); }); }); @@ -222,8 +201,12 @@ describe('ConfigValidator', () => { it('should be invalid with invalid coverageAnalysis', () => { let brokenConfig = breakConfig(config, 'coverageAnalysis', 'invalid'); sut = new ConfigValidator(brokenConfig, testFramework()); - sut.validate(); - expect(exitStub).calledWith(1); + actValidationError(); expect(log.fatal).calledWith('Value "invalid" is invalid for `coverageAnalysis`. Expected one of the following: "perTest", "all", "off"'); }); + + function actValidationError() { + expect(() => sut.validate()).throws('Stryker could not recover from this configuration error, see fatal log message(s) above.'); + } + }); diff --git a/packages/stryker/test/unit/MutantTestMatcherSpec.ts b/packages/stryker/test/unit/MutantTestMatcherSpec.ts index e1c01f7fe5..84951516d4 100644 --- a/packages/stryker/test/unit/MutantTestMatcherSpec.ts +++ b/packages/stryker/test/unit/MutantTestMatcherSpec.ts @@ -1,4 +1,4 @@ -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { Mutant } from 'stryker-api/mutant'; import { TestSelection } from 'stryker-api/test_framework'; import { expect } from 'chai'; @@ -6,7 +6,7 @@ import { RunResult, TestResult, RunStatus, TestStatus, CoverageCollection, Cover import { StrykerOptions, File } from 'stryker-api/core'; import { MatchedMutant } from 'stryker-api/report'; import MutantTestMatcher from '../../src/MutantTestMatcher'; -import currentLogMock from '../helpers/log4jsMock'; +import currentLogMock from '../helpers/logMock'; import { testResult, mutant, Mock, mock } from '../helpers/producers'; import TestableMutant, { TestSelectionResult } from '../../src/TestableMutant'; import SourceFile from '../../src/SourceFile'; diff --git a/packages/stryker/test/unit/PluginLoaderSpec.ts b/packages/stryker/test/unit/PluginLoaderSpec.ts index e876f341ff..2197f17291 100644 --- a/packages/stryker/test/unit/PluginLoaderSpec.ts +++ b/packages/stryker/test/unit/PluginLoaderSpec.ts @@ -1,11 +1,11 @@ import * as path from 'path'; import * as fs from 'mz/fs'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import * as sinon from 'sinon'; import { expect } from 'chai'; import * as fileUtils from '../../src/utils/fileUtils'; import PluginLoader from '../../src/PluginLoader'; -import currentLogMock from '../helpers/log4jsMock'; +import currentLogMock from '../helpers/logMock'; import { Mock } from '../helpers/producers'; describe('PluginLoader', () => { diff --git a/packages/stryker/test/unit/SandboxSpec.ts b/packages/stryker/test/unit/SandboxSpec.ts index 705c28e998..15067c7c83 100644 --- a/packages/stryker/test/unit/SandboxSpec.ts +++ b/packages/stryker/test/unit/SandboxSpec.ts @@ -1,4 +1,4 @@ -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { Mutant } from 'stryker-api/mutant'; import { Config } from 'stryker-api/config'; import * as sinon from 'sinon'; @@ -17,7 +17,7 @@ import SourceFile from '../../src/SourceFile'; import '../helpers/globals'; import TranspiledMutant from '../../src/TranspiledMutant'; import * as fileUtils from '../../src/utils/fileUtils'; -import currentLogMock from '../helpers/log4jsMock'; +import currentLogMock from '../helpers/logMock'; import TestRunnerDecorator from '../../src/isolated-runner/TestRunnerDecorator'; describe('Sandbox', () => { diff --git a/packages/stryker/test/unit/ScoreResultCalculatorSpec.ts b/packages/stryker/test/unit/ScoreResultCalculatorSpec.ts index 52b8a4ed6e..8dc114906f 100644 --- a/packages/stryker/test/unit/ScoreResultCalculatorSpec.ts +++ b/packages/stryker/test/unit/ScoreResultCalculatorSpec.ts @@ -1,12 +1,12 @@ import * as path from 'path'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { expect } from 'chai'; import * as sinon from 'sinon'; import { MutantStatus, ScoreResult } from 'stryker-api/report'; import ScoreResultCalculator from '../../src/ScoreResultCalculator'; import * as objectUtils from '../../src/utils/objectUtils'; import { mutantResult, scoreResult, mutationScoreThresholds, Mock } from '../helpers/producers'; -import currentLogMock from '../helpers/log4jsMock'; +import currentLogMock from '../helpers/logMock'; describe('ScoreResult', () => { let log: Mock; diff --git a/packages/stryker/test/unit/StrykerSpec.ts b/packages/stryker/test/unit/StrykerSpec.ts index 598a88fd1b..277021a892 100644 --- a/packages/stryker/test/unit/StrykerSpec.ts +++ b/packages/stryker/test/unit/StrykerSpec.ts @@ -17,12 +17,13 @@ import ConfigValidator, * as configValidator from '../../src/ConfigValidator'; import ScoreResultCalculator, * as scoreResultCalculatorModule from '../../src/ScoreResultCalculator'; import PluginLoader, * as pluginLoader from '../../src/PluginLoader'; import { TempFolder } from '../../src/utils/TempFolder'; -import currentLogMock from '../helpers/log4jsMock'; +import currentLogMock from '../helpers/logMock'; import { mock, Mock, testFramework as testFrameworkMock, config, runResult, testableMutant, mutantResult } from '../helpers/producers'; import BroadcastReporter from '../../src/reporters/BroadcastReporter'; import TestableMutant from '../../src/TestableMutant'; import '../helpers/globals'; import InputFileCollection from '../../src/input/InputFileCollection'; +import LogConfigurator from '../../src/utils/LogConfigurator'; class FakeConfigEditor implements ConfigEditor { constructor() { } @@ -47,6 +48,7 @@ describe('Stryker', function () { let reporter: Mock; let tempFolderMock: Mock; let scoreResultCalculator: ScoreResultCalculator; + let logConfiguratorForMasterStub: sinon.SinonStub; beforeEach(() => { strykerConfig = config(); @@ -58,6 +60,7 @@ describe('Stryker', function () { const reporterOrchestratorMock = mock(ReporterOrchestrator); mutantRunResultMatcherMock = mock(MutantRunResultMatcher); mutatorMock = mock(MutatorFacade); + logConfiguratorForMasterStub = sandbox.stub(LogConfigurator, 'forMaster'); inputFileResolverMock = mock(InputFileResolver); reporterOrchestratorMock.createBroadcastReporter.returns(reporter); testFramework = testFrameworkMock(); @@ -94,6 +97,10 @@ describe('Stryker', function () { expect(sut.config.testRunner).to.be.eq('fakeTestRunner'); }); + it('should configure logging for master', () => { + expect(logConfiguratorForMasterStub).calledThrice; + }); + it('should freeze the config', () => { expect(Object.isFrozen(sut.config)).to.be.eq(true); }); diff --git a/packages/stryker/test/unit/TestFrameworkOrchestratorSpec.ts b/packages/stryker/test/unit/TestFrameworkOrchestratorSpec.ts index 2b77cd9576..4856b75268 100644 --- a/packages/stryker/test/unit/TestFrameworkOrchestratorSpec.ts +++ b/packages/stryker/test/unit/TestFrameworkOrchestratorSpec.ts @@ -1,10 +1,10 @@ import TestFrameworkOrchestrator from '../../src/TestFrameworkOrchestrator'; import { expect } from 'chai'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import * as sinon from 'sinon'; import { TestFrameworkFactory } from 'stryker-api/test_framework'; import { StrykerOptions } from 'stryker-api/core'; -import currentLogMock from '../helpers/log4jsMock'; +import currentLogMock from '../helpers/logMock'; import { Mock } from '../helpers/producers'; describe('TestFrameworkOrchestrator', () => { diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts index 435a4303f1..a43c6aaeb4 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts @@ -2,17 +2,17 @@ import ChildProcessProxyWorker from '../../../src/child-proxy/ChildProcessProxyW import { expect } from 'chai'; import { serialize } from '../../../src/utils/objectUtils'; import { WorkerMessage, WorkerMessageKind, ParentMessage, WorkResult, WorkMessage, ParentMessageKind } from '../../../src/child-proxy/messageProtocol'; -import * as log4js from 'log4js'; import PluginLoader, * as pluginLoader from '../../../src/PluginLoader'; import { Mock, mock } from '../../helpers/producers'; import HelloClass from './HelloClass'; +import LogConfigurator from '../../../src/utils/LogConfigurator'; describe('ChildProcessProxyWorker', () => { let processOnStub: sinon.SinonStub; let processSendStub: sinon.SinonStub; let processListenersStub: sinon.SinonStub; - let setGlobalLogLevelStub: sinon.SinonStub; + let logConfiguratorForWorkerStub: sinon.SinonStub; let processRemoveListenerStub: sinon.SinonStub; let pluginLoaderMock: Mock; let originalProcessSend: undefined | NodeJS.MessageListener; @@ -28,7 +28,7 @@ describe('ChildProcessProxyWorker', () => { // process.send is normally undefined originalProcessSend = process.send; process.send = processSendStub; - setGlobalLogLevelStub = sandbox.stub(log4js, 'setGlobalLogLevel'); + logConfiguratorForWorkerStub = sandbox.stub(LogConfigurator, 'forWorker'); pluginLoaderMock = mock(PluginLoader); sandbox.stub(pluginLoader, 'default').returns(pluginLoaderMock); }); @@ -87,7 +87,7 @@ describe('ChildProcessProxyWorker', () => { it('should set global log level', () => { processOnStub.callArgWith(1, serialize(initMessage)); - expect(setGlobalLogLevelStub).calledWith('FooLevel'); + expect(logConfiguratorForWorkerStub).called; }); it('should load plugins', () => { diff --git a/packages/stryker/test/unit/initializer/StrykerInitializerSpec.ts b/packages/stryker/test/unit/initializer/StrykerInitializerSpec.ts index 5a3af29771..a21bfad032 100644 --- a/packages/stryker/test/unit/initializer/StrykerInitializerSpec.ts +++ b/packages/stryker/test/unit/initializer/StrykerInitializerSpec.ts @@ -1,12 +1,12 @@ import * as child from 'child_process'; import * as fs from 'mz/fs'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import * as sinon from 'sinon'; import { expect } from 'chai'; import * as inquirer from 'inquirer'; import StrykerInitializer from '../../../src/initializer/StrykerInitializer'; import * as restClient from 'typed-rest-client/RestClient'; -import currentLogMock from '../../helpers/log4jsMock'; +import currentLogMock from '../../helpers/logMock'; import { Mock } from '../../helpers/producers'; describe('StrykerInitializer', () => { diff --git a/packages/stryker/test/unit/input/InputFileResolverSpec.ts b/packages/stryker/test/unit/input/InputFileResolverSpec.ts index 8af2b49cc8..97ef2545ca 100644 --- a/packages/stryker/test/unit/input/InputFileResolverSpec.ts +++ b/packages/stryker/test/unit/input/InputFileResolverSpec.ts @@ -2,13 +2,13 @@ import * as path from 'path'; import { expect } from 'chai'; import * as fs from 'mz/fs'; import * as childProcess from 'mz/child_process'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { File } from 'stryker-api/core'; import { SourceFile } from 'stryker-api/report'; import InputFileResolver from '../../../src/input/InputFileResolver'; import * as sinon from 'sinon'; import * as fileUtils from '../../../src/utils/fileUtils'; -import currentLogMock from '../../helpers/log4jsMock'; +import currentLogMock from '../../helpers/logMock'; import BroadcastReporter from '../../../src/reporters/BroadcastReporter'; import { Mock, mock, createFileNotFoundError } from '../../helpers/producers'; import { errorToString, normalizeWhiteSpaces } from '../../../src/utils/objectUtils'; @@ -32,8 +32,8 @@ describe('InputFileResolver', () => { reporter = mock(BroadcastReporter); globStub = sandbox.stub(fileUtils, 'glob'); readFileStub = sandbox.stub(fs, 'readFile') - .withArgs(sinon.match.string).resolves(new Buffer(0)) // fallback - .withArgs(sinon.match.string).resolves(new Buffer(0)) // fallback + .withArgs(sinon.match.string).resolves(Buffer.from('')) // fallback + .withArgs(sinon.match.string).resolves(Buffer.from('')) // fallback .withArgs(sinon.match('file1')).resolves(Buffer.from('file 1 content')) .withArgs(sinon.match('file2')).resolves(Buffer.from('file 2 content')) .withArgs(sinon.match('file3')).resolves(Buffer.from('file 3 content')) diff --git a/packages/stryker/test/unit/process/InitialTestExecutorSpec.ts b/packages/stryker/test/unit/process/InitialTestExecutorSpec.ts index 31ff0259a7..a06a2b653c 100644 --- a/packages/stryker/test/unit/process/InitialTestExecutorSpec.ts +++ b/packages/stryker/test/unit/process/InitialTestExecutorSpec.ts @@ -1,6 +1,6 @@ import { EOL } from 'os'; import { expect } from 'chai'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { default as StrykerSandbox } from '../../../src/Sandbox'; import InitialTestExecutor, { InitialTestRunResult } from '../../../src/process/InitialTestExecutor'; import { File } from 'stryker-api/core'; @@ -11,7 +11,7 @@ import CoverageInstrumenterTranspiler, * as coverageInstrumenterTranspiler from import TranspilerFacade, * as transpilerFacade from '../../../src/transpiler/TranspilerFacade'; import { TranspilerOptions } from 'stryker-api/transpile'; import { RunStatus, RunResult, TestStatus } from 'stryker-api/test_runner'; -import currentLogMock from '../../helpers/log4jsMock'; +import currentLogMock from '../../helpers/logMock'; import Timer from '../../../src/utils/Timer'; import { Mock, coverageMaps } from '../../helpers/producers'; import InputFileCollection from '../../../src/input/InputFileCollection'; diff --git a/packages/stryker/test/unit/reporters/BroadcastReporterSpec.ts b/packages/stryker/test/unit/reporters/BroadcastReporterSpec.ts index 8ea19774a1..0ef6166a84 100644 --- a/packages/stryker/test/unit/reporters/BroadcastReporterSpec.ts +++ b/packages/stryker/test/unit/reporters/BroadcastReporterSpec.ts @@ -1,7 +1,7 @@ import * as sinon from 'sinon'; -import { Logger } from 'log4js'; +import { Logger } from 'stryker-api/logging'; import { expect } from 'chai'; -import currentLogMock from '../../helpers/log4jsMock'; +import currentLogMock from '../../helpers/logMock'; import BroadcastReporter from '../../../src/reporters/BroadcastReporter'; import { ALL_REPORTER_EVENTS, Mock } from '../../helpers/producers'; diff --git a/packages/stryker/test/unit/reporters/DashboardReporterSpec.ts b/packages/stryker/test/unit/reporters/DashboardReporterSpec.ts index c8e0a3bf94..b85f415aac 100644 --- a/packages/stryker/test/unit/reporters/DashboardReporterSpec.ts +++ b/packages/stryker/test/unit/reporters/DashboardReporterSpec.ts @@ -4,8 +4,8 @@ import DashboardReporter from '../../../src/reporters/DashboardReporter'; import * as environmentVariables from '../../../src/utils/objectUtils'; import StrykerDashboardClient, { StrykerDashboardReport } from '../../../src/reporters/dashboard-reporter/DashboardReporterClient'; import { scoreResult, mock, Mock } from '../../helpers/producers'; -import { Logger } from 'log4js'; -import currentLogMock from '../../helpers/log4jsMock'; +import { Logger } from 'stryker-api/logging'; +import currentLogMock from '../../helpers/logMock'; import { Config } from 'stryker-api/config'; describe('DashboardReporter', () => { diff --git a/packages/stryker/test/unit/reporters/EventRecorderReporterSpec.ts b/packages/stryker/test/unit/reporters/EventRecorderReporterSpec.ts index b348dbf9ac..c54f0852a4 100644 --- a/packages/stryker/test/unit/reporters/EventRecorderReporterSpec.ts +++ b/packages/stryker/test/unit/reporters/EventRecorderReporterSpec.ts @@ -4,7 +4,7 @@ import * as fs from 'mz/fs'; import { Reporter } from 'stryker-api/report'; import EventRecorderReporter from '../../../src/reporters/EventRecorderReporter'; import * as fileUtils from '../../../src/utils/fileUtils'; -import currentLogMock from '../../helpers/log4jsMock'; +import currentLogMock from '../../helpers/logMock'; import StrictReporter from '../../../src/reporters/StrictReporter'; import { ALL_REPORTER_EVENTS } from '../../helpers/producers'; diff --git a/packages/stryker/test/unit/reporters/dashboard-reporter/DashboardReporterClientSpec.ts b/packages/stryker/test/unit/reporters/dashboard-reporter/DashboardReporterClientSpec.ts index 4e43ab75a0..0a9b2608fb 100644 --- a/packages/stryker/test/unit/reporters/dashboard-reporter/DashboardReporterClientSpec.ts +++ b/packages/stryker/test/unit/reporters/dashboard-reporter/DashboardReporterClientSpec.ts @@ -2,8 +2,8 @@ import StrykerDashboardClient, { StrykerDashboardReport } from '../../../../src/ import { HttpClient } from 'typed-rest-client/HttpClient'; import { Mock, mock } from '../../../helpers/producers'; import { expect } from 'chai'; -import { Logger } from 'log4js'; -import currentLogMock from '../../../helpers/log4jsMock'; +import { Logger } from 'stryker-api/logging'; +import currentLogMock from '../../../helpers/logMock'; describe('DashboardReporterClient', () => { From 8e50b4f4afd3efa86271d1fe1e29d5499bb9ed28 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sun, 27 May 2018 23:21:05 +0200 Subject: [PATCH 03/54] Update log4js 2.7 --- package-lock.json | 2 +- packages/stryker-api/src/core/LogLevel.ts | 4 ++ .../stryker-api/src/core/StrykerOptions.ts | 43 ++++++++++-------- packages/stryker/package-lock.json | 44 ++++++++++++++++--- packages/stryker/package.json | 2 +- 5 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 packages/stryker-api/src/core/LogLevel.ts diff --git a/package-lock.json b/package-lock.json index aad7e607c1..4afc8030b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,7 +4,7 @@ "dependencies": { "@sinonjs/formatio": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/@sinonjs/formatio/-/formatio-2.0.0.tgz", "integrity": "sha512-ls6CAMA6/5gG+O/IdsBcblvnd8qcO/l1TYoNeAzp3wcISOxlPXQEus0mLcdwazEkWjaBdaJ3TaxmNgCLWwvWzg==", "dev": true, "requires": { diff --git a/packages/stryker-api/src/core/LogLevel.ts b/packages/stryker-api/src/core/LogLevel.ts new file mode 100644 index 0000000000..416b135b3a --- /dev/null +++ b/packages/stryker-api/src/core/LogLevel.ts @@ -0,0 +1,4 @@ + +type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'; + +export default LogLevel; \ No newline at end of file diff --git a/packages/stryker-api/src/core/StrykerOptions.ts b/packages/stryker-api/src/core/StrykerOptions.ts index 9f3dc91e09..ee2d7ddf3f 100644 --- a/packages/stryker-api/src/core/StrykerOptions.ts +++ b/packages/stryker-api/src/core/StrykerOptions.ts @@ -1,30 +1,31 @@ import MutationScoreThresholds from './MutationScoreThresholds'; import MutatorDescriptor from './MutatorDescriptor'; +import LogLevel from './LogLevel'; interface StrykerOptions { - // this ensures that custom config for for example 'karma' can be added under the 'karma' key + // this ensures that plugins can load custom config. [customConfig: string]: any; /** - * The files array determines which files are in scope for mutation testing. - * These include library files, test files and files to mutate, but should NOT include test framework files (for example jasmine). - * Each element can be either a string or an object with 2 properties - * * `string`: A globbing expression used for selecting the files needed to run the tests. - * * { pattern: 'pattern', included: true, mutated: false, transpiled: true }: - * * The `pattern` property is mandatory and contains the globbing expression used for selecting the files - * * The `included` property is optional and determines whether or not this file should be loaded initially by the test-runner (default: true) - * * The `mutated` property is optional and determines whether or not this file should be targeted for mutations (default: false) - * * The `transpiled` property is optional and determines whether or not this file should be transpiled by a transpiler (see `transpilers` config option) (default: true) - * - * @example - * files: ['test/helpers/**\/*.js', 'test/unit/**\/*.js', { pattern: 'src/**\/*.js', included: false }], + * A list of globbing expression used for selecting the files that should be mutated. */ - files?: string[]; + mutate?: string[]; /** - * A list of globbing expression used for selecting the files that should be mutated. + * With `files` you can choose which files should be included in your test runner sandbox. + * This is normally not needed as it defaults to all files not ignored by git. + * Try it out yourself with this command: `git ls-files --others --exclude-standard --cached --exclude .stryker-tmp`. + * + * If you do need to override `files` (for example: when your project does not live in a git repository), + * you can override the files here. + * + * When using the command line, the list can only contain a comma separated list of globbing expressions. + * When using the config file you can provide an array with `string`s + * + * You can *ignore* files by adding an exclamation mark (`!`) at the start of an expression. + * */ - mutate?: string[]; + files?: string[]; /** * Specify the maximum number of concurrent test runners. Useful if you don't want to use @@ -104,9 +105,15 @@ interface StrykerOptions { reporter?: string | string[]; /** - * The log4js log level. Possible values: fatal, error, warn, info, debug, trace, all and off. Default is "info" + * The log level for logging to a file. If defined, stryker will output a log file called "stryker.log". + * Default: undefined + */ + fileLogLevel?: LogLevel; + + /** + * The log level for logging to the console. Default: "info". */ - logLevel?: string; + logLevel?: LogLevel; /** * Indicates whether or not to symlink the node_modules folder inside the sandbox folder(s). diff --git a/packages/stryker/package-lock.json b/packages/stryker/package-lock.json index 3a5f30fb6e..621bd87de9 100644 --- a/packages/stryker/package-lock.json +++ b/packages/stryker/package-lock.json @@ -1,16 +1,20 @@ { - "requires": true, + "name": "stryker", + "version": "0.24.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "@types/babel-types": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.2.tgz", - "integrity": "sha512-ylggu8DwwxT6mk3jVoJeohWAePWMNWEYm06MSoJ19kwp3hT9eY2Z4NNZn3oevzgFmClgNQ2GQF500hPDvNsGHg==" + "integrity": "sha512-ylggu8DwwxT6mk3jVoJeohWAePWMNWEYm06MSoJ19kwp3hT9eY2Z4NNZn3oevzgFmClgNQ2GQF500hPDvNsGHg==", + "dev": true }, "@types/inquirer": { "version": "0.0.41", "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-0.0.41.tgz", "integrity": "sha512-kIWkK3FECGKt9OrURxRvi59gwMNiWTePXWOvaJn+xhplbEvu91hIDMfLe5PUu+cEEMmD6EFU4VFJJKKp5kzCtw==", + "dev": true, "requires": { "@types/rx": "*", "@types/through": "*" @@ -19,12 +23,14 @@ "@types/istanbul-lib-coverage": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz", - "integrity": "sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ==" + "integrity": "sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ==", + "dev": true }, "@types/istanbul-lib-instrument": { "version": "1.7.1", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.1.tgz", "integrity": "sha512-Ll2qAzv7NItqVliZZ8OMAgAvGstddK2995/7X5YPU84lD3CFnqDfP4sTu5Q1GKReh5Ttw3shKR2e3Fe6Xo0C7A==", + "dev": true, "requires": { "@types/babel-types": "*", "@types/istanbul-lib-coverage": "*", @@ -34,17 +40,20 @@ "@types/node": { "version": "10.0.8", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.0.8.tgz", - "integrity": "sha512-MFFKFv2X4iZy/NFl1m1E8uwE1CR96SGwJjgHma09PLtqOWoj3nqeJHMG+P/EuJGVLvC2I6MdQRQsr4TcRduIow==" + "integrity": "sha512-MFFKFv2X4iZy/NFl1m1E8uwE1CR96SGwJjgHma09PLtqOWoj3nqeJHMG+P/EuJGVLvC2I6MdQRQsr4TcRduIow==", + "dev": true }, "@types/prettier": { "version": "1.12.2", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.12.2.tgz", - "integrity": "sha512-PEzK3/vS/GIM5PR5KZztIUKQayv5yddV/EYfGKaM+YOm9HVEJovUdBMbCzSrB83P6yGiohc6EacXzHDuLYeWMQ==" + "integrity": "sha512-PEzK3/vS/GIM5PR5KZztIUKQayv5yddV/EYfGKaM+YOm9HVEJovUdBMbCzSrB83P6yGiohc6EacXzHDuLYeWMQ==", + "dev": true }, "@types/progress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/progress/-/progress-2.0.1.tgz", "integrity": "sha512-1Smw4LvkCM4zgie7Zo/GtzrMx1Zlq1XVfPoOBXPLIkmtep06wBE7sXupVDq7MXWrHCYtsM0d6i5eF6OM+LJJrQ==", + "dev": true, "requires": { "@types/node": "*" } @@ -53,6 +62,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/@types/rx/-/rx-4.1.1.tgz", "integrity": "sha1-WY/JSla67ZdfGUV04PVy/Y5iekg=", + "dev": true, "requires": { "@types/rx-core": "*", "@types/rx-core-binding": "*", @@ -71,12 +81,14 @@ "@types/rx-core": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-core/-/rx-core-4.0.3.tgz", - "integrity": "sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=" + "integrity": "sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=", + "dev": true }, "@types/rx-core-binding": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz", "integrity": "sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ==", + "dev": true, "requires": { "@types/rx-core": "*" } @@ -85,6 +97,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/rx-lite/-/rx-lite-4.0.5.tgz", "integrity": "sha512-KZk5XTR1dm/kNgBx8iVpjno6fRYtAUQWBOmj+O8j724+nk097sz4fOoHJNpCkOJUtHUurZlJC7QvSFCZHbkC+w==", + "dev": true, "requires": { "@types/rx-core": "*", "@types/rx-core-binding": "*" @@ -94,6 +107,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-aggregates/-/rx-lite-aggregates-4.0.3.tgz", "integrity": "sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -102,6 +116,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/rx-lite-async/-/rx-lite-async-4.0.2.tgz", "integrity": "sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -110,6 +125,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-backpressure/-/rx-lite-backpressure-4.0.3.tgz", "integrity": "sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -118,6 +134,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-coincidence/-/rx-lite-coincidence-4.0.3.tgz", "integrity": "sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -126,6 +143,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/rx-lite-experimental/-/rx-lite-experimental-4.0.1.tgz", "integrity": "sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0=", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -134,6 +152,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/rx-lite-joinpatterns/-/rx-lite-joinpatterns-4.0.1.tgz", "integrity": "sha1-9w/jcFGKhDLykVjMkv+1a05K/D4=", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -142,6 +161,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/rx-lite-testing/-/rx-lite-testing-4.0.1.tgz", "integrity": "sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek=", + "dev": true, "requires": { "@types/rx-lite-virtualtime": "*" } @@ -150,6 +170,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-time/-/rx-lite-time-4.0.3.tgz", "integrity": "sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -158,6 +179,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-virtualtime/-/rx-lite-virtualtime-4.0.3.tgz", "integrity": "sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -166,6 +188,7 @@ "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.29.tgz", "integrity": "sha512-9a7C5VHh+1BKblaYiq+7Tfc+EOmjMdZaD1MYtkQjSoxgB69tBjW98ry6SKsi4zEIWztLOMRuL87A3bdT/Fc/4w==", + "dev": true, "requires": { "@types/node": "*" } @@ -2243,6 +2266,15 @@ "ansi-regex": "^3.0.0" } }, + "stryker-api": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/stryker-api/-/stryker-api-0.17.1.tgz", + "integrity": "sha512-D2t4WnxEeLlL7Heej3ld9RTQvGn+Ms2bD0fmh0VqqIWnkclxA95yMCmV57YGlq2fRim4LxljjybpNtLZ1lqDjg==", + "dev": true, + "requires": { + "tslib": "^1.6.0" + } + }, "supports-color": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", diff --git a/packages/stryker/package.json b/packages/stryker/package.json index bd1eb6bf55..735fe185bf 100644 --- a/packages/stryker/package.json +++ b/packages/stryker/package.json @@ -61,7 +61,7 @@ "inquirer": "^5.2.0", "istanbul-lib-instrument": "^1.9.2", "lodash": "^4.17.4", - "log4js": "^2.6.1", + "log4js": "^2.7.0", "mkdirp": "^0.5.1", "mz": "^2.6.0", "prettier": "^1.6.1", From c50d69d01d8a86c43a42fe97bea7d22fe69546c7 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 11:57:15 +0200 Subject: [PATCH 04/54] feat: add file log level option to stryker config --- packages/stryker-api/core.ts | 3 ++- packages/stryker-api/src/config/Config.ts | 5 +++-- packages/stryker-api/src/core/LogLevel.ts | 10 +++++++++- .../stryker-api/src/core/StrykerOptions.ts | 2 +- .../test/unit/core/LogLevelSpec.ts | 19 +++++++++++++++++++ .../test/integration/KarmaTestRunner.it.ts | 5 +++-- 6 files changed, 37 insertions(+), 7 deletions(-) create mode 100644 packages/stryker-api/test/unit/core/LogLevelSpec.ts diff --git a/packages/stryker-api/core.ts b/packages/stryker-api/core.ts index 8db5735a93..cb8fbcab1f 100644 --- a/packages/stryker-api/core.ts +++ b/packages/stryker-api/core.ts @@ -5,4 +5,5 @@ export { default as Position } from './src/core/Position'; export { default as Location } from './src/core/Location'; export { default as Range } from './src/core/Range'; export { default as MutatorDescriptor } from './src/core/MutatorDescriptor'; -export { default as MutationScoreThresholds } from './src/core/MutationScoreThresholds'; \ No newline at end of file +export { default as MutationScoreThresholds } from './src/core/MutationScoreThresholds'; +export { default as LogLevel } from './src/core/LogLevel'; \ No newline at end of file diff --git a/packages/stryker-api/src/config/Config.ts b/packages/stryker-api/src/config/Config.ts index 2e46ffefad..cc59e1beb3 100644 --- a/packages/stryker-api/src/config/Config.ts +++ b/packages/stryker-api/src/config/Config.ts @@ -1,4 +1,4 @@ -import { StrykerOptions, MutatorDescriptor, MutationScoreThresholds } from '../../core'; +import { LogLevel, StrykerOptions, MutatorDescriptor, MutationScoreThresholds } from '../../core'; export default class Config implements StrykerOptions { @@ -7,7 +7,8 @@ export default class Config implements StrykerOptions { files: string[]; mutate: string[]; - logLevel = 'info'; + logLevel: LogLevel = LogLevel.Information; + fileLogLevel: LogLevel = LogLevel.Off; timeoutMs = 5000; timeoutFactor = 1.5; plugins: string[] = ['stryker-*']; diff --git a/packages/stryker-api/src/core/LogLevel.ts b/packages/stryker-api/src/core/LogLevel.ts index 416b135b3a..310a53e242 100644 --- a/packages/stryker-api/src/core/LogLevel.ts +++ b/packages/stryker-api/src/core/LogLevel.ts @@ -1,4 +1,12 @@ -type LogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace'; +enum LogLevel { + Off = 'off', + Fatal = 'fatal', + Error = 'error', + Warning = 'warn', + Information = 'info', + Debug = 'debug', + Trace = 'trace' +} export default LogLevel; \ No newline at end of file diff --git a/packages/stryker-api/src/core/StrykerOptions.ts b/packages/stryker-api/src/core/StrykerOptions.ts index ee2d7ddf3f..b9fad23c28 100644 --- a/packages/stryker-api/src/core/StrykerOptions.ts +++ b/packages/stryker-api/src/core/StrykerOptions.ts @@ -106,7 +106,7 @@ interface StrykerOptions { /** * The log level for logging to a file. If defined, stryker will output a log file called "stryker.log". - * Default: undefined + * Default: "off" */ fileLogLevel?: LogLevel; diff --git a/packages/stryker-api/test/unit/core/LogLevelSpec.ts b/packages/stryker-api/test/unit/core/LogLevelSpec.ts new file mode 100644 index 0000000000..8afcd3e3fe --- /dev/null +++ b/packages/stryker-api/test/unit/core/LogLevelSpec.ts @@ -0,0 +1,19 @@ +import { expect } from 'chai'; +import LogLevel from '../../../src/core/LogLevel'; + +describe('LogLevel', () => { + + function arrangeActAssertLogLevel(actual: LogLevel, expected: string) { + it(`should provide "${expected}" for log level "${actual}"`, () => { + expect(actual).eq(expected); + }); + } + + arrangeActAssertLogLevel(LogLevel.Off, 'off'); + arrangeActAssertLogLevel(LogLevel.Fatal, 'fatal'); + arrangeActAssertLogLevel(LogLevel.Error, 'error'); + arrangeActAssertLogLevel(LogLevel.Warning, 'warn'); + arrangeActAssertLogLevel(LogLevel.Information, 'info'); + arrangeActAssertLogLevel(LogLevel.Debug, 'debug'); + arrangeActAssertLogLevel(LogLevel.Trace, 'trace'); +}); \ No newline at end of file diff --git a/packages/stryker-karma-runner/test/integration/KarmaTestRunner.it.ts b/packages/stryker-karma-runner/test/integration/KarmaTestRunner.it.ts index a39113ab9e..833e07c83c 100644 --- a/packages/stryker-karma-runner/test/integration/KarmaTestRunner.it.ts +++ b/packages/stryker-karma-runner/test/integration/KarmaTestRunner.it.ts @@ -1,6 +1,7 @@ import * as fs from 'fs'; import { expect } from 'chai'; import { CoverageCollection, RunnerOptions, RunResult, RunStatus, TestStatus } from 'stryker-api/test_runner'; +import { LogLevel } from 'stryker-api/core'; import KarmaTestRunner from '../../src/KarmaTestRunner'; import JasmineTestFramework from 'stryker-jasmine/src/JasmineTestFramework'; import { expectTestResults } from '../helpers/assertions'; @@ -43,7 +44,7 @@ describe('KarmaTestRunner', function () { testRunnerOptions = { port: 9877, strykerOptions: { - logLevel: 'trace', + logLevel: LogLevel.Trace, karmaConfig: { files: [ 'testResources/sampleProject/src/Add.js', @@ -96,7 +97,7 @@ describe('KarmaTestRunner', function () { const testRunnerOptions = { port: 9878, strykerOptions: { - logLevel: 'trace', + logLevel: LogLevel.Trace, karmaConfig: { files: [ 'testResources/sampleProject/src/Add.js', From 98c2bfb27c9ebc8c75683a6141a0de8f4403aa82 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 11:58:11 +0200 Subject: [PATCH 05/54] chore: add stryker.log to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e95567c4b2..d723f4e8ba 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules lerna-debug.log npm-debug.log +stryker.log coverage reports From c002d5c3c2f17b4c5cb4f3b05fd853e775a54570 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 11:58:36 +0200 Subject: [PATCH 06/54] docs(stryker): Document new file log level option --- packages/stryker/README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/stryker/README.md b/packages/stryker/README.md index 48439bce37..a943622750 100644 --- a/packages/stryker/README.md +++ b/packages/stryker/README.md @@ -318,6 +318,15 @@ It is not allowed to only supply one value of the values (it's all or nothing). **Default value:** `info` **Mandatory**: no **Description:** - Set the `log4js` log level that Stryker uses (default is `info`). Possible values: `fatal`, `error`, `warn`, `info`, `debug`, `trace`, `all` and `off`. + Set the log level that Stryker uses to write to the console. Possible values: `off`, `fatal`, `error`, `warn`, `info`, `debug` and `trace` + *Note*: Test runners are run as child processes of the Stryker Node process. All output (stdout) of the `testRunner` is logged as `trace`. Thus, to see logging output from the test runner set the `logLevel` to `all` or `trace`. + +#### Log level +**Command line:** `--fileLogLevel info` +**Config file:** `fileLogLevel: 'info'` +**Default value:** `off` +**Mandatory**: no +**Description:** + Set the log level that Stryker uses to write to the "stryker.log" file. Possible values: `off`, `fatal`, `error`, `warn`, `info`, `debug` and `trace` From 7d2f3df1b7d61b7d380823644a53e9c283101e6b Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 11:59:03 +0200 Subject: [PATCH 07/54] feat(file logging): add logging server --- packages/stryker/.vscode/launch.json | 2 +- packages/stryker/package-lock.json | 46 +++++- packages/stryker/package.json | 2 + packages/stryker/src/Sandbox.ts | 10 +- packages/stryker/src/SandboxPool.ts | 5 +- packages/stryker/src/Stryker.ts | 17 +-- packages/stryker/src/StrykerCli.ts | 7 +- .../src/child-proxy/ChildProcessProxy.ts | 15 +- .../child-proxy/ChildProcessProxyWorker.ts | 8 +- .../src/child-proxy/messageProtocol.ts | 4 +- .../stryker/src/{ => config}/ConfigReader.ts | 2 +- .../src/{ => config}/ConfigValidator.ts | 13 +- .../isolated-runner/IsolatedRunnerOptions.ts | 2 + .../IsolatedTestRunnerAdapterWorker.ts | 8 +- .../stryker/src/logging/LogConfigurator.ts | 132 ++++++++++++++++++ .../src/logging/LoggingClientContext.ts | 7 + packages/stryker/src/logging/MultiAppender.ts | 20 +++ packages/stryker/src/logging/logUtils.ts | 20 +++ .../src/process/InitialTestExecutor.ts | 5 +- .../src/process/MutationTestExecutor.ts | 8 +- .../src/transpiler/MutantTranspiler.ts | 5 +- packages/stryker/src/utils/LogConfigurator.ts | 57 -------- packages/stryker/stryker.conf.js | 2 +- .../child-proxy/ChildProcessProxy.it.ts | 85 ++++++++++- .../test/integration/child-proxy/Echo.ts | 12 ++ .../config-reader/ConfigReaderSpec.ts | 2 +- .../ResilientTestRunnerFactorySpec.ts | 4 +- packages/stryker/test/unit/SandboxPoolSpec.ts | 9 +- packages/stryker/test/unit/SandboxSpec.ts | 45 +++--- packages/stryker/test/unit/StrykerSpec.ts | 38 +++-- .../unit/child-proxy/ChildProcessProxySpec.ts | 16 ++- .../child-proxy/ChildProcessWorkerSpec.ts | 10 +- .../unit/{ => config}/ConfigValidatorSpec.ts | 10 +- .../IsolatedTestRunnerAdapterSpec.ts | 5 +- .../unit/process/InitialTestExecutorSpec.ts | 12 +- .../unit/process/MutationTestExecutorSpec.ts | 13 +- .../unit/transpiler/MutantTranspilerSpec.ts | 25 ++-- 37 files changed, 504 insertions(+), 179 deletions(-) rename packages/stryker/src/{ => config}/ConfigReader.ts (98%) rename packages/stryker/src/{ => config}/ConfigValidator.ts (91%) create mode 100644 packages/stryker/src/logging/LogConfigurator.ts create mode 100644 packages/stryker/src/logging/LoggingClientContext.ts create mode 100644 packages/stryker/src/logging/MultiAppender.ts create mode 100644 packages/stryker/src/logging/logUtils.ts delete mode 100644 packages/stryker/src/utils/LogConfigurator.ts rename packages/stryker/test/unit/{ => config}/ConfigValidatorSpec.ts (96%) diff --git a/packages/stryker/.vscode/launch.json b/packages/stryker/.vscode/launch.json index 8a8337fe5f..5d87b722b7 100644 --- a/packages/stryker/.vscode/launch.json +++ b/packages/stryker/.vscode/launch.json @@ -77,7 +77,7 @@ "run", "stryker.conf.js" ], - "cwd": "${workspaceRoot}/../../integrationTest/test/typescript-transpiling", + "cwd": "${workspaceRoot}", "runtimeExecutable": null, "runtimeArgs": [ "--nolazy" diff --git a/packages/stryker/package-lock.json b/packages/stryker/package-lock.json index 0bd70bc62a..e70fd90709 100644 --- a/packages/stryker/package-lock.json +++ b/packages/stryker/package-lock.json @@ -1,16 +1,26 @@ { - "requires": true, + "name": "stryker", + "version": "0.24.1", "lockfileVersion": 1, + "requires": true, "dependencies": { "@types/babel-types": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.4.tgz", - "integrity": "sha512-WiZhq3SVJHFRgRYLXvpf65XnV6ipVHhnNaNvE8yCimejrGglkg38kEj0JcizqwSHxmPSjcTlig/6JouxLGEhGw==" + "integrity": "sha512-WiZhq3SVJHFRgRYLXvpf65XnV6ipVHhnNaNvE8yCimejrGglkg38kEj0JcizqwSHxmPSjcTlig/6JouxLGEhGw==", + "dev": true + }, + "@types/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha512-TiNg8R1kjDde5Pub9F9vCwZA/BNW9HeXP5b9j7Qucqncy/McfPZ6xze/EyBdXS5FhMIGN6Fx3vg75l5KHy3V1Q==", + "dev": true }, "@types/inquirer": { "version": "0.0.41", "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-0.0.41.tgz", "integrity": "sha512-kIWkK3FECGKt9OrURxRvi59gwMNiWTePXWOvaJn+xhplbEvu91hIDMfLe5PUu+cEEMmD6EFU4VFJJKKp5kzCtw==", + "dev": true, "requires": { "@types/rx": "*", "@types/through": "*" @@ -19,12 +29,14 @@ "@types/istanbul-lib-coverage": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.0.tgz", - "integrity": "sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ==" + "integrity": "sha512-ohkhb9LehJy+PA40rDtGAji61NCgdtKLAlFoYp4cnuuQEswwdK3vz9SOIkkyc3wrk8dzjphQApNs56yyXLStaQ==", + "dev": true }, "@types/istanbul-lib-instrument": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.2.tgz", "integrity": "sha512-SWIpdKneXqThfrKIokt9dXSPeslS2NWcxhtr+/a2+N81aLyOMAsVTMmwaKuCoEahcI0FfhY3/79AR6Vilk9i8A==", + "dev": true, "requires": { "@types/babel-types": "*", "@types/istanbul-lib-coverage": "*", @@ -34,17 +46,20 @@ "@types/node": { "version": "10.5.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-10.5.1.tgz", - "integrity": "sha512-AFLl1IALIuyt6oK4AYZsgWVJ/5rnyzQWud7IebaZWWV3YmgtPZkQmYio9R5Ze/2pdd7XfqF5bP+hWS11mAKoOQ==" + "integrity": "sha512-AFLl1IALIuyt6oK4AYZsgWVJ/5rnyzQWud7IebaZWWV3YmgtPZkQmYio9R5Ze/2pdd7XfqF5bP+hWS11mAKoOQ==", + "dev": true }, "@types/prettier": { "version": "1.13.1", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-1.13.1.tgz", - "integrity": "sha512-OlcCdqLtMvl+Hq4UkAxxppKX252NXsBm6RyJZVuBZtkduu3Dl8pdx78XS4K7oPGPOxpD6T+KzK0DV11G8ykTkw==" + "integrity": "sha512-OlcCdqLtMvl+Hq4UkAxxppKX252NXsBm6RyJZVuBZtkduu3Dl8pdx78XS4K7oPGPOxpD6T+KzK0DV11G8ykTkw==", + "dev": true }, "@types/progress": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@types/progress/-/progress-2.0.1.tgz", "integrity": "sha512-1Smw4LvkCM4zgie7Zo/GtzrMx1Zlq1XVfPoOBXPLIkmtep06wBE7sXupVDq7MXWrHCYtsM0d6i5eF6OM+LJJrQ==", + "dev": true, "requires": { "@types/node": "*" } @@ -53,6 +68,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/@types/rx/-/rx-4.1.1.tgz", "integrity": "sha1-WY/JSla67ZdfGUV04PVy/Y5iekg=", + "dev": true, "requires": { "@types/rx-core": "*", "@types/rx-core-binding": "*", @@ -71,12 +87,14 @@ "@types/rx-core": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-core/-/rx-core-4.0.3.tgz", - "integrity": "sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=" + "integrity": "sha1-CzNUsSOM7b4rdPYybxOdvHpZHWA=", + "dev": true }, "@types/rx-core-binding": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz", "integrity": "sha512-5pkfxnC4w810LqBPUwP5bg7SFR/USwhMSaAeZQQbEHeBp57pjKXRlXmqpMrLJB4y1oglR/c2502853uN0I+DAQ==", + "dev": true, "requires": { "@types/rx-core": "*" } @@ -85,6 +103,7 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/@types/rx-lite/-/rx-lite-4.0.5.tgz", "integrity": "sha512-KZk5XTR1dm/kNgBx8iVpjno6fRYtAUQWBOmj+O8j724+nk097sz4fOoHJNpCkOJUtHUurZlJC7QvSFCZHbkC+w==", + "dev": true, "requires": { "@types/rx-core": "*", "@types/rx-core-binding": "*" @@ -94,6 +113,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-aggregates/-/rx-lite-aggregates-4.0.3.tgz", "integrity": "sha512-MAGDAHy8cRatm94FDduhJF+iNS5//jrZ/PIfm+QYw9OCeDgbymFHChM8YVIvN2zArwsRftKgE33QfRWvQk4DPg==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -102,6 +122,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/rx-lite-async/-/rx-lite-async-4.0.2.tgz", "integrity": "sha512-vTEv5o8l6702ZwfAM5aOeVDfUwBSDOs+ARoGmWAKQ6LOInQ8J4/zjM7ov12fuTpktUKdMQjkeCp07Vd73mPkxw==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -110,6 +131,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-backpressure/-/rx-lite-backpressure-4.0.3.tgz", "integrity": "sha512-Y6aIeQCtNban5XSAF4B8dffhIKu6aAy/TXFlScHzSxh6ivfQBQw6UjxyEJxIOt3IT49YkS+siuayM2H/Q0cmgA==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -118,6 +140,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-coincidence/-/rx-lite-coincidence-4.0.3.tgz", "integrity": "sha512-1VNJqzE9gALUyMGypDXZZXzR0Tt7LC9DdAZQ3Ou/Q0MubNU35agVUNXKGHKpNTba+fr8GdIdkC26bRDqtCQBeQ==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -126,6 +149,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/rx-lite-experimental/-/rx-lite-experimental-4.0.1.tgz", "integrity": "sha1-xTL1y98/LBXaFt7Ykw0bKYQCPL0=", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -134,6 +158,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/rx-lite-joinpatterns/-/rx-lite-joinpatterns-4.0.1.tgz", "integrity": "sha1-9w/jcFGKhDLykVjMkv+1a05K/D4=", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -142,6 +167,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@types/rx-lite-testing/-/rx-lite-testing-4.0.1.tgz", "integrity": "sha1-IbGdEfTf1v/vWp0WSOnIh5v+Iek=", + "dev": true, "requires": { "@types/rx-lite-virtualtime": "*" } @@ -150,6 +176,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-time/-/rx-lite-time-4.0.3.tgz", "integrity": "sha512-ukO5sPKDRwCGWRZRqPlaAU0SKVxmWwSjiOrLhoQDoWxZWg6vyB9XLEZViKOzIO6LnTIQBlk4UylYV0rnhJLxQw==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -158,6 +185,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/rx-lite-virtualtime/-/rx-lite-virtualtime-4.0.3.tgz", "integrity": "sha512-3uC6sGmjpOKatZSVHI2xB1+dedgml669ZRvqxy+WqmGJDVusOdyxcKfyzjW0P3/GrCiN4nmRkLVMhPwHCc5QLg==", + "dev": true, "requires": { "@types/rx-lite": "*" } @@ -166,6 +194,7 @@ "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.29.tgz", "integrity": "sha512-9a7C5VHh+1BKblaYiq+7Tfc+EOmjMdZaD1MYtkQjSoxgB69tBjW98ry6SKsi4zEIWztLOMRuL87A3bdT/Fc/4w==", + "dev": true, "requires": { "@types/node": "*" } @@ -858,6 +887,11 @@ "is-property": "^1.0.0" } }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=" + }, "get-uri": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.2.tgz", diff --git a/packages/stryker/package.json b/packages/stryker/package.json index 25c540d46c..90513d274a 100644 --- a/packages/stryker/package.json +++ b/packages/stryker/package.json @@ -57,6 +57,7 @@ "commander": "^2.12.2", "escodegen": "^1.8.0", "esprima": "^2.7.0", + "get-port": "^3.2.0", "glob": "^7.0.3", "inquirer": "^6.0.0", "istanbul-lib-instrument": "^1.9.2", @@ -74,6 +75,7 @@ "typed-rest-client": "^1.0.7" }, "devDependencies": { + "@types/get-port": "^3.2.0", "@types/inquirer": "0.0.41", "@types/istanbul-lib-instrument": "^1.7.0", "@types/prettier": "^1.6.0", diff --git a/packages/stryker/src/Sandbox.ts b/packages/stryker/src/Sandbox.ts index 3b48b781b8..58989560e4 100644 --- a/packages/stryker/src/Sandbox.ts +++ b/packages/stryker/src/Sandbox.ts @@ -13,6 +13,7 @@ import { TempFolder } from './utils/TempFolder'; import { writeFile, findNodeModules, symlinkJunction } from './utils/fileUtils'; import TestableMutant, { TestSelectionResult } from './TestableMutant'; import TranspiledMutant from './TranspiledMutant'; +import LoggingClientContext from './logging/LoggingClientContext'; interface FileMap { [sourceFile: string]: string; @@ -26,7 +27,7 @@ export default class Sandbox { private files: File[]; private workingFolder: string; - private constructor(private options: Config, private index: number, files: ReadonlyArray, private testFramework: TestFramework | null, private timeOverheadMS: number) { + private constructor(private options: Config, private index: number, files: ReadonlyArray, private testFramework: TestFramework | null, private timeOverheadMS: number, private loggingContext: LoggingClientContext) { this.workingFolder = TempFolder.instance().createRandomFolder('sandbox'); this.log.debug('Creating a sandbox for files in %s', this.workingFolder); this.files = files.slice(); // Create a copy @@ -38,9 +39,9 @@ export default class Sandbox { return this.initializeTestRunner(); } - public static create(options: Config, index: number, files: ReadonlyArray, testFramework: TestFramework | null, timeoutOverheadMS: number) + public static create(options: Config, index: number, files: ReadonlyArray, testFramework: TestFramework | null, timeoutOverheadMS: number, loggingContext: LoggingClientContext) : Promise { - const sandbox = new Sandbox(options, index, files, testFramework, timeoutOverheadMS); + const sandbox = new Sandbox(options, index, files, testFramework, timeoutOverheadMS, loggingContext); return sandbox.initialize().then(() => sandbox); } @@ -117,7 +118,8 @@ export default class Sandbox { fileNames: Object.keys(this.fileMap).map(sourceFileName => this.fileMap[sourceFileName]), strykerOptions: this.options, port: this.options.port + this.index, - sandboxWorkingFolder: this.workingFolder + sandboxWorkingFolder: this.workingFolder, + loggingContext: this.loggingContext }; this.log.debug(`Creating test runner %s using settings {port: %s}`, this.index, settings.port); this.testRunner = ResilientTestRunnerFactory.create(settings.strykerOptions.testRunner || '', settings); diff --git a/packages/stryker/src/SandboxPool.ts b/packages/stryker/src/SandboxPool.ts index 6bffe8f363..ebc6355185 100644 --- a/packages/stryker/src/SandboxPool.ts +++ b/packages/stryker/src/SandboxPool.ts @@ -6,13 +6,14 @@ import { Config } from 'stryker-api/config'; import { File } from 'stryker-api/core'; import { TestFramework } from 'stryker-api/test_framework'; import Sandbox from './Sandbox'; +import LoggingClientContext from './logging/LoggingClientContext'; export default class SandboxPool { private readonly log = getLogger(SandboxPool.name); private readonly sandboxes: Promise[] = []; - constructor(private options: Config, private testFramework: TestFramework | null, private initialFiles: ReadonlyArray, private overheadTimeMS: number) { + constructor(private options: Config, private testFramework: TestFramework | null, private initialFiles: ReadonlyArray, private overheadTimeMS: number, private loggingContext: LoggingClientContext) { } public streamSandboxes(): Observable { @@ -32,7 +33,7 @@ export default class SandboxPool { this.log.info(`Creating ${numConcurrentRunners} test runners (based on ${numConcurrentRunnersSource})`); const sandboxes = range(0, numConcurrentRunners) - .pipe(flatMap(n => this.registerSandbox(Sandbox.create(this.options, n, this.initialFiles, this.testFramework, this.overheadTimeMS)))); + .pipe(flatMap(n => this.registerSandbox(Sandbox.create(this.options, n, this.initialFiles, this.testFramework, this.overheadTimeMS, this.loggingContext)))); return sandboxes; } diff --git a/packages/stryker/src/Stryker.ts b/packages/stryker/src/Stryker.ts index 1b2617057a..1de9880a3d 100644 --- a/packages/stryker/src/Stryker.ts +++ b/packages/stryker/src/Stryker.ts @@ -8,10 +8,10 @@ import ReporterOrchestrator from './ReporterOrchestrator'; import TestFrameworkOrchestrator from './TestFrameworkOrchestrator'; import MutantTestMatcher from './MutantTestMatcher'; import InputFileResolver from './input/InputFileResolver'; -import ConfigReader from './ConfigReader'; +import ConfigReader from './config/ConfigReader'; import PluginLoader from './PluginLoader'; import ScoreResultCalculator from './ScoreResultCalculator'; -import ConfigValidator from './ConfigValidator'; +import ConfigValidator from './config/ConfigValidator'; import { freezeRecursively, isPromise } from './utils/objectUtils'; import { TempFolder } from './utils/TempFolder'; import Timer from './utils/Timer'; @@ -20,7 +20,7 @@ import MutatorFacade from './MutatorFacade'; import InitialTestExecutor, { InitialTestRunResult } from './process/InitialTestExecutor'; import MutationTestExecutor from './process/MutationTestExecutor'; import InputFileCollection from './input/InputFileCollection'; -import LogConfigurator from './utils/LogConfigurator'; +import LogConfigurator from './logging/LogConfigurator'; export default class Stryker { @@ -36,14 +36,14 @@ export default class Stryker { * @param {Object} [options] - Optional options. */ constructor(options: StrykerOptions) { - LogConfigurator.forMaster(options.logLevel); + LogConfigurator.forMaster(options.logLevel, options.fileLogLevel); this.log = getLogger(Stryker.name); let configReader = new ConfigReader(options); this.config = configReader.readConfig(); - LogConfigurator.forMaster(this.config.logLevel); // logLevel could be changed + LogConfigurator.forMaster(this.config.logLevel, this.config.fileLogLevel); // logLevel could be changed this.loadPlugins(); this.applyConfigEditors(); - LogConfigurator.forMaster(this.config.logLevel); // logLevel could be changed + LogConfigurator.forMaster(this.config.logLevel, this.config.fileLogLevel); // logLevel could be changed this.freezeConfig(); this.reporter = new ReporterOrchestrator(this.config).createBroadcastReporter(); this.testFramework = new TestFrameworkOrchestrator(this.config).determineTestFramework(); @@ -51,16 +51,17 @@ export default class Stryker { } async runMutationTest(): Promise { + const loggingContext = await LogConfigurator.forServer(this.config.logLevel, this.config.fileLogLevel); this.timer.reset(); const inputFiles = await new InputFileResolver(this.config.mutate, this.config.files, this.reporter).resolve(); if (inputFiles.files.length) { TempFolder.instance().initialize(); - const initialTestRunProcess = new InitialTestExecutor(this.config, inputFiles, this.testFramework, this.timer); + const initialTestRunProcess = new InitialTestExecutor(this.config, inputFiles, this.testFramework, this.timer, loggingContext); const initialTestRunResult = await initialTestRunProcess.run(); const testableMutants = await this.mutate(inputFiles, initialTestRunResult); if (initialTestRunResult.runResult.tests.length && testableMutants.length) { const mutationTestExecutor = new MutationTestExecutor(this.config, inputFiles.files, this.testFramework, this.reporter, - initialTestRunResult.overheadTimeMS); + initialTestRunResult.overheadTimeMS, loggingContext); const mutantResults = await mutationTestExecutor.run(testableMutants); this.reportScore(mutantResults); await this.wrapUpReporter(); diff --git a/packages/stryker/src/StrykerCli.ts b/packages/stryker/src/StrykerCli.ts index 27f184c04b..c16d782506 100644 --- a/packages/stryker/src/StrykerCli.ts +++ b/packages/stryker/src/StrykerCli.ts @@ -1,9 +1,9 @@ import * as program from 'commander'; -import { CONFIG_SYNTAX_HELP } from './ConfigReader'; +import { CONFIG_SYNTAX_HELP } from './config/ConfigReader'; import Stryker from './Stryker'; import StrykerInitializer from './initializer/StrykerInitializer'; import { getLogger } from 'stryker-api/logging'; -import LogConfigurator from './utils/LogConfigurator'; +import LogConfigurator from './logging/LogConfigurator'; export default class StrykerCli { @@ -45,7 +45,8 @@ export default class StrykerCli { .option('--timeoutMs ', 'Tweak the absolute timeout used to wait for a test runner to complete', parseInt) .option('--timeoutFactor ', 'Tweak the standard deviation relative to the normal test run of a mutated test', parseFloat) .option('--maxConcurrentTestRunners ', 'Set the number of max concurrent test runner to spawn (default: cpuCount)', parseInt) - .option('--logLevel ', 'Set the log4js log level. Possible values: fatal, error, warn, info, debug, trace, all and off. Default is "info"') + .option('--logLevel ', 'Set the log level for the console. Possible values: fatal, error, warn, info, debug, trace, all and off. Default is "info"') + .option('--fileLogLevel ', 'Set the log4js log level for the "stryker.log" file. Possible values: fatal, error, warn, info, debug, trace, all and off. Default is "off"') .parse(this.argv); LogConfigurator.forMaster(program['logLevel']); diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index 0de57e88bf..e5fd08ca90 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -1,9 +1,10 @@ import { fork, ChildProcess } from 'child_process'; import { File } from 'stryker-api/core'; +import { getLogger } from 'stryker-api/logging'; import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol'; import { serialize, deserialize } from '../utils/objectUtils'; import Task from '../utils/Task'; -import { getLogger } from 'stryker-api/logging'; +import LoggingClientContext from '../logging/LoggingClientContext'; export type ChildProxy = { [K in keyof T]: (...args: any[]) => Promise; @@ -18,12 +19,12 @@ export default class ChildProcessProxy { private workerTasks: Task[] = []; private log = getLogger(ChildProcessProxy.name); - private constructor(requirePath: string, logLevel: string, plugins: string[], private constructorFunction: { new(...params: any[]): T }, constructorParams: any[]) { + private constructor(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], private constructorFunction: { new(...params: any[]): T }, constructorParams: any[]) { this.worker = fork(require.resolve('./ChildProcessProxyWorker'), [autoStart], { silent: false, execArgv: [] }); this.initTask = new Task(); this.send({ kind: WorkerMessageKind.Init, - logLevel, + loggingContext, plugins, requirePath, constructorArgs: constructorParams @@ -35,16 +36,16 @@ export default class ChildProcessProxy { /** * Creates a proxy where each function of the object created using the constructorFunction arg is ran inside of a child process */ - static create(requirePath: string, logLevel: string, plugins: string[], constructorFunction: { new(arg: P1): T }, arg: P1): ChildProcessProxy; + static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], constructorFunction: { new(arg: P1): T }, arg: P1): ChildProcessProxy; /** * Creates a proxy where each function of the object created using the constructorFunction arg is ran inside of a child process */ - static create(requirePath: string, logLevel: string, plugins: string[], constructorFunction: { new(arg: P1, arg2: P2): T }, arg1: P1, arg2: P2): ChildProcessProxy; + static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], constructorFunction: { new(arg: P1, arg2: P2): T }, arg1: P1, arg2: P2): ChildProcessProxy; /** * Creates a proxy where each function of the object created using the constructorFunction arg is ran inside of a child process */ - static create(requirePath: string, logLevel: string, plugins: string[], constructorFunction: { new(...params: any[]): T }, ...constructorArgs: any[]) { - return new ChildProcessProxy(requirePath, logLevel, plugins, constructorFunction, constructorArgs); + static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], constructorFunction: { new(...params: any[]): T }, ...constructorArgs: any[]) { + return new ChildProcessProxy(requirePath, loggingContext, plugins, constructorFunction, constructorArgs); } private send(message: WorkerMessage) { diff --git a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts index 47ad8ba46b..008ce8e2f3 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts @@ -3,17 +3,15 @@ import { File } from 'stryker-api/core'; import { serialize, deserialize, errorToString } from '../utils/objectUtils'; import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol'; import PluginLoader from '../PluginLoader'; -import LogConfigurator from '../utils/LogConfigurator'; +import LogConfigurator from '../logging/LogConfigurator'; export default class ChildProcessProxyWorker { - private readonly log: Logger; + private log: Logger; realSubject: any; constructor() { - LogConfigurator.forWorker(); - this.log = getLogger(ChildProcessProxyWorker.name); this.listenToParent(); } @@ -29,6 +27,8 @@ export default class ChildProcessProxyWorker { const message = deserialize(serializedMessage, [File]); switch (message.kind) { case WorkerMessageKind.Init: + LogConfigurator.forWorker(message.loggingContext); + this.log = getLogger(ChildProcessProxyWorker.name); new PluginLoader(message.plugins).load(); const RealSubjectClass = require(message.requirePath).default; this.realSubject = new RealSubjectClass(...message.constructorArgs); diff --git a/packages/stryker/src/child-proxy/messageProtocol.ts b/packages/stryker/src/child-proxy/messageProtocol.ts index 1b2b3b4155..b93669aec5 100644 --- a/packages/stryker/src/child-proxy/messageProtocol.ts +++ b/packages/stryker/src/child-proxy/messageProtocol.ts @@ -1,3 +1,5 @@ +import LoggingClientContext from '../logging/LoggingClientContext'; + export enum WorkerMessageKind { 'Init', 'Work', @@ -20,7 +22,7 @@ export const autoStart = 'childProcessAutoStart12937129s7d'; export interface InitMessage { kind: WorkerMessageKind.Init; - logLevel: string; + loggingContext: LoggingClientContext; plugins: string[]; requirePath: string; constructorArgs: any[]; diff --git a/packages/stryker/src/ConfigReader.ts b/packages/stryker/src/config/ConfigReader.ts similarity index 98% rename from packages/stryker/src/ConfigReader.ts rename to packages/stryker/src/config/ConfigReader.ts index fc0ce25bb8..4a721e7c6e 100644 --- a/packages/stryker/src/ConfigReader.ts +++ b/packages/stryker/src/config/ConfigReader.ts @@ -4,7 +4,7 @@ import * as fs from 'mz/fs'; import * as log4js from 'stryker-api/logging'; import * as path from 'path'; import * as _ from 'lodash'; -import StrykerError from './utils/StrykerError'; +import StrykerError from '../utils/StrykerError'; export const CONFIG_SYNTAX_HELP = ' module.exports = function(config) {\n' + ' config.set({\n' + diff --git a/packages/stryker/src/ConfigValidator.ts b/packages/stryker/src/config/ConfigValidator.ts similarity index 91% rename from packages/stryker/src/ConfigValidator.ts rename to packages/stryker/src/config/ConfigValidator.ts index 3b844d200c..02d6b278af 100644 --- a/packages/stryker/src/ConfigValidator.ts +++ b/packages/stryker/src/config/ConfigValidator.ts @@ -1,8 +1,8 @@ import { TestFramework } from 'stryker-api/test_framework'; -import { MutatorDescriptor, MutationScoreThresholds } from 'stryker-api/core'; +import { MutatorDescriptor, MutationScoreThresholds, LogLevel } from 'stryker-api/core'; import { Config } from 'stryker-api/config'; import { getLogger } from 'stryker-api/logging'; -import StrykerError from './utils/StrykerError'; +import StrykerError from '../utils/StrykerError'; export default class ConfigValidator { @@ -16,7 +16,8 @@ export default class ConfigValidator { this.validateTestFramework(); this.validateThresholds(); this.validateMutator(); - this.validateLogLevel(); + this.validateLogLevel('logLevel'); + this.validateLogLevel('fileLogLevel'); this.validateTimeout(); this.validateIsNumber('port', this.strykerConfig.port); this.validateIsNumber('maxConcurrentTestRunners', this.strykerConfig.maxConcurrentTestRunners); @@ -69,9 +70,9 @@ export default class ConfigValidator { } } - private validateLogLevel() { - const logLevel = this.strykerConfig.logLevel; - const VALID_LOG_LEVEL_VALUES = ['fatal', 'error', 'warn', 'info', 'debug', 'trace', 'all', 'off']; + private validateLogLevel(logProperty: 'logLevel' | 'fileLogLevel') { + const logLevel = this.strykerConfig[logProperty]; + const VALID_LOG_LEVEL_VALUES = [LogLevel.Fatal, LogLevel.Error, LogLevel.Warning, LogLevel.Information, LogLevel.Debug, LogLevel.Trace, LogLevel.Off]; if (VALID_LOG_LEVEL_VALUES.indexOf(logLevel) < 0) { this.invalidate(`Value "${logLevel}" is invalid for \`logLevel\`. Expected one of the following: ${this.joinQuotedList(VALID_LOG_LEVEL_VALUES)}`); } diff --git a/packages/stryker/src/isolated-runner/IsolatedRunnerOptions.ts b/packages/stryker/src/isolated-runner/IsolatedRunnerOptions.ts index f7cfe31fbf..646e9d5aba 100644 --- a/packages/stryker/src/isolated-runner/IsolatedRunnerOptions.ts +++ b/packages/stryker/src/isolated-runner/IsolatedRunnerOptions.ts @@ -1,7 +1,9 @@ import { RunnerOptions } from 'stryker-api/test_runner'; +import LoggingClientContext from '../logging/LoggingClientContext'; interface IsolatedRunnerOptions extends RunnerOptions { sandboxWorkingFolder: string; + loggingContext: LoggingClientContext; } export default IsolatedRunnerOptions; \ No newline at end of file diff --git a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts index 8f49b4bcd4..23c9e24050 100644 --- a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts +++ b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts @@ -3,16 +3,14 @@ import { TestRunner, RunStatus, TestRunnerFactory, RunResult } from 'stryker-api import PluginLoader from '../PluginLoader'; import { getLogger, Logger } from 'stryker-api/logging'; import { deserialize, errorToString } from '../utils/objectUtils'; -import LogConfigurator from '../utils/LogConfigurator'; +import LogConfigurator from '../logging/LogConfigurator'; class IsolatedTestRunnerAdapterWorker { - private readonly log: Logger; + private log: Logger; private underlyingTestRunner: TestRunner; constructor() { - LogConfigurator.forWorker(); - this.log = getLogger(IsolatedTestRunnerAdapterWorker.name); this.handlePromiseRejections(); this.listenToMessages(); } @@ -61,6 +59,8 @@ class IsolatedTestRunnerAdapterWorker { } start(message: StartMessage) { + LogConfigurator.forWorker(message.runnerOptions.loggingContext); + this.log = getLogger(IsolatedTestRunnerAdapterWorker.name); this.loadPlugins(message.runnerOptions.strykerOptions.plugins || []); this.log.debug(`Changing current working directory for this process to ${message.runnerOptions.sandboxWorkingFolder}`); process.chdir(message.runnerOptions.sandboxWorkingFolder); diff --git a/packages/stryker/src/logging/LogConfigurator.ts b/packages/stryker/src/logging/LogConfigurator.ts new file mode 100644 index 0000000000..d0f385ea54 --- /dev/null +++ b/packages/stryker/src/logging/LogConfigurator.ts @@ -0,0 +1,132 @@ +import * as log4js from 'log4js'; +import { LoggerFactory } from 'stryker-api/logging'; +import { LogLevel } from 'stryker-api/core'; +import { minLevel } from './logUtils'; +import LoggingClientContext from './LoggingClientContext'; +import * as getPort from 'get-port'; + +const PREFERRED_LOG_SERVER_PORT = 5000; + +enum AppenderName { + File = 'file', + FilteredFile = 'filteredFile', + Console = 'console', + FilteredConsole = 'filteredConsole', + All = 'all', + Server = 'server' +} + +interface AppendersConfiguration { + [name: string]: log4js.Appender; +} + +const LOG_FILE_NAME = 'stryker.log'; +export default class LogConfigurator { + + private static createMasterAppenders(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): AppendersConfiguration { + const layout: log4js.PatternLayout = { + type: 'pattern', + pattern: '%[%r (%z) %p %c%] %m' + }; + + const multiAppender = { type: require.resolve('./MultiAppender'), appenders: ['filteredConsole'] }; + let allAppenders: AppendersConfiguration = { + [AppenderName.Console]: { type: 'stdout', layout }, + [AppenderName.FilteredConsole]: { type: 'logLevelFilter', appender: 'console', level: consoleLogLevel }, + [AppenderName.All]: multiAppender, + }; + + // only add file if it is needed. Otherwise log4js will create the file directly, pretty annoying. + if (fileLogLevel.toUpperCase() !== LogLevel.Off.toUpperCase()) { + const fileAppender: log4js.FileAppender = { type: 'file', filename: LOG_FILE_NAME, layout }; + const filteredFileAppender: log4js.LogLevelFilterAppender = { type: 'logLevelFilter', appender: 'file', level: fileLogLevel }; + + // Don't simply add the appenders, instead actually make sure they are ordinal "before" the others. + // See https://github.com/log4js-node/log4js-node/issues/746 + allAppenders = Object.assign({ [AppenderName.File]: fileAppender, [AppenderName.FilteredFile]: filteredFileAppender }, allAppenders); + + multiAppender.appenders.push(AppenderName.FilteredFile); + } + + return allAppenders; + } + + private static createLog4jsConfig(defaultLogLevel: LogLevel, appenders: AppendersConfiguration): log4js.Configuration { + return { + appenders, + categories: { + default: { + appenders: [AppenderName.All], level: defaultLogLevel + } + } + }; + } + + private static setImplementation(): void { + LoggerFactory.setLogImplementation(log4js.getLogger); + } + + /** + * Configure logging for the master process. Either call this method or `forWorker` before any `getLogger` calls. + * @param consoleLogLevel The log level to configure for the console + * @param fileLogLevel The log level to configure for the "stryker.log" file + */ + static forMaster(consoleLogLevel: LogLevel = LogLevel.Information, fileLogLevel: LogLevel = LogLevel.Off) { + this.setImplementation(); + const appenders = this.createMasterAppenders(consoleLogLevel, fileLogLevel); + log4js.configure(this.createLog4jsConfig(minLevel(consoleLogLevel, fileLogLevel), appenders)); + } + + /** + * Configure the logging for the server. Includes the master configuration. + * This method can only be called ONCE, as it starts the log4js server to listen for log events. + * It returns the logging client context that should be used to doe the `forWorker` calls. + * @param consoleLogLevel the console log level + * @param fileLogLevel the file log level + * @returns the context + */ + static forServer(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): PromiseLike { + this.setImplementation(); + return getPort({ port: PREFERRED_LOG_SERVER_PORT }).then(loggerPort => { + const appenders = this.createMasterAppenders(consoleLogLevel, fileLogLevel); + const multiProcessAppender: log4js.MultiprocessAppender = { + type: 'multiprocess', + mode: 'master', + appender: AppenderName.All, + loggerPort + }; + appenders[AppenderName.Server] = multiProcessAppender; + const defaultLogLevel = minLevel(consoleLogLevel, fileLogLevel); + log4js.configure(this.createLog4jsConfig(defaultLogLevel, appenders)); + const context: LoggingClientContext = { + port: loggerPort, + level: defaultLogLevel + } + return context; + }); + } + + /** + * Configures the logging for a worker process. Sends all logging to the master process. + * Either call this method or `forMaster` before any `getLogger` calls. + * @param context the logging client context used to configure the logging client + */ + static forWorker(context: LoggingClientContext) { + this.setImplementation(); + const clientAppender: log4js.MultiprocessAppender = { type: 'multiprocess', mode: 'worker', loggerPort: context.port }; + const appenders: AppendersConfiguration = { [AppenderName.All]: clientAppender }; + log4js.configure(this.createLog4jsConfig(context.level, appenders)); + } + + static shutdown(): Promise { + return new Promise((res, rej) => { + log4js.shutdown(err => { + if (err) { + rej(err); + } else { + res(); + } + }); + }); + } +} \ No newline at end of file diff --git a/packages/stryker/src/logging/LoggingClientContext.ts b/packages/stryker/src/logging/LoggingClientContext.ts new file mode 100644 index 0000000000..c1b757a69e --- /dev/null +++ b/packages/stryker/src/logging/LoggingClientContext.ts @@ -0,0 +1,7 @@ +import { LogLevel } from 'stryker-api/core'; + + +export default interface LoggingClientContext { + readonly port: number; + readonly level: LogLevel; +} \ No newline at end of file diff --git a/packages/stryker/src/logging/MultiAppender.ts b/packages/stryker/src/logging/MultiAppender.ts new file mode 100644 index 0000000000..2aa80ba38d --- /dev/null +++ b/packages/stryker/src/logging/MultiAppender.ts @@ -0,0 +1,20 @@ +import { LoggingEvent } from 'log4js'; + +interface RuntimeAppender { + (loggingEvent: LoggingEvent): void; +} + +export class MultiAppender { + + constructor(private appenders: RuntimeAppender[]) { } + + append(loggingEvent: LoggingEvent) { + this.appenders.forEach(appender => appender(loggingEvent)); + } +} + +export function configure(config: { appenders: string[] }, layouts: any, findAppender: (name: string) => RuntimeAppender ) { + const multiAppender = new MultiAppender(config.appenders.map(name => findAppender(name))); + return multiAppender.append.bind(multiAppender); +} + diff --git a/packages/stryker/src/logging/logUtils.ts b/packages/stryker/src/logging/logUtils.ts new file mode 100644 index 0000000000..a84cdd953a --- /dev/null +++ b/packages/stryker/src/logging/logUtils.ts @@ -0,0 +1,20 @@ +import { LogLevel } from 'stryker-api/core'; +import * as log4js from 'log4js'; + +/** + * Determines the minimal log level (where trace < off) + * @param a one log level + * @param b other log level + */ +export function minLevel(a: LogLevel, b: LogLevel){ + if (getLevel(b).isGreaterThanOrEqualTo(getLevel(a))) { + return a; + } else { + return b; + } +} + +function getLevel(level: LogLevel): log4js.Level { + // Needs an any cast here, wrongly typed, see https://github.com/log4js-node/log4js-node/pull/745 + return (log4js.levels as any).getLevel(level); +} diff --git a/packages/stryker/src/process/InitialTestExecutor.ts b/packages/stryker/src/process/InitialTestExecutor.ts index a9a0c3c39f..3f6ae01749 100644 --- a/packages/stryker/src/process/InitialTestExecutor.ts +++ b/packages/stryker/src/process/InitialTestExecutor.ts @@ -12,6 +12,7 @@ import CoverageInstrumenterTranspiler, { CoverageMapsByFile } from '../transpile import InputFileCollection from '../input/InputFileCollection'; import SourceMapper from '../transpiler/SourceMapper'; import { coveragePerTestHooks } from '../transpiler/coverageHooks'; +import LoggingClientContext from '../logging/LoggingClientContext'; // The initial run might take a while. // For example: angular-bootstrap takes up to 45 seconds. @@ -45,7 +46,7 @@ export default class InitialTestExecutor { private readonly log = getLogger(InitialTestExecutor.name); - constructor(private options: Config, private inputFiles: InputFileCollection, private testFramework: TestFramework | null, private timer: Timer) { + constructor(private options: Config, private inputFiles: InputFileCollection, private testFramework: TestFramework | null, private timer: Timer, private loggingContext: LoggingClientContext) { } async run(): Promise { @@ -77,7 +78,7 @@ export default class InitialTestExecutor { } private async runInSandbox(files: ReadonlyArray): Promise<{ runResult: RunResult, grossTimeMS: number }> { - const sandbox = await Sandbox.create(this.options, 0, files, this.testFramework, 0); + const sandbox = await Sandbox.create(this.options, 0, files, this.testFramework, 0, this.loggingContext); this.timer.mark(INITIAL_TEST_RUN_MARKER); const runResult = await sandbox.run(INITIAL_RUN_TIMEOUT, this.getCollectCoverageHooksIfNeeded()); const grossTimeMS = this.timer.elapsedMs(INITIAL_TEST_RUN_MARKER); diff --git a/packages/stryker/src/process/MutationTestExecutor.ts b/packages/stryker/src/process/MutationTestExecutor.ts index 647b904ef7..c226e675fa 100644 --- a/packages/stryker/src/process/MutationTestExecutor.ts +++ b/packages/stryker/src/process/MutationTestExecutor.ts @@ -11,6 +11,7 @@ import TestableMutant from '../TestableMutant'; import TranspiledMutant from '../TranspiledMutant'; import StrictReporter from '../reporters/StrictReporter'; import MutantTranspiler from '../transpiler/MutantTranspiler'; +import LoggingClientContext from '../logging/LoggingClientContext'; export default class MutationTestExecutor { @@ -19,13 +20,14 @@ export default class MutationTestExecutor { private inputFiles: ReadonlyArray, private testFramework: TestFramework | null, private reporter: StrictReporter, - private overheadTimeMS: number) { + private overheadTimeMS: number, + private loggingContext: LoggingClientContext) { } async run(allMutants: TestableMutant[]): Promise { - const mutantTranspiler = new MutantTranspiler(this.config); + const mutantTranspiler = new MutantTranspiler(this.config, this.loggingContext); const transpiledFiles = await mutantTranspiler.initialize(this.inputFiles); - const sandboxPool = new SandboxPool(this.config, this.testFramework, transpiledFiles, this.overheadTimeMS); + const sandboxPool = new SandboxPool(this.config, this.testFramework, transpiledFiles, this.overheadTimeMS, this.loggingContext); const result = await this.runInsideSandboxes( sandboxPool.streamSandboxes(), mutantTranspiler.transpileMutants(allMutants)); diff --git a/packages/stryker/src/transpiler/MutantTranspiler.ts b/packages/stryker/src/transpiler/MutantTranspiler.ts index ed691e1853..18892af347 100644 --- a/packages/stryker/src/transpiler/MutantTranspiler.ts +++ b/packages/stryker/src/transpiler/MutantTranspiler.ts @@ -9,6 +9,7 @@ import { TranspilerOptions } from 'stryker-api/transpile'; import TranspiledMutant from '../TranspiledMutant'; import TranspileResult from './TranspileResult'; import { errorToString } from '../utils/objectUtils'; +import LoggingClientContext from '../logging/LoggingClientContext'; export default class MutantTranspiler { @@ -22,12 +23,12 @@ export default class MutantTranspiler { * Otherwise will just forward input as output in same process. * @param config The Stryker config */ - constructor(config: Config) { + constructor(config: Config, loggingContext: LoggingClientContext) { const transpilerOptions: TranspilerOptions = { config, produceSourceMaps: false }; if (config.transpilers.length) { this.transpilerChildProcess = ChildProcessProxy.create( require.resolve('./TranspilerFacade'), - config.logLevel, + loggingContext, config.plugins, TranspilerFacade, transpilerOptions diff --git a/packages/stryker/src/utils/LogConfigurator.ts b/packages/stryker/src/utils/LogConfigurator.ts deleted file mode 100644 index 06773a644d..0000000000 --- a/packages/stryker/src/utils/LogConfigurator.ts +++ /dev/null @@ -1,57 +0,0 @@ -import * as log4js from 'log4js'; -import { LoggerFactory } from 'stryker-api/logging'; - -let notConfigured = true; - -export default class LogConfigurator { - - static setImplementation(): void { - LoggerFactory.setLogImplementation(log4js.getLogger); - } - - static forMaster(logLevel = 'info') { - const layout: log4js.PatternLayout = { - type: 'pattern', - pattern: '%[%r (%z) %p %c%] %m' - }; - this.setImplementation(); - if (notConfigured) { - log4js.configure({ - appenders: { - console: { type: 'stdout', layout }, - file: { type: 'file', filename: 'application.log', layout }, - filteredConsole: { type: 'logLevelFilter', appender: 'console', level: logLevel }, - server: { type: 'multiprocess', mode: 'master', appender: 'file' } - }, - categories: { - default: { appenders: ['filteredConsole', 'file'], level: 'trace' } - }, - }); - notConfigured = false; - } - } - - static forWorker() { - this.setImplementation(); - log4js.configure({ - appenders: { - server: { type: 'multiprocess', mode: 'worker' } - }, - categories: { - default: { appenders: ['server'], level: 'trace' } - }, - }); - } - - static shutdown(): Promise { - return new Promise((res, rej) => { - log4js.shutdown(err => { - if (err) { - rej(err); - } else { - res(); - } - }); - }; - } -} \ No newline at end of file diff --git a/packages/stryker/stryker.conf.js b/packages/stryker/stryker.conf.js index e50fe48a8e..a978330e52 100644 --- a/packages/stryker/stryker.conf.js +++ b/packages/stryker/stryker.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { '!test/**/*.d.ts' ], symlinkNodeModules: false, - mutate: ['src/**/*.ts'], + mutate: ['src/Stryker.ts'], coverageAnalysis: 'perTest', tsconfigFile: 'tsconfig.json', mutator: 'typescript', diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index b601e181ac..1e237daf95 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -1,18 +1,27 @@ import { expect } from 'chai'; import Echo from './Echo'; import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; -import { File } from 'stryker-api/core'; +import { File, LogLevel } from 'stryker-api/core'; +import * as net from 'net'; +import * as log4js from 'log4js'; +import { Observable, Subscriber } from 'rxjs'; +import * as getPort from 'get-port'; +import Task from '../../../src/utils/Task'; describe('ChildProcessProxy', () => { let sut: ChildProcessProxy; + let loggingServer: LoggingServer; - beforeEach(() => { - sut = ChildProcessProxy.create(require.resolve('./Echo'), 'info', [], Echo, 'World'); + beforeEach(async () => { + const port = await getPort(); + loggingServer = new LoggingServer(port); + sut = ChildProcessProxy.create(require.resolve('./Echo'), { port, level: LogLevel.Debug }, [], Echo, 'World'); }); - afterEach(() => { - sut.dispose(); + afterEach(async () => { + await sut.dispose(); + await loggingServer.dispose(); }); it('should be able to get direct result', async () => { @@ -39,4 +48,70 @@ describe('ChildProcessProxy', () => { it('should be able to receive a promise rejection', () => { return expect(sut.proxy.reject('Foobar error')).rejectedWith('Foobar error'); }); + + it('should be able to log on debug when LogLevel.Debug is allowed', async () => { + const firstLogEventTask = new Task(); + loggingServer.event$.subscribe(firstLogEventTask.resolve.bind(firstLogEventTask)); + sut.proxy.debug('test message'); + const log = await firstLogEventTask.promise; + expect(log.categoryName).eq(Echo.name); + expect(log.data).deep.eq(['test message']); + }); + + it('should not log on trace if LogLevel.Debug is allowed as min log level', async () => { + const firstLogEventTask = new Task(); + loggingServer.event$.subscribe(firstLogEventTask.resolve.bind(firstLogEventTask)); + sut.proxy.trace('foo') + sut.proxy.debug('bar'); + const log = await firstLogEventTask.promise; + expect(log.categoryName).eq(Echo.name); + expect(log.data).deep.eq(['bar']); + expect(toLogLevel(log.level)).eq(LogLevel.Debug); + }); }); + +function toLogLevel(level: log4js.Level) { + const levelName = (level as any).levelStr.toLowerCase(); + return [LogLevel.Debug, LogLevel.Error, LogLevel.Fatal, LogLevel.Information, LogLevel.Off, LogLevel.Trace, LogLevel.Warning].find(level => level === levelName); +} + +class LoggingServer { + + private readonly server: net.Server; + private subscribers: Subscriber[] = []; + public readonly event$: Observable; + + constructor(private port: number) { + this.server = net.createServer(socket => { + socket.on('data', data => { + const str = data.toString(); + try { + const json = JSON.parse(str); + this.subscribers.map(sub => sub.next(json)); + } catch { + // IDLE. Log4js also sends "__LOG4JS__" to signal an event end. Ignore those. + } + }); + }); + this.server.listen(this.port); + + this.event$ = new Observable(subscriber => { + this.subscribers.push(subscriber); + this.server.on('close', () => { + subscriber.complete(); + }); + }); + } + + dispose(): Promise { + return new Promise((res, rej) => { + this.server.close((err: Error) => { + if (err) { + rej(err); + } else { + res(); + } + }); + }); + } +} \ No newline at end of file diff --git a/packages/stryker/test/integration/child-proxy/Echo.ts b/packages/stryker/test/integration/child-proxy/Echo.ts index 53452c85f3..71abd62a25 100644 --- a/packages/stryker/test/integration/child-proxy/Echo.ts +++ b/packages/stryker/test/integration/child-proxy/Echo.ts @@ -1,8 +1,12 @@ import { File } from 'stryker-api/core'; +import { getLogger } from 'stryker-api/logging'; export default class Echo { + private logger = getLogger(Echo.name); + constructor(private name: string) { + } say(value: string) { @@ -25,6 +29,14 @@ export default class Echo { return new File('foobar.txt', 'hello foobar'); } + debug(message: string) { + this.logger.debug(message); + } + + trace(message: string) { + this.logger.trace(message); + } + reject(error: string) { return Promise.reject(new Error(error)); } diff --git a/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts b/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts index d12a85c37a..7e26420e8a 100644 --- a/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts +++ b/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; import * as log4js from 'stryker-api/logging'; -import ConfigReader from '../../../src/ConfigReader'; +import ConfigReader from '../../../src/config/ConfigReader'; import { Config } from 'stryker-api/config'; import currentLogMock from '../../helpers/logMock'; import { Mock } from '../../helpers/producers'; diff --git a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts index 1b9cad373f..9bf134c65f 100644 --- a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts +++ b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts @@ -7,6 +7,7 @@ import IsolatedRunnerOptions from '../../../src/isolated-runner/IsolatedRunnerOp import TestRunnerDecorator from '../../../src/isolated-runner/TestRunnerDecorator'; import currentLogMock from '../../helpers/logMock'; import { Mock } from '../../helpers/producers'; +import { LogLevel } from 'stryker-api/core'; function sleep(ms: number) { return new Promise(res => { @@ -29,7 +30,8 @@ describe('ResilientTestRunnerFactory', function () { }, port: 0, fileNames: [], - sandboxWorkingFolder: path.resolve('./test/integration/isolated-runner') + sandboxWorkingFolder: path.resolve('./test/integration/isolated-runner'), + loggingContext: { port: 4200, level: LogLevel.Fatal } }; beforeEach(() => { diff --git a/packages/stryker/test/unit/SandboxPoolSpec.ts b/packages/stryker/test/unit/SandboxPoolSpec.ts index 31a3eb83f4..694fe0ce68 100644 --- a/packages/stryker/test/unit/SandboxPoolSpec.ts +++ b/packages/stryker/test/unit/SandboxPoolSpec.ts @@ -2,15 +2,20 @@ import { expect } from 'chai'; import * as os from 'os'; import { flatMap, toArray } from 'rxjs/operators'; import { Config } from 'stryker-api/config'; -import { File } from 'stryker-api/core'; +import { File, LogLevel } from 'stryker-api/core'; import { TestFramework } from 'stryker-api/test_framework'; import Sandbox from '../../src/Sandbox'; import SandboxPool from '../../src/SandboxPool'; import Task from '../../src/utils/Task'; import '../helpers/globals'; import { Mock, config, file, mock, testFramework } from '../helpers/producers'; +import LoggingClientContext from '../../src/logging/LoggingClientContext'; const OVERHEAD_TIME_MS = 42; +const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ + port: 4200, + level: LogLevel.Fatal +}); describe('SandboxPool', () => { let sut: SandboxPool; @@ -36,7 +41,7 @@ describe('SandboxPool', () => { .onCall(1).resolves(secondSandbox); expectedInputFiles = [file()]; - sut = new SandboxPool(options, expectedTestFramework, expectedInputFiles, OVERHEAD_TIME_MS); + sut = new SandboxPool(options, expectedTestFramework, expectedInputFiles, OVERHEAD_TIME_MS, LOGGING_CONTEXT); }); describe('streamSandboxes', () => { diff --git a/packages/stryker/test/unit/SandboxSpec.ts b/packages/stryker/test/unit/SandboxSpec.ts index 8c70937230..9b1bf91ad6 100644 --- a/packages/stryker/test/unit/SandboxSpec.ts +++ b/packages/stryker/test/unit/SandboxSpec.ts @@ -5,7 +5,7 @@ import * as sinon from 'sinon'; import * as path from 'path'; import * as mkdirp from 'mkdirp'; import { expect } from 'chai'; -import { File } from 'stryker-api/core'; +import { File, LogLevel } from 'stryker-api/core'; import { wrapInClosure, normalizeWhiteSpaces } from '../../src/utils/objectUtils'; import Sandbox from '../../src/Sandbox'; import { TempFolder } from '../../src/utils/TempFolder'; @@ -19,8 +19,13 @@ import TranspiledMutant from '../../src/TranspiledMutant'; import * as fileUtils from '../../src/utils/fileUtils'; import currentLogMock from '../helpers/logMock'; import TestRunnerDecorator from '../../src/isolated-runner/TestRunnerDecorator'; +import LoggingClientContext from '../../src/logging/LoggingClientContext'; const OVERHEAD_TIME_MS = 0; +const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ + port: 4200, + level: LogLevel.Fatal +}); const SANDBOX_INDEX = 3; describe('Sandbox', () => { @@ -69,41 +74,42 @@ describe('Sandbox', () => { describe('create()', () => { it('should copy input files when created', async () => { - await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS); + await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS, LOGGING_CONTEXT); expect(fileUtils.writeFile).calledWith(expectedTargetFileToMutate, files[0].content); expect(fileUtils.writeFile).calledWith(path.join(sandboxFolder, 'file2'), files[1].content); }); it('should copy a local file when created', async () => { - await Sandbox.create(options, SANDBOX_INDEX, [new File('localFile.js', 'foobar')], null, OVERHEAD_TIME_MS); + await Sandbox.create(options, SANDBOX_INDEX, [new File('localFile.js', 'foobar')], null, OVERHEAD_TIME_MS, LOGGING_CONTEXT); expect(fileUtils.writeFile).calledWith(path.join(sandboxFolder, 'localFile.js'), Buffer.from('foobar')); }); it('should have created the isolated test runner', async () => { - await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS); + await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS, LOGGING_CONTEXT); const expectedSettings: IsolatedRunnerOptions = { port: 46, strykerOptions: options, sandboxWorkingFolder: sandboxFolder, - fileNames: [path.resolve('random-folder-3', 'file1'), path.resolve('random-folder-3', 'file2')] + fileNames: [path.resolve('random-folder-3', 'file1'), path.resolve('random-folder-3', 'file2')], + loggingContext: LOGGING_CONTEXT }; expect(ResilientTestRunnerFactory.create).to.have.been.calledWith(options.testRunner, expectedSettings); }); it('should have created a sandbox folder', async () => { - await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS); + await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS, LOGGING_CONTEXT); expect(TempFolder.instance().createRandomFolder).to.have.been.calledWith('sandbox'); }); it('should symlink node modules in sandbox directory if exists', async () => { - await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS); + await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS, LOGGING_CONTEXT); expect(findNodeModulesStub).calledWith(process.cwd()); expect(symlinkJunctionStub).calledWith('node_modules', path.join(sandboxFolder, 'node_modules')); }); it('should not symlink node modules in sandbox directory if no node_modules exist', async () => { findNodeModulesStub.resolves(null); - await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS); + await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS, LOGGING_CONTEXT); expect(log.warn).calledWithMatch('Could not find a node_modules'); expect(log.warn).calledWithMatch(process.cwd()); expect(symlinkJunctionStub).not.called; @@ -112,7 +118,7 @@ describe('Sandbox', () => { it('should log a warning if "node_modules" already exists in the working folder', async () => { findNodeModulesStub.resolves('node_modules'); symlinkJunctionStub.rejects(createFileAlreadyExistsError()); - await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS); + await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS, LOGGING_CONTEXT); expect(log.warn).calledWithMatch(normalizeWhiteSpaces( `Could not symlink "node_modules" in sandbox directory, it is already created in the sandbox. Please remove the node_modules from your sandbox files. Alternatively, set \`symlinkNodeModules\` @@ -123,14 +129,14 @@ describe('Sandbox', () => { findNodeModulesStub.resolves('basePath/node_modules'); const error = new Error('unknown'); symlinkJunctionStub.rejects(error); - await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS); + await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS, LOGGING_CONTEXT); expect(log.warn).calledWithMatch(normalizeWhiteSpaces( `Unexpected error while trying to symlink "basePath/node_modules" in sandbox directory.`), error); }); it('should symlink node modules in sandbox directory if `symlinkNodeModules` is `false`', async () => { options.symlinkNodeModules = false; - await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS); + await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS, LOGGING_CONTEXT); expect(symlinkJunctionStub).not.called; expect(findNodeModulesStub).not.called; }); @@ -138,7 +144,7 @@ describe('Sandbox', () => { describe('run()', () => { it('should run the testRunner', async () => { - const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, 0); + const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, 0, LOGGING_CONTEXT); await sut.run(231313, 'hooks'); expect(testRunner.run).to.have.been.calledWith({ timeout: 231313, @@ -166,21 +172,21 @@ describe('Sandbox', () => { }); it('should save the mutant to disk', async () => { - const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS); + const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS, LOGGING_CONTEXT); await sut.runMutant(transpiledMutant); expect(fileUtils.writeFile).calledWith(expectedTargetFileToMutate, Buffer.from('mutated code')); expect(log.warn).not.called; }); it('should nog log a warning if test selection was failed but already reported', async () => { - const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS); + const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS, LOGGING_CONTEXT); transpiledMutant.mutant.testSelectionResult = TestSelectionResult.FailedButAlreadyReported; await sut.runMutant(transpiledMutant); expect(log.warn).not.called; }); it('should log a warning if tests could not have been selected', async () => { - const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS); + const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS, LOGGING_CONTEXT); transpiledMutant.mutant.testSelectionResult = TestSelectionResult.Failed; await sut.runMutant(transpiledMutant); const expectedLogMessage = `Failed find coverage data for this mutant, running all tests. This might have an impact on performance: ${transpiledMutant.mutant.toString()}`; @@ -188,7 +194,7 @@ describe('Sandbox', () => { }); it('should filter the scoped tests', async () => { - const sut = await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS); + const sut = await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, OVERHEAD_TIME_MS, LOGGING_CONTEXT); await sut.runMutant(transpiledMutant); expect(testFrameworkStub.filter).to.have.been.calledWith(transpiledMutant.mutant.selectedTests); }); @@ -197,14 +203,14 @@ describe('Sandbox', () => { options.timeoutMs = 1000; const overheadTimeMS = 42; const totalTimeSpend = 12; - const sut = await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, overheadTimeMS); + const sut = await Sandbox.create(options, SANDBOX_INDEX, files, testFrameworkStub, overheadTimeMS, LOGGING_CONTEXT); await sut.runMutant(transpiledMutant); const expectedRunOptions = { testHooks: wrapInClosure(testFilterCodeFragment), timeout: totalTimeSpend * options.timeoutFactor + options.timeoutMs + overheadTimeMS }; expect(testRunner.run).calledWith(expectedRunOptions); }); it('should have reset the source file', async () => { - const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS); + const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS, LOGGING_CONTEXT); await sut.runMutant(transpiledMutant); let timesCalled = writeFileStub.getCalls().length - 1; let lastCall = writeFileStub.getCall(timesCalled); @@ -212,11 +218,10 @@ describe('Sandbox', () => { }); it('should not filter any tests when testFramework = null', async () => { - const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS); + const sut = await Sandbox.create(options, SANDBOX_INDEX, files, null, OVERHEAD_TIME_MS, LOGGING_CONTEXT); const mutant = new TestableMutant('2', createMutant(), new SourceFile(new File('', ''))); sut.runMutant(new TranspiledMutant(mutant, { outputFiles: [new File(expectedTargetFileToMutate, '')], error: null }, true)); expect(fileUtils.writeFile).not.calledWith(expectedTestFrameworkHooksFile); }); - }); }); diff --git a/packages/stryker/test/unit/StrykerSpec.ts b/packages/stryker/test/unit/StrykerSpec.ts index 277021a892..6f75398358 100644 --- a/packages/stryker/test/unit/StrykerSpec.ts +++ b/packages/stryker/test/unit/StrykerSpec.ts @@ -1,19 +1,20 @@ -import Stryker from '../../src/Stryker'; -import { File } from 'stryker-api/core'; +import * as sinon from 'sinon'; import { MutantResult } from 'stryker-api/report'; -import { Config, ConfigEditorFactory, ConfigEditor } from 'stryker-api/config'; +import { File, LogLevel } from 'stryker-api/core'; import { RunResult } from 'stryker-api/test_runner'; import { TestFramework } from 'stryker-api/test_framework'; +import Stryker from '../../src/Stryker'; +import { Config, ConfigEditorFactory, ConfigEditor } from 'stryker-api/config'; import { expect } from 'chai'; import InputFileResolver, * as inputFileResolver from '../../src/input/InputFileResolver'; -import ConfigReader, * as configReader from '../../src/ConfigReader'; +import ConfigReader, * as configReader from '../../src/config/ConfigReader'; import TestFrameworkOrchestrator, * as testFrameworkOrchestrator from '../../src/TestFrameworkOrchestrator'; import ReporterOrchestrator, * as reporterOrchestrator from '../../src/ReporterOrchestrator'; import MutatorFacade, * as mutatorFacade from '../../src/MutatorFacade'; import MutantRunResultMatcher, * as mutantRunResultMatcher from '../../src/MutantTestMatcher'; import InitialTestExecutor, * as initialTestExecutor from '../../src/process/InitialTestExecutor'; import MutationTestExecutor, * as mutationTestExecutor from '../../src/process/MutationTestExecutor'; -import ConfigValidator, * as configValidator from '../../src/ConfigValidator'; +import ConfigValidator, * as configValidator from '../../src/config/ConfigValidator'; import ScoreResultCalculator, * as scoreResultCalculatorModule from '../../src/ScoreResultCalculator'; import PluginLoader, * as pluginLoader from '../../src/PluginLoader'; import { TempFolder } from '../../src/utils/TempFolder'; @@ -23,7 +24,8 @@ import BroadcastReporter from '../../src/reporters/BroadcastReporter'; import TestableMutant from '../../src/TestableMutant'; import '../helpers/globals'; import InputFileCollection from '../../src/input/InputFileCollection'; -import LogConfigurator from '../../src/utils/LogConfigurator'; +import LogConfigurator from '../../src/logging/LogConfigurator'; +import LoggingClientContext from '../../src/logging/LoggingClientContext'; class FakeConfigEditor implements ConfigEditor { constructor() { } @@ -32,6 +34,11 @@ class FakeConfigEditor implements ConfigEditor { } } +const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ + port: 4200, + level: LogLevel.Debug +}); + describe('Stryker', function () { let sut: Stryker; let testFramework: TestFramework; @@ -49,6 +56,7 @@ describe('Stryker', function () { let tempFolderMock: Mock; let scoreResultCalculator: ScoreResultCalculator; let logConfiguratorForMasterStub: sinon.SinonStub; + let logConfiguratorForServerStub: sinon.SinonStub; beforeEach(() => { strykerConfig = config(); @@ -61,6 +69,8 @@ describe('Stryker', function () { mutantRunResultMatcherMock = mock(MutantRunResultMatcher); mutatorMock = mock(MutatorFacade); logConfiguratorForMasterStub = sandbox.stub(LogConfigurator, 'forMaster'); + logConfiguratorForServerStub = sandbox.stub(LogConfigurator, 'forServer'); + logConfiguratorForServerStub.resolves(LOGGING_CONTEXT); inputFileResolverMock = mock(InputFileResolver); reporterOrchestratorMock.createBroadcastReporter.returns(reporter); testFramework = testFrameworkMock(); @@ -154,6 +164,12 @@ describe('Stryker', function () { sut = new Stryker({}); }); + it('should reject when logging server rejects', async () => { + const expectedError = Error('expected error'); + logConfiguratorForServerStub.rejects(expectedError); + await expect(sut.runMutationTest()).rejectedWith(expectedError); + }); + it('should reject when input file globbing results in a rejection', async () => { const expectedError = Error('expected error'); inputFileResolverMock.resolve.rejects(expectedError); @@ -199,6 +215,10 @@ describe('Stryker', function () { return sut.runMutationTest(); }); + it('should configure the logging server', () => { + expect(logConfiguratorForServerStub).calledWith(strykerConfig.logLevel, strykerConfig.fileLogLevel); + }); + it('should report mutant score', () => { expect(reporter.onScoreCalculated).to.have.been.called; }); @@ -219,9 +239,9 @@ describe('Stryker', function () { expect(inputFileResolverMock.resolve).called; }); - it('should create the InitialTestRunner', () => { + it('should create the InitialTestExecutor', () => { expect(initialTestExecutor.default).calledWithNew; - expect(initialTestExecutor.default).calledWith(strykerConfig, inputFiles); + expect(initialTestExecutor.default).calledWith(strykerConfig, inputFiles, testFramework, sinon.match.any, LOGGING_CONTEXT); expect(initialTestExecutorMock.run).called; }); @@ -233,7 +253,7 @@ describe('Stryker', function () { it('should create the mutation test executor', () => { expect(mutationTestExecutor.default).calledWithNew; - expect(mutationTestExecutor.default).calledWith(strykerConfig, inputFiles.files, testFramework, reporter); + expect(mutationTestExecutor.default).calledWith(strykerConfig, inputFiles.files, testFramework, reporter, undefined, LOGGING_CONTEXT); expect(mutationTestExecutorMock.run).calledWith(mutants); }); diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 9a604a6bee..7d02507055 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -4,7 +4,13 @@ import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; import { autoStart, InitMessage, WorkerMessageKind, ParentMessage, WorkerMessage, ParentMessageKind } from '../../../src/child-proxy/messageProtocol'; import { serialize } from '../../../src/utils/objectUtils'; import HelloClass from './HelloClass'; +import LoggingClientContext from '../../../src/logging/LoggingClientContext'; +import { LogLevel } from 'stryker-api/core'; +const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ + port: 4200, + level: LogLevel.Fatal +}); describe('ChildProcessProxy', () => { @@ -27,28 +33,28 @@ describe('ChildProcessProxy', () => { describe('create', () => { it('should create child process', () => { - ChildProcessProxy.create('foobar', 'FATAL', ['examplePlugin', 'secondExamplePlugin'], HelloClass, 'something'); + ChildProcessProxy.create('foobar', LOGGING_CONTEXT, ['examplePlugin', 'secondExamplePlugin'], HelloClass, 'something'); expect(forkStub).calledWith(require.resolve('../../../src/child-proxy/ChildProcessProxyWorker'), [autoStart], { silent: false, execArgv: [] }); }); it('should send init message to child process', () => { const expectedMessage: InitMessage = { kind: WorkerMessageKind.Init, - logLevel: 'FATAL ;)', + loggingContext: LOGGING_CONTEXT, plugins: ['examplePlugin', 'secondExamplePlugin'], requirePath: 'foobar', constructorArgs: ['something'] }; // Act - ChildProcessProxy.create('foobar', 'FATAL ;)', ['examplePlugin', 'secondExamplePlugin'], HelloClass, 'something'); + ChildProcessProxy.create('foobar', LOGGING_CONTEXT, ['examplePlugin', 'secondExamplePlugin'], HelloClass, 'something'); // Assert expect(childProcessMock.send).calledWith(serialize(expectedMessage)); }); it('should listen to worker process', () => { - ChildProcessProxy.create('foobar', '', [], HelloClass, ''); + ChildProcessProxy.create('foobar', LOGGING_CONTEXT, [], HelloClass, ''); expect(childProcessMock.on).calledWith('message'); }); }); @@ -56,7 +62,7 @@ describe('ChildProcessProxy', () => { describe('when calling methods', () => { beforeEach(() => { - sut = ChildProcessProxy.create('', '', [], HelloClass, ''); + sut = ChildProcessProxy.create('', LOGGING_CONTEXT, [], HelloClass, ''); const initDoneResult: ParentMessage = { kind: ParentMessageKind.Initialized }; const msg = serialize(initDoneResult); childProcessMock.on.callArgWith(1, [msg]); diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts index a43c6aaeb4..49719ac7a2 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts @@ -5,7 +5,11 @@ import { WorkerMessage, WorkerMessageKind, ParentMessage, WorkResult, WorkMessag import PluginLoader, * as pluginLoader from '../../../src/PluginLoader'; import { Mock, mock } from '../../helpers/producers'; import HelloClass from './HelloClass'; -import LogConfigurator from '../../../src/utils/LogConfigurator'; +import LogConfigurator from '../../../src/logging/LogConfigurator'; +import { LogLevel } from 'stryker-api/core'; +import LoggingClientContext from '../../../src/logging/LoggingClientContext'; + +const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ port: 4200, level: LogLevel.Fatal }); describe('ChildProcessProxyWorker', () => { @@ -51,7 +55,7 @@ describe('ChildProcessProxyWorker', () => { sut = new ChildProcessProxyWorker(); initMessage = { kind: WorkerMessageKind.Init, - logLevel: 'FooLevel', + loggingContext: LOGGING_CONTEXT, constructorArgs: ['FooBarName'], plugins: ['fooPlugin', 'barPlugin'], requirePath: require.resolve('./HelloClass') @@ -87,7 +91,7 @@ describe('ChildProcessProxyWorker', () => { it('should set global log level', () => { processOnStub.callArgWith(1, serialize(initMessage)); - expect(logConfiguratorForWorkerStub).called; + expect(logConfiguratorForWorkerStub).calledWith(LOGGING_CONTEXT); }); it('should load plugins', () => { diff --git a/packages/stryker/test/unit/ConfigValidatorSpec.ts b/packages/stryker/test/unit/config/ConfigValidatorSpec.ts similarity index 96% rename from packages/stryker/test/unit/ConfigValidatorSpec.ts rename to packages/stryker/test/unit/config/ConfigValidatorSpec.ts index 02670ce36d..a24d9bf471 100644 --- a/packages/stryker/test/unit/ConfigValidatorSpec.ts +++ b/packages/stryker/test/unit/config/ConfigValidatorSpec.ts @@ -2,9 +2,9 @@ import { expect } from 'chai'; import * as sinon from 'sinon'; import { Logger } from 'stryker-api/logging'; import { Config } from 'stryker-api/config'; -import ConfigValidator from './../../src/ConfigValidator'; -import currentLogMock from '../helpers/logMock'; -import { testFramework, Mock } from '../helpers/producers'; +import ConfigValidator from '../../../src/config/ConfigValidator'; +import currentLogMock from '../../helpers/logMock'; +import { testFramework, Mock } from '../../helpers/producers'; describe('ConfigValidator', () => { @@ -73,10 +73,10 @@ describe('ConfigValidator', () => { }); it('should be invalid with invalid logLevel', () => { - config.logLevel = 'thisTestPasses'; + config.logLevel = 'thisTestPasses' as any; sut = new ConfigValidator(config, testFramework()); actValidationError(); - expect(log.fatal).calledWith('Value "thisTestPasses" is invalid for `logLevel`. Expected one of the following: "fatal", "error", "warn", "info", "debug", "trace", "all", "off"'); + expect(log.fatal).calledWith('Value "thisTestPasses" is invalid for `logLevel`. Expected one of the following: "fatal", "error", "warn", "info", "debug", "trace", "off"'); }); it('should be invalid with nonnumeric timeoutMs', () => { diff --git a/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts b/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts index 03837a2154..4d2fa16a94 100644 --- a/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts +++ b/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts @@ -9,6 +9,8 @@ import IsolatedTestRunnerAdapter from '../../../src/isolated-runner/IsolatedTest import IsolatedRunnerOptions from '../../../src/isolated-runner/IsolatedRunnerOptions'; import { WorkerMessage, RunMessage, ResultMessage } from '../../../src/isolated-runner/MessageProtocol'; import { serialize } from '../../../src/utils/objectUtils'; +import { LogLevel } from 'stryker-api/core'; +import LogConfigurator from '../../../src/logging/LogConfigurator'; describe('IsolatedTestRunnerAdapter', () => { let sut: IsolatedTestRunnerAdapter; @@ -26,7 +28,8 @@ describe('IsolatedTestRunnerAdapter', () => { fileNames: [], port: 42, sandboxWorkingFolder: 'a working directory', - strykerOptions: {} + strykerOptions: {}, + loggingContext: { port: 4200, level: LogLevel.Fatal } }; sinonSandbox = sinon.createSandbox(); fakeChildProcess = { diff --git a/packages/stryker/test/unit/process/InitialTestExecutorSpec.ts b/packages/stryker/test/unit/process/InitialTestExecutorSpec.ts index f995a4d383..323e1d5313 100644 --- a/packages/stryker/test/unit/process/InitialTestExecutorSpec.ts +++ b/packages/stryker/test/unit/process/InitialTestExecutorSpec.ts @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { Logger } from 'stryker-api/logging'; import { default as StrykerSandbox } from '../../../src/Sandbox'; import InitialTestExecutor, { InitialTestRunResult } from '../../../src/process/InitialTestExecutor'; -import { File } from 'stryker-api/core'; +import { File, LogLevel } from 'stryker-api/core'; import { Config } from 'stryker-api/config'; import * as producers from '../../helpers/producers'; import { TestFramework } from 'stryker-api/test_framework'; @@ -17,8 +17,14 @@ import { Mock, coverageMaps } from '../../helpers/producers'; import InputFileCollection from '../../../src/input/InputFileCollection'; import * as coverageHooks from '../../../src/transpiler/coverageHooks'; import SourceMapper, { PassThroughSourceMapper } from '../../../src/transpiler/SourceMapper'; +import LoggingClientContext from '../../../src/logging/LoggingClientContext'; const EXPECTED_INITIAL_TIMEOUT = 60 * 1000 * 5; +const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ + port: 4200, + level: LogLevel.Fatal +}); + describe('InitialTestExecutor run', () => { let log: Mock; @@ -67,7 +73,7 @@ describe('InitialTestExecutor run', () => { beforeEach(() => { inputFiles = new InputFileCollection([new File('mutate.js', ''), new File('mutate.spec.js', '')], ['mutate.js']); - sut = new InitialTestExecutor(options, inputFiles, testFrameworkMock, timer as any); + sut = new InitialTestExecutor(options, inputFiles, testFrameworkMock, timer as any, LOGGING_CONTEXT); }); it('should create a sandbox with correct arguments', async () => { @@ -194,7 +200,7 @@ describe('InitialTestExecutor run', () => { }); it('should result log a warning if coverage analysis is "perTest" and there is no testFramework', async () => { - sut = new InitialTestExecutor(options, inputFiles, /* test framework */ null, timer as any); + sut = new InitialTestExecutor(options, inputFiles, /* test framework */ null, timer as any, LOGGING_CONTEXT); sandbox.stub(coverageHooks, 'coveragePerTestHooks').returns('test hook foobar'); await sut.run(); expect(log.warn).calledWith('Cannot measure coverage results per test, there is no testFramework and thus no way of executing code right before and after each test.'); diff --git a/packages/stryker/test/unit/process/MutationTestExecutorSpec.ts b/packages/stryker/test/unit/process/MutationTestExecutorSpec.ts index e8bce94529..a61d78fcea 100644 --- a/packages/stryker/test/unit/process/MutationTestExecutorSpec.ts +++ b/packages/stryker/test/unit/process/MutationTestExecutorSpec.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import * as _ from 'lodash'; import { empty, of } from 'rxjs'; import { Config } from 'stryker-api/config'; -import { File } from 'stryker-api/core'; +import { File, LogLevel } from 'stryker-api/core'; import { MutantStatus } from 'stryker-api/report'; import { TestFramework } from 'stryker-api/test_framework'; import { RunStatus, TestStatus } from 'stryker-api/test_runner'; @@ -15,6 +15,7 @@ import BroadcastReporter from '../../../src/reporters/BroadcastReporter'; import MutantTranspiler, * as mutantTranspiler from '../../../src/transpiler/MutantTranspiler'; import '../../helpers/globals'; import { Mock, config, file, mock, mutantResult, testFramework, testResult, testableMutant, transpiledMutant } from '../../helpers/producers'; +import LoggingClientContext from '../../../src/logging/LoggingClientContext'; const createTranspiledMutants = (...n: number[]) => { return n.map(n => { @@ -26,6 +27,12 @@ const createTranspiledMutants = (...n: number[]) => { }); }; +const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ + port: 4200, + level: LogLevel.Fatal +}); + + describe('MutationTestExecutor', () => { let sandboxPoolMock: Mock; @@ -57,7 +64,7 @@ describe('MutationTestExecutor', () => { describe('run', () => { beforeEach(async () => { - sut = new MutantTestExecutor(expectedConfig, inputFiles, testFrameworkMock, reporter, 42); + sut = new MutantTestExecutor(expectedConfig, inputFiles, testFrameworkMock, reporter, 42, LOGGING_CONTEXT); const sandbox = mock(Sandbox); sandbox.runMutant.resolves(mutantResult()); sandboxPoolMock.streamSandboxes.returns(of(sandbox)); @@ -97,7 +104,7 @@ describe('MutationTestExecutor', () => { mutantTranspilerMock.transpileMutants.returns(of(...transpiledMutants)); sandboxPoolMock.streamSandboxes.returns(of(firstSandbox, secondSandbox)); - sut = new MutantTestExecutor(config(), inputFiles, testFrameworkMock, reporter, 42); + sut = new MutantTestExecutor(config(), inputFiles, testFrameworkMock, reporter, 42, LOGGING_CONTEXT); // The uncovered, transpile error and changedAnyTranspiledFiles = false should not be ran in a sandbox // Mock first sandbox to return first success, then failed diff --git a/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts b/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts index fd764b592a..c0fd4186ad 100644 --- a/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts +++ b/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts @@ -1,6 +1,6 @@ import { expect } from 'chai'; import { toArray } from 'rxjs/operators'; -import { File } from 'stryker-api/core'; +import { File, LogLevel } from 'stryker-api/core'; import TranspiledMutant from '../../../src/TranspiledMutant'; import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; import MutantTranspiler from '../../../src/transpiler/MutantTranspiler'; @@ -9,6 +9,12 @@ import TranspilerFacade, * as transpilerFacade from '../../../src/transpiler/Tra import { errorToString } from '../../../src/utils/objectUtils'; import '../../helpers/globals'; import { Mock, config, file, mock, testableMutant } from '../../helpers/producers'; +import LoggingClientContext from '../../../src/logging/LoggingClientContext'; + +const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ + port: 4200, + level: LogLevel.Fatal +}); describe('MutantTranspiler', () => { let sut: MutantTranspiler; @@ -32,21 +38,22 @@ describe('MutantTranspiler', () => { describe('with a transpiler', () => { it('should construct use the ChildProcessProxy to spawn a new MutantTranspiler in a separated process', () => { - const expectedConfig = config({ transpilers: ['transpiler'], plugins: ['plugin1'], logLevel: 'someLogLevel' }); - sut = new MutantTranspiler(expectedConfig); + const expectedConfig = config({ transpilers: ['transpiler'], plugins: ['plugin1'] }); + sut = new MutantTranspiler(expectedConfig, LOGGING_CONTEXT); expect(ChildProcessProxy.create).calledWith( require.resolve('../../../src/transpiler/TranspilerFacade'), - 'someLogLevel', + LOGGING_CONTEXT, ['plugin1'], TranspilerFacade, - { config: expectedConfig, produceSourceMaps: false }); + { config: expectedConfig, produceSourceMaps: false } + ); }); describe('initialize', () => { it('should transpile all files', () => { const expectedFiles = [file()]; - sut = new MutantTranspiler(config({ transpilers: ['transpiler'] })); + sut = new MutantTranspiler(config({ transpilers: ['transpiler'] }), LOGGING_CONTEXT); const actualResult = sut.initialize(expectedFiles); expect(transpilerFacadeMock.transpile).calledWith(expectedFiles); return expect(actualResult).eventually.eq(transpiledFilesOne); @@ -55,7 +62,7 @@ describe('MutantTranspiler', () => { describe('dispose', () => { it('should dispose the child process', () => { - sut = new MutantTranspiler(config({ transpilers: ['transpiler'] })); + sut = new MutantTranspiler(config({ transpilers: ['transpiler'] }), LOGGING_CONTEXT); sut.dispose(); expect(childProcessProxyMock.dispose).called; }); @@ -64,7 +71,7 @@ describe('MutantTranspiler', () => { describe('transpileMutants', () => { beforeEach(() => { - sut = new MutantTranspiler(config({ transpilers: ['transpiler'] })); + sut = new MutantTranspiler(config({ transpilers: ['transpiler'] }), LOGGING_CONTEXT); }); it('should transpile mutants', async () => { @@ -158,7 +165,7 @@ describe('MutantTranspiler', () => { describe('without a transpiler', () => { beforeEach(() => { - sut = new MutantTranspiler(config()); + sut = new MutantTranspiler(config(), LOGGING_CONTEXT); }); From 6590624e55277bdbe01a3bfca83bcfa291e368b2 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 12:02:00 +0200 Subject: [PATCH 08/54] refactor: remove unused import --- .../test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts b/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts index 4d2fa16a94..72f69247e1 100644 --- a/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts +++ b/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts @@ -10,7 +10,6 @@ import IsolatedRunnerOptions from '../../../src/isolated-runner/IsolatedRunnerOp import { WorkerMessage, RunMessage, ResultMessage } from '../../../src/isolated-runner/MessageProtocol'; import { serialize } from '../../../src/utils/objectUtils'; import { LogLevel } from 'stryker-api/core'; -import LogConfigurator from '../../../src/logging/LogConfigurator'; describe('IsolatedTestRunnerAdapter', () => { let sut: IsolatedTestRunnerAdapter; From 691e3a7c1c3857eadda6ac04833edf9dd90bf5de Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 12:22:25 +0200 Subject: [PATCH 09/54] test(logging): Add unit test for multi appender --- .../stryker/src/logging/LogConfigurator.ts | 2 +- packages/stryker/src/logging/MultiAppender.ts | 4 +- .../test/unit/logging/LogConfiguratorSpec.ts | 0 .../test/unit/logging/MultiAppenderSpec.ts | 40 +++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 packages/stryker/test/unit/logging/LogConfiguratorSpec.ts create mode 100644 packages/stryker/test/unit/logging/MultiAppenderSpec.ts diff --git a/packages/stryker/src/logging/LogConfigurator.ts b/packages/stryker/src/logging/LogConfigurator.ts index d0f385ea54..35f614fbff 100644 --- a/packages/stryker/src/logging/LogConfigurator.ts +++ b/packages/stryker/src/logging/LogConfigurator.ts @@ -101,7 +101,7 @@ export default class LogConfigurator { const context: LoggingClientContext = { port: loggerPort, level: defaultLogLevel - } + }; return context; }); } diff --git a/packages/stryker/src/logging/MultiAppender.ts b/packages/stryker/src/logging/MultiAppender.ts index 2aa80ba38d..175eb79fa7 100644 --- a/packages/stryker/src/logging/MultiAppender.ts +++ b/packages/stryker/src/logging/MultiAppender.ts @@ -1,6 +1,6 @@ import { LoggingEvent } from 'log4js'; -interface RuntimeAppender { +export interface RuntimeAppender { (loggingEvent: LoggingEvent): void; } @@ -13,7 +13,7 @@ export class MultiAppender { } } -export function configure(config: { appenders: string[] }, layouts: any, findAppender: (name: string) => RuntimeAppender ) { +export function configure(config: { appenders: string[] }, _: any, findAppender: (name: string) => RuntimeAppender ): RuntimeAppender { const multiAppender = new MultiAppender(config.appenders.map(name => findAppender(name))); return multiAppender.append.bind(multiAppender); } diff --git a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/stryker/test/unit/logging/MultiAppenderSpec.ts b/packages/stryker/test/unit/logging/MultiAppenderSpec.ts new file mode 100644 index 0000000000..95d04547c4 --- /dev/null +++ b/packages/stryker/test/unit/logging/MultiAppenderSpec.ts @@ -0,0 +1,40 @@ +import { expect } from 'chai'; +import * as log4js from 'log4js'; +import { configure, RuntimeAppender } from '../../../src/logging/MultiAppender'; + +describe('MultiAppender', () => { + let sut: RuntimeAppender; + let fooLogEvents: log4js.LoggingEvent[]; + let barLogEvents: log4js.LoggingEvent[]; + + beforeEach(() => { + fooLogEvents = []; + barLogEvents = []; + sut = configure({ appenders: ['foo', 'bar'] }, null, name => { + switch (name) { + case 'foo': + return event => fooLogEvents.push(event); + case 'bar': + return event => barLogEvents.push(event); + default: + throw new Error(`${name} is not supported`); + } + }); + }); + + it('should fan out events to all appenders', () => { + const loggingEvent: log4js.LoggingEvent = { + categoryName: 'category', + context: null, + data: ['foo data'], + level: (log4js.levels as any).DEBUG, + pid: 42, + startTime: new Date(42) + }; + sut(loggingEvent); + expect(fooLogEvents).lengthOf(1); + expect(barLogEvents).lengthOf(1); + expect(fooLogEvents).contains(loggingEvent); + expect(barLogEvents).contains(loggingEvent); + }); +}); \ No newline at end of file From 042117e01abaa397445d8b3ac3054dd32f0b79ba Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 12:23:21 +0200 Subject: [PATCH 10/54] refactor(stryker): Add semicolons --- packages/stryker/src/logging/logUtils.ts | 4 ++-- .../test/integration/child-proxy/ChildProcessProxy.it.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stryker/src/logging/logUtils.ts b/packages/stryker/src/logging/logUtils.ts index a84cdd953a..54e51413d3 100644 --- a/packages/stryker/src/logging/logUtils.ts +++ b/packages/stryker/src/logging/logUtils.ts @@ -6,7 +6,7 @@ import * as log4js from 'log4js'; * @param a one log level * @param b other log level */ -export function minLevel(a: LogLevel, b: LogLevel){ +export function minLevel(a: LogLevel, b: LogLevel) { if (getLevel(b).isGreaterThanOrEqualTo(getLevel(a))) { return a; } else { @@ -16,5 +16,5 @@ export function minLevel(a: LogLevel, b: LogLevel){ function getLevel(level: LogLevel): log4js.Level { // Needs an any cast here, wrongly typed, see https://github.com/log4js-node/log4js-node/pull/745 - return (log4js.levels as any).getLevel(level); + return (log4js.levels as any).getLevel(level); } diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index 1e237daf95..160be566b0 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -61,7 +61,7 @@ describe('ChildProcessProxy', () => { it('should not log on trace if LogLevel.Debug is allowed as min log level', async () => { const firstLogEventTask = new Task(); loggingServer.event$.subscribe(firstLogEventTask.resolve.bind(firstLogEventTask)); - sut.proxy.trace('foo') + sut.proxy.trace('foo'); sut.proxy.debug('bar'); const log = await firstLogEventTask.promise; expect(log.categoryName).eq(Echo.name); From 188bada2b9e25fd7c3c7f19d12d084d42accde3b Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 14:02:15 +0200 Subject: [PATCH 11/54] test(logging): Add unit tests for the log configurator --- .../stryker/src/logging/LogConfigurator.ts | 2 +- packages/stryker/src/utils/netUtils.ts | 3 + .../test/unit/logging/LogConfiguratorSpec.ts | 98 +++++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 packages/stryker/src/utils/netUtils.ts diff --git a/packages/stryker/src/logging/LogConfigurator.ts b/packages/stryker/src/logging/LogConfigurator.ts index 35f614fbff..3bf3dd6590 100644 --- a/packages/stryker/src/logging/LogConfigurator.ts +++ b/packages/stryker/src/logging/LogConfigurator.ts @@ -3,7 +3,7 @@ import { LoggerFactory } from 'stryker-api/logging'; import { LogLevel } from 'stryker-api/core'; import { minLevel } from './logUtils'; import LoggingClientContext from './LoggingClientContext'; -import * as getPort from 'get-port'; +import { getPort } from '../utils/netUtils'; const PREFERRED_LOG_SERVER_PORT = 5000; diff --git a/packages/stryker/src/utils/netUtils.ts b/packages/stryker/src/utils/netUtils.ts new file mode 100644 index 0000000000..e7c9c15780 --- /dev/null +++ b/packages/stryker/src/utils/netUtils.ts @@ -0,0 +1,3 @@ +import * as getPortModule from 'get-port'; + +export const getPort = getPortModule; \ No newline at end of file diff --git a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts index e69de29bb2..9b7e552ff2 100644 --- a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts +++ b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts @@ -0,0 +1,98 @@ +import * as log4js from 'log4js'; +import { expect } from 'chai'; +import { LogLevel } from 'stryker-api/core'; +import LogConfigurator from '../../../src/logging/LogConfigurator'; +import * as netUtils from '../../../src/utils/netUtils'; +import LoggingClientContext from '../../../src/logging/LoggingClientContext'; + +describe.only('LogConfigurator', () => { + + const sut = LogConfigurator; + let getPortStub: sinon.SinonStub; + let log4jsConfigure: sinon.SinonStub; + let log4jsShutdown: sinon.SinonStub; + + beforeEach(() => { + getPortStub = sandbox.stub(netUtils, 'getPort'); + log4jsConfigure = sandbox.stub(log4js, 'configure'); + log4jsShutdown = sandbox.stub(log4js, 'shutdown'); + }); + + describe('forMaster', () => { + it('should configure console and file', () => { + sut.forMaster(LogLevel.Information, LogLevel.Trace); + expect(log4jsConfigure).calledWith(createMasterConfig(LogLevel.Information, LogLevel.Trace, LogLevel.Trace)); + }); + + it('should not configure file if it is "off"', () => { + sut.forMaster(LogLevel.Information, LogLevel.Off); + const masterConfig = createMasterConfig(LogLevel.Information, LogLevel.Off, LogLevel.Information); + delete masterConfig.appenders.file; + delete masterConfig.appenders.filteredFile; + (masterConfig.appenders.all as any).appenders = ['filteredConsole']; + expect(log4jsConfigure).calledWith(masterConfig); + }); + }); + + describe('forServer', () => { + it('should configure console, file and server', async () => { + // Arrange + const expectedLoggingContext: LoggingClientContext = { port: 42, level: LogLevel.Error }; + getPortStub.resolves(expectedLoggingContext.port); + const expectedConfig = createMasterConfig(LogLevel.Error, LogLevel.Fatal, LogLevel.Error); + const serverAppender: log4js.MultiprocessAppender = { type: 'multiprocess', mode: 'master', loggerPort: 42, appender: 'all' }; + expectedConfig.appenders.server = serverAppender; + + // Act + const actualLoggingContext = await sut.forServer(LogLevel.Error, LogLevel.Fatal); + + // Assert + expect(log4jsConfigure).calledWith(expectedConfig); + expect(getPortStub).calledWith({ port: 5000 }); + expect(actualLoggingContext).deep.eq(expectedLoggingContext); + }); + }); + + describe('forWorker', () => { + it('should configure the logging client', () => { + sut.forWorker({ port: 42, level: LogLevel.Information }); + const multiProcessAppender: log4js.MultiprocessAppender = { type: 'multiprocess', mode: 'worker', loggerPort: 42 }; + const expectedConfig: log4js.Configuration = { + appenders: { + all: multiProcessAppender + }, + categories: { + default: { level: LogLevel.Information, appenders: ['all'] } + } + }; + expect(log4jsConfigure).calledWith(expectedConfig); + }); + }); + + describe('shutdown', () => { + it('should shutdown log4js', async () => { + log4jsShutdown.callsArg(0); + await sut.shutdown(); + expect(log4jsShutdown).called; + }); + }); + + function createMasterConfig(consoleLevel: LogLevel, fileLevel: LogLevel, defaultLevel: LogLevel): log4js.Configuration { + const layout: log4js.PatternLayout = { + type: 'pattern', + pattern: '%[%r (%z) %p %c%] %m' + }; + return { + appenders: { + console: { type: 'stdout', layout }, + file: { type: 'file', layout, filename: 'stryker.log' }, + filteredConsole: { type: 'logLevelFilter', appender: 'console', level: consoleLevel }, + filteredFile: { type: 'logLevelFilter', appender: 'file', level: fileLevel }, + all: { type: require.resolve('../../../src/logging/MultiAppender'), appenders: ['filteredConsole', 'filteredFile'] } + }, + categories: { + default: { level: defaultLevel, appenders: ['all'] } + } + }; + } +}); \ No newline at end of file From 4fdc25017c0b323738cb1e7a71db72b0479d8a28 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 14:32:50 +0200 Subject: [PATCH 12/54] fix(karma-runner): remove logging logic from karma --- packages/stryker-karma-runner/src/KarmaTestRunner.ts | 6 ++---- .../test/integration/KarmaTestRunner.it.ts | 7 ++----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/stryker-karma-runner/src/KarmaTestRunner.ts b/packages/stryker-karma-runner/src/KarmaTestRunner.ts index aee188f618..40cbc5e452 100644 --- a/packages/stryker-karma-runner/src/KarmaTestRunner.ts +++ b/packages/stryker-karma-runner/src/KarmaTestRunner.ts @@ -1,9 +1,8 @@ -import * as log4js from 'log4js'; import { TestRunner, TestResult, RunStatus, RunResult, RunnerOptions, CoverageCollection, CoveragePerTestResult } from 'stryker-api/test_runner'; +import { getLogger } from 'stryker-api/logging'; import * as karma from 'karma'; import StrykerKarmaSetup, { DEPRECATED_KARMA_CONFIG, DEPRECATED_KARMA_CONFIG_FILE, KARMA_CONFIG_KEY } from './StrykerKarmaSetup'; import TestHooksMiddleware from './TestHooksMiddleware'; -import { setGlobalLogLevel } from 'log4js'; import StrykerReporter from './StrykerReporter'; import strykerKarmaConf = require('./starters/stryker-karma.conf'); import ProjectStarter from './starters/ProjectStarter'; @@ -13,7 +12,7 @@ export interface ConfigOptions extends karma.ConfigOptions { } export default class KarmaTestRunner implements TestRunner { - private log = log4js.getLogger(KarmaTestRunner.name); + private log = getLogger(KarmaTestRunner.name); private currentTestResults: TestResult[]; private currentErrorMessages: string[]; private currentCoverageReport?: CoverageCollection | CoveragePerTestResult; @@ -24,7 +23,6 @@ export default class KarmaTestRunner implements TestRunner { constructor(private options: RunnerOptions) { const setup = this.loadSetup(options); this.starter = new ProjectStarter(setup.project); - setGlobalLogLevel(options.strykerOptions.logLevel || 'info'); this.setGlobals(setup, options.port); this.cleanRun(); this.listenToRunComplete(); diff --git a/packages/stryker-karma-runner/test/integration/KarmaTestRunner.it.ts b/packages/stryker-karma-runner/test/integration/KarmaTestRunner.it.ts index 10b6f45e62..6d2087487e 100644 --- a/packages/stryker-karma-runner/test/integration/KarmaTestRunner.it.ts +++ b/packages/stryker-karma-runner/test/integration/KarmaTestRunner.it.ts @@ -1,6 +1,5 @@ import { expect } from 'chai'; import { CoverageCollection, RunnerOptions, RunResult, RunStatus, TestStatus } from 'stryker-api/test_runner'; -import { LogLevel } from 'stryker-api/core'; import KarmaTestRunner from '../../src/KarmaTestRunner'; import JasmineTestFramework from 'stryker-jasmine/src/JasmineTestFramework'; import { expectTestResults } from '../helpers/assertions'; @@ -37,7 +36,6 @@ describe('KarmaTestRunner', function () { testRunnerOptions = { port: 9877, strykerOptions: { - logLevel: 'trace', karma: { config: { files: [ @@ -89,10 +87,9 @@ describe('KarmaTestRunner', function () { describe('when some tests fail', () => { before(() => { - const testRunnerOptions = { + const testRunnerOptions: RunnerOptions = { port: 9878, strykerOptions: { - logLevel: 'trace', karma: { config: { files: [ @@ -102,7 +99,7 @@ describe('KarmaTestRunner', function () { ] } } - }, + }, fileNames: [] }; sut = new KarmaTestRunner(testRunnerOptions); From 172979456adb5ddfbe6163d0e4161689f9177316 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 14:33:24 +0200 Subject: [PATCH 13/54] build(dev depedencies): remove unused types for old log4js --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index bd17307cd3..9f9c6c3165 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,6 @@ "@types/istanbul": "^0.4.29", "@types/karma": "^1.7.4", "@types/lodash": "^4.14.110", - "@types/log4js": "0.0.32", "@types/mkdirp": "^0.5.2", "@types/mocha": "^2.2.44", "@types/mz": "0.0.32", From c14a520c0e3427fd2783afcf671b0bcac6eda624 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 14:56:16 +0200 Subject: [PATCH 14/54] chore(karma-runner): Add express.js types back --- packages/stryker-karma-runner/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stryker-karma-runner/package.json b/packages/stryker-karma-runner/package.json index 08bf799819..f57a0a57f0 100644 --- a/packages/stryker-karma-runner/package.json +++ b/packages/stryker-karma-runner/package.json @@ -34,6 +34,7 @@ "stryker-api": ">=0.15.0 <0.18.0" }, "devDependencies": { + "@types/express": "^4.11.1", "@types/semver": "^5.5.0", "jasmine-core": "^2.4.1", "karma": "^2.0.4", From 0a30c08af9d99eb379769c39299da0d31d38f312 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 15:06:23 +0200 Subject: [PATCH 15/54] test(stryker-api): fix failing test --- packages/stryker-api/testResources/module/useCore.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stryker-api/testResources/module/useCore.ts b/packages/stryker-api/testResources/module/useCore.ts index 816f14eea1..af6c3ea136 100644 --- a/packages/stryker-api/testResources/module/useCore.ts +++ b/packages/stryker-api/testResources/module/useCore.ts @@ -1,4 +1,4 @@ -import { StrykerOptions, Factory, File, Position, Location, Range } from 'stryker-api/core'; +import { StrykerOptions, Factory, File, Position, Location, Range, LogLevel } from 'stryker-api/core'; const options: StrykerOptions = {}; const optionsAllArgs: StrykerOptions = { @@ -8,7 +8,7 @@ const optionsAllArgs: StrykerOptions = { testFramework: 'string', testRunner: 'string', reporter: 'string', - logLevel: 'string', + logLevel: LogLevel.Fatal, timeoutMs: 1, timeoutFactor: 2, plugins: ['string'], From 5a92cc3efc6c09445402243786286ade9805e34c Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 6 Jul 2018 17:34:37 +0200 Subject: [PATCH 16/54] test(logging): Remove accidental `.only` --- packages/stryker/test/unit/logging/LogConfiguratorSpec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts index 9b7e552ff2..221e087dcb 100644 --- a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts +++ b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts @@ -5,7 +5,7 @@ import LogConfigurator from '../../../src/logging/LogConfigurator'; import * as netUtils from '../../../src/utils/netUtils'; import LoggingClientContext from '../../../src/logging/LoggingClientContext'; -describe.only('LogConfigurator', () => { +describe('LogConfigurator', () => { const sut = LogConfigurator; let getPortStub: sinon.SinonStub; From be5477fb543fb59f29fcbf07143537d75b92af91 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 7 Jul 2018 00:25:46 +0200 Subject: [PATCH 17/54] fix(logging): Remove color from file layout --- .../stryker/src/logging/LogConfigurator.ts | 19 +++++++++++++------ .../test/unit/logging/LogConfiguratorSpec.ts | 10 +++++++--- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/stryker/src/logging/LogConfigurator.ts b/packages/stryker/src/logging/LogConfigurator.ts index 3bf3dd6590..9d9e1aa903 100644 --- a/packages/stryker/src/logging/LogConfigurator.ts +++ b/packages/stryker/src/logging/LogConfigurator.ts @@ -16,6 +16,17 @@ enum AppenderName { Server = 'server' } +const layouts: { color: log4js.PatternLayout, noColor: log4js.PatternLayout } = { + color: { + type: 'pattern', + pattern: '%[%r (%z) %p %c%] %m' + }, + noColor: { + type: 'pattern', + pattern: '%r (%z) %p %c %m' + } +} + interface AppendersConfiguration { [name: string]: log4js.Appender; } @@ -24,21 +35,17 @@ const LOG_FILE_NAME = 'stryker.log'; export default class LogConfigurator { private static createMasterAppenders(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): AppendersConfiguration { - const layout: log4js.PatternLayout = { - type: 'pattern', - pattern: '%[%r (%z) %p %c%] %m' - }; const multiAppender = { type: require.resolve('./MultiAppender'), appenders: ['filteredConsole'] }; let allAppenders: AppendersConfiguration = { - [AppenderName.Console]: { type: 'stdout', layout }, + [AppenderName.Console]: { type: 'stdout', layout: layouts.color }, [AppenderName.FilteredConsole]: { type: 'logLevelFilter', appender: 'console', level: consoleLogLevel }, [AppenderName.All]: multiAppender, }; // only add file if it is needed. Otherwise log4js will create the file directly, pretty annoying. if (fileLogLevel.toUpperCase() !== LogLevel.Off.toUpperCase()) { - const fileAppender: log4js.FileAppender = { type: 'file', filename: LOG_FILE_NAME, layout }; + const fileAppender: log4js.FileAppender = { type: 'file', filename: LOG_FILE_NAME, layout: layouts.noColor }; const filteredFileAppender: log4js.LogLevelFilterAppender = { type: 'logLevelFilter', appender: 'file', level: fileLogLevel }; // Don't simply add the appenders, instead actually make sure they are ordinal "before" the others. diff --git a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts index 221e087dcb..88536433c6 100644 --- a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts +++ b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts @@ -78,14 +78,18 @@ describe('LogConfigurator', () => { }); function createMasterConfig(consoleLevel: LogLevel, fileLevel: LogLevel, defaultLevel: LogLevel): log4js.Configuration { - const layout: log4js.PatternLayout = { + const coloredLayout: log4js.PatternLayout = { type: 'pattern', pattern: '%[%r (%z) %p %c%] %m' }; + const notColoredLayout: log4js.PatternLayout = { + type: 'pattern', + pattern: '%r (%z) %p %c %m' + } return { appenders: { - console: { type: 'stdout', layout }, - file: { type: 'file', layout, filename: 'stryker.log' }, + console: { type: 'stdout', layout: coloredLayout }, + file: { type: 'file', layout: notColoredLayout, filename: 'stryker.log' }, filteredConsole: { type: 'logLevelFilter', appender: 'console', level: consoleLevel }, filteredFile: { type: 'logLevelFilter', appender: 'file', level: fileLevel }, all: { type: require.resolve('../../../src/logging/MultiAppender'), appenders: ['filteredConsole', 'filteredFile'] } From 33390860779183b8be5300684bfd7c080984e31a Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 7 Jul 2018 00:36:05 +0200 Subject: [PATCH 18/54] test(logging): Add logging integration test --- integrationTest/test/jasmine-jasmine/package.json | 2 +- integrationTest/test/jasmine-jasmine/stryker.conf.js | 6 ++++-- integrationTest/test/jasmine-jasmine/verify/verify.ts | 7 +++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/integrationTest/test/jasmine-jasmine/package.json b/integrationTest/test/jasmine-jasmine/package.json index 646cb2e295..80274018cb 100644 --- a/integrationTest/test/jasmine-jasmine/package.json +++ b/integrationTest/test/jasmine-jasmine/package.json @@ -5,7 +5,7 @@ "description": "A module to perform an integration test", "main": "index.js", "scripts": { - "pretest": "rimraf \"reports\" \"verify/*.map\" && tsc -p .", + "pretest": "rimraf \"reports\" \"verify/*.map\" \"stryker.log\"", "test": "stryker run", "posttest": "mocha --require ts-node/register verify/*.ts" }, diff --git a/integrationTest/test/jasmine-jasmine/stryker.conf.js b/integrationTest/test/jasmine-jasmine/stryker.conf.js index f51e1e58d9..0e6e278843 100644 --- a/integrationTest/test/jasmine-jasmine/stryker.conf.js +++ b/integrationTest/test/jasmine-jasmine/stryker.conf.js @@ -1,3 +1,4 @@ +const { LogLevel } = require('stryker-api/core'); module.exports = function (config) { config.set({ mutate: ['lib/**/*.js'], @@ -6,7 +7,8 @@ module.exports = function (config) { testFramework: 'jasmine', testRunner: 'jasmine', reporter: ['clear-text', 'event-recorder'], - maxConcurrentTestRunners: 2, - jasmineConfigFile: 'spec/support/jasmine.json' + maxConcurrentTestRunners: 1, + jasmineConfigFile: 'spec/support/jasmine.json', + fileLogLevel: LogLevel.Debug }); }; diff --git a/integrationTest/test/jasmine-jasmine/verify/verify.ts b/integrationTest/test/jasmine-jasmine/verify/verify.ts index dd7878a7d8..c085b06a8a 100644 --- a/integrationTest/test/jasmine-jasmine/verify/verify.ts +++ b/integrationTest/test/jasmine-jasmine/verify/verify.ts @@ -14,4 +14,11 @@ describe('After running stryker with test runner jasmine, test framework jasmine expect(scoreResult.noCoverage).eq(1); expect(scoreResult.mutationScore).greaterThan(85).and.lessThan(86); }); + + it('should write to a log file', async () => { + const strykerLog = await fs.readFile('./stryker.log', 'utf8'); + expect(strykerLog).contains('INFO InputFileResolver Found 2 of 10 file(s) to be mutated'); + expect(strykerLog).matches(/Stryker Done in \d+ seconds/); + // expect(strykerLog).not.contains('ERROR'); TODO + }); }); \ No newline at end of file From 10bed57a7ae361859f646dec47e114a83e2a8bc5 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 7 Jul 2018 01:47:34 +0200 Subject: [PATCH 19/54] refactor(ConfigReader): don't use `process.exit` --- packages/stryker/src/config/ConfigReader.ts | 16 ++++------ .../config-reader/ConfigReaderSpec.ts | 32 ++++++++----------- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/packages/stryker/src/config/ConfigReader.ts b/packages/stryker/src/config/ConfigReader.ts index 4a721e7c6e..6357f7fc74 100644 --- a/packages/stryker/src/config/ConfigReader.ts +++ b/packages/stryker/src/config/ConfigReader.ts @@ -51,26 +51,24 @@ export default class ConfigReader { if (this.cliOptions.configFile) { this.log.debug(`Loading config ${this.cliOptions.configFile}`); + const configFileName = path.resolve(this.cliOptions.configFile); try { - configModule = require(`${process.cwd()}/${this.cliOptions.configFile}`); + configModule = require(configFileName); } catch (e) { if (e.code === 'MODULE_NOT_FOUND' && e.message.indexOf(this.cliOptions.configFile) !== -1) { - this.log.fatal(`File ${process.cwd()}/${this.cliOptions.configFile} does not exist!`); - this.log.fatal(e); + throw new StrykerError(`File ${configFileName} does not exist!`, e); } else { - this.log.fatal('Invalid config file!\n ' + e.stack); + this.log.info('Stryker can help you setup a `stryker.conf` file for your project.'); + this.log.info('Please execute `stryker init` in your project\'s root directory.'); + throw new StrykerError('Invalid config file', e); } - this.log.info('Stryker can help you setup a `stryker.conf` file for your project.'); - this.log.info('Please execute `stryker init` in your project\'s root directory.'); - process.exit(1); } if (!_.isFunction(configModule)) { this.log.fatal('Config file must export a function!\n' + CONFIG_SYNTAX_HELP); - process.exit(1); + throw new StrykerError('Config file must export a function!'); } } return configModule; } - } \ No newline at end of file diff --git a/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts b/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts index 7e26420e8a..98532329be 100644 --- a/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts +++ b/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts @@ -1,5 +1,6 @@ +import * as path from 'path'; import { expect } from 'chai'; -import * as log4js from 'stryker-api/logging'; +import * as logging from 'stryker-api/logging'; import ConfigReader from '../../../src/config/ConfigReader'; import { Config } from 'stryker-api/config'; import currentLogMock from '../../helpers/logMock'; @@ -7,16 +8,15 @@ import { Mock } from '../../helpers/producers'; describe('ConfigReader', () => { let sut: ConfigReader; - let log: Mock; + let log: Mock; beforeEach(() => { log = currentLogMock(); - sandbox.stub(process, 'exit'); }); it('should create a logger with the correct name', () => { sut = new ConfigReader({}); - expect(log4js.getLogger).to.have.been.calledWith('ConfigReader'); + expect(logging.getLogger).to.have.been.calledWith('ConfigReader'); }); describe('readConfig()', () => { @@ -87,27 +87,22 @@ describe('ConfigReader', () => { describe('with non-existing config file', () => { beforeEach(() => { - sut = new ConfigReader({ configFile: '/did/you/know/that/this/file/does/not/exists/questionmark' }); - result = sut.readConfig(); - }); - - it('should report a fatal error', () => { - expect(log.fatal).to.have.been.calledWith(`File ${process.cwd()}//did/you/know/that/this/file/does/not/exists/questionmark does not exist!`); + sut = new ConfigReader({ configFile: 'no-file.js' }); }); - it('should exit with 1', () => { - expect(process.exit).to.have.been.calledWith(1); + it('should throw an error', () => { + expect(() => sut.readConfig()).throws(`File ${path.resolve('no-file.js')} does not exist!`); }); }); - describe('with an existing file, but not a module', () => { + describe('with an existing file, but not a function', () => { beforeEach(() => { sut = new ConfigReader({ configFile: 'testResources/config-reader/invalid.conf.js' }); - result = sut.readConfig(); }); it('should report a fatal error', () => { + expect(() => sut.readConfig()).throws(); expect(log.fatal).to.have.been.calledWith(`Config file must export a function! module.exports = function(config) { config.set({ @@ -116,8 +111,8 @@ describe('ConfigReader', () => { };`); }); - it('should exit with 1', () => { - expect(process.exit).to.have.been.calledWith(1); + it('should throw an error', () => { + expect(() => sut.readConfig()).throws('Config file must export a function'); }); }); @@ -125,11 +120,10 @@ describe('ConfigReader', () => { beforeEach(() => { sut = new ConfigReader({ configFile: 'testResources/config-reader/syntax-error.conf.js' }); - result = sut.readConfig(); }); - it('should report a fatal error', () => { - expect(log.fatal).to.have.been.calledWithMatch(/Invalid config file!.*/); + it('should throw an error', () => { + expect(() => sut.readConfig()).throws('Invalid config file. Inner error: SyntaxError: Unexpected identifier'); }); }); }); From a820577fc9cfc26601ad7643cb88e2bba48f459d Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 7 Jul 2018 01:49:20 +0200 Subject: [PATCH 20/54] fix(taskkill): make killing of tasks more relient on windows --- .../IsolatedTestRunnerAdapter.ts | 3 +- .../IsolatedTestRunnerAdapterWorker.ts | 13 +++--- .../isolated-runner/TestRunnerDecorator.ts | 2 - packages/stryker/src/utils/objectUtils.ts | 10 ++++- .../stryker/test/helpers/LoggingServer.ts | 44 ++++++++++++++++++ .../child-proxy/ChildProcessProxy.it.ts | 44 +----------------- .../isolated-runner/AdditionalTestRunners.ts | 45 +++++++++---------- .../ResilientTestRunnerFactorySpec.ts | 42 +++++++++++------ 8 files changed, 113 insertions(+), 90 deletions(-) create mode 100644 packages/stryker/test/helpers/LoggingServer.ts diff --git a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts index 23724058ca..c147325b99 100644 --- a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts +++ b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts @@ -7,6 +7,7 @@ import { serialize, kill } from '../utils/objectUtils'; import { AdapterMessage, WorkerMessage } from './MessageProtocol'; import IsolatedRunnerOptions from './IsolatedRunnerOptions'; import Task from '../utils/Task'; +import StrykerError from '../utils/StrykerError'; const MAX_WAIT_FOR_DISPOSE = 2000; @@ -109,7 +110,7 @@ export default class TestRunnerChildProcessAdapter extends EventEmitter implemen if (code !== 0 && code !== null) { this.log.error(`Child process exited with non-zero exit code ${code}. Last 10 message from the child process were: \r\n${this.lastMessagesQueue.map(msg => `\t${msg}`).join('\r\n')}`); if (this.currentTask) { - this.currentTask.reject(`Test runner child process exited with non-zero exit code ${code}`); + this.currentTask.reject(new StrykerError(`Test runner child process exited with non-zero exit code ${code}`)); } } }); diff --git a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts index 23c9e24050..af28cbbcd9 100644 --- a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts +++ b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts @@ -29,7 +29,8 @@ class IsolatedTestRunnerAdapterWorker { this.init(); break; case 'dispose': - this.dispose(); + const sendDisposeDone = this.sendDisposeDone.bind(this); + this.dispose().then(sendDisposeDone, sendDisposeDone); break; default: this.logReceivedMessageWarning(message); @@ -86,11 +87,13 @@ class IsolatedTestRunnerAdapterWorker { } async dispose() { - if (this.underlyingTestRunner.dispose) { - await this.underlyingTestRunner.dispose(); + try { + if (this.underlyingTestRunner.dispose) { + await this.underlyingTestRunner.dispose(); + } + } finally { + await LogConfigurator.shutdown(); } - await LogConfigurator.shutdown(); - this.sendDisposeDone(); } sendDisposeDone() { diff --git a/packages/stryker/src/isolated-runner/TestRunnerDecorator.ts b/packages/stryker/src/isolated-runner/TestRunnerDecorator.ts index c6b61eff26..53bb984c5c 100644 --- a/packages/stryker/src/isolated-runner/TestRunnerDecorator.ts +++ b/packages/stryker/src/isolated-runner/TestRunnerDecorator.ts @@ -30,6 +30,4 @@ export default class TestRunnerDecorator implements TestRunner { return Promise.resolve(); } } - - } \ No newline at end of file diff --git a/packages/stryker/src/utils/objectUtils.ts b/packages/stryker/src/utils/objectUtils.ts index 2823b2a802..4bd520d8c8 100644 --- a/packages/stryker/src/utils/objectUtils.ts +++ b/packages/stryker/src/utils/objectUtils.ts @@ -86,12 +86,18 @@ export function normalizeWhiteSpaces(str: string) { export function kill(pid: number): Promise { return new Promise((res, rej) => { - treeKill(pid, 'SIGKILL', err => { - if (err) { + treeKill(pid, 'SIGKILL', (err: { code?: number } & Error) => { + if (err && !canIgnore(err.code)) { rej(err); } else { res(); } }); + + function canIgnore(code: number | undefined) { + // https://docs.microsoft.com/en-us/windows/desktop/Debug/system-error-codes--0-499- + // these error codes mean the program is _already_ closed. + return code === 255 || code === 128; + } }); } \ No newline at end of file diff --git a/packages/stryker/test/helpers/LoggingServer.ts b/packages/stryker/test/helpers/LoggingServer.ts new file mode 100644 index 0000000000..d801edd21e --- /dev/null +++ b/packages/stryker/test/helpers/LoggingServer.ts @@ -0,0 +1,44 @@ +import * as net from 'net'; +import * as log4js from 'log4js'; +import { Subscriber, Observable } from 'rxjs'; + +export default class LoggingServer { + + private readonly server: net.Server; + private subscribers: Subscriber[] = []; + public readonly event$: Observable; + + constructor(public readonly port: number) { + this.server = net.createServer(socket => { + socket.on('data', data => { + const str = data.toString(); + try { + const json = JSON.parse(str); + this.subscribers.map(sub => sub.next(json)); + } catch { + // IDLE. Log4js also sends "__LOG4JS__" to signal an event end. Ignore those. + } + }); + }); + this.server.listen(this.port); + + this.event$ = new Observable(subscriber => { + this.subscribers.push(subscriber); + this.server.on('close', () => { + subscriber.complete(); + }); + }); + } + + dispose(): Promise { + return new Promise((res, rej) => { + this.server.close((err: Error) => { + if (err) { + rej(err); + } else { + res(); + } + }); + }); + } +} \ No newline at end of file diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index 160be566b0..cee5064e8a 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -2,11 +2,10 @@ import { expect } from 'chai'; import Echo from './Echo'; import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; import { File, LogLevel } from 'stryker-api/core'; -import * as net from 'net'; import * as log4js from 'log4js'; -import { Observable, Subscriber } from 'rxjs'; import * as getPort from 'get-port'; import Task from '../../../src/utils/Task'; +import LoggingServer from '../../helpers/LoggingServer'; describe('ChildProcessProxy', () => { @@ -74,44 +73,3 @@ function toLogLevel(level: log4js.Level) { const levelName = (level as any).levelStr.toLowerCase(); return [LogLevel.Debug, LogLevel.Error, LogLevel.Fatal, LogLevel.Information, LogLevel.Off, LogLevel.Trace, LogLevel.Warning].find(level => level === levelName); } - -class LoggingServer { - - private readonly server: net.Server; - private subscribers: Subscriber[] = []; - public readonly event$: Observable; - - constructor(private port: number) { - this.server = net.createServer(socket => { - socket.on('data', data => { - const str = data.toString(); - try { - const json = JSON.parse(str); - this.subscribers.map(sub => sub.next(json)); - } catch { - // IDLE. Log4js also sends "__LOG4JS__" to signal an event end. Ignore those. - } - }); - }); - this.server.listen(this.port); - - this.event$ = new Observable(subscriber => { - this.subscribers.push(subscriber); - this.server.on('close', () => { - subscriber.complete(); - }); - }); - } - - dispose(): Promise { - return new Promise((res, rej) => { - this.server.close((err: Error) => { - if (err) { - rej(err); - } else { - res(); - } - }); - }); - } -} \ No newline at end of file diff --git a/packages/stryker/test/integration/isolated-runner/AdditionalTestRunners.ts b/packages/stryker/test/integration/isolated-runner/AdditionalTestRunners.ts index 6e84b2d593..303a9afe37 100644 --- a/packages/stryker/test/integration/isolated-runner/AdditionalTestRunners.ts +++ b/packages/stryker/test/integration/isolated-runner/AdditionalTestRunners.ts @@ -1,39 +1,36 @@ -import { EventEmitter } from 'events'; -import { RunResult, RunStatus, RunOptions, RunnerOptions, TestRunner, TestRunnerFactory } from 'stryker-api/test_runner'; +import { RunResult, RunStatus, RunnerOptions, TestRunner, TestRunnerFactory } from 'stryker-api/test_runner'; import { isRegExp } from 'util'; -class CoverageReportingTestRunner extends EventEmitter implements TestRunner { - run(options: RunOptions) { +class CoverageReportingTestRunner implements TestRunner { + run() { (global as any).__coverage__ = 'overridden'; return Promise.resolve({ status: RunStatus.Complete, tests: [], coverage: 'realCoverage' }); } } -class TimeBombTestRunner extends EventEmitter implements TestRunner { +class TimeBombTestRunner implements TestRunner { constructor() { - super(); // Setting a time bomb after 100 ms setTimeout(() => process.exit(), 100); } - run(options: RunOptions) { + run() { return Promise.resolve({ status: RunStatus.Complete, tests: [] }); } } -class DirectResolvedTestRunner extends EventEmitter implements TestRunner { - run(options: RunOptions) { +class DirectResolvedTestRunner implements TestRunner { + run() { (global as any).__coverage__ = 'coverageObject'; return Promise.resolve({ status: RunStatus.Complete, tests: [] }); } } -class DiscoverRegexTestRunner extends EventEmitter implements TestRunner { +class DiscoverRegexTestRunner implements TestRunner { constructor(private runnerOptions: RunnerOptions) { - super(); } - run(options: RunOptions): Promise { + run(): Promise { if (isRegExp(this.runnerOptions.strykerOptions['someRegex'])) { return Promise.resolve({ status: RunStatus.Complete, tests: [] }); } else { @@ -43,9 +40,9 @@ class DiscoverRegexTestRunner extends EventEmitter implements TestRunner { } -class ErroredTestRunner extends EventEmitter implements TestRunner { +class ErroredTestRunner implements TestRunner { - run(options: RunOptions) { + run() { let expectedError: any = null; try { throw new SyntaxError('This is invalid syntax!'); @@ -62,18 +59,18 @@ class RejectInitRunner implements TestRunner { return Promise.reject(new Error('Init was rejected')); } - run(options: RunOptions): Promise { + run(): Promise { throw new Error(); } } -class NeverResolvedTestRunner extends EventEmitter implements TestRunner { - run(options: RunOptions) { - return new Promise(res => { }); +class NeverResolvedTestRunner implements TestRunner { + run() { + return new Promise(() => { }); } } -class SlowInitAndDisposeTestRunner extends EventEmitter implements TestRunner { +class SlowInitAndDisposeTestRunner implements TestRunner { inInit: boolean; @@ -87,7 +84,7 @@ class SlowInitAndDisposeTestRunner extends EventEmitter implements TestRunner { }); } - run(options: RunOptions) { + run() { if (this.inInit) { throw new Error('Test should fail! Not yet initialized!'); } @@ -98,11 +95,11 @@ class SlowInitAndDisposeTestRunner extends EventEmitter implements TestRunner { return this.init(); } } -class VerifyWorkingFolderTestRunner extends EventEmitter implements TestRunner { +class VerifyWorkingFolderTestRunner implements TestRunner { runResult: RunResult = { status: RunStatus.Complete, tests: [] }; - run(options: RunOptions) { + run() { if (process.cwd().toLowerCase() === __dirname.toLowerCase()) { return Promise.resolve(this.runResult); } else { @@ -111,14 +108,14 @@ class VerifyWorkingFolderTestRunner extends EventEmitter implements TestRunner { } } -class AsyncronousPromiseRejectionHandlerTestRunner extends EventEmitter implements TestRunner { +class AsyncronousPromiseRejectionHandlerTestRunner implements TestRunner { promise: Promise; init() { this.promise = Promise.reject('Reject for now, but will be caught asynchronously'); } - run(options: RunOptions) { + run() { this.promise.catch(() => { }); return Promise.resolve({ status: RunStatus.Complete, tests: [] }); } diff --git a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts index 9bf134c65f..2237cec5e3 100644 --- a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts +++ b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts @@ -1,6 +1,7 @@ import * as path from 'path'; import { Logger } from 'stryker-api/logging'; import { expect } from 'chai'; +import * as getPort from 'get-port'; import { RunResult, RunStatus } from 'stryker-api/test_runner'; import ResilientTestRunnerFactory from '../../../src/isolated-runner/ResilientTestRunnerFactory'; import IsolatedRunnerOptions from '../../../src/isolated-runner/IsolatedRunnerOptions'; @@ -8,6 +9,7 @@ import TestRunnerDecorator from '../../../src/isolated-runner/TestRunnerDecorato import currentLogMock from '../../helpers/logMock'; import { Mock } from '../../helpers/producers'; import { LogLevel } from 'stryker-api/core'; +import LoggingServer from '../../helpers/LoggingServer'; function sleep(ms: number) { return new Promise(res => { @@ -20,24 +22,38 @@ describe('ResilientTestRunnerFactory', function () { this.timeout(15000); let log: Mock; let sut: TestRunnerDecorator; - let options: IsolatedRunnerOptions = { - strykerOptions: { - plugins: ['../../test/integration/isolated-runner/AdditionalTestRunners'], - testRunner: 'karma', - testFramework: 'jasmine', - port: 0, - 'someRegex': /someRegex/ - }, - port: 0, - fileNames: [], - sandboxWorkingFolder: path.resolve('./test/integration/isolated-runner'), - loggingContext: { port: 4200, level: LogLevel.Fatal } - }; + let options: IsolatedRunnerOptions; beforeEach(() => { log = currentLogMock(); }); + let loggingServer: LoggingServer; + + before(async () => { + // Make sure there is a logging server listening + const port = await getPort(); + loggingServer = new LoggingServer(port); + + options = { + strykerOptions: { + plugins: ['../../test/integration/isolated-runner/AdditionalTestRunners'], + testRunner: 'karma', + testFramework: 'jasmine', + port: 0, + 'someRegex': /someRegex/ + }, + port: 0, + fileNames: [], + sandboxWorkingFolder: path.resolve('./test/integration/isolated-runner'), + loggingContext: { port, level: LogLevel.Fatal } + }; + }); + + after(() => { + return loggingServer.dispose(); + }); + describe('when sending a regex in the options', () => { before(() => sut = ResilientTestRunnerFactory.create('discover-regex', options)); From ee1efda93de934cab5c49d158cb00fcf3b451027 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 7 Jul 2018 02:09:20 +0200 Subject: [PATCH 21/54] test(api): Improve error logging on integration test --- .../install-module/install-module.ts | 18 ++++++++++++++---- .../stryker/src/logging/LogConfigurator.ts | 2 +- .../test/unit/logging/LogConfiguratorSpec.ts | 2 +- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/stryker-api/test/integration/install-module/install-module.ts b/packages/stryker-api/test/integration/install-module/install-module.ts index 155d56115c..22f3745597 100644 --- a/packages/stryker-api/test/integration/install-module/install-module.ts +++ b/packages/stryker-api/test/integration/install-module/install-module.ts @@ -8,10 +8,20 @@ describe('we have a module using stryker', function () { const modulePath = path.resolve(__dirname, '../../../testResources/module'); - const execInModule = (command: string) => { - console.log(`Exec '${command}' in ${modulePath}`); - return exec(command, { cwd: modulePath }); - }; + function execInModule (command: string): Promise<[string, string]> { + return new Promise((res, rej) => { + console.log(`Exec '${command}' in ${modulePath}`); + exec(command, { cwd: modulePath }, (error, stdout, stderr) => { + if (error) { + console.log(stdout); + console.error(stderr); + rej(error); + } else { + res([stdout, stderr]); + } + }); + }); + } describe('after installing Stryker', () => { diff --git a/packages/stryker/src/logging/LogConfigurator.ts b/packages/stryker/src/logging/LogConfigurator.ts index 9d9e1aa903..2cc86e2cb6 100644 --- a/packages/stryker/src/logging/LogConfigurator.ts +++ b/packages/stryker/src/logging/LogConfigurator.ts @@ -25,7 +25,7 @@ const layouts: { color: log4js.PatternLayout, noColor: log4js.PatternLayout } = type: 'pattern', pattern: '%r (%z) %p %c %m' } -} +}; interface AppendersConfiguration { [name: string]: log4js.Appender; diff --git a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts index 88536433c6..c9c91e9a2a 100644 --- a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts +++ b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts @@ -85,7 +85,7 @@ describe('LogConfigurator', () => { const notColoredLayout: log4js.PatternLayout = { type: 'pattern', pattern: '%r (%z) %p %c %m' - } + }; return { appenders: { console: { type: 'stdout', layout: coloredLayout }, From 33aa4d90b490698f6eeda2deb687b8b7fe88ae29 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 7 Jul 2018 02:48:49 +0200 Subject: [PATCH 22/54] test(karma-runner): Fix failing test in karma runner after merge --- .../stryker-karma-runner/test/unit/KarmaTestRunnerSpec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stryker-karma-runner/test/unit/KarmaTestRunnerSpec.ts b/packages/stryker-karma-runner/test/unit/KarmaTestRunnerSpec.ts index e9c5498912..909c1a0c7e 100644 --- a/packages/stryker-karma-runner/test/unit/KarmaTestRunnerSpec.ts +++ b/packages/stryker-karma-runner/test/unit/KarmaTestRunnerSpec.ts @@ -1,6 +1,6 @@ import { EventEmitter } from 'events'; import { expect } from 'chai'; -import * as log4js from 'log4js'; +import * as logging from 'stryker-api/logging'; import * as karma from 'karma'; import strykerKarmaConf = require('../../src/starters/stryker-karma.conf'); import ProjectStarter, * as projectStarterModule from '../../src/starters/ProjectStarter'; @@ -28,7 +28,7 @@ describe('KarmaTestRunner', () => { projectStarterMock = sandbox.createStubInstance(ProjectStarter); logMock = new LoggerStub(); sandbox.stub(projectStarterModule, 'default').returns(projectStarterMock); - sandbox.stub(log4js, 'getLogger').returns(logMock); + sandbox.stub(logging, 'getLogger').returns(logMock); sandbox.stub(StrykerReporter, 'instance').value(reporterMock); setGlobalsStub = sandbox.stub(strykerKarmaConf, 'setGlobals'); karmaRunStub = sandbox.stub(karma.runner, 'run'); From c2882b98b79af2fde4c9fb3343ac5727095067db Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 7 Jul 2018 03:16:51 +0200 Subject: [PATCH 23/54] fix(logging): Make logging server more robust against race conditions --- .../stryker/src/logging/LogConfigurator.ts | 37 +++++++++++++++---- packages/stryker/src/utils/netUtils.ts | 2 +- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/packages/stryker/src/logging/LogConfigurator.ts b/packages/stryker/src/logging/LogConfigurator.ts index 2cc86e2cb6..a49410e76a 100644 --- a/packages/stryker/src/logging/LogConfigurator.ts +++ b/packages/stryker/src/logging/LogConfigurator.ts @@ -92,9 +92,10 @@ export default class LogConfigurator { * @param fileLogLevel the file log level * @returns the context */ - static forServer(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): PromiseLike { + static forServer(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): Promise { this.setImplementation(); - return getPort({ port: PREFERRED_LOG_SERVER_PORT }).then(loggerPort => { + + const configureServerLogging = (loggerPort: number): LogLevel => { const appenders = this.createMasterAppenders(consoleLogLevel, fileLogLevel); const multiProcessAppender: log4js.MultiprocessAppender = { type: 'multiprocess', @@ -105,14 +106,34 @@ export default class LogConfigurator { appenders[AppenderName.Server] = multiProcessAppender; const defaultLogLevel = minLevel(consoleLogLevel, fileLogLevel); log4js.configure(this.createLog4jsConfig(defaultLogLevel, appenders)); - const context: LoggingClientContext = { - port: loggerPort, - level: defaultLogLevel - }; - return context; - }); + return defaultLogLevel; + }; + + /** + * Tries to configure the log4js server. + * Because of race conditions, this can fail. + * In case of failure, retry a few times + * @param triesLeft the number of retries to get a free server port + */ + const tryForServer = (triesLeft = 10): Promise => { + const attempt = getPort({ port: PREFERRED_LOG_SERVER_PORT }).then(loggerPort => { + const defaultLogLevel = configureServerLogging(loggerPort); + const context: LoggingClientContext = { + port: loggerPort, + level: defaultLogLevel + }; + return context; + }); + if (triesLeft > 0) { + return attempt.catch(() => tryForServer(triesLeft - 1)); + } else { + return attempt; + } + }; + return tryForServer(); } + /** * Configures the logging for a worker process. Sends all logging to the master process. * Either call this method or `forMaster` before any `getLogger` calls. diff --git a/packages/stryker/src/utils/netUtils.ts b/packages/stryker/src/utils/netUtils.ts index e7c9c15780..6ee01dfe8c 100644 --- a/packages/stryker/src/utils/netUtils.ts +++ b/packages/stryker/src/utils/netUtils.ts @@ -1,3 +1,3 @@ import * as getPortModule from 'get-port'; -export const getPort = getPortModule; \ No newline at end of file +export const getPort: (options?: { port?: number, host?: string }) => Promise = getPortModule as any; \ No newline at end of file From f59d0c28e44b5a36021cff896a77431ae81e43ab Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 7 Jul 2018 03:29:35 +0200 Subject: [PATCH 24/54] test(stryker): Higher timeout for integration tests --- packages/stryker/package.json | 2 +- .../test/integration/child-proxy/ChildProcessProxy.it.ts | 3 ++- .../test/integration/config-reader/ConfigReaderSpec.ts | 4 +++- .../stryker/test/integration/source-mapper/SourceMapperIT.ts | 3 ++- packages/stryker/test/integration/utils/fileUtilsSpec.ts | 4 +++- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/stryker/package.json b/packages/stryker/package.json index 671bb06e15..a648dae759 100644 --- a/packages/stryker/package.json +++ b/packages/stryker/package.json @@ -9,7 +9,7 @@ "prebuild": "rimraf \"+(test|src)/**/*+(.d.ts|.js|.map)\" .nyc_output reports coverage", "build": "tsc -p .", "postbuild": "tslint -p tsconfig.json", - "test": "nyc --check-coverage --reporter=html --report-dir=reports/coverage --lines 80 --functions 80 --branches 75 mocha \"test/**/*.js\"", + "test": "nyc --check-coverage --reporter=html --report-dir=reports/coverage --lines 80 --functions 80 --branches 75 mocha \"test/helpers/**/*.js\" \"test/unit/**/*.js\" \"test/integration/**/*.js\"", "stryker": "node bin/stryker run" }, "repository": { diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index cee5064e8a..43abe6b0c2 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -7,8 +7,9 @@ import * as getPort from 'get-port'; import Task from '../../../src/utils/Task'; import LoggingServer from '../../helpers/LoggingServer'; -describe('ChildProcessProxy', () => { +describe('ChildProcessProxy', function () { + this.timeout(15000); let sut: ChildProcessProxy; let loggingServer: LoggingServer; diff --git a/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts b/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts index 98532329be..aa4896eace 100644 --- a/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts +++ b/packages/stryker/test/integration/config-reader/ConfigReaderSpec.ts @@ -6,7 +6,9 @@ import { Config } from 'stryker-api/config'; import currentLogMock from '../../helpers/logMock'; import { Mock } from '../../helpers/producers'; -describe('ConfigReader', () => { +describe('ConfigReader', function() { + this.timeout(15000); + let sut: ConfigReader; let log: Mock; diff --git a/packages/stryker/test/integration/source-mapper/SourceMapperIT.ts b/packages/stryker/test/integration/source-mapper/SourceMapperIT.ts index 5fc263982d..0e72f5ba98 100644 --- a/packages/stryker/test/integration/source-mapper/SourceMapperIT.ts +++ b/packages/stryker/test/integration/source-mapper/SourceMapperIT.ts @@ -14,8 +14,9 @@ function readFiles(...files: string[]): Promise { .map(fileName => fs.readFile(fileName).then(content => new File(fileName, content)))); } -describe('Source mapper integration', () => { +describe('Source mapper integration', function () { + this.timeout(15000); let sut: TranspiledSourceMapper; describe('with external source maps', () => { diff --git a/packages/stryker/test/integration/utils/fileUtilsSpec.ts b/packages/stryker/test/integration/utils/fileUtilsSpec.ts index 8f8e871c4b..e00933608e 100644 --- a/packages/stryker/test/integration/utils/fileUtilsSpec.ts +++ b/packages/stryker/test/integration/utils/fileUtilsSpec.ts @@ -2,7 +2,9 @@ import { expect } from 'chai'; import * as sinon from 'sinon'; import * as fileUtils from '../../../src/utils/fileUtils'; -describe('fileUtils', () => { +describe('fileUtils', function () { + + this.timeout(15000); let sandbox: sinon.SinonSandbox; From 9d6a4f6fd81388f2755359a42743885713f5c9d3 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 7 Jul 2018 13:21:51 +0200 Subject: [PATCH 25/54] refactor: Remove code responsible for retrying different ports as it was not working, instead hope for the best --- .../stryker/src/logging/LogConfigurator.ts | 54 ++++++------------- packages/stryker/src/utils/netUtils.ts | 2 +- .../test/unit/logging/LogConfiguratorSpec.ts | 9 ++-- 3 files changed, 22 insertions(+), 43 deletions(-) diff --git a/packages/stryker/src/logging/LogConfigurator.ts b/packages/stryker/src/logging/LogConfigurator.ts index a49410e76a..c24e64fc36 100644 --- a/packages/stryker/src/logging/LogConfigurator.ts +++ b/packages/stryker/src/logging/LogConfigurator.ts @@ -3,9 +3,7 @@ import { LoggerFactory } from 'stryker-api/logging'; import { LogLevel } from 'stryker-api/core'; import { minLevel } from './logUtils'; import LoggingClientContext from './LoggingClientContext'; -import { getPort } from '../utils/netUtils'; - -const PREFERRED_LOG_SERVER_PORT = 5000; +import { getFreePort } from '../utils/netUtils'; enum AppenderName { File = 'file', @@ -92,45 +90,25 @@ export default class LogConfigurator { * @param fileLogLevel the file log level * @returns the context */ - static forServer(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): Promise { + static async forServer(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): Promise { this.setImplementation(); - - const configureServerLogging = (loggerPort: number): LogLevel => { - const appenders = this.createMasterAppenders(consoleLogLevel, fileLogLevel); - const multiProcessAppender: log4js.MultiprocessAppender = { - type: 'multiprocess', - mode: 'master', - appender: AppenderName.All, - loggerPort - }; - appenders[AppenderName.Server] = multiProcessAppender; - const defaultLogLevel = minLevel(consoleLogLevel, fileLogLevel); - log4js.configure(this.createLog4jsConfig(defaultLogLevel, appenders)); - return defaultLogLevel; + const loggerPort = await getFreePort(); + const appenders = this.createMasterAppenders(consoleLogLevel, fileLogLevel); + const multiProcessAppender: log4js.MultiprocessAppender = { + type: 'multiprocess', + mode: 'master', + appender: AppenderName.All, + loggerPort }; + appenders[AppenderName.Server] = multiProcessAppender; + const defaultLogLevel = minLevel(consoleLogLevel, fileLogLevel); + log4js.configure(this.createLog4jsConfig(defaultLogLevel, appenders)); - /** - * Tries to configure the log4js server. - * Because of race conditions, this can fail. - * In case of failure, retry a few times - * @param triesLeft the number of retries to get a free server port - */ - const tryForServer = (triesLeft = 10): Promise => { - const attempt = getPort({ port: PREFERRED_LOG_SERVER_PORT }).then(loggerPort => { - const defaultLogLevel = configureServerLogging(loggerPort); - const context: LoggingClientContext = { - port: loggerPort, - level: defaultLogLevel - }; - return context; - }); - if (triesLeft > 0) { - return attempt.catch(() => tryForServer(triesLeft - 1)); - } else { - return attempt; - } + const context: LoggingClientContext = { + port: loggerPort, + level: defaultLogLevel }; - return tryForServer(); + return context; } diff --git a/packages/stryker/src/utils/netUtils.ts b/packages/stryker/src/utils/netUtils.ts index 6ee01dfe8c..79ea9dc040 100644 --- a/packages/stryker/src/utils/netUtils.ts +++ b/packages/stryker/src/utils/netUtils.ts @@ -1,3 +1,3 @@ import * as getPortModule from 'get-port'; -export const getPort: (options?: { port?: number, host?: string }) => Promise = getPortModule as any; \ No newline at end of file +export const getFreePort = getPortModule; \ No newline at end of file diff --git a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts index c9c91e9a2a..0979a1a0a3 100644 --- a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts +++ b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts @@ -8,12 +8,12 @@ import LoggingClientContext from '../../../src/logging/LoggingClientContext'; describe('LogConfigurator', () => { const sut = LogConfigurator; - let getPortStub: sinon.SinonStub; + let getFreePortStub: sinon.SinonStub; let log4jsConfigure: sinon.SinonStub; let log4jsShutdown: sinon.SinonStub; beforeEach(() => { - getPortStub = sandbox.stub(netUtils, 'getPort'); + getFreePortStub = sandbox.stub(netUtils, 'getFreePort'); log4jsConfigure = sandbox.stub(log4js, 'configure'); log4jsShutdown = sandbox.stub(log4js, 'shutdown'); }); @@ -38,7 +38,7 @@ describe('LogConfigurator', () => { it('should configure console, file and server', async () => { // Arrange const expectedLoggingContext: LoggingClientContext = { port: 42, level: LogLevel.Error }; - getPortStub.resolves(expectedLoggingContext.port); + getFreePortStub.resolves(expectedLoggingContext.port); const expectedConfig = createMasterConfig(LogLevel.Error, LogLevel.Fatal, LogLevel.Error); const serverAppender: log4js.MultiprocessAppender = { type: 'multiprocess', mode: 'master', loggerPort: 42, appender: 'all' }; expectedConfig.appenders.server = serverAppender; @@ -48,9 +48,10 @@ describe('LogConfigurator', () => { // Assert expect(log4jsConfigure).calledWith(expectedConfig); - expect(getPortStub).calledWith({ port: 5000 }); + expect(getFreePortStub).called; expect(actualLoggingContext).deep.eq(expectedLoggingContext); }); + }); describe('forWorker', () => { From 145e5835b45a16bde7cfec672c5707c29c480d62 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Thu, 12 Jul 2018 17:29:41 +0200 Subject: [PATCH 26/54] feat(jest-runner): Use new logging API --- packages/stryker-jest-runner/package.json | 2 -- packages/stryker-jest-runner/src/JestTestRunner.ts | 7 ++----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/stryker-jest-runner/package.json b/packages/stryker-jest-runner/package.json index baa524b5d5..7befe65545 100644 --- a/packages/stryker-jest-runner/package.json +++ b/packages/stryker-jest-runner/package.json @@ -39,7 +39,6 @@ }, "homepage": "https://github.com/stryker-mutator/stryker/tree/master/packages/stryker-jest-runner#readme", "devDependencies": { - "@types/log4js": "0.0.32", "@types/semver": "~5.5.0", "jest": "~22.0.0", "react": "~16.2.0", @@ -53,7 +52,6 @@ "jest": "^20.0.0" }, "dependencies": { - "log4js": "~1.1.1", "semver": "~5.5.0" }, "initStrykerConfig": { diff --git a/packages/stryker-jest-runner/src/JestTestRunner.ts b/packages/stryker-jest-runner/src/JestTestRunner.ts index 2c747b03e5..1aa17775f4 100644 --- a/packages/stryker-jest-runner/src/JestTestRunner.ts +++ b/packages/stryker-jest-runner/src/JestTestRunner.ts @@ -1,17 +1,14 @@ -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { RunnerOptions, RunResult, TestRunner, RunStatus, TestResult, TestStatus } from 'stryker-api/test_runner'; -import { EventEmitter } from 'events'; import * as jest from 'jest'; import JestTestAdapterFactory from './jestTestAdapters/JestTestAdapterFactory'; -export default class JestTestRunner extends EventEmitter implements TestRunner { +export default class JestTestRunner implements TestRunner { private log = getLogger(JestTestRunner.name); private jestConfig: jest.Configuration; private processEnvRef: NodeJS.ProcessEnv; public constructor(options: RunnerOptions, processEnvRef?: NodeJS.ProcessEnv) { - super(); - // Make sure process can be mocked by tests by passing it in the constructor this.processEnvRef = processEnvRef || /* istanbul ignore next */ process.env; From d10b5231433abe5d5338f0123d4bd91319d493df Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Thu, 12 Jul 2018 20:25:03 +0200 Subject: [PATCH 27/54] build(karma-runner): Add express types back again --- packages/stryker-karma-runner/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/stryker-karma-runner/package.json b/packages/stryker-karma-runner/package.json index 3088719d64..3a2f86932d 100644 --- a/packages/stryker-karma-runner/package.json +++ b/packages/stryker-karma-runner/package.json @@ -34,6 +34,7 @@ "stryker-api": ">=0.15.0 <0.18.0" }, "devDependencies": { + "@types/express": "~4.11.1", "@types/semver": "~5.5.0", "jasmine-core": "~2.4.1", "karma": "~2.0.4", From cbe94cc575082e832916e164a1789b0f4b1e2def Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Thu, 12 Jul 2018 21:18:45 +0200 Subject: [PATCH 28/54] refactor(logging): Implement review comments * Add js docs * Add references to log4js documentation * Rename all wrong `log4js` references in plugins to `logging` --- .../test/jasmine-jasmine/verify/verify.ts | 3 ++- .../src/logging/LoggerFactoryMethod.ts | 4 +-- .../test/unit/BabelConfigReaderSpec.ts | 4 +-- .../stryker-html-reporter/src/HtmlReporter.ts | 11 ++++---- .../helpers/{log4jsMock.ts => loggingMock.ts} | 4 +-- .../test/integration/MathReportSpec.ts | 2 +- .../test/helpers/initSinon.ts | 4 +-- .../JestPromiseTestAdapter.ts | 2 +- .../JestTestAdapterFactory.ts | 2 +- .../test/unit/JestTestRunnerSpec.ts | 4 +-- .../JestPromiseTestAdapterSpec.ts | 4 +-- .../src/starters/stryker-karma.conf.ts | 2 +- .../unit/starters/stryker-karma.confSpec.ts | 6 ++--- .../src/StrykerMochaReporter.ts | 15 ++++++----- .../test/unit/MochaOptionsLoaderSpec.ts | 6 ++--- .../test/unit/MochaTestRunnerSpec.ts | 6 ++--- .../test/unit/TypescriptConfigEditorSpec.ts | 4 +-- .../test/helpers/sinonInit.ts | 4 +-- packages/stryker/README.md | 2 +- packages/stryker/src/Stryker.ts | 8 +++--- packages/stryker/src/StrykerCli.ts | 2 +- .../child-proxy/ChildProcessProxyWorker.ts | 2 +- packages/stryker/src/config/ConfigReader.ts | 4 +-- .../IsolatedTestRunnerAdapterWorker.ts | 2 +- .../stryker/src/logging/LogConfigurator.ts | 25 +++++++++++-------- .../src/logging/LoggingClientContext.ts | 6 +++++ packages/stryker/src/logging/MultiAppender.ts | 8 ++++++ packages/stryker/src/logging/logUtils.ts | 7 +----- packages/stryker/src/utils/netUtils.ts | 3 +++ packages/stryker/stryker.conf.js | 2 +- .../ResilientTestRunnerFactorySpec.ts | 2 +- packages/stryker/test/unit/StrykerSpec.ts | 16 ++++++------ .../child-proxy/ChildProcessWorkerSpec.ts | 6 ++--- .../test/unit/logging/LogConfiguratorSpec.ts | 14 +++++------ 34 files changed, 106 insertions(+), 90 deletions(-) rename packages/stryker-html-reporter/test/helpers/{log4jsMock.ts => loggingMock.ts} (85%) diff --git a/integrationTest/test/jasmine-jasmine/verify/verify.ts b/integrationTest/test/jasmine-jasmine/verify/verify.ts index c085b06a8a..32acb9838d 100644 --- a/integrationTest/test/jasmine-jasmine/verify/verify.ts +++ b/integrationTest/test/jasmine-jasmine/verify/verify.ts @@ -19,6 +19,7 @@ describe('After running stryker with test runner jasmine, test framework jasmine const strykerLog = await fs.readFile('./stryker.log', 'utf8'); expect(strykerLog).contains('INFO InputFileResolver Found 2 of 10 file(s) to be mutated'); expect(strykerLog).matches(/Stryker Done in \d+ seconds/); - // expect(strykerLog).not.contains('ERROR'); TODO + // TODO, we now have an error because of a memory leak: https://github.com/jasmine/jasmine-npm/issues/134 + // expect(strykerLog).not.contains('ERROR'); }); }); \ No newline at end of file diff --git a/packages/stryker-api/src/logging/LoggerFactoryMethod.ts b/packages/stryker-api/src/logging/LoggerFactoryMethod.ts index 5bb9a43651..7aaf3e47d4 100644 --- a/packages/stryker-api/src/logging/LoggerFactoryMethod.ts +++ b/packages/stryker-api/src/logging/LoggerFactoryMethod.ts @@ -1,11 +1,11 @@ import Logger from './Logger'; /** - * Get a logger instance. Instance is cached on categoryName level. + * Represents a factory to get loggers by category name. + * This interface is used to describe the shape of a logger factory method. * * @param {String} [categoryName] name of category to log to. * @returns {Logger} instance of logger for the category - * @static */ export default interface LoggerFactoryMethod { (categoryName?: string): Logger; diff --git a/packages/stryker-babel-transpiler/test/unit/BabelConfigReaderSpec.ts b/packages/stryker-babel-transpiler/test/unit/BabelConfigReaderSpec.ts index d9fdbdf8c4..5e2e009b5a 100644 --- a/packages/stryker-babel-transpiler/test/unit/BabelConfigReaderSpec.ts +++ b/packages/stryker-babel-transpiler/test/unit/BabelConfigReaderSpec.ts @@ -2,7 +2,7 @@ import BabelConfigReader from '../../src/BabelConfigReader'; import { Config } from 'stryker-api/config'; import { expect } from 'chai'; import * as fs from 'fs'; -import * as log4js from 'stryker-api/logging'; +import * as logging from 'stryker-api/logging'; import * as sinon from 'sinon'; import * as path from 'path'; @@ -24,7 +24,7 @@ describe('BabelConfigReader', () => { debug: sandbox.stub() }; - sandbox.stub(log4js, 'getLogger').returns(logStub); + sandbox.stub(logging, 'getLogger').returns(logStub); }); afterEach(() => { diff --git a/packages/stryker-html-reporter/src/HtmlReporter.ts b/packages/stryker-html-reporter/src/HtmlReporter.ts index 73aba313f5..1f7444f689 100644 --- a/packages/stryker-html-reporter/src/HtmlReporter.ts +++ b/packages/stryker-html-reporter/src/HtmlReporter.ts @@ -1,4 +1,4 @@ -import * as logging from 'stryker-api/logging'; +import { getLogger } from 'stryker-api/logging'; import fileUrl = require('file-url'); import * as path from 'path'; import { Config } from 'stryker-api/config'; @@ -7,12 +7,11 @@ import * as util from './util'; import * as templates from './templates'; import Breadcrumb from './Breadcrumb'; -const log = logging.getLogger('HtmlReporter'); const DEFAULT_BASE_FOLDER = path.normalize('reports/mutation/html'); export const RESOURCES_DIR_NAME = 'strykerResources'; export default class HtmlReporter implements Reporter { - + private log = getLogger(HtmlReporter.name); private _baseDir: string; private mainPromise: Promise; private mutantResults: MutantResult[]; @@ -43,7 +42,7 @@ export default class HtmlReporter implements Reporter { return this.cleanBaseFolder() .then(() => this.writeCommonResources()) .then(() => this.writeReportDirectory()) - .then(location => log.info(`Your report can be found at: ${fileUrl(location)}`)); + .then(location => this.log.info(`Your report can be found at: ${fileUrl(location)}`)); } private writeCommonResources() { @@ -106,9 +105,9 @@ export default class HtmlReporter implements Reporter { if (!this._baseDir) { if (this.options['htmlReporter'] && this.options['htmlReporter']['baseDir']) { this._baseDir = this.options['htmlReporter']['baseDir']; - log.debug(`Using configured output folder ${this._baseDir}`); + this.log.debug(`Using configured output folder ${this._baseDir}`); } else { - log.debug(`No base folder configuration found (using configuration: htmlReporter: { baseDir: 'output/folder' }), using default ${DEFAULT_BASE_FOLDER}`); + this.log.debug(`No base folder configuration found (using configuration: htmlReporter: { baseDir: 'output/folder' }), using default ${DEFAULT_BASE_FOLDER}`); this._baseDir = DEFAULT_BASE_FOLDER; } } diff --git a/packages/stryker-html-reporter/test/helpers/log4jsMock.ts b/packages/stryker-html-reporter/test/helpers/loggingMock.ts similarity index 85% rename from packages/stryker-html-reporter/test/helpers/log4jsMock.ts rename to packages/stryker-html-reporter/test/helpers/loggingMock.ts index 2e1a7080fb..1c084bcbdf 100644 --- a/packages/stryker-html-reporter/test/helpers/log4jsMock.ts +++ b/packages/stryker-html-reporter/test/helpers/loggingMock.ts @@ -1,4 +1,4 @@ -import * as log4js from 'stryker-api/logging'; +import * as logging from 'stryker-api/logging'; import * as sinon from 'sinon'; let logger = { @@ -16,7 +16,7 @@ let logger = { fatal: sinon.stub() }; -sinon.stub(log4js, 'getLogger').returns(logger); +sinon.stub(logging, 'getLogger').returns(logger); beforeEach(() => { logger.trace.reset(); diff --git a/packages/stryker-html-reporter/test/integration/MathReportSpec.ts b/packages/stryker-html-reporter/test/integration/MathReportSpec.ts index 328d40ffdf..640accd84e 100644 --- a/packages/stryker-html-reporter/test/integration/MathReportSpec.ts +++ b/packages/stryker-html-reporter/test/integration/MathReportSpec.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as path from 'path'; import { expect } from 'chai'; import { Config } from 'stryker-api/config'; -import logger from '../helpers/log4jsMock'; +import logger from '../helpers/loggingMock'; import EventPlayer from '../helpers/EventPlayer'; import fileUrl = require('file-url'); import HtmlReporter from '../../src/HtmlReporter'; diff --git a/packages/stryker-javascript-mutator/test/helpers/initSinon.ts b/packages/stryker-javascript-mutator/test/helpers/initSinon.ts index f94e4da3c2..825f513e46 100644 --- a/packages/stryker-javascript-mutator/test/helpers/initSinon.ts +++ b/packages/stryker-javascript-mutator/test/helpers/initSinon.ts @@ -1,11 +1,11 @@ import * as sinon from 'sinon'; -import * as log4js from 'stryker-api/logging'; +import * as logging from 'stryker-api/logging'; import LogMock from './LogMock'; beforeEach(() => { global.sandbox = sinon.createSandbox(); global.logMock = new LogMock(); - global.sandbox.stub(log4js, 'getLogger').returns(global.logMock); + global.sandbox.stub(logging, 'getLogger').returns(global.logMock); }); afterEach(() => { diff --git a/packages/stryker-jest-runner/src/jestTestAdapters/JestPromiseTestAdapter.ts b/packages/stryker-jest-runner/src/jestTestAdapters/JestPromiseTestAdapter.ts index 665e547d76..d2004f9098 100644 --- a/packages/stryker-jest-runner/src/jestTestAdapters/JestPromiseTestAdapter.ts +++ b/packages/stryker-jest-runner/src/jestTestAdapters/JestPromiseTestAdapter.ts @@ -1,5 +1,5 @@ import JestTestAdapter from './JestTestAdapter'; -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import { Configuration, runCLI, RunResult } from 'jest'; export default class JestPromiseTestAdapter implements JestTestAdapter { diff --git a/packages/stryker-jest-runner/src/jestTestAdapters/JestTestAdapterFactory.ts b/packages/stryker-jest-runner/src/jestTestAdapters/JestTestAdapterFactory.ts index 39839d0258..b1905b18e3 100644 --- a/packages/stryker-jest-runner/src/jestTestAdapters/JestTestAdapterFactory.ts +++ b/packages/stryker-jest-runner/src/jestTestAdapters/JestTestAdapterFactory.ts @@ -1,4 +1,4 @@ -import { getLogger } from 'log4js'; +import { getLogger } from 'stryker-api/logging'; import JestTestAdapter from './JestTestAdapter'; import JestPromiseAdapter from './JestPromiseTestAdapter'; diff --git a/packages/stryker-jest-runner/test/unit/JestTestRunnerSpec.ts b/packages/stryker-jest-runner/test/unit/JestTestRunnerSpec.ts index 66d481b1e8..2bc0c187a8 100644 --- a/packages/stryker-jest-runner/test/unit/JestTestRunnerSpec.ts +++ b/packages/stryker-jest-runner/test/unit/JestTestRunnerSpec.ts @@ -5,7 +5,7 @@ import * as fakeResults from '../helpers/testResultProducer'; import * as sinon from 'sinon'; import { assert, expect } from 'chai'; import { RunStatus, TestStatus } from 'stryker-api/test_runner'; -import * as log4js from 'log4js'; +import * as logging from 'stryker-api/logging'; describe('JestTestRunner', () => { const basePath = '/path/to/project/root'; @@ -26,7 +26,7 @@ describe('JestTestRunner', () => { runJestStub.resolves({ results: { testResults: [] } }); debugLoggerStub = sandbox.stub(); - sandbox.stub(log4js, 'getLogger').returns({ debug: debugLoggerStub }); + sandbox.stub(logging, 'getLogger').returns({ debug: debugLoggerStub }); strykerOptions = new Config; strykerOptions.set({ jest: { config: { property: 'value' } }, basePath }); diff --git a/packages/stryker-jest-runner/test/unit/jestTestAdapters/JestPromiseTestAdapterSpec.ts b/packages/stryker-jest-runner/test/unit/jestTestAdapters/JestPromiseTestAdapterSpec.ts index b15b6aa34e..3ab9f9afad 100644 --- a/packages/stryker-jest-runner/test/unit/jestTestAdapters/JestPromiseTestAdapterSpec.ts +++ b/packages/stryker-jest-runner/test/unit/jestTestAdapters/JestPromiseTestAdapterSpec.ts @@ -1,7 +1,7 @@ import JestPromiseTestAdapter from '../../../src/jestTestAdapters/JestPromiseTestAdapter'; import * as sinon from 'sinon'; import { expect, assert } from 'chai'; -import * as log4js from 'log4js'; +import * as logging from 'stryker-api/logging'; import * as jest from 'jest'; describe('JestPromiseTestAdapter', () => { @@ -24,7 +24,7 @@ describe('JestPromiseTestAdapter', () => { })); traceLoggerStub = sinon.stub(); - sandbox.stub(log4js, 'getLogger').returns({ trace: traceLoggerStub }); + sandbox.stub(logging, 'getLogger').returns({ trace: traceLoggerStub }); jestPromiseTestAdapter = new JestPromiseTestAdapter(); }); diff --git a/packages/stryker-karma-runner/src/starters/stryker-karma.conf.ts b/packages/stryker-karma-runner/src/starters/stryker-karma.conf.ts index 0d6637a104..88a8258fa7 100644 --- a/packages/stryker-karma-runner/src/starters/stryker-karma.conf.ts +++ b/packages/stryker-karma-runner/src/starters/stryker-karma.conf.ts @@ -3,7 +3,7 @@ import * as path from 'path'; import { requireModule } from '../utils'; import TestHooksMiddleware, { TEST_HOOKS_FILE_NAME } from '../TestHooksMiddleware'; import StrykerReporter from '../StrykerReporter'; -import { getLogger, Logger } from 'log4js'; +import { getLogger, Logger } from 'stryker-api/logging'; function setDefaultOptions(config: Config) { config.set({ diff --git a/packages/stryker-karma-runner/test/unit/starters/stryker-karma.confSpec.ts b/packages/stryker-karma-runner/test/unit/starters/stryker-karma.confSpec.ts index 5d6a65551b..bd3a995bc0 100644 --- a/packages/stryker-karma-runner/test/unit/starters/stryker-karma.confSpec.ts +++ b/packages/stryker-karma-runner/test/unit/starters/stryker-karma.confSpec.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import * as log4js from 'log4js'; +import * as logging from 'stryker-api/logging'; import sut = require('../../../src/starters/stryker-karma.conf'); import { Config, ConfigOptions } from 'karma'; import { expect } from 'chai'; @@ -17,7 +17,7 @@ describe('stryker-karma.conf.js', () => { beforeEach(() => { config = new KarmaConfigMock(); logMock = new LoggerStub(); - sandbox.stub(log4js, 'getLogger').returns(logMock); + sandbox.stub(logging, 'getLogger').returns(logMock); requireModuleStub = sandbox.stub(utils, 'requireModule'); }); @@ -27,7 +27,7 @@ describe('stryker-karma.conf.js', () => { it('should create the correct logger', () => { sut(config); - expect(log4js.getLogger).calledWith('stryker-karma.conf.js'); + expect(logging.getLogger).calledWith('stryker-karma.conf.js'); }); it('should set default options', () => { diff --git a/packages/stryker-mocha-runner/src/StrykerMochaReporter.ts b/packages/stryker-mocha-runner/src/StrykerMochaReporter.ts index 3cb7a4a980..b80d524570 100644 --- a/packages/stryker-mocha-runner/src/StrykerMochaReporter.ts +++ b/packages/stryker-mocha-runner/src/StrykerMochaReporter.ts @@ -1,11 +1,10 @@ import { RunResult, RunStatus, TestStatus } from 'stryker-api/test_runner'; -import * as log4js from 'stryker-api/logging'; +import { getLogger } from 'stryker-api/logging'; import Timer from './Timer'; -const log = log4js.getLogger('StrykerMochaReporter'); - export default class StrykerMochaReporter { - + + private readonly log = getLogger(StrykerMochaReporter.name); public runResult: RunResult; private timer = new Timer(); private passedCount = 0; @@ -26,7 +25,7 @@ export default class StrykerMochaReporter { tests: [], errorMessages: [] }; - log.debug('Starting Mocha test run'); + this.log.debug('Starting Mocha test run'); }); this.runner.on('pass', (test: any) => { @@ -37,7 +36,7 @@ export default class StrykerMochaReporter { }); this.passedCount++; this.timer.reset(); - log.debug(`Test passed: ${test.fullTitle()}`); + this.log.debug(`Test passed: ${test.fullTitle()}`); }); this.runner.on('fail', (test: any, err: any) => { @@ -51,12 +50,12 @@ export default class StrykerMochaReporter { this.runResult.errorMessages = []; } this.runResult.errorMessages.push(err.message); - log.debug(`Test failed: ${test.fullTitle()}. Error: ${err.message}`); + this.log.debug(`Test failed: ${test.fullTitle()}. Error: ${err.message}`); }); this.runner.on('end', () => { this.runResult.status = RunStatus.Complete; - log.debug(`Mocha test run completed: ${this.passedCount}/${this.runResult.tests.length} passed`); + this.log.debug(`Mocha test run completed: ${this.passedCount}/${this.runResult.tests.length} passed`); }); } } \ No newline at end of file diff --git a/packages/stryker-mocha-runner/test/unit/MochaOptionsLoaderSpec.ts b/packages/stryker-mocha-runner/test/unit/MochaOptionsLoaderSpec.ts index 857ce7efe6..854df633a9 100644 --- a/packages/stryker-mocha-runner/test/unit/MochaOptionsLoaderSpec.ts +++ b/packages/stryker-mocha-runner/test/unit/MochaOptionsLoaderSpec.ts @@ -3,7 +3,7 @@ import * as fs from 'fs'; import { Config } from 'stryker-api/config'; import MochaOptionsLoader from '../../src/MochaOptionsLoader'; import { expect } from 'chai'; -import * as log4js from 'stryker-api/logging'; +import * as logging from 'stryker-api/logging'; import MochaRunnerOptions from '../../src/MochaRunnerOptions'; import { logger, Mock } from '../helpers/mockHelpers'; @@ -12,11 +12,11 @@ describe('MochaOptionsLoader', () => { let readFileStub: sinon.SinonStub; let config: Config; let sut: MochaOptionsLoader; - let log: Mock; + let log: Mock; beforeEach(() => { log = logger(); - sandbox.stub(log4js, 'getLogger').returns(log); + sandbox.stub(logging, 'getLogger').returns(log); readFileStub = sandbox.stub(fs, 'readFileSync'); sut = new MochaOptionsLoader(); config = new Config(); diff --git a/packages/stryker-mocha-runner/test/unit/MochaTestRunnerSpec.ts b/packages/stryker-mocha-runner/test/unit/MochaTestRunnerSpec.ts index 063cdf8a66..dfbb531856 100644 --- a/packages/stryker-mocha-runner/test/unit/MochaTestRunnerSpec.ts +++ b/packages/stryker-mocha-runner/test/unit/MochaTestRunnerSpec.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import { EventEmitter } from 'events'; import * as Mocha from 'mocha'; -import * as log4js from 'stryker-api/logging'; +import * as logging from 'stryker-api/logging'; import { expect } from 'chai'; import { RunOptions } from 'stryker-api/test_runner'; import MochaTestRunner from '../../src/MochaTestRunner'; @@ -17,7 +17,7 @@ describe('MochaTestRunner', () => { let sut: MochaTestRunner; let requireStub: sinon.SinonStub; let multimatchStub: sinon.SinonStub; - let log: Mock; + let log: Mock; beforeEach(() => { MochaStub = sandbox.stub(LibWrapper, 'Mocha'); @@ -28,7 +28,7 @@ describe('MochaTestRunner', () => { mocha.suite = mock(EventEmitter); MochaStub.returns(mocha); log = logger(); - sandbox.stub(log4js, 'getLogger').returns(log); + sandbox.stub(logging, 'getLogger').returns(log); }); afterEach(() => { diff --git a/packages/stryker-typescript/test/unit/TypescriptConfigEditorSpec.ts b/packages/stryker-typescript/test/unit/TypescriptConfigEditorSpec.ts index 8a9d726433..244356bb1d 100644 --- a/packages/stryker-typescript/test/unit/TypescriptConfigEditorSpec.ts +++ b/packages/stryker-typescript/test/unit/TypescriptConfigEditorSpec.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as log4js from 'stryker-api/logging'; +import * as logging from 'stryker-api/logging'; import * as ts from 'typescript'; import { expect } from 'chai'; import { SinonStub, match } from 'sinon'; @@ -27,7 +27,7 @@ describe('TypescriptConfigEditor edit', () => { info: sandbox.stub(), error: sandbox.stub() }; - sandbox.stub(log4js, 'getLogger').returns(loggerStub); + sandbox.stub(logging, 'getLogger').returns(loggerStub); config = new Config(); sut = new TypescriptConfigEditor(); }); diff --git a/packages/stryker-webpack-transpiler/test/helpers/sinonInit.ts b/packages/stryker-webpack-transpiler/test/helpers/sinonInit.ts index f4e5baea1f..99416bd9a7 100644 --- a/packages/stryker-webpack-transpiler/test/helpers/sinonInit.ts +++ b/packages/stryker-webpack-transpiler/test/helpers/sinonInit.ts @@ -1,5 +1,5 @@ import * as sinon from 'sinon'; -import * as log4js from 'stryker-api/logging'; +import * as logging from 'stryker-api/logging'; beforeEach(() => { global.sandbox = sinon.sandbox.create(); @@ -9,7 +9,7 @@ beforeEach(() => { warn: sandbox.stub(), error: sandbox.stub() }; - sandbox.stub(log4js, 'getLogger').returns(global.logMock); + sandbox.stub(logging, 'getLogger').returns(global.logMock); }); afterEach(() => { diff --git a/packages/stryker/README.md b/packages/stryker/README.md index a943622750..b07e9e6338 100644 --- a/packages/stryker/README.md +++ b/packages/stryker/README.md @@ -323,7 +323,7 @@ It is not allowed to only supply one value of the values (it's all or nothing). *Note*: Test runners are run as child processes of the Stryker Node process. All output (stdout) of the `testRunner` is logged as `trace`. Thus, to see logging output from the test runner set the `logLevel` to `all` or `trace`. -#### Log level +#### File log level **Command line:** `--fileLogLevel info` **Config file:** `fileLogLevel: 'info'` **Default value:** `off` diff --git a/packages/stryker/src/Stryker.ts b/packages/stryker/src/Stryker.ts index 1de9880a3d..acd4a4061f 100644 --- a/packages/stryker/src/Stryker.ts +++ b/packages/stryker/src/Stryker.ts @@ -36,14 +36,14 @@ export default class Stryker { * @param {Object} [options] - Optional options. */ constructor(options: StrykerOptions) { - LogConfigurator.forMaster(options.logLevel, options.fileLogLevel); + LogConfigurator.configureMainProcess(options.logLevel, options.fileLogLevel); this.log = getLogger(Stryker.name); let configReader = new ConfigReader(options); this.config = configReader.readConfig(); - LogConfigurator.forMaster(this.config.logLevel, this.config.fileLogLevel); // logLevel could be changed + LogConfigurator.configureMainProcess(this.config.logLevel, this.config.fileLogLevel); // logLevel could be changed this.loadPlugins(); this.applyConfigEditors(); - LogConfigurator.forMaster(this.config.logLevel, this.config.fileLogLevel); // logLevel could be changed + LogConfigurator.configureMainProcess(this.config.logLevel, this.config.fileLogLevel); // logLevel could be changed this.freezeConfig(); this.reporter = new ReporterOrchestrator(this.config).createBroadcastReporter(); this.testFramework = new TestFrameworkOrchestrator(this.config).determineTestFramework(); @@ -51,7 +51,7 @@ export default class Stryker { } async runMutationTest(): Promise { - const loggingContext = await LogConfigurator.forServer(this.config.logLevel, this.config.fileLogLevel); + const loggingContext = await LogConfigurator.configureLoggingServer(this.config.logLevel, this.config.fileLogLevel); this.timer.reset(); const inputFiles = await new InputFileResolver(this.config.mutate, this.config.files, this.reporter).resolve(); if (inputFiles.files.length) { diff --git a/packages/stryker/src/StrykerCli.ts b/packages/stryker/src/StrykerCli.ts index c16d782506..0da8904f2a 100644 --- a/packages/stryker/src/StrykerCli.ts +++ b/packages/stryker/src/StrykerCli.ts @@ -49,7 +49,7 @@ export default class StrykerCli { .option('--fileLogLevel ', 'Set the log4js log level for the "stryker.log" file. Possible values: fatal, error, warn, info, debug, trace, all and off. Default is "off"') .parse(this.argv); - LogConfigurator.forMaster(program['logLevel']); + LogConfigurator.configureMainProcess(program['logLevel']); const log = getLogger(StrykerCli.name); // Cleanup commander state delete program['options']; diff --git a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts index 008ce8e2f3..d7a8d8c981 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts @@ -27,7 +27,7 @@ export default class ChildProcessProxyWorker { const message = deserialize(serializedMessage, [File]); switch (message.kind) { case WorkerMessageKind.Init: - LogConfigurator.forWorker(message.loggingContext); + LogConfigurator.configureChildProcess(message.loggingContext); this.log = getLogger(ChildProcessProxyWorker.name); new PluginLoader(message.plugins).load(); const RealSubjectClass = require(message.requirePath).default; diff --git a/packages/stryker/src/config/ConfigReader.ts b/packages/stryker/src/config/ConfigReader.ts index 6357f7fc74..3f2feecc8d 100644 --- a/packages/stryker/src/config/ConfigReader.ts +++ b/packages/stryker/src/config/ConfigReader.ts @@ -1,7 +1,7 @@ import { Config } from 'stryker-api/config'; import { StrykerOptions } from 'stryker-api/core'; import * as fs from 'mz/fs'; -import * as log4js from 'stryker-api/logging'; +import { getLogger } from 'stryker-api/logging'; import * as path from 'path'; import * as _ from 'lodash'; import StrykerError from '../utils/StrykerError'; @@ -16,7 +16,7 @@ const DEFAULT_CONFIG_FILE = 'stryker.conf.js'; export default class ConfigReader { - private readonly log = log4js.getLogger(ConfigReader.name); + private readonly log = getLogger(ConfigReader.name); constructor(private cliOptions: StrykerOptions) { } diff --git a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts index af28cbbcd9..45a6bf156b 100644 --- a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts +++ b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts @@ -60,7 +60,7 @@ class IsolatedTestRunnerAdapterWorker { } start(message: StartMessage) { - LogConfigurator.forWorker(message.runnerOptions.loggingContext); + LogConfigurator.configureChildProcess(message.runnerOptions.loggingContext); this.log = getLogger(IsolatedTestRunnerAdapterWorker.name); this.loadPlugins(message.runnerOptions.strykerOptions.plugins || []); this.log.debug(`Changing current working directory for this process to ${message.runnerOptions.sandboxWorkingFolder}`); diff --git a/packages/stryker/src/logging/LogConfigurator.ts b/packages/stryker/src/logging/LogConfigurator.ts index c24e64fc36..e8192810da 100644 --- a/packages/stryker/src/logging/LogConfigurator.ts +++ b/packages/stryker/src/logging/LogConfigurator.ts @@ -32,9 +32,11 @@ interface AppendersConfiguration { const LOG_FILE_NAME = 'stryker.log'; export default class LogConfigurator { - private static createMasterAppenders(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): AppendersConfiguration { + private static createMainProcessAppenders(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): AppendersConfiguration { + // Add the custom "multiAppender": https://log4js-node.github.io/log4js-node/appenders.html#other-appenders const multiAppender = { type: require.resolve('./MultiAppender'), appenders: ['filteredConsole'] }; + let allAppenders: AppendersConfiguration = { [AppenderName.Console]: { type: 'stdout', layout: layouts.color }, [AppenderName.FilteredConsole]: { type: 'logLevelFilter', appender: 'console', level: consoleLogLevel }, @@ -72,28 +74,31 @@ export default class LogConfigurator { } /** - * Configure logging for the master process. Either call this method or `forWorker` before any `getLogger` calls. + * Configure logging for the master process. Either call this method or `configureChildProcess` before any `getLogger` calls. * @param consoleLogLevel The log level to configure for the console * @param fileLogLevel The log level to configure for the "stryker.log" file */ - static forMaster(consoleLogLevel: LogLevel = LogLevel.Information, fileLogLevel: LogLevel = LogLevel.Off) { + static configureMainProcess(consoleLogLevel: LogLevel = LogLevel.Information, fileLogLevel: LogLevel = LogLevel.Off) { this.setImplementation(); - const appenders = this.createMasterAppenders(consoleLogLevel, fileLogLevel); + const appenders = this.createMainProcessAppenders(consoleLogLevel, fileLogLevel); log4js.configure(this.createLog4jsConfig(minLevel(consoleLogLevel, fileLogLevel), appenders)); } /** * Configure the logging for the server. Includes the master configuration. - * This method can only be called ONCE, as it starts the log4js server to listen for log events. - * It returns the logging client context that should be used to doe the `forWorker` calls. + * This method should only be called ONCE, as it starts the log4js server to listen for log events. + * It returns the logging client context that should be used to configure the child processes. + * * @param consoleLogLevel the console log level * @param fileLogLevel the file log level * @returns the context */ - static async forServer(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): Promise { + static async configureLoggingServer(consoleLogLevel: LogLevel, fileLogLevel: LogLevel): Promise { this.setImplementation(); const loggerPort = await getFreePort(); - const appenders = this.createMasterAppenders(consoleLogLevel, fileLogLevel); + + // Include the appenders for the main Stryker process, as log4js has only one single `configure` method. + const appenders = this.createMainProcessAppenders(consoleLogLevel, fileLogLevel); const multiProcessAppender: log4js.MultiprocessAppender = { type: 'multiprocess', mode: 'master', @@ -114,10 +119,10 @@ export default class LogConfigurator { /** * Configures the logging for a worker process. Sends all logging to the master process. - * Either call this method or `forMaster` before any `getLogger` calls. + * Either call this method or `configureMainProcess` before any `getLogger` calls. * @param context the logging client context used to configure the logging client */ - static forWorker(context: LoggingClientContext) { + static configureChildProcess(context: LoggingClientContext) { this.setImplementation(); const clientAppender: log4js.MultiprocessAppender = { type: 'multiprocess', mode: 'worker', loggerPort: context.port }; const appenders: AppendersConfiguration = { [AppenderName.All]: clientAppender }; diff --git a/packages/stryker/src/logging/LoggingClientContext.ts b/packages/stryker/src/logging/LoggingClientContext.ts index c1b757a69e..2c7a5d345f 100644 --- a/packages/stryker/src/logging/LoggingClientContext.ts +++ b/packages/stryker/src/logging/LoggingClientContext.ts @@ -2,6 +2,12 @@ import { LogLevel } from 'stryker-api/core'; export default interface LoggingClientContext { + /** + * The port where the logging server listens for logging events on the localhost + */ readonly port: number; + /** + * The minimal log level to use for configuration + */ readonly level: LogLevel; } \ No newline at end of file diff --git a/packages/stryker/src/logging/MultiAppender.ts b/packages/stryker/src/logging/MultiAppender.ts index 175eb79fa7..39f505ee93 100644 --- a/packages/stryker/src/logging/MultiAppender.ts +++ b/packages/stryker/src/logging/MultiAppender.ts @@ -13,6 +13,14 @@ export class MultiAppender { } } +/** + * This method is expected by log4js to have this _exact_ name + * and signature. + * @see https://log4js-node.github.io/log4js-node/writing-appenders.html + * @param config The appender configuration delivered by log4js + * @param _ The layouts provided by log4js + * @param findAppender A method to locate other appenders + */ export function configure(config: { appenders: string[] }, _: any, findAppender: (name: string) => RuntimeAppender ): RuntimeAppender { const multiAppender = new MultiAppender(config.appenders.map(name => findAppender(name))); return multiAppender.append.bind(multiAppender); diff --git a/packages/stryker/src/logging/logUtils.ts b/packages/stryker/src/logging/logUtils.ts index 54e51413d3..4de24a60b5 100644 --- a/packages/stryker/src/logging/logUtils.ts +++ b/packages/stryker/src/logging/logUtils.ts @@ -7,14 +7,9 @@ import * as log4js from 'log4js'; * @param b other log level */ export function minLevel(a: LogLevel, b: LogLevel) { - if (getLevel(b).isGreaterThanOrEqualTo(getLevel(a))) { + if (log4js.levels.getLevel(b).isGreaterThanOrEqualTo(log4js.levels.getLevel(a))) { return a; } else { return b; } } - -function getLevel(level: LogLevel): log4js.Level { - // Needs an any cast here, wrongly typed, see https://github.com/log4js-node/log4js-node/pull/745 - return (log4js.levels as any).getLevel(level); -} diff --git a/packages/stryker/src/utils/netUtils.ts b/packages/stryker/src/utils/netUtils.ts index 79ea9dc040..1ef6b28ab9 100644 --- a/packages/stryker/src/utils/netUtils.ts +++ b/packages/stryker/src/utils/netUtils.ts @@ -1,3 +1,6 @@ import * as getPortModule from 'get-port'; +/** + * A wrapper around `getPort` for testing purposes + */ export const getFreePort = getPortModule; \ No newline at end of file diff --git a/packages/stryker/stryker.conf.js b/packages/stryker/stryker.conf.js index a978330e52..e50fe48a8e 100644 --- a/packages/stryker/stryker.conf.js +++ b/packages/stryker/stryker.conf.js @@ -15,7 +15,7 @@ module.exports = function (config) { '!test/**/*.d.ts' ], symlinkNodeModules: false, - mutate: ['src/Stryker.ts'], + mutate: ['src/**/*.ts'], coverageAnalysis: 'perTest', tsconfigFile: 'tsconfig.json', mutator: 'typescript', diff --git a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts index 2237cec5e3..74d30c6145 100644 --- a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts +++ b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactorySpec.ts @@ -67,7 +67,7 @@ describe('ResilientTestRunnerFactory', function () { before(() => sut = ResilientTestRunnerFactory.create('coverage-reporting', options)); it('should not be overridden by the worker', - () => expect(sut.run({ timeout: 3000 })).to.eventually.have.property('coverage', 'realCoverage')); + () => expect(sut.run({ timeout: 4000 })).to.eventually.have.property('coverage', 'realCoverage')); after(() => sut.dispose()); }); diff --git a/packages/stryker/test/unit/StrykerSpec.ts b/packages/stryker/test/unit/StrykerSpec.ts index 6f75398358..687ae4e342 100644 --- a/packages/stryker/test/unit/StrykerSpec.ts +++ b/packages/stryker/test/unit/StrykerSpec.ts @@ -55,8 +55,8 @@ describe('Stryker', function () { let reporter: Mock; let tempFolderMock: Mock; let scoreResultCalculator: ScoreResultCalculator; - let logConfiguratorForMasterStub: sinon.SinonStub; - let logConfiguratorForServerStub: sinon.SinonStub; + let configureMainProcessStub: sinon.SinonStub; + let configureLoggingServerStub: sinon.SinonStub; beforeEach(() => { strykerConfig = config(); @@ -68,9 +68,9 @@ describe('Stryker', function () { const reporterOrchestratorMock = mock(ReporterOrchestrator); mutantRunResultMatcherMock = mock(MutantRunResultMatcher); mutatorMock = mock(MutatorFacade); - logConfiguratorForMasterStub = sandbox.stub(LogConfigurator, 'forMaster'); - logConfiguratorForServerStub = sandbox.stub(LogConfigurator, 'forServer'); - logConfiguratorForServerStub.resolves(LOGGING_CONTEXT); + configureMainProcessStub = sandbox.stub(LogConfigurator, 'configureMainProcess'); + configureLoggingServerStub = sandbox.stub(LogConfigurator, 'configureLoggingServer'); + configureLoggingServerStub.resolves(LOGGING_CONTEXT); inputFileResolverMock = mock(InputFileResolver); reporterOrchestratorMock.createBroadcastReporter.returns(reporter); testFramework = testFrameworkMock(); @@ -108,7 +108,7 @@ describe('Stryker', function () { }); it('should configure logging for master', () => { - expect(logConfiguratorForMasterStub).calledThrice; + expect(configureMainProcessStub).calledThrice; }); it('should freeze the config', () => { @@ -166,7 +166,7 @@ describe('Stryker', function () { it('should reject when logging server rejects', async () => { const expectedError = Error('expected error'); - logConfiguratorForServerStub.rejects(expectedError); + configureLoggingServerStub.rejects(expectedError); await expect(sut.runMutationTest()).rejectedWith(expectedError); }); @@ -216,7 +216,7 @@ describe('Stryker', function () { }); it('should configure the logging server', () => { - expect(logConfiguratorForServerStub).calledWith(strykerConfig.logLevel, strykerConfig.fileLogLevel); + expect(configureLoggingServerStub).calledWith(strykerConfig.logLevel, strykerConfig.fileLogLevel); }); it('should report mutant score', () => { diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts index 49719ac7a2..b4791db94c 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts @@ -16,7 +16,7 @@ describe('ChildProcessProxyWorker', () => { let processOnStub: sinon.SinonStub; let processSendStub: sinon.SinonStub; let processListenersStub: sinon.SinonStub; - let logConfiguratorForWorkerStub: sinon.SinonStub; + let configureChildProcessStub: sinon.SinonStub; let processRemoveListenerStub: sinon.SinonStub; let pluginLoaderMock: Mock; let originalProcessSend: undefined | NodeJS.MessageListener; @@ -32,7 +32,7 @@ describe('ChildProcessProxyWorker', () => { // process.send is normally undefined originalProcessSend = process.send; process.send = processSendStub; - logConfiguratorForWorkerStub = sandbox.stub(LogConfigurator, 'forWorker'); + configureChildProcessStub = sandbox.stub(LogConfigurator, 'configureChildProcess'); pluginLoaderMock = mock(PluginLoader); sandbox.stub(pluginLoader, 'default').returns(pluginLoaderMock); }); @@ -91,7 +91,7 @@ describe('ChildProcessProxyWorker', () => { it('should set global log level', () => { processOnStub.callArgWith(1, serialize(initMessage)); - expect(logConfiguratorForWorkerStub).calledWith(LOGGING_CONTEXT); + expect(configureChildProcessStub).calledWith(LOGGING_CONTEXT); }); it('should load plugins', () => { diff --git a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts index 0979a1a0a3..edca8d9618 100644 --- a/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts +++ b/packages/stryker/test/unit/logging/LogConfiguratorSpec.ts @@ -18,14 +18,14 @@ describe('LogConfigurator', () => { log4jsShutdown = sandbox.stub(log4js, 'shutdown'); }); - describe('forMaster', () => { + describe('configureMainProcess', () => { it('should configure console and file', () => { - sut.forMaster(LogLevel.Information, LogLevel.Trace); + sut.configureMainProcess(LogLevel.Information, LogLevel.Trace); expect(log4jsConfigure).calledWith(createMasterConfig(LogLevel.Information, LogLevel.Trace, LogLevel.Trace)); }); it('should not configure file if it is "off"', () => { - sut.forMaster(LogLevel.Information, LogLevel.Off); + sut.configureMainProcess(LogLevel.Information, LogLevel.Off); const masterConfig = createMasterConfig(LogLevel.Information, LogLevel.Off, LogLevel.Information); delete masterConfig.appenders.file; delete masterConfig.appenders.filteredFile; @@ -34,7 +34,7 @@ describe('LogConfigurator', () => { }); }); - describe('forServer', () => { + describe('configureLoggingServer', () => { it('should configure console, file and server', async () => { // Arrange const expectedLoggingContext: LoggingClientContext = { port: 42, level: LogLevel.Error }; @@ -44,7 +44,7 @@ describe('LogConfigurator', () => { expectedConfig.appenders.server = serverAppender; // Act - const actualLoggingContext = await sut.forServer(LogLevel.Error, LogLevel.Fatal); + const actualLoggingContext = await sut.configureLoggingServer(LogLevel.Error, LogLevel.Fatal); // Assert expect(log4jsConfigure).calledWith(expectedConfig); @@ -54,9 +54,9 @@ describe('LogConfigurator', () => { }); - describe('forWorker', () => { + describe('configureChildProcess', () => { it('should configure the logging client', () => { - sut.forWorker({ port: 42, level: LogLevel.Information }); + sut.configureChildProcess({ port: 42, level: LogLevel.Information }); const multiProcessAppender: log4js.MultiprocessAppender = { type: 'multiprocess', mode: 'worker', loggerPort: 42 }; const expectedConfig: log4js.Configuration = { appenders: { From c37a500e8a0ea376c9ec58c616b892168f108190 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Fri, 13 Jul 2018 16:44:09 +0200 Subject: [PATCH 29/54] refactor(mapped-types): Make use of conditional types to describe child process interface --- .../stryker/src/child-proxy/ChildProcessProxy.ts | 12 +++++++++--- packages/stryker/src/transpiler/MutantTranspiler.ts | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index e5fd08ca90..e7a34768d7 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -6,12 +6,18 @@ import { serialize, deserialize } from '../utils/objectUtils'; import Task from '../utils/Task'; import LoggingClientContext from '../logging/LoggingClientContext'; -export type ChildProxy = { - [K in keyof T]: (...args: any[]) => Promise; +type MethodPromised = { (...args: any[]): Promise }; + +export type Promisified = { + [K in keyof T]: T[K] extends MethodPromised ? T[K] : (...args: any[]) => Promise; }; +// Missing features: +// 1. CWD this.log.debug(`Changing current working directory for this process to ${message.runnerOptions.sandboxWorkingFolder}`); +// 2. Error handling + export default class ChildProcessProxy { - readonly proxy: ChildProxy = {} as ChildProxy; + readonly proxy: Promisified = {} as Promisified; private worker: ChildProcess; private initTask: Task; diff --git a/packages/stryker/src/transpiler/MutantTranspiler.ts b/packages/stryker/src/transpiler/MutantTranspiler.ts index 18892af347..8dec457242 100644 --- a/packages/stryker/src/transpiler/MutantTranspiler.ts +++ b/packages/stryker/src/transpiler/MutantTranspiler.ts @@ -4,7 +4,7 @@ import TranspilerFacade from './TranspilerFacade'; import TestableMutant from '../TestableMutant'; import { File } from 'stryker-api/core'; import SourceFile from '../SourceFile'; -import ChildProcessProxy, { ChildProxy } from '../child-proxy/ChildProcessProxy'; +import ChildProcessProxy, { Promisified } from '../child-proxy/ChildProcessProxy'; import { TranspilerOptions } from 'stryker-api/transpile'; import TranspiledMutant from '../TranspiledMutant'; import TranspileResult from './TranspileResult'; @@ -14,7 +14,7 @@ import LoggingClientContext from '../logging/LoggingClientContext'; export default class MutantTranspiler { private transpilerChildProcess: ChildProcessProxy | undefined; - private proxy: ChildProxy; + private proxy: Promisified; private currentMutatedFile: SourceFile; private unMutatedFiles: ReadonlyArray; From e1a51918cc49a8fb86faa9157c6b50b301ad8163 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Wed, 18 Jul 2018 18:30:31 +0200 Subject: [PATCH 30/54] Temp commit --- .../stryker/src/child-proxy/ChildProcessProxy.ts | 15 +++++++++------ .../src/child-proxy/ChildProcessProxyWorker.ts | 11 ++++++++--- .../stryker/src/child-proxy/messageProtocol.ts | 8 ++++---- .../child-proxy/ChildProcessProxy.it.ts | 6 +++++- .../stryker/test/integration/child-proxy/Echo.ts | 2 +- .../unit/child-proxy/ChildProcessProxySpec.ts | 2 +- .../unit/child-proxy/ChildProcessWorkerSpec.ts | 16 ++++++++-------- 7 files changed, 36 insertions(+), 24 deletions(-) diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index e7a34768d7..e6ecfd7b2f 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -9,9 +9,12 @@ import LoggingClientContext from '../logging/LoggingClientContext'; type MethodPromised = { (...args: any[]): Promise }; export type Promisified = { - [K in keyof T]: T[K] extends MethodPromised ? T[K] : (...args: any[]) => Promise; + [K in keyof T]: T[K] extends MethodPromised ? T[K] : T[K] extends Function ? MethodPromised : () => Promise; }; + + + // Missing features: // 1. CWD this.log.debug(`Changing current working directory for this process to ${message.runnerOptions.sandboxWorkingFolder}`); // 2. Error handling @@ -60,24 +63,24 @@ export default class ChildProcessProxy { private initProxy() { Object.keys(this.constructorFunction.prototype).forEach(methodName => { - this.proxyMethod(methodName as keyof T); + this.proxyMethod(methodName); }); } - private proxyMethod(methodName: any) { - this.proxy[(methodName as keyof T)] = (...args: any[]) => { + private proxyMethod(methodName: string) { + this.proxy[methodName as keyof T] = ((...args: any[]) => { const workerTask = new Task(); this.initTask.promise.then(() => { const correlationId = this.workerTasks.push(workerTask) - 1; this.send({ - kind: WorkerMessageKind.Work, + kind: WorkerMessageKind.Call, correlationId, methodName, args }); }); return workerTask.promise; - }; + }) as any; } private listenToWorkerMessages() { diff --git a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts index d7a8d8c981..574f784fea 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts @@ -1,7 +1,7 @@ import { getLogger, Logger } from 'stryker-api/logging'; import { File } from 'stryker-api/core'; import { serialize, deserialize, errorToString } from '../utils/objectUtils'; -import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol'; +import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind, CallMessage } from './messageProtocol'; import PluginLoader from '../PluginLoader'; import LogConfigurator from '../logging/LogConfigurator'; @@ -35,8 +35,8 @@ export default class ChildProcessProxyWorker { this.send({ kind: ParentMessageKind.Initialized }); this.removeAnyAdditionalMessageListeners(handler); break; - case WorkerMessageKind.Work: - new Promise(resolve => resolve(this.realSubject[message.methodName](...message.args))) + case WorkerMessageKind.Call: + new Promise(resolve => resolve(this.doCall(message))) .then(result => { this.send({ kind: ParentMessageKind.Result, @@ -65,6 +65,11 @@ export default class ChildProcessProxyWorker { process.on('message', handler); } + private doCall(message: CallMessage): {} | PromiseLike<{}> | undefined { + if( this.realSubject[message.methodName]) + return this.realSubject[message.methodName](...message.args); + } + /** * Remove any addition message listeners that might me eavesdropping. * the @ngtools/webpack plugin listens to messages and throws an error whenever it could not handle a message diff --git a/packages/stryker/src/child-proxy/messageProtocol.ts b/packages/stryker/src/child-proxy/messageProtocol.ts index b93669aec5..0bea20f727 100644 --- a/packages/stryker/src/child-proxy/messageProtocol.ts +++ b/packages/stryker/src/child-proxy/messageProtocol.ts @@ -2,7 +2,7 @@ import LoggingClientContext from '../logging/LoggingClientContext'; export enum WorkerMessageKind { 'Init', - 'Work', + 'Call', 'Dispose' } @@ -13,7 +13,7 @@ export enum ParentMessageKind { 'DisposeCompleted' } -export type WorkerMessage = InitMessage | WorkMessage | { kind: WorkerMessageKind.Dispose }; +export type WorkerMessage = InitMessage | CallMessage | { kind: WorkerMessageKind.Dispose }; export type ParentMessage = WorkResult | { kind: ParentMessageKind.Initialized | ParentMessageKind.DisposeCompleted } | RejectionResult; // Make this an unlikely command line argument @@ -40,9 +40,9 @@ export interface RejectionResult { error: string; } -export interface WorkMessage { +export interface CallMessage { correlationId: number; - kind: WorkerMessageKind.Work; + kind: WorkerMessageKind.Call; args: any[]; methodName: string; } diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index 43abe6b0c2..8c953c6c6d 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -7,7 +7,7 @@ import * as getPort from 'get-port'; import Task from '../../../src/utils/Task'; import LoggingServer from '../../helpers/LoggingServer'; -describe('ChildProcessProxy', function () { +describe.only('ChildProcessProxy', function () { this.timeout(15000); let sut: ChildProcessProxy; @@ -48,6 +48,10 @@ describe('ChildProcessProxy', function () { it('should be able to receive a promise rejection', () => { return expect(sut.proxy.reject('Foobar error')).rejectedWith('Foobar error'); }); + + it.only('should be able to receive public properties as promised', () => { + return expect(sut.proxy.name()).eventually.eq('Echo'); + }); it('should be able to log on debug when LogLevel.Debug is allowed', async () => { const firstLogEventTask = new Task(); diff --git a/packages/stryker/test/integration/child-proxy/Echo.ts b/packages/stryker/test/integration/child-proxy/Echo.ts index 71abd62a25..37acbefa3e 100644 --- a/packages/stryker/test/integration/child-proxy/Echo.ts +++ b/packages/stryker/test/integration/child-proxy/Echo.ts @@ -5,7 +5,7 @@ export default class Echo { private logger = getLogger(Echo.name); - constructor(private name: string) { + constructor(public name: string) { } diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 7d02507055..2861b22327 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -76,7 +76,7 @@ describe('ChildProcessProxy', () => { result: 'ack' }; const expectedWorkerMessage: WorkerMessage = { - kind: WorkerMessageKind.Work, + kind: WorkerMessageKind.Call, correlationId: 0, methodName: 'sayHello', args: ['echo'] diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts index b4791db94c..5202dbc1e8 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts @@ -1,7 +1,7 @@ import ChildProcessProxyWorker from '../../../src/child-proxy/ChildProcessProxyWorker'; import { expect } from 'chai'; import { serialize } from '../../../src/utils/objectUtils'; -import { WorkerMessage, WorkerMessageKind, ParentMessage, WorkResult, WorkMessage, ParentMessageKind } from '../../../src/child-proxy/messageProtocol'; +import { WorkerMessage, WorkerMessageKind, ParentMessage, WorkResult, CallMessage, ParentMessageKind } from '../../../src/child-proxy/messageProtocol'; import PluginLoader, * as pluginLoader from '../../../src/PluginLoader'; import { Mock, mock } from '../../helpers/producers'; import HelloClass from './HelloClass'; @@ -103,7 +103,7 @@ describe('ChildProcessProxyWorker', () => { describe('on worker message', () => { - async function actAndAssert(workerMessage: WorkMessage, expectedResult: WorkResult) { + async function actAndAssert(workerMessage: CallMessage, expectedResult: WorkResult) { // Act processOnStub.callArgWith(1, serialize(initMessage)); processOnStub.callArgWith(1, serialize(workerMessage)); @@ -112,7 +112,7 @@ describe('ChildProcessProxyWorker', () => { expect(processSendStub).calledWith(serialize(expectedResult)); } - async function actAndAssertRejection(workerMessage: WorkMessage, expectedError: string) { + async function actAndAssertRejection(workerMessage: CallMessage, expectedError: string) { // Act processOnStub.callArgWith(1, serialize(initMessage)); processOnStub.callArgWith(1, serialize(workerMessage)); @@ -126,7 +126,7 @@ describe('ChildProcessProxyWorker', () => { it('should send the result', async () => { // Arrange const workerMessage: WorkerMessage = { - kind: WorkerMessageKind.Work, + kind: WorkerMessageKind.Call, correlationId: 32, args: [], methodName: 'sayHello' @@ -143,7 +143,7 @@ describe('ChildProcessProxyWorker', () => { it('should send a rejection', async () => { // Arrange const workerMessage: WorkerMessage = { - kind: WorkerMessageKind.Work, + kind: WorkerMessageKind.Call, correlationId: 32, args: [], methodName: 'reject' @@ -154,7 +154,7 @@ describe('ChildProcessProxyWorker', () => { it('should send a thrown synchronous error as rejection', async () => { // Arrange const workerMessage: WorkerMessage = { - kind: WorkerMessageKind.Work, + kind: WorkerMessageKind.Call, correlationId: 32, args: ['foo bar'], methodName: 'throw' @@ -165,7 +165,7 @@ describe('ChildProcessProxyWorker', () => { it('should use correct arguments', async () => { // Arrange const workerMessage: WorkerMessage = { - kind: WorkerMessageKind.Work, + kind: WorkerMessageKind.Call, correlationId: 32, args: ['foo', 'bar', 'chair'], methodName: 'say' @@ -182,7 +182,7 @@ describe('ChildProcessProxyWorker', () => { it('should work with promises from real class', async () => { // Arrange const workerMessage: WorkerMessage = { - kind: WorkerMessageKind.Work, + kind: WorkerMessageKind.Call, correlationId: 32, args: [], methodName: 'sayDelayed' From 6054561615f9b1eb2192527c19ad4e346c26624a Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 21 Jul 2018 00:37:33 +0200 Subject: [PATCH 31/54] feat(ChildProcess): improve resilience * Make use of `Proxy` class to forward methods * Handle unexpected 'exit' events * Use kill tree --- .../src/child-proxy/ChildProcessProxy.ts | 154 +++++++++++----- .../child-proxy/ChildProcessProxyWorker.ts | 31 +++- .../src/child-proxy/messageProtocol.ts | 5 +- .../src/transpiler/MutantTranspiler.ts | 1 + .../child-proxy/ChildProcessProxy.it.ts | 24 ++- .../test/integration/child-proxy/Echo.ts | 4 + .../ResilientTestRunnerFactory.it.ts | 7 +- .../unit/child-proxy/ChildProcessProxySpec.ts | 170 +++++++++++++++--- .../child-proxy/ChildProcessWorkerSpec.ts | 68 +++++-- .../unit/transpiler/MutantTranspilerSpec.ts | 1 + tsconfig.json | 3 +- 11 files changed, 376 insertions(+), 92 deletions(-) diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index e6ecfd7b2f..17f69aceb0 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -1,10 +1,12 @@ +import * as os from 'os'; import { fork, ChildProcess } from 'child_process'; import { File } from 'stryker-api/core'; import { getLogger } from 'stryker-api/logging'; import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol'; -import { serialize, deserialize } from '../utils/objectUtils'; +import { serialize, deserialize, kill } from '../utils/objectUtils'; import Task from '../utils/Task'; import LoggingClientContext from '../logging/LoggingClientContext'; +import StrykerError from '../utils/StrykerError'; type MethodPromised = { (...args: any[]): Promise }; @@ -12,78 +14,92 @@ export type Promisified = { [K in keyof T]: T[K] extends MethodPromised ? T[K] : T[K] extends Function ? MethodPromised : () => Promise; }; - - - -// Missing features: -// 1. CWD this.log.debug(`Changing current working directory for this process to ${message.runnerOptions.sandboxWorkingFolder}`); -// 2. Error handling - export default class ChildProcessProxy { - readonly proxy: Promisified = {} as Promisified; + readonly proxy: Promisified; private worker: ChildProcess; private initTask: Task; - private disposeTask: Task; + private disposeTask: Task | undefined; + private currentError: StrykerError | undefined; private workerTasks: Task[] = []; private log = getLogger(ChildProcessProxy.name); + private lastMessagesQueue: string[] = []; + private isDisposed = false; - private constructor(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], private constructorFunction: { new(...params: any[]): T }, constructorParams: any[]) { - this.worker = fork(require.resolve('./ChildProcessProxyWorker'), [autoStart], { silent: false, execArgv: [] }); + private constructor(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, constructorParams: any[]) { + this.worker = fork(require.resolve('./ChildProcessProxyWorker'), [autoStart], { silent: true, execArgv: [] }); this.initTask = new Task(); this.send({ kind: WorkerMessageKind.Init, loggingContext, plugins, requirePath, - constructorArgs: constructorParams + constructorArgs: constructorParams, + workingDirectory }); - this.listenToWorkerMessages(); - this.initProxy(); + this.listenForMessages(); + this.listenToStdoutAndStderr(); + // This is important! Be sure to bind to `this` + this.handleUnexpectedExit = this.handleUnexpectedExit.bind(this); + this.worker.on('exit', this.handleUnexpectedExit); + this.proxy = this.initProxy(); } /** * Creates a proxy where each function of the object created using the constructorFunction arg is ran inside of a child process */ - static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], constructorFunction: { new(arg: P1): T }, arg: P1): ChildProcessProxy; + static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, constructorFunction: { new(arg: P1): T }, arg: P1): ChildProcessProxy; /** * Creates a proxy where each function of the object created using the constructorFunction arg is ran inside of a child process */ - static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], constructorFunction: { new(arg: P1, arg2: P2): T }, arg1: P1, arg2: P2): ChildProcessProxy; + static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, constructorFunction: { new(arg: P1, arg2: P2): T }, arg1: P1, arg2: P2): ChildProcessProxy; /** * Creates a proxy where each function of the object created using the constructorFunction arg is ran inside of a child process */ - static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], constructorFunction: { new(...params: any[]): T }, ...constructorArgs: any[]) { - return new ChildProcessProxy(requirePath, loggingContext, plugins, constructorFunction, constructorArgs); + static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, _: { new(...params: any[]): T }, ...constructorArgs: any[]) { + return new ChildProcessProxy(requirePath, loggingContext, plugins, workingDirectory, constructorArgs); } private send(message: WorkerMessage) { this.worker.send(serialize(message)); } - private initProxy() { - Object.keys(this.constructorFunction.prototype).forEach(methodName => { - this.proxyMethod(methodName); - }); + private initProxy(): Promisified { + // This proxy is a genuine javascript `Proxy` class + // More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy + const self = this; + return new Proxy({} as Promisified, { + get(_, propertyKey) { + if (typeof propertyKey === 'string') { + return self.forward(propertyKey); + } else { + return undefined; + } + } + }) } - private proxyMethod(methodName: string) { - this.proxy[methodName as keyof T] = ((...args: any[]) => { - const workerTask = new Task(); - this.initTask.promise.then(() => { + private forward(methodName: string) { + return (...args: any[]) => { + if (this.currentError) { + return Promise.reject(this.currentError); + } else { + const workerTask = new Task(); const correlationId = this.workerTasks.push(workerTask) - 1; - this.send({ - kind: WorkerMessageKind.Call, - correlationId, - methodName, - args + this.initTask.promise.then(() => { + this.send({ + kind: WorkerMessageKind.Call, + correlationId, + methodName, + args + }); }); - }); - return workerTask.promise; - }) as any; + return workerTask.promise; + } + }; } - private listenToWorkerMessages() { + private listenForMessages() { this.worker.on('message', (serializedMessage: string) => { const message: ParentMessage = deserialize(serializedMessage, [File]); switch (message.kind) { @@ -92,12 +108,16 @@ export default class ChildProcessProxy { break; case ParentMessageKind.Result: this.workerTasks[message.correlationId].resolve(message.result); + delete this.workerTasks[message.correlationId]; break; case ParentMessageKind.Rejection: this.workerTasks[message.correlationId].reject(new Error(message.error)); + delete this.workerTasks[message.correlationId]; break; case ParentMessageKind.DisposeCompleted: - this.disposeTask.resolve(undefined); + if (this.disposeTask) { + this.disposeTask.resolve(undefined); + } break; default: this.logUnidentifiedMessage(message); @@ -106,12 +126,62 @@ export default class ChildProcessProxy { }); } + private listenToStdoutAndStderr() { + const traceEnabled = this.log.isTraceEnabled(); + const handleData = (data: Buffer) => { + const msg = data.toString(); + this.lastMessagesQueue.push(msg); + if (this.lastMessagesQueue.length > 10) { + this.lastMessagesQueue.shift(); + } + + if (traceEnabled) { + this.log.trace(msg); + } + }; + + if (this.worker.stdout) { + this.worker.stdout.on('data', handleData); + } + + if (this.worker.stderr) { + this.worker.stderr.on('data', handleData); + } + } + + private handleUnexpectedExit(code: number | null, signal: string) { + this.log.debug(`Child process exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr(this.lastMessagesQueue)}`); + this.currentError = new StrykerError(`Child process exited unexpectedly (code ${code})`); + this.workerTasks + .filter(task => !task.isResolved) + .forEach(task => task.reject(this.currentError)); + this.isDisposed = true; + + function stdoutAndStderr(messages: string[]) { + if (messages.length) { + return `Last part of stdout and stderr was: ${os.EOL}${ + messages.map(msg => `\t${msg}`).join(os.EOL)}`; + } else { + return 'Stdout and stderr were empty.'; + } + } + } + public dispose(): Promise { - this.disposeTask = new Task(); - this.send({ kind: WorkerMessageKind.Dispose }); - return this.disposeTask.promise - .then(() => this.worker.kill()) - .catch(() => this.worker.kill()); + this.worker.removeListener('exit', this.handleUnexpectedExit); + if (this.isDisposed) { + return Promise.resolve(); + } else { + this.disposeTask = new Task(); + this.send({ kind: WorkerMessageKind.Dispose }); + const killWorker = () => { + kill(this.worker.pid); + this.isDisposed = true; + }; + return this.disposeTask.promise + .then(killWorker) + .catch(killWorker); + } } private logUnidentifiedMessage(message: never) { diff --git a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts index 574f784fea..a9aeeb4ed6 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts @@ -1,3 +1,4 @@ +import * as path from 'path'; import { getLogger, Logger } from 'stryker-api/logging'; import { File } from 'stryker-api/core'; import { serialize, deserialize, errorToString } from '../utils/objectUtils'; @@ -29,8 +30,14 @@ export default class ChildProcessProxyWorker { case WorkerMessageKind.Init: LogConfigurator.configureChildProcess(message.loggingContext); this.log = getLogger(ChildProcessProxyWorker.name); + this.handlePromiseRejections(); new PluginLoader(message.plugins).load(); const RealSubjectClass = require(message.requirePath).default; + const workingDir = path.resolve(message.workingDirectory); + if (process.cwd() !== workingDir) { + this.log.debug(`Changing current working directory for this process to ${workingDir}`); + process.chdir(workingDir); + } this.realSubject = new RealSubjectClass(...message.constructorArgs); this.send({ kind: ParentMessageKind.Initialized }); this.removeAnyAdditionalMessageListeners(handler); @@ -66,8 +73,11 @@ export default class ChildProcessProxyWorker { } private doCall(message: CallMessage): {} | PromiseLike<{}> | undefined { - if( this.realSubject[message.methodName]) - return this.realSubject[message.methodName](...message.args); + if (typeof this.realSubject[message.methodName] === 'function') { + return this.realSubject[message.methodName](...message.args); + } else { + return this.realSubject[message.methodName]; + } } /** @@ -84,6 +94,23 @@ export default class ChildProcessProxyWorker { } }); } + + /** + * During mutation testing, it's to be expected that promise rejections are not handled synchronously anymore (or not at all) + * Let's handle those events so future versions of node don't crash + * See issue 350: https://github.com/stryker-mutator/stryker/issues/350 + */ + private handlePromiseRejections() { + const unhandledRejections: Promise[] = []; + process.on('unhandledRejection', (reason, promise) => { + const unhandledPromiseId = unhandledRejections.push(promise); + this.log.debug(`UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: ${unhandledPromiseId}): ${reason}`); + }); + process.on('rejectionHandled', (promise) => { + const unhandledPromiseId = unhandledRejections.indexOf(promise) + 1; + this.log.debug(`PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: ${unhandledPromiseId})`); + }); + } } // Prevent side effects for merely requiring the file diff --git a/packages/stryker/src/child-proxy/messageProtocol.ts b/packages/stryker/src/child-proxy/messageProtocol.ts index 0bea20f727..9272fdec37 100644 --- a/packages/stryker/src/child-proxy/messageProtocol.ts +++ b/packages/stryker/src/child-proxy/messageProtocol.ts @@ -13,7 +13,7 @@ export enum ParentMessageKind { 'DisposeCompleted' } -export type WorkerMessage = InitMessage | CallMessage | { kind: WorkerMessageKind.Dispose }; +export type WorkerMessage = InitMessage | CallMessage | DisposeMessage; export type ParentMessage = WorkResult | { kind: ParentMessageKind.Initialized | ParentMessageKind.DisposeCompleted } | RejectionResult; // Make this an unlikely command line argument @@ -24,10 +24,13 @@ export interface InitMessage { kind: WorkerMessageKind.Init; loggingContext: LoggingClientContext; plugins: string[]; + workingDirectory: string; requirePath: string; constructorArgs: any[]; } +export interface DisposeMessage { kind: WorkerMessageKind.Dispose; } + export interface WorkResult { kind: ParentMessageKind.Result; correlationId: number; diff --git a/packages/stryker/src/transpiler/MutantTranspiler.ts b/packages/stryker/src/transpiler/MutantTranspiler.ts index 8dec457242..3831c76200 100644 --- a/packages/stryker/src/transpiler/MutantTranspiler.ts +++ b/packages/stryker/src/transpiler/MutantTranspiler.ts @@ -30,6 +30,7 @@ export default class MutantTranspiler { require.resolve('./TranspilerFacade'), loggingContext, config.plugins, + process.cwd(), TranspilerFacade, transpilerOptions ); diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index 8c953c6c6d..ab92b75f6d 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -1,22 +1,25 @@ +import * as path from 'path'; +import * as getPort from 'get-port'; +import * as log4js from 'log4js'; import { expect } from 'chai'; import Echo from './Echo'; import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; import { File, LogLevel } from 'stryker-api/core'; -import * as log4js from 'log4js'; -import * as getPort from 'get-port'; import Task from '../../../src/utils/Task'; import LoggingServer from '../../helpers/LoggingServer'; -describe.only('ChildProcessProxy', function () { +describe('ChildProcessProxy', function () { this.timeout(15000); let sut: ChildProcessProxy; let loggingServer: LoggingServer; + const echoName = 'The Echo Server'; + const workingDir = '..'; beforeEach(async () => { const port = await getPort(); loggingServer = new LoggingServer(port); - sut = ChildProcessProxy.create(require.resolve('./Echo'), { port, level: LogLevel.Debug }, [], Echo, 'World'); + sut = ChildProcessProxy.create(require.resolve('./Echo'), { port, level: LogLevel.Debug }, [], workingDir, Echo, echoName); }); afterEach(async () => { @@ -26,12 +29,17 @@ describe.only('ChildProcessProxy', function () { it('should be able to get direct result', async () => { const actual = await sut.proxy.say('hello'); - expect(actual).eq('World: hello'); + expect(actual).eq(`${echoName}: hello`); }); it('should be able to get delayed result', async () => { const actual = await sut.proxy.sayDelayed('hello', 2); - expect(actual).eq('World: hello (2 ms)'); + expect(actual).eq(`${echoName}: hello (2 ms)`); + }); + + it('should set the current working directory', async () => { + const actual = await sut.proxy.cwd(); + expect(actual).eq(path.resolve(workingDir)); }); it('should be able to receive files', async () => { @@ -49,8 +57,8 @@ describe.only('ChildProcessProxy', function () { return expect(sut.proxy.reject('Foobar error')).rejectedWith('Foobar error'); }); - it.only('should be able to receive public properties as promised', () => { - return expect(sut.proxy.name()).eventually.eq('Echo'); + it('should be able to receive public properties as promised', () => { + return expect(sut.proxy.name()).eventually.eq(echoName); }); it('should be able to log on debug when LogLevel.Debug is allowed', async () => { diff --git a/packages/stryker/test/integration/child-proxy/Echo.ts b/packages/stryker/test/integration/child-proxy/Echo.ts index 37acbefa3e..0f3cd87f44 100644 --- a/packages/stryker/test/integration/child-proxy/Echo.ts +++ b/packages/stryker/test/integration/child-proxy/Echo.ts @@ -29,6 +29,10 @@ export default class Echo { return new File('foobar.txt', 'hello foobar'); } + cwd() { + return process.cwd(); + } + debug(message: string) { this.logger.debug(message); } diff --git a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts index 5687be8008..6b672ec615 100644 --- a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts +++ b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts @@ -153,8 +153,11 @@ describe('ResilientTestRunnerFactory integration', function () { alreadyDisposed = true; await loggingServer.dispose(); const actualLogEvents = await logEvents; - expect(actualLogEvents.find(logEvent => - log4js.levels.DEBUG.isEqualTo(logEvent.level) && logEvent.data.toString().indexOf('UnhandledPromiseRejectionWarning: Unhandled promise rejection') > -1)).ok; + expect( + actualLogEvents.find(logEvent => + log4js.levels.DEBUG.isEqualTo(logEvent.level) + && logEvent.data.toString().indexOf('UnhandledPromiseRejectionWarning: Unhandled promise rejection') > -1) + ).ok; }); }); diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 2861b22327..41af0e449d 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -1,40 +1,57 @@ +import * as os from 'os'; import { expect } from 'chai'; import * as childProcess from 'child_process'; import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; -import { autoStart, InitMessage, WorkerMessageKind, ParentMessage, WorkerMessage, ParentMessageKind } from '../../../src/child-proxy/messageProtocol'; +import { autoStart, InitMessage, WorkerMessageKind, ParentMessage, WorkerMessage, ParentMessageKind, DisposeMessage } from '../../../src/child-proxy/messageProtocol'; import { serialize } from '../../../src/utils/objectUtils'; import HelloClass from './HelloClass'; import LoggingClientContext from '../../../src/logging/LoggingClientContext'; import { LogLevel } from 'stryker-api/core'; +import * as objectUtils from '../../../src/utils/objectUtils'; +import { EventEmitter } from 'events'; +import { Logger } from 'stryker-api/logging'; +import { Mock } from '../../helpers/producers'; +import currentLogMock from '../../helpers/logMock'; const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ port: 4200, level: LogLevel.Fatal }); +class ChildProcessMock extends EventEmitter { + send = sandbox.stub(); + stderr = new EventEmitter(); + stdout = new EventEmitter(); + pid = 4648 +} + describe('ChildProcessProxy', () => { let sut: ChildProcessProxy; let forkStub: sinon.SinonStub; - let childProcessMock: { - send: sinon.SinonStub; - on: sinon.SinonStub; - }; + let childProcessMock: ChildProcessMock; + let killStub: sinon.SinonStub; + let logMock: Mock; beforeEach(() => { forkStub = sandbox.stub(childProcess, 'fork'); - childProcessMock = { - send: sandbox.stub(), - on: sandbox.stub() - }; + childProcessMock = new ChildProcessMock(); + killStub = sandbox.stub(objectUtils, 'kill'); forkStub.returns(childProcessMock); + logMock = currentLogMock(); + }); + + afterEach(() => { + childProcessMock.removeAllListeners(); + childProcessMock.stderr.removeAllListeners(); + childProcessMock.stdout.removeAllListeners(); }); - describe('create', () => { + describe('constructor', () => { it('should create child process', () => { - ChildProcessProxy.create('foobar', LOGGING_CONTEXT, ['examplePlugin', 'secondExamplePlugin'], HelloClass, 'something'); - expect(forkStub).calledWith(require.resolve('../../../src/child-proxy/ChildProcessProxyWorker'), [autoStart], { silent: false, execArgv: [] }); + sut = createSut(); + expect(forkStub).calledWith(require.resolve('../../../src/child-proxy/ChildProcessProxyWorker'), [autoStart], { silent: true, execArgv: [] }); }); it('should send init message to child process', () => { @@ -43,29 +60,76 @@ describe('ChildProcessProxy', () => { loggingContext: LOGGING_CONTEXT, plugins: ['examplePlugin', 'secondExamplePlugin'], requirePath: 'foobar', - constructorArgs: ['something'] + constructorArgs: ['something'], + workingDirectory: 'workingDirectory' }; // Act - ChildProcessProxy.create('foobar', LOGGING_CONTEXT, ['examplePlugin', 'secondExamplePlugin'], HelloClass, 'something'); + createSut({ + arg: expectedMessage.constructorArgs[0], + loggingContext: LOGGING_CONTEXT, + plugins: expectedMessage.plugins, + workingDir: expectedMessage.workingDirectory, + requirePath: expectedMessage.requirePath + }); + ChildProcessProxy.create(expectedMessage.requirePath, LOGGING_CONTEXT, expectedMessage.plugins, + expectedMessage.workingDirectory, HelloClass, expectedMessage.constructorArgs[0]); // Assert expect(childProcessMock.send).calledWith(serialize(expectedMessage)); }); it('should listen to worker process', () => { - ChildProcessProxy.create('foobar', LOGGING_CONTEXT, [], HelloClass, ''); - expect(childProcessMock.on).calledWith('message'); + createSut(); + expect(childProcessMock.listeners('message')).lengthOf(1); + }); + + it('should listen for exit calls', () => { + createSut(); + expect(childProcessMock.listeners('exit')).lengthOf(1); + }); + }); + + describe('on exit', () => { + beforeEach(() => { + sut = createSut(); + }); + + it('should log stdout and stderr on debug', () => { + childProcessMock.stderr.emit('data', 'foo'); + childProcessMock.stdout.emit('data', 'bar'); + actExit(23, 'SIGTERM'); + expect(logMock.debug).calledWith(`Child process exited unexpectedly with exit code 23 (SIGTERM). Last part of stdout and stderr was: ${os.EOL + }\tfoo${os.EOL}\tbar`); + }); + + it('should log that no stdout was available', () => { + actExit(23, 'SIGTERM'); + expect(logMock.debug).calledWith('Child process exited unexpectedly with exit code 23 (SIGTERM). Stdout and stderr were empty.'); }); + + it('should reject any outstanding worker promises with the error', () => { + const expectedError = 'Child process exited unexpectedly (code 646)'; + const actualPromise = sut.proxy.say('test'); + actExit(646); + return expect(actualPromise).rejectedWith(expectedError); + }); + + it('should reject any new calls immediately', () => { + actExit(646); + return expect(sut.proxy.say('')).rejected; + }); + + function actExit(code = 1, signal = 'SIGINT') { + childProcessMock.emit('exit', code, signal); + } }); describe('when calling methods', () => { beforeEach(() => { - sut = ChildProcessProxy.create('', LOGGING_CONTEXT, [], HelloClass, ''); - const initDoneResult: ParentMessage = { kind: ParentMessageKind.Initialized }; - const msg = serialize(initDoneResult); - childProcessMock.on.callArgWith(1, [msg]); + sut = createSut(); + receiveMessage({ kind: ParentMessageKind.Initialized }); }); it('should proxy the message', async () => { @@ -85,17 +149,75 @@ describe('ChildProcessProxy', () => { // Act const delayedEcho = sut.proxy.sayHello('echo'); await tick(); - childProcessMock.on.callArgWith(1, [serialize(workerResponse)]); // resolve the promise + receiveMessage(workerResponse); const result: string = await delayedEcho; // Assert expect(result).eq('ack'); expect(childProcessMock.send).calledWith(serialize(expectedWorkerMessage)); }); + }); + + describe('dispose', () => { + + beforeEach(() => { + sut = createSut(); + }); + + it('should send a dispose message', async () => { + await actDispose(); + const expectedWorkerMessage: DisposeMessage = { kind: WorkerMessageKind.Dispose }; + expect(childProcessMock.send).calledWith(serialize(expectedWorkerMessage)); + }); + + it('should kill the child process', async () => { + await actDispose(); + expect(killStub).calledWith(childProcessMock.pid); + }); + + it('should not do anything if already disposed', async () => { + await actDispose(); + await actDispose(); + expect(killStub).calledOnce; + expect(childProcessMock.send).calledTwice; // 1 init, 1 dispose + }); + + it('should not do anything if the process already exited', async () => { + childProcessMock.emit('exit', 1); + await actDispose(); + expect(killStub).not.called; + expect(childProcessMock.send).calledOnce; // init + }); + + async function actDispose() { + const disposePromise = sut.dispose(); + receiveMessage({ kind: ParentMessageKind.DisposeCompleted }); + await disposePromise; + } }); - function tick() { - return new Promise(res => setTimeout(res, 0)); + function receiveMessage(workerResponse: ParentMessage) { + childProcessMock.emit('message', serialize(workerResponse)); } -}); \ No newline at end of file +}); + +function tick() { + return new Promise(res => setTimeout(res, 0)); +} + +function createSut(overrides: { + requirePath?: string; + loggingContext?: LoggingClientContext; + plugins?: string[]; + workingDir?: string; + arg?: string; +} = {}): ChildProcessProxy { + return ChildProcessProxy.create( + overrides.requirePath || 'foobar', + overrides.loggingContext || LOGGING_CONTEXT, + overrides.plugins || ['examplePlugin', 'secondExamplePlugin'], + overrides.workingDir || 'workingDir', + HelloClass, + overrides.arg || 'someArg'); +} diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts index 5202dbc1e8..e860cadfcb 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessWorkerSpec.ts @@ -1,13 +1,16 @@ +import * as path from 'path'; import ChildProcessProxyWorker from '../../../src/child-proxy/ChildProcessProxyWorker'; import { expect } from 'chai'; import { serialize } from '../../../src/utils/objectUtils'; -import { WorkerMessage, WorkerMessageKind, ParentMessage, WorkResult, CallMessage, ParentMessageKind } from '../../../src/child-proxy/messageProtocol'; +import { WorkerMessage, WorkerMessageKind, ParentMessage, WorkResult, CallMessage, ParentMessageKind, InitMessage } from '../../../src/child-proxy/messageProtocol'; import PluginLoader, * as pluginLoader from '../../../src/PluginLoader'; import { Mock, mock } from '../../helpers/producers'; import HelloClass from './HelloClass'; import LogConfigurator from '../../../src/logging/LogConfigurator'; import { LogLevel } from 'stryker-api/core'; import LoggingClientContext from '../../../src/logging/LoggingClientContext'; +import { Logger } from 'stryker-api/logging'; +import currentLogMock from '../../helpers/logMock'; const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ port: 4200, level: LogLevel.Fatal }); @@ -18,12 +21,16 @@ describe('ChildProcessProxyWorker', () => { let processListenersStub: sinon.SinonStub; let configureChildProcessStub: sinon.SinonStub; let processRemoveListenerStub: sinon.SinonStub; + let processChdirStub: sinon.SinonStub; + let logMock: Mock; let pluginLoaderMock: Mock; let originalProcessSend: undefined | NodeJS.MessageListener; let processes: NodeJS.MessageListener[]; + const workingDir = 'working dir'; beforeEach(() => { processes = []; + logMock = currentLogMock(); processOnStub = sandbox.stub(process, 'on'); processListenersStub = sandbox.stub(process, 'listeners'); processListenersStub.returns(processes); @@ -32,6 +39,7 @@ describe('ChildProcessProxyWorker', () => { // process.send is normally undefined originalProcessSend = process.send; process.send = processSendStub; + processChdirStub = sandbox.stub(process, 'chdir'); configureChildProcessStub = sandbox.stub(LogConfigurator, 'configureChildProcess'); pluginLoaderMock = mock(PluginLoader); sandbox.stub(pluginLoader, 'default').returns(pluginLoaderMock); @@ -49,7 +57,7 @@ describe('ChildProcessProxyWorker', () => { describe('after init message', () => { let sut: ChildProcessProxyWorker; - let initMessage: WorkerMessage; + let initMessage: InitMessage; beforeEach(() => { sut = new ChildProcessProxyWorker(); @@ -58,19 +66,34 @@ describe('ChildProcessProxyWorker', () => { loggingContext: LOGGING_CONTEXT, constructorArgs: ['FooBarName'], plugins: ['fooPlugin', 'barPlugin'], - requirePath: require.resolve('./HelloClass') + requirePath: require.resolve('./HelloClass'), + workingDirectory: workingDir }; }); it('should create the correct real instance', () => { - processOnStub.callArgWith(1, [serialize(initMessage)]); + processOnMessage(initMessage); expect(sut.realSubject).instanceOf(HelloClass); const actual = sut.realSubject as HelloClass; expect(actual.name).eq('FooBarName'); }); + it('should change the current working directory', () => { + processOnMessage(initMessage); + const fullWorkingDir = path.resolve(workingDir); + expect(logMock.debug).calledWith(`Changing current working directory for this process to ${fullWorkingDir}`); + expect(processChdirStub).calledWith(fullWorkingDir); + }); + + it('should not change the current working directory if it didn\'t change', () => { + initMessage.workingDirectory = process.cwd(); + processOnMessage(initMessage); + expect(logMock.debug).not.called; + expect(processChdirStub).not.called; + }); + it('should send "init_done"', async () => { - processOnStub.callArgWith(1, [serialize(initMessage)]); + processOnMessage(initMessage); const expectedWorkerResponse: ParentMessage = { kind: ParentMessageKind.Initialized }; await tick(); // make sure promise is resolved expect(processSendStub).calledWith(serialize(expectedWorkerResponse)); @@ -82,7 +105,7 @@ describe('ChildProcessProxyWorker', () => { processes.push(noop); // Act - processOnStub.callArgWith(1, [serialize(initMessage)]); + processOnMessage(initMessage); await tick(); // make sure promise is resolved // Assert @@ -95,18 +118,31 @@ describe('ChildProcessProxyWorker', () => { }); it('should load plugins', () => { - processOnStub.callArgWith(1, serialize(initMessage)); + processOnMessage(initMessage); expect(pluginLoader.default).calledWithNew; expect(pluginLoader.default).calledWith(['fooPlugin', 'barPlugin']); expect(pluginLoaderMock.load).called; }); + + it('should handle unhandledRejection events', () => { + processOnMessage(initMessage); + const error = new Error('foobar'); + processOnStub.withArgs('unhandledRejection').callArgWith(1, error); + expect(logMock.debug).calledWith(`UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): ${error}`); + }); + + it('should handle rejectionHandled events', () => { + processOnMessage(initMessage); + processOnStub.withArgs('rejectionHandled').callArgWith(1); + expect(logMock.debug).calledWith('PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: 0)'); + }); describe('on worker message', () => { async function actAndAssert(workerMessage: CallMessage, expectedResult: WorkResult) { // Act - processOnStub.callArgWith(1, serialize(initMessage)); - processOnStub.callArgWith(1, serialize(workerMessage)); + processOnMessage(initMessage); + processOnMessage(workerMessage); await tick(); // Assert expect(processSendStub).calledWith(serialize(expectedResult)); @@ -114,8 +150,8 @@ describe('ChildProcessProxyWorker', () => { async function actAndAssertRejection(workerMessage: CallMessage, expectedError: string) { // Act - processOnStub.callArgWith(1, serialize(initMessage)); - processOnStub.callArgWith(1, serialize(workerMessage)); + processOnMessage(initMessage); + processOnMessage(workerMessage); await tick(); // Assert expect(processSendStub).calledWithMatch(`"correlationId": ${workerMessage.correlationId.toString()}`); @@ -151,7 +187,7 @@ describe('ChildProcessProxyWorker', () => { await actAndAssertRejection(workerMessage, 'Rejected'); }); - it('should send a thrown synchronous error as rejection', async () => { + it('should send a thrown synchronous error as rejection', async () => { // Arrange const workerMessage: WorkerMessage = { kind: WorkerMessageKind.Call, @@ -198,8 +234,16 @@ describe('ChildProcessProxyWorker', () => { }); }); + + function processOnMessage(message: WorkerMessage) { + processOnStub + .withArgs('message') + .callArgWith(1, [serialize(message)]); + } + }); + function tick() { return new Promise(res => setTimeout(res, 0)); } \ No newline at end of file diff --git a/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts b/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts index c0fd4186ad..58943dce1b 100644 --- a/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts +++ b/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts @@ -44,6 +44,7 @@ describe('MutantTranspiler', () => { require.resolve('../../../src/transpiler/TranspilerFacade'), LOGGING_CONTEXT, ['plugin1'], + process.cwd(), TranspilerFacade, { config: expectedConfig, produceSourceMaps: false } ); diff --git a/tsconfig.json b/tsconfig.json index 38781d60c3..15a7eac702 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,7 +18,8 @@ "es2015.promise", "es2015.core", "es2015.symbol", - "es2015.symbol.wellknown" + "es2015.symbol.wellknown", + "es2015.proxy" ] } } \ No newline at end of file From 556b80f30765c9cb0c240d50b845df8da71e8f4e Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sun, 22 Jul 2018 16:29:39 +0200 Subject: [PATCH 32/54] test(ChildProcess): test crash scenarios --- .../src/child-proxy/ChildProcessProxy.ts | 12 +-- .../child-proxy/ChildProcessProxyWorker.ts | 94 +++++++++---------- .../stryker/test/helpers/LoggingServer.ts | 3 + packages/stryker/test/helpers/utils.ts | 5 + .../child-proxy/ChildProcessProxy.it.ts | 62 +++++++++--- .../test/integration/child-proxy/Echo.ts | 13 +++ .../ResilientTestRunnerFactory.it.ts | 7 +- .../unit/child-proxy/ChildProcessProxySpec.ts | 10 +- 8 files changed, 128 insertions(+), 78 deletions(-) create mode 100644 packages/stryker/test/helpers/utils.ts diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index 17f69aceb0..8018ce02fa 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -76,7 +76,7 @@ export default class ChildProcessProxy { return undefined; } } - }) + }); } private forward(methodName: string) { @@ -129,14 +129,14 @@ export default class ChildProcessProxy { private listenToStdoutAndStderr() { const traceEnabled = this.log.isTraceEnabled(); const handleData = (data: Buffer) => { - const msg = data.toString(); - this.lastMessagesQueue.push(msg); + const messages = data.toString().split('\n').filter(Boolean); + this.lastMessagesQueue.push(...messages); if (this.lastMessagesQueue.length > 10) { this.lastMessagesQueue.shift(); } if (traceEnabled) { - this.log.trace(msg); + messages.forEach(message => this.log.trace(message)); } }; @@ -150,12 +150,12 @@ export default class ChildProcessProxy { } private handleUnexpectedExit(code: number | null, signal: string) { - this.log.debug(`Child process exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr(this.lastMessagesQueue)}`); + this.isDisposed = true; + this.log.warn(`Child process exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr(this.lastMessagesQueue)}`); this.currentError = new StrykerError(`Child process exited unexpectedly (code ${code})`); this.workerTasks .filter(task => !task.isResolved) .forEach(task => task.reject(this.currentError)); - this.isDisposed = true; function stdoutAndStderr(messages: string[]) { if (messages.length) { diff --git a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts index a9aeeb4ed6..bd4b3243a3 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxyWorker.ts @@ -13,7 +13,9 @@ export default class ChildProcessProxyWorker { realSubject: any; constructor() { - this.listenToParent(); + // Make sure to bind the methods in order to ensure the `this` pointer + this.handleMessage = this.handleMessage.bind(this); + process.on('message', this.handleMessage); } private send(value: ParentMessage) { @@ -22,54 +24,50 @@ export default class ChildProcessProxyWorker { } } - private listenToParent() { - - const handler = (serializedMessage: string) => { - const message = deserialize(serializedMessage, [File]); - switch (message.kind) { - case WorkerMessageKind.Init: - LogConfigurator.configureChildProcess(message.loggingContext); - this.log = getLogger(ChildProcessProxyWorker.name); - this.handlePromiseRejections(); - new PluginLoader(message.plugins).load(); - const RealSubjectClass = require(message.requirePath).default; - const workingDir = path.resolve(message.workingDirectory); - if (process.cwd() !== workingDir) { - this.log.debug(`Changing current working directory for this process to ${workingDir}`); - process.chdir(workingDir); - } - this.realSubject = new RealSubjectClass(...message.constructorArgs); - this.send({ kind: ParentMessageKind.Initialized }); - this.removeAnyAdditionalMessageListeners(handler); - break; - case WorkerMessageKind.Call: - new Promise(resolve => resolve(this.doCall(message))) - .then(result => { - this.send({ - kind: ParentMessageKind.Result, - correlationId: message.correlationId, - result - }); - }).catch(error => { - this.send({ - kind: ParentMessageKind.Rejection, - error: errorToString(error), - correlationId: message.correlationId - }); + private handleMessage(serializedMessage: string) { + const message = deserialize(serializedMessage, [File]); + switch (message.kind) { + case WorkerMessageKind.Init: + LogConfigurator.configureChildProcess(message.loggingContext); + this.log = getLogger(ChildProcessProxyWorker.name); + this.handlePromiseRejections(); + new PluginLoader(message.plugins).load(); + const RealSubjectClass = require(message.requirePath).default; + const workingDir = path.resolve(message.workingDirectory); + if (process.cwd() !== workingDir) { + this.log.debug(`Changing current working directory for this process to ${workingDir}`); + process.chdir(workingDir); + } + this.realSubject = new RealSubjectClass(...message.constructorArgs); + this.send({ kind: ParentMessageKind.Initialized }); + this.removeAnyAdditionalMessageListeners(this.handleMessage); + break; + case WorkerMessageKind.Call: + new Promise(resolve => resolve(this.doCall(message))) + .then(result => { + this.send({ + kind: ParentMessageKind.Result, + correlationId: message.correlationId, + result }); - this.removeAnyAdditionalMessageListeners(handler); - break; - case WorkerMessageKind.Dispose: - const sendCompleted = () => { - this.send({ kind: ParentMessageKind.DisposeCompleted }); - }; - LogConfigurator.shutdown() - .then(sendCompleted) - .catch(sendCompleted); - break; - } - }; - process.on('message', handler); + }).catch(error => { + this.send({ + kind: ParentMessageKind.Rejection, + error: errorToString(error), + correlationId: message.correlationId + }); + }); + this.removeAnyAdditionalMessageListeners(this.handleMessage); + break; + case WorkerMessageKind.Dispose: + const sendCompleted = () => { + this.send({ kind: ParentMessageKind.DisposeCompleted }); + }; + LogConfigurator.shutdown() + .then(sendCompleted) + .catch(sendCompleted); + break; + } } private doCall(message: CallMessage): {} | PromiseLike<{}> | undefined { diff --git a/packages/stryker/test/helpers/LoggingServer.ts b/packages/stryker/test/helpers/LoggingServer.ts index dc1e3dfdff..9c54971cd6 100644 --- a/packages/stryker/test/helpers/LoggingServer.ts +++ b/packages/stryker/test/helpers/LoggingServer.ts @@ -17,6 +17,9 @@ export default class LoggingServer { const loggingEvents: log4js.LoggingEvent[] = logEventStrings.map(logEventString => JSON.parse(logEventString)); loggingEvents.forEach(event => this.subscriber && this.subscriber.next(event)); }); + socket.on('error', () => { + // Idle + }); }); this.server.listen(this.port); diff --git a/packages/stryker/test/helpers/utils.ts b/packages/stryker/test/helpers/utils.ts new file mode 100644 index 0000000000..e9f0fcb0bb --- /dev/null +++ b/packages/stryker/test/helpers/utils.ts @@ -0,0 +1,5 @@ +export function sleep(ms: number) { + return new Promise(res => { + setTimeout(res, ms); + }); +} \ No newline at end of file diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index ab92b75f6d..998440e5ec 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -2,29 +2,40 @@ import * as path from 'path'; import * as getPort from 'get-port'; import * as log4js from 'log4js'; import { expect } from 'chai'; +import { File, LogLevel } from 'stryker-api/core'; +import { Logger } from 'stryker-api/logging'; import Echo from './Echo'; import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; -import { File, LogLevel } from 'stryker-api/core'; import Task from '../../../src/utils/Task'; import LoggingServer from '../../helpers/LoggingServer'; +import { filter } from 'rxjs/operators'; +import { Mock } from '../../helpers/producers'; +import currentLogMock from '../../helpers/logMock'; +import { sleep } from '../../helpers/utils'; describe('ChildProcessProxy', function () { this.timeout(15000); let sut: ChildProcessProxy; let loggingServer: LoggingServer; + let log: Mock; const echoName = 'The Echo Server'; const workingDir = '..'; beforeEach(async () => { const port = await getPort(); + log = currentLogMock(); loggingServer = new LoggingServer(port); sut = ChildProcessProxy.create(require.resolve('./Echo'), { port, level: LogLevel.Debug }, [], workingDir, Echo, echoName); }); afterEach(async () => { - await sut.dispose(); - await loggingServer.dispose(); + try { + await sut.dispose(); + await loggingServer.dispose(); + } catch (error) { + console.error(error); + } }); it('should be able to get direct result', async () => { @@ -53,33 +64,58 @@ describe('ChildProcessProxy', function () { expect(actual.name).eq('foobar.txt'); }); - it('should be able to receive a promise rejection', () => { - return expect(sut.proxy.reject('Foobar error')).rejectedWith('Foobar error'); + it('should be able to receive a promise rejection', async () => { + await expect(sut.proxy.reject('Foobar error')).rejectedWith('Foobar error'); }); - - it('should be able to receive public properties as promised', () => { + + it('should be able to receive public properties as promised', () => { return expect(sut.proxy.name()).eventually.eq(echoName); }); it('should be able to log on debug when LogLevel.Debug is allowed', async () => { - const firstLogEventTask = new Task(); - loggingServer.event$.subscribe(firstLogEventTask.resolve.bind(firstLogEventTask)); + const logEventTask = new Task(); + loggingServer.event$.pipe( + filter(event => event.categoryName === Echo.name) + ).subscribe(logEventTask.resolve.bind(logEventTask)); sut.proxy.debug('test message'); - const log = await firstLogEventTask.promise; + const log = await logEventTask.promise; expect(log.categoryName).eq(Echo.name); expect(log.data).deep.eq(['test message']); }); it('should not log on trace if LogLevel.Debug is allowed as min log level', async () => { - const firstLogEventTask = new Task(); - loggingServer.event$.subscribe(firstLogEventTask.resolve.bind(firstLogEventTask)); + const logEventTask = new Task(); + loggingServer.event$.pipe( + filter(event => event.categoryName === Echo.name) + ).subscribe(logEventTask.resolve.bind(logEventTask)); sut.proxy.trace('foo'); sut.proxy.debug('bar'); - const log = await firstLogEventTask.promise; + const log = await logEventTask.promise; expect(log.categoryName).eq(Echo.name); expect(log.data).deep.eq(['bar']); expect(toLogLevel(log.level)).eq(LogLevel.Debug); }); + + it('should reject when the child process exits', () => { + return expect(sut.proxy.exit(42)).rejectedWith('Child process exited unexpectedly (code 42)'); + }); + + it('should log stdout and stderr on warning when a child process crashed', async () => { + sut.proxy.stdout('stdout message'); + sut.proxy.stderr('stderr message'); + // Give nodejs the chance to flush the stdout and stderr buffers + await sleep(10); + await expect(sut.proxy.exit(12)).rejected; + const call = log.warn.getCall(0); + expect(call.args[0]).includes('Child process exited unexpectedly with exit code 12 (without signal). Last part of stdout and stderr was:'); + expect(call.args[0]).includes('stdout message'); + expect(call.args[0]).includes('stderr message'); + }); + + it('should immediately reject any subsequent calls when the child process exits', async () => { + await expect(sut.proxy.exit(1)).rejected; + await expect(sut.proxy.say()).rejectedWith('Child process exited unexpectedly (code 1)'); + }); }); function toLogLevel(level: log4js.Level) { diff --git a/packages/stryker/test/integration/child-proxy/Echo.ts b/packages/stryker/test/integration/child-proxy/Echo.ts index 0f3cd87f44..cc41983e30 100644 --- a/packages/stryker/test/integration/child-proxy/Echo.ts +++ b/packages/stryker/test/integration/child-proxy/Echo.ts @@ -25,6 +25,11 @@ export default class Echo { return file.textContent; } + exit(code: number) { + process.exit(code); + return new Promise(res => {/*never resolve*/ }); + } + readFile() { return new File('foobar.txt', 'hello foobar'); } @@ -44,4 +49,12 @@ export default class Echo { reject(error: string) { return Promise.reject(new Error(error)); } + + stdout(...args: string[]) { + args.forEach(arg => console.log(arg)); + } + + stderr(...args: string[]) { + args.forEach(arg => console.error(arg)); + } } \ No newline at end of file diff --git a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts index 6b672ec615..9d1aaaef68 100644 --- a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts +++ b/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts @@ -9,12 +9,7 @@ import { LogLevel } from 'stryker-api/core'; import LoggingServer from '../../helpers/LoggingServer'; import LoggingClientContext from '../../../src/logging/LoggingClientContext'; import { toArray } from 'rxjs/operators'; - -function sleep(ms: number) { - return new Promise(res => { - setTimeout(res, ms); - }); -} +import { sleep } from '../../helpers/utils'; describe('ResilientTestRunnerFactory integration', function () { diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 41af0e449d..21480890c5 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -22,7 +22,7 @@ class ChildProcessMock extends EventEmitter { send = sandbox.stub(); stderr = new EventEmitter(); stdout = new EventEmitter(); - pid = 4648 + pid = 4648; } describe('ChildProcessProxy', () => { @@ -34,8 +34,8 @@ describe('ChildProcessProxy', () => { let logMock: Mock; beforeEach(() => { - forkStub = sandbox.stub(childProcess, 'fork'); childProcessMock = new ChildProcessMock(); + forkStub = sandbox.stub(childProcess, 'fork'); killStub = sandbox.stub(objectUtils, 'kill'); forkStub.returns(childProcessMock); logMock = currentLogMock(); @@ -95,17 +95,17 @@ describe('ChildProcessProxy', () => { sut = createSut(); }); - it('should log stdout and stderr on debug', () => { + it('should log stdout and stderr on warning', () => { childProcessMock.stderr.emit('data', 'foo'); childProcessMock.stdout.emit('data', 'bar'); actExit(23, 'SIGTERM'); - expect(logMock.debug).calledWith(`Child process exited unexpectedly with exit code 23 (SIGTERM). Last part of stdout and stderr was: ${os.EOL + expect(logMock.warn).calledWith(`Child process exited unexpectedly with exit code 23 (SIGTERM). Last part of stdout and stderr was: ${os.EOL }\tfoo${os.EOL}\tbar`); }); it('should log that no stdout was available', () => { actExit(23, 'SIGTERM'); - expect(logMock.debug).calledWith('Child process exited unexpectedly with exit code 23 (SIGTERM). Stdout and stderr were empty.'); + expect(logMock.warn).calledWith('Child process exited unexpectedly with exit code 23 (SIGTERM). Stdout and stderr were empty.'); }); it('should reject any outstanding worker promises with the error', () => { From f6b9d91bd5a6b65141c23cd64d32c738b313e05c Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sun, 22 Jul 2018 19:27:27 +0200 Subject: [PATCH 33/54] refactor(TestRunners): Generalize child process logic * Replace the custom child process logic with the more `ChildProxy`. * Create a unified error to that is thrown when a child process crashes --- packages/stryker/src/Sandbox.ts | 4 +- .../child-proxy/ChildProcessCrashedError.ts | 10 + .../src/child-proxy/ChildProcessProxy.ts | 35 +++- .../IsolatedTestRunnerAdapter.ts | 180 ------------------ .../IsolatedTestRunnerAdapterWorker.ts | 155 --------------- .../src/isolated-runner/MessageProtocol.ts | 37 ---- .../ChildProcessTestRunnerDecorator.ts | 50 +++++ .../ChildProcessTestRunnerWorker.ts | 46 +++++ .../ResilientTestRunnerFactory.ts | 4 +- .../RetryDecorator.ts | 6 +- .../TestRunnerDecorator.ts | 0 .../TimeoutDecorator.ts | 0 packages/stryker/src/utils/objectUtils.ts | 6 + packages/stryker/test/helpers/utils.ts | 5 - .../child-proxy/ChildProcessProxy.it.ts | 4 +- .../AdditionalTestRunners.ts | 1 - .../ResilientTestRunnerFactory.it.ts | 57 +++--- packages/stryker/test/unit/SandboxSpec.ts | 4 +- .../unit/child-proxy/ChildProcessProxySpec.ts | 4 +- .../ChildProcessTestRunnerAdapterSpec.ts | 84 ++++++++ .../IsolatedTestRunnerAdapterSpec.ts | 178 ----------------- .../isolated-runner/RetryDecoratorSpec.ts | 25 ++- .../TestRunnerDecoratorSpec.ts | 2 +- .../isolated-runner/TimeoutDecoratorSpec.ts | 2 +- 24 files changed, 279 insertions(+), 620 deletions(-) create mode 100644 packages/stryker/src/child-proxy/ChildProcessCrashedError.ts delete mode 100644 packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts delete mode 100644 packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts delete mode 100644 packages/stryker/src/isolated-runner/MessageProtocol.ts create mode 100644 packages/stryker/src/test-runner/ChildProcessTestRunnerDecorator.ts create mode 100644 packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts rename packages/stryker/src/{isolated-runner => test-runner}/ResilientTestRunnerFactory.ts (69%) rename packages/stryker/src/{isolated-runner => test-runner}/RetryDecorator.ts (90%) rename packages/stryker/src/{isolated-runner => test-runner}/TestRunnerDecorator.ts (100%) rename packages/stryker/src/{isolated-runner => test-runner}/TimeoutDecorator.ts (100%) delete mode 100644 packages/stryker/test/helpers/utils.ts rename packages/stryker/test/integration/{isolated-runner => test-runner}/AdditionalTestRunners.ts (99%) rename packages/stryker/test/integration/{isolated-runner => test-runner}/ResilientTestRunnerFactory.it.ts (77%) create mode 100644 packages/stryker/test/unit/isolated-runner/ChildProcessTestRunnerAdapterSpec.ts delete mode 100644 packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts diff --git a/packages/stryker/src/Sandbox.ts b/packages/stryker/src/Sandbox.ts index ee92e5fe24..818730b150 100644 --- a/packages/stryker/src/Sandbox.ts +++ b/packages/stryker/src/Sandbox.ts @@ -6,8 +6,8 @@ import { RunResult, RunnerOptions } from 'stryker-api/test_runner'; import { File } from 'stryker-api/core'; import { TestFramework } from 'stryker-api/test_framework'; import { wrapInClosure, normalizeWhiteSpaces } from './utils/objectUtils'; -import TestRunnerDecorator from './isolated-runner/TestRunnerDecorator'; -import ResilientTestRunnerFactory from './isolated-runner/ResilientTestRunnerFactory'; +import TestRunnerDecorator from './test-runner/TestRunnerDecorator'; +import ResilientTestRunnerFactory from './test-runner/ResilientTestRunnerFactory'; import { TempFolder } from './utils/TempFolder'; import { writeFile, findNodeModules, symlinkJunction } from './utils/fileUtils'; import TestableMutant, { TestSelectionResult } from './TestableMutant'; diff --git a/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts b/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts new file mode 100644 index 0000000000..ed2f19bedc --- /dev/null +++ b/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts @@ -0,0 +1,10 @@ +import StrykerError from '../utils/StrykerError'; + +export default class ChildProcessCrashedError extends StrykerError { + constructor(exitCode: number | null, innerError?: Error) { + super(`Child process exited unexpectedly (code ${exitCode === null ? 'unknown' : exitCode})`, innerError); + Error.captureStackTrace(this, ChildProcessCrashedError); + // TS recommendation: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work + Object.setPrototypeOf(this, ChildProcessCrashedError.prototype); + } +} \ No newline at end of file diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index 8018ce02fa..a825aa3e86 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -3,10 +3,11 @@ import { fork, ChildProcess } from 'child_process'; import { File } from 'stryker-api/core'; import { getLogger } from 'stryker-api/logging'; import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol'; -import { serialize, deserialize, kill } from '../utils/objectUtils'; +import { serialize, deserialize, kill, isErrnoException } from '../utils/objectUtils'; import Task from '../utils/Task'; import LoggingClientContext from '../logging/LoggingClientContext'; import StrykerError from '../utils/StrykerError'; +import ChildProcessCrashedError from './ChildProcessCrashedError'; type MethodPromised = { (...args: any[]): Promise }; @@ -14,6 +15,9 @@ export type Promisified = { [K in keyof T]: T[K] extends MethodPromised ? T[K] : T[K] extends Function ? MethodPromised : () => Promise; }; +const BROKEN_PIPE_ERROR_CODE = 'EPIPE'; +const IPC_CHANNEL_CLOSED_ERROR_CODE = 'ERR_IPC_CHANNEL_CLOSED'; + export default class ChildProcessProxy { readonly proxy: Promisified; @@ -41,7 +45,9 @@ export default class ChildProcessProxy { this.listenToStdoutAndStderr(); // This is important! Be sure to bind to `this` this.handleUnexpectedExit = this.handleUnexpectedExit.bind(this); + this.handleError = this.handleError.bind(this); this.worker.on('exit', this.handleUnexpectedExit); + this.worker.on('error', this.handleError); this.proxy = this.initProxy(); } @@ -149,13 +155,17 @@ export default class ChildProcessProxy { } } - private handleUnexpectedExit(code: number | null, signal: string) { - this.isDisposed = true; - this.log.warn(`Child process exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr(this.lastMessagesQueue)}`); - this.currentError = new StrykerError(`Child process exited unexpectedly (code ${code})`); + private reportError(error: Error) { this.workerTasks .filter(task => !task.isResolved) - .forEach(task => task.reject(this.currentError)); + .forEach(task => task.reject(error)); + } + + private handleUnexpectedExit(code: number | null, signal: string) { + this.isDisposed = true; + this.log.warn(`Child process [pid ${this.worker.pid}] exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr(this.lastMessagesQueue)}`); + this.currentError = new ChildProcessCrashedError(code); + this.reportError(this.currentError); function stdoutAndStderr(messages: string[]) { if (messages.length) { @@ -167,6 +177,19 @@ export default class ChildProcessProxy { } } + private handleError(error: Error) { + if (this.innerProcessIsCrashed(error)) { + this.log.warn(`Child process [pid ${this.worker.pid}] has crashed. See other warning messages for more info.`, error); + this.reportError(new ChildProcessCrashedError(null, error)); + } else { + this.reportError(error); + } + } + + private innerProcessIsCrashed(error: any) { + return isErrnoException(error) && (error.code === BROKEN_PIPE_ERROR_CODE || error.code === IPC_CHANNEL_CLOSED_ERROR_CODE); + } + public dispose(): Promise { this.worker.removeListener('exit', this.handleUnexpectedExit); if (this.isDisposed) { diff --git a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts deleted file mode 100644 index 0f73744b0f..0000000000 --- a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapter.ts +++ /dev/null @@ -1,180 +0,0 @@ -import { EventEmitter } from 'events'; -import { getLogger } from 'stryker-api/logging'; -import * as _ from 'lodash'; -import { fork, ChildProcess } from 'child_process'; -import { TestRunner, RunResult, RunOptions, RunnerOptions } from 'stryker-api/test_runner'; -import { serialize, kill } from '../utils/objectUtils'; -import { AdapterMessage, WorkerMessage } from './MessageProtocol'; -import Task from '../utils/Task'; -import StrykerError from '../utils/StrykerError'; -import LoggingClientContext from '../logging/LoggingClientContext'; - -const MAX_WAIT_FOR_DISPOSE = 2000; - -class InitTask extends Task { - readonly kind = 'init'; -} -class DisposeTask extends Task { - readonly kind = 'dispose'; -} -class RunTask extends Task { - readonly kind = 'run'; -} -type WorkerTask = InitTask | DisposeTask | RunTask; - - -/** - * Runs the given test runner in a child process and forwards reports about test results - * Also implements timeout-mechanism (on timeout, restart the child runner and report timeout) - */ -export default class TestRunnerChildProcessAdapter extends EventEmitter implements TestRunner { - - private readonly log = getLogger(TestRunnerChildProcessAdapter.name); - private workerProcess: ChildProcess; - private currentTask: WorkerTask; - private lastMessagesQueue: string[] = []; - - constructor(private realTestRunnerName: string, private options: RunnerOptions, private sandboxWorkingDirectory: string, private loggingContext: LoggingClientContext) { - super(); - this.startWorker(); - } - - private startWorker() { - // Remove --debug-brk from process arguments. - // When debugging, it will try to reuse the same debug port, which will be taken by the main process. - let execArgv = _.clone(process.execArgv); - _.remove(execArgv, arg => arg.substr(0, 11) === '--debug-brk'); - this.workerProcess = fork(`${__dirname}/IsolatedTestRunnerAdapterWorker`, [], { silent: true, execArgv: [] }); - this.sendStartCommand(); - this.listenToWorkerProcess(); - } - - private listenToWorkerProcess() { - - if (this.workerProcess.stdout) { - let traceEnabled = this.log.isTraceEnabled(); - this.workerProcess.stdout.on('data', (data: Buffer) => { - const msg = data.toString(); - - this.lastMessagesQueue.push(msg); - if (this.lastMessagesQueue.length > 10) { - this.lastMessagesQueue.shift(); - } - - if (traceEnabled) { - this.log.trace(msg); - } - }); - } - - if (this.workerProcess.stderr) { - this.workerProcess.stderr.on('data', (data: any) => { - this.log.error(data.toString()); - }); - } - - this.workerProcess.on('message', (message: WorkerMessage) => { - switch (message.kind) { - case 'result': - if (this.currentTask.kind === 'run') { - this.currentTask.resolve(message.result); - } else { - this.logReceivedUnexpectedMessageWarning(message); - } - break; - case 'initDone': - if (this.currentTask.kind === 'init') { - if (message.errorMessage) { - this.currentTask.reject(message.errorMessage); - } else { - this.currentTask.resolve(undefined); - } - } else { - this.logReceivedUnexpectedMessageWarning(message); - } - break; - case 'disposeDone': - if (this.currentTask.kind === 'dispose') { - this.currentTask.resolve(undefined); - } else { - this.logReceivedUnexpectedMessageWarning(message); - } - break; - default: - this.logReceivedMessageWarning(message); - break; - } - }); - - this.workerProcess.on('exit', (code: number | null, signal: string) => { - if (code !== 0 && code !== null) { - this.log.error(`Child process exited with non-zero exit code ${code}. Last 10 message from the child process were: \r\n${this.lastMessagesQueue.map(msg => `\t${msg}`).join('\r\n')}`); - if (this.currentTask) { - this.currentTask.reject(new StrykerError(`Test runner child process exited with non-zero exit code ${code}`)); - } - } - }); - } - - private logReceivedUnexpectedMessageWarning(message: WorkerMessage) { - this.log.warn(`Received unexpected message from test runner worker process: "${message.kind}" while current task is ${this.currentTask.kind}. Ignoring this message.`); - } - - private logReceivedMessageWarning(message: never) { - this.log.error(`Retrieved unrecognized message from child process: ${JSON.stringify(message)}`); - } - - init(): Promise { - this.currentTask = new InitTask(); - this.sendInitCommand(); - return this.currentTask.promise; - } - - run(options: RunOptions): Promise { - this.currentTask = new RunTask(); - this.sendRunCommand(options); - return this.currentTask.promise; - } - - dispose(): Promise { - this.currentTask = new DisposeTask(MAX_WAIT_FOR_DISPOSE); - this.sendDisposeCommand(); - return this.currentTask.promise - .then(() => kill(this.workerProcess.pid)); - } - - private sendRunCommand(options: RunOptions) { - this.send({ - kind: 'run', - runOptions: options - }); - } - - private send(message: AdapterMessage) { - try { - // Serialize message before sending to preserve all javascript, including regex's and functions - // See https://github.com/stryker-mutator/stryker/issues/143 - this.workerProcess.send(serialize(message)); - } catch (error) { - this.currentTask.reject(error); - } - } - - private sendStartCommand() { - this.send({ - kind: 'start', - runnerName: this.realTestRunnerName, - runnerOptions: this.options, - sandboxWorkingDirectory: this.sandboxWorkingDirectory, - loggingContext: this.loggingContext - }); - } - - private sendInitCommand() { - this.send({ kind: 'init' }); - } - - private sendDisposeCommand() { - this.send({ kind: 'dispose' }); - } -} \ No newline at end of file diff --git a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts b/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts deleted file mode 100644 index 8a21099ed7..0000000000 --- a/packages/stryker/src/isolated-runner/IsolatedTestRunnerAdapterWorker.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { AdapterMessage, RunMessage, StartMessage, WorkerMessage, InitDoneMessage } from './MessageProtocol'; -import { TestRunner, RunStatus, TestRunnerFactory, RunResult } from 'stryker-api/test_runner'; -import PluginLoader from '../PluginLoader'; -import { getLogger, Logger } from 'stryker-api/logging'; -import { deserialize, errorToString } from '../utils/objectUtils'; -import LogConfigurator from '../logging/LogConfigurator'; - -class IsolatedTestRunnerAdapterWorker { - - private log: Logger; - private underlyingTestRunner: TestRunner; - - constructor() { - this.handlePromiseRejections(); - this.listenToMessages(); - } - - private listenToMessages() { - process.on('message', (serializedMessage: string) => { - const message = deserialize(serializedMessage); - switch (message.kind) { - case 'start': - this.start(message); - break; - case 'run': - this.run(message); - break; - case 'init': - this.init(); - break; - case 'dispose': - const sendDisposeDone = this.sendDisposeDone.bind(this); - this.dispose().then(sendDisposeDone, sendDisposeDone); - break; - default: - this.logReceivedMessageWarning(message); - } - }); - } - - /** - * During mutation testing, it's to be expected that promise rejections are not handled synchronously anymore (or not at all) - * Let's handle those events so future versions of node don't crash - * See issue 350: https://github.com/stryker-mutator/stryker/issues/350 - */ - private handlePromiseRejections() { - const unhandledRejections: Promise[] = []; - process.on('unhandledRejection', (reason, promise) => { - const unhandledPromiseId = unhandledRejections.push(promise); - this.log.debug(`UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: ${unhandledPromiseId}): ${reason}`); - }); - process.on('rejectionHandled', (promise) => { - const unhandledPromiseId = unhandledRejections.indexOf(promise) + 1; - this.log.debug(`PromiseRejectionHandledWarning: Promise rejection was handled asynchronously (rejection id: ${unhandledPromiseId})`); - }); - } - - private logReceivedMessageWarning(message: never) { - this.log.warn('Received unsupported message: {}', JSON.stringify(message)); - } - - start(message: StartMessage) { - LogConfigurator.configureChildProcess(message.loggingContext); - this.log = getLogger(IsolatedTestRunnerAdapterWorker.name); - this.loadPlugins(message.runnerOptions.strykerOptions.plugins || []); - this.log.debug(`Changing current working directory for this process to ${message.sandboxWorkingDirectory}`); - process.chdir(message.sandboxWorkingDirectory); - this.underlyingTestRunner = TestRunnerFactory.instance().create(message.runnerName, message.runnerOptions); - } - - async init() { - if (this.underlyingTestRunner.init) { - try { - await this.underlyingTestRunner.init(); - } catch (err) { - this.sendInitDone(errorToString(err)); - } - } - this.sendInitDone(); - } - - sendInitDone(errorMessage: string | null = null) { - const message: InitDoneMessage = { kind: 'initDone', errorMessage }; - if (process.send) { - process.send(message); - } - } - - async dispose() { - try { - if (this.underlyingTestRunner.dispose) { - await this.underlyingTestRunner.dispose(); - } - } finally { - await LogConfigurator.shutdown(); - } - } - - sendDisposeDone() { - this.send({ kind: 'disposeDone' }); - } - - async run(body: RunMessage) { - try { - let res = await this.underlyingTestRunner.run(body.runOptions); - this.reportResult(res); - } catch (error) { - this.reportErrorResult(error); - } - } - - private send(message: WorkerMessage) { - if (process.send) { - process.send(message); - } - } - - private loadPlugins(plugins: string[]) { - new PluginLoader(plugins).load(); - } - - private reportResult(result: RunResult) { - // If the test runner didn't report on coverage, let's try to do it ourselves. - if (!result.coverage) { - result.coverage = (Function('return this'))().__coverage__; - } - if (result.errorMessages) { - // errorMessages should be a string[] - // Just in case the test runner implementer forgot to convert `Error`s to string, we will do it here - // https://github.com/stryker-mutator/stryker/issues/141 - result.errorMessages = result.errorMessages.map(errorToString); - } - this.send({ - kind: 'result', - result - }); - } - - private reportErrorResult(error: any) { - const runResult: RunResult = { - tests: [], - status: RunStatus.Error, - }; - if (error) { - if (Array.isArray(error)) { - runResult.errorMessages = error.map((e: any) => e); - } else { - runResult.errorMessages = [error]; - } - } - this.reportResult(runResult); - } -} - -new IsolatedTestRunnerAdapterWorker(); \ No newline at end of file diff --git a/packages/stryker/src/isolated-runner/MessageProtocol.ts b/packages/stryker/src/isolated-runner/MessageProtocol.ts deleted file mode 100644 index 05e6ae31d5..0000000000 --- a/packages/stryker/src/isolated-runner/MessageProtocol.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { RunResult, RunnerOptions } from 'stryker-api/test_runner'; -import { RunOptions } from 'stryker-api/test_runner'; -import LoggingClientContext from '../logging/LoggingClientContext'; - -export type AdapterMessage = RunMessage | StartMessage | EmptyAdapterMessage; -export type WorkerMessage = ResultMessage | EmptyWorkerMessage | InitDoneMessage; - -export interface ResultMessage { - kind: 'result'; - result: RunResult; -} - -export interface RunMessage { - kind: 'run'; - runOptions: RunOptions; -} - -export interface StartMessage { - kind: 'start'; - runnerName: string; - runnerOptions: RunnerOptions; - sandboxWorkingDirectory: string; - loggingContext: LoggingClientContext; -} - -export interface InitDoneMessage { - kind: 'initDone'; - errorMessage: string | null; -} - -export interface EmptyAdapterMessage { - kind: 'init' | 'dispose'; -} - -export interface EmptyWorkerMessage { - kind: 'disposeDone'; -} \ No newline at end of file diff --git a/packages/stryker/src/test-runner/ChildProcessTestRunnerDecorator.ts b/packages/stryker/src/test-runner/ChildProcessTestRunnerDecorator.ts new file mode 100644 index 0000000000..4fcdbb9004 --- /dev/null +++ b/packages/stryker/src/test-runner/ChildProcessTestRunnerDecorator.ts @@ -0,0 +1,50 @@ +import { TestRunner, RunResult, RunOptions, RunnerOptions } from 'stryker-api/test_runner'; +import LoggingClientContext from '../logging/LoggingClientContext'; +import ChildProcessProxy from '../child-proxy/ChildProcessProxy'; +import ChildProcessTestRunnerWorker from './ChildProcessTestRunnerWorker'; +import { sleep } from '../utils/objectUtils'; + +const MAX_WAIT_FOR_DISPOSE = 2000; + +/** + * Runs the given test runner in a child process and forwards reports about test results + * Also implements timeout-mechanism (on timeout, restart the child runner and report timeout) + */ +export default class ChildProcessTestRunnerDecorator implements TestRunner { + + private readonly worker: ChildProcessProxy; + + constructor(realTestRunnerName: string, + options: RunnerOptions, + sandboxWorkingDirectory: string, + loggingContext: LoggingClientContext) { + this.worker = ChildProcessProxy.create( + require.resolve('./ChildProcessTestRunnerWorker.js'), + loggingContext, + options.strykerOptions.plugins || [], + sandboxWorkingDirectory, + ChildProcessTestRunnerWorker, realTestRunnerName, options); + } + + init(): Promise { + return this.worker.proxy.init(); + } + + run(options: RunOptions): Promise { + return this.worker.proxy.run(options); + } + + async dispose(): Promise { + + await Promise.race([ + // First let the inner test runner dispose + this.worker.proxy.dispose(), + + // ... but don't wait forever on that + sleep(MAX_WAIT_FOR_DISPOSE) + ]); + + // After that, dispose the child process itself + await this.worker.dispose(); + } +} \ No newline at end of file diff --git a/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts b/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts new file mode 100644 index 0000000000..759f493e28 --- /dev/null +++ b/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts @@ -0,0 +1,46 @@ +import { TestRunner, TestRunnerFactory, RunnerOptions, RunOptions } from 'stryker-api/test_runner'; +import { errorToString } from '../utils/objectUtils'; + +/** + * + */ +export default class ChildProcessTestRunnerWorker implements TestRunner { + + private underlyingTestRunner: TestRunner; + + constructor(realTestRunnerName: string, options: RunnerOptions) { + this.underlyingTestRunner = TestRunnerFactory.instance().create(realTestRunnerName, options); + } + + init(): Promise | void { + if (this.underlyingTestRunner.init) { + return this.underlyingTestRunner.init(); + } else { + return; + } + } + + dispose() { + if (this.underlyingTestRunner.dispose) { + return this.underlyingTestRunner.dispose(); + } else { + return; + } + } + + + async run(options: RunOptions) { + const result = await this.underlyingTestRunner.run(options); + // If the test runner didn't report on coverage, let's try to do it ourselves. + if (!result.coverage) { + result.coverage = (Function('return this'))().__coverage__; + } + if (result.errorMessages) { + // errorMessages should be a string[] + // Just in case the test runner implementer forgot to convert `Error`s to string, we will do it here + // https://github.com/stryker-mutator/stryker/issues/141 + result.errorMessages = result.errorMessages.map(errorToString); + } + return result; + } +} \ No newline at end of file diff --git a/packages/stryker/src/isolated-runner/ResilientTestRunnerFactory.ts b/packages/stryker/src/test-runner/ResilientTestRunnerFactory.ts similarity index 69% rename from packages/stryker/src/isolated-runner/ResilientTestRunnerFactory.ts rename to packages/stryker/src/test-runner/ResilientTestRunnerFactory.ts index 711e27361a..aa2984d068 100644 --- a/packages/stryker/src/isolated-runner/ResilientTestRunnerFactory.ts +++ b/packages/stryker/src/test-runner/ResilientTestRunnerFactory.ts @@ -1,4 +1,4 @@ -import IsolatedTestRunnerAdapter from './IsolatedTestRunnerAdapter'; +import ChildProcessTestRunnerDecorator from './ChildProcessTestRunnerDecorator'; import TimeoutDecorator from './TimeoutDecorator'; import RetryDecorator from './RetryDecorator'; import TestRunnerDecorator from './TestRunnerDecorator'; @@ -9,6 +9,6 @@ import { RunnerOptions } from 'stryker-api/test_runner'; export default { create(testRunnerName: string, settings: RunnerOptions, sandboxWorkingDirectory: string, loggingContext: LoggingClientContext): TestRunnerDecorator { return new RetryDecorator(() => - new TimeoutDecorator(() => new IsolatedTestRunnerAdapter(testRunnerName, settings, sandboxWorkingDirectory, loggingContext))); + new TimeoutDecorator(() => new ChildProcessTestRunnerDecorator(testRunnerName, settings, sandboxWorkingDirectory, loggingContext))); } }; \ No newline at end of file diff --git a/packages/stryker/src/isolated-runner/RetryDecorator.ts b/packages/stryker/src/test-runner/RetryDecorator.ts similarity index 90% rename from packages/stryker/src/isolated-runner/RetryDecorator.ts rename to packages/stryker/src/test-runner/RetryDecorator.ts index b8f87bdccc..a3a46c84f6 100644 --- a/packages/stryker/src/isolated-runner/RetryDecorator.ts +++ b/packages/stryker/src/test-runner/RetryDecorator.ts @@ -1,9 +1,9 @@ import { RunOptions, RunResult, RunStatus } from 'stryker-api/test_runner'; -import { isErrnoException, errorToString } from '../utils/objectUtils'; +import { errorToString } from '../utils/objectUtils'; import TestRunnerDecorator from './TestRunnerDecorator'; import Task from '../utils/Task'; +import ChildProcessCrashedError from '../child-proxy/ChildProcessCrashedError'; -const BROKEN_PIPE_ERROR_CODE = 'EPIPE'; const ERROR_MESSAGE = 'Test runner crashed. Tried twice to restart it without any luck. Last time the error message was: '; /** @@ -30,7 +30,7 @@ export default class RetryDecorator extends TestRunnerDecorator { } private innerProcessIsCrashed(error: any) { - return isErrnoException(error) && error.code === BROKEN_PIPE_ERROR_CODE; + return error instanceof ChildProcessCrashedError; } private tryRun(options: RunOptions, retriesLeft = 2, lastError?: any) { diff --git a/packages/stryker/src/isolated-runner/TestRunnerDecorator.ts b/packages/stryker/src/test-runner/TestRunnerDecorator.ts similarity index 100% rename from packages/stryker/src/isolated-runner/TestRunnerDecorator.ts rename to packages/stryker/src/test-runner/TestRunnerDecorator.ts diff --git a/packages/stryker/src/isolated-runner/TimeoutDecorator.ts b/packages/stryker/src/test-runner/TimeoutDecorator.ts similarity index 100% rename from packages/stryker/src/isolated-runner/TimeoutDecorator.ts rename to packages/stryker/src/test-runner/TimeoutDecorator.ts diff --git a/packages/stryker/src/utils/objectUtils.ts b/packages/stryker/src/utils/objectUtils.ts index 4bd520d8c8..40567b8f65 100644 --- a/packages/stryker/src/utils/objectUtils.ts +++ b/packages/stryker/src/utils/objectUtils.ts @@ -100,4 +100,10 @@ export function kill(pid: number): Promise { return code === 255 || code === 128; } }); +} + +export function sleep(ms: number) { + return new Promise(res => { + setTimeout(res, ms); + }); } \ No newline at end of file diff --git a/packages/stryker/test/helpers/utils.ts b/packages/stryker/test/helpers/utils.ts deleted file mode 100644 index e9f0fcb0bb..0000000000 --- a/packages/stryker/test/helpers/utils.ts +++ /dev/null @@ -1,5 +0,0 @@ -export function sleep(ms: number) { - return new Promise(res => { - setTimeout(res, ms); - }); -} \ No newline at end of file diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index 998440e5ec..6cbc01fb06 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -11,7 +11,7 @@ import LoggingServer from '../../helpers/LoggingServer'; import { filter } from 'rxjs/operators'; import { Mock } from '../../helpers/producers'; import currentLogMock from '../../helpers/logMock'; -import { sleep } from '../../helpers/utils'; +import { sleep } from '../../../src/utils/objectUtils'; describe('ChildProcessProxy', function () { @@ -107,7 +107,7 @@ describe('ChildProcessProxy', function () { await sleep(10); await expect(sut.proxy.exit(12)).rejected; const call = log.warn.getCall(0); - expect(call.args[0]).includes('Child process exited unexpectedly with exit code 12 (without signal). Last part of stdout and stderr was:'); + expect(call.args[0]).matches(/Child process \[pid \d+\] exited unexpectedly with exit code 12 \(without signal\)\. Last part of stdout and stderr was/g); expect(call.args[0]).includes('stdout message'); expect(call.args[0]).includes('stderr message'); }); diff --git a/packages/stryker/test/integration/isolated-runner/AdditionalTestRunners.ts b/packages/stryker/test/integration/test-runner/AdditionalTestRunners.ts similarity index 99% rename from packages/stryker/test/integration/isolated-runner/AdditionalTestRunners.ts rename to packages/stryker/test/integration/test-runner/AdditionalTestRunners.ts index 303a9afe37..ae10b9c88a 100644 --- a/packages/stryker/test/integration/isolated-runner/AdditionalTestRunners.ts +++ b/packages/stryker/test/integration/test-runner/AdditionalTestRunners.ts @@ -39,7 +39,6 @@ class DiscoverRegexTestRunner implements TestRunner { } } - class ErroredTestRunner implements TestRunner { run() { diff --git a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts b/packages/stryker/test/integration/test-runner/ResilientTestRunnerFactory.it.ts similarity index 77% rename from packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts rename to packages/stryker/test/integration/test-runner/ResilientTestRunnerFactory.it.ts index 9d1aaaef68..9d6d4a15c5 100644 --- a/packages/stryker/test/integration/isolated-runner/ResilientTestRunnerFactory.it.ts +++ b/packages/stryker/test/integration/test-runner/ResilientTestRunnerFactory.it.ts @@ -3,13 +3,13 @@ import { expect } from 'chai'; import * as getPort from 'get-port'; import { RunStatus, RunnerOptions } from 'stryker-api/test_runner'; import * as log4js from 'log4js'; -import ResilientTestRunnerFactory from '../../../src/isolated-runner/ResilientTestRunnerFactory'; -import TestRunnerDecorator from '../../../src/isolated-runner/TestRunnerDecorator'; +import ResilientTestRunnerFactory from '../../../src/test-runner/ResilientTestRunnerFactory'; +import TestRunnerDecorator from '../../../src/test-runner/TestRunnerDecorator'; import { LogLevel } from 'stryker-api/core'; import LoggingServer from '../../helpers/LoggingServer'; import LoggingClientContext from '../../../src/logging/LoggingClientContext'; import { toArray } from 'rxjs/operators'; -import { sleep } from '../../helpers/utils'; +import { sleep } from '../../../src/utils/objectUtils'; describe('ResilientTestRunnerFactory integration', function () { @@ -17,7 +17,7 @@ describe('ResilientTestRunnerFactory integration', function () { let sut: TestRunnerDecorator; let options: RunnerOptions; - const sandboxWorkingDirectory = path.resolve('./test/integration/isolated-runner'); + const sandboxWorkingDirectory = path.resolve('./test/integration/test-runner'); let loggingContext: LoggingClientContext; let loggingServer: LoggingServer; @@ -30,7 +30,7 @@ describe('ResilientTestRunnerFactory integration', function () { loggingContext = { port, level: LogLevel.Trace }; options = { strykerOptions: { - plugins: ['../../test/integration/isolated-runner/AdditionalTestRunners'], + plugins: [require.resolve('./AdditionalTestRunners')], testRunner: 'karma', testFramework: 'jasmine', port: 0, @@ -49,8 +49,13 @@ describe('ResilientTestRunnerFactory integration', function () { await loggingServer.dispose(); }); - function arrangeSut(name: string): TestRunnerDecorator { - return sut = ResilientTestRunnerFactory.create(name, options, sandboxWorkingDirectory, loggingContext); + function createSut(name: string) { + sut = ResilientTestRunnerFactory.create(name, options, sandboxWorkingDirectory, loggingContext); + } + + async function arrangeSut(name: string): Promise { + createSut(name); + await sut.init(); } function actRun(timeout = 4000) { @@ -58,47 +63,44 @@ describe('ResilientTestRunnerFactory integration', function () { } it('should be able to receive a regex', async () => { - sut = arrangeSut('discover-regex'); + await arrangeSut('discover-regex'); const result = await actRun(); expect(result.status).eq(RunStatus.Complete); }); it('should pass along the coverage result from the test runner behind', async () => { - sut = arrangeSut('coverage-reporting'); + await arrangeSut('coverage-reporting'); const result = await actRun(); expect(result.coverage).eq('realCoverage'); }); it('should pass along the run result', async () => { - sut = arrangeSut('direct-resolved'); + await arrangeSut('direct-resolved'); const result = await actRun(); expect(result.status).eq(RunStatus.Complete); }); it('should try to report coverage from the global scope, even when the test runner behind does not', async () => { - sut = arrangeSut('direct-resolved'); + await arrangeSut('direct-resolved'); const result = await actRun(); expect(result.coverage).eq('coverageObject'); }); it('should resolve in a timeout if the test runner never resolves', async () => { - sut = arrangeSut('never-resolved'); - await sut.init(); + await arrangeSut('never-resolved'); const result = await actRun(1000); expect(RunStatus[result.status]).eq(RunStatus[RunStatus.Timeout]); }); it('should be able to recover from a timeout by creating a new child process', async () => { - sut = arrangeSut('never-resolved'); - await sut.init(); + await arrangeSut('never-resolved'); await actRun(1000); // first timeout const result = await actRun(1000); expect(RunStatus[result.status]).eq(RunStatus[RunStatus.Timeout]); }); it('should convert any `Error` objects to string', async () => { - sut = arrangeSut('errored'); - await sut.init(); + await arrangeSut('errored'); const result = await actRun(1000); expect(RunStatus[result.status]).to.be.eq(RunStatus[RunStatus.Error]); expect(result.errorMessages).to.have.length(1); @@ -106,33 +108,31 @@ describe('ResilientTestRunnerFactory integration', function () { }); it('should run only after initialization, even when it is slow', async () => { - sut = arrangeSut('slow-init-dispose'); - await sut.init(); + await arrangeSut('slow-init-dispose'); const result = await actRun(1000); expect(RunStatus[result.status]).eq(RunStatus[RunStatus.Complete]); }); it('should be able to run twice in quick succession', async () => { - sut = arrangeSut('direct-resolved'); - await actRun(); + await arrangeSut('direct-resolved'); const result = await actRun(); expect(RunStatus[result.status]).eq(RunStatus[RunStatus.Complete]); }); - it('should reject when `init` of test runner behind rejects', () => { - sut = arrangeSut('reject-init'); - return expect(sut.init()).rejectedWith('Init was rejected'); + it('should reject when `init` of test runner behind rejects', async () => { + createSut('reject-init'); + await expect(sut.init()).rejectedWith('Init was rejected'); }); it('should change the current working directory to the sandbox directory', async () => { - sut = arrangeSut('verify-working-folder'); + await arrangeSut('verify-working-folder'); const result = await actRun(); expect(result.errorMessages).undefined; }); - it('should be able to recover from any crash', async () => { + it('should be able to recover from a crash', async () => { // time-bomb will crash after 100 ms - sut = arrangeSut('time-bomb'); + await arrangeSut('time-bomb'); await sleep(101); const result = await actRun(); expect(RunStatus[result.status]).eq(RunStatus[RunStatus.Complete]); @@ -141,8 +141,7 @@ describe('ResilientTestRunnerFactory integration', function () { it('should handle asynchronously handled promise rejections from the underlying test runner', async () => { const logEvents = loggingServer.event$.pipe(toArray()).toPromise(); - sut = arrangeSut('async-promise-rejection-handler'); - await sut.init(); + await arrangeSut('async-promise-rejection-handler'); await actRun(); await sut.dispose(); alreadyDisposed = true; diff --git a/packages/stryker/test/unit/SandboxSpec.ts b/packages/stryker/test/unit/SandboxSpec.ts index ebbaec40d6..2b06285b27 100644 --- a/packages/stryker/test/unit/SandboxSpec.ts +++ b/packages/stryker/test/unit/SandboxSpec.ts @@ -9,7 +9,7 @@ import { File, LogLevel } from 'stryker-api/core'; import { wrapInClosure, normalizeWhiteSpaces } from '../../src/utils/objectUtils'; import Sandbox from '../../src/Sandbox'; import { TempFolder } from '../../src/utils/TempFolder'; -import ResilientTestRunnerFactory from '../../src/isolated-runner/ResilientTestRunnerFactory'; +import ResilientTestRunnerFactory from '../../src/test-runner/ResilientTestRunnerFactory'; import TestableMutant, { TestSelectionResult } from '../../src/TestableMutant'; import { mutant as createMutant, testResult, Mock, createFileAlreadyExistsError } from '../helpers/producers'; import SourceFile from '../../src/SourceFile'; @@ -17,7 +17,7 @@ import '../helpers/globals'; import TranspiledMutant from '../../src/TranspiledMutant'; import * as fileUtils from '../../src/utils/fileUtils'; import currentLogMock from '../helpers/logMock'; -import TestRunnerDecorator from '../../src/isolated-runner/TestRunnerDecorator'; +import TestRunnerDecorator from '../../src/test-runner/TestRunnerDecorator'; import LoggingClientContext from '../../src/logging/LoggingClientContext'; import { RunnerOptions } from 'stryker-api/test_runner'; diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 21480890c5..5bc8e1078a 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -99,13 +99,13 @@ describe('ChildProcessProxy', () => { childProcessMock.stderr.emit('data', 'foo'); childProcessMock.stdout.emit('data', 'bar'); actExit(23, 'SIGTERM'); - expect(logMock.warn).calledWith(`Child process exited unexpectedly with exit code 23 (SIGTERM). Last part of stdout and stderr was: ${os.EOL + expect(logMock.warn).calledWithMatch(`Child process [pid ${childProcessMock.pid}] exited unexpectedly with exit code 23 (SIGTERM). Last part of stdout and stderr was: ${os.EOL }\tfoo${os.EOL}\tbar`); }); it('should log that no stdout was available', () => { actExit(23, 'SIGTERM'); - expect(logMock.warn).calledWith('Child process exited unexpectedly with exit code 23 (SIGTERM). Stdout and stderr were empty.'); + expect(logMock.warn).calledWith(`Child process [pid ${childProcessMock.pid}] exited unexpectedly with exit code 23 (SIGTERM). Stdout and stderr were empty.`); }); it('should reject any outstanding worker promises with the error', () => { diff --git a/packages/stryker/test/unit/isolated-runner/ChildProcessTestRunnerAdapterSpec.ts b/packages/stryker/test/unit/isolated-runner/ChildProcessTestRunnerAdapterSpec.ts new file mode 100644 index 0000000000..abbd3a13b6 --- /dev/null +++ b/packages/stryker/test/unit/isolated-runner/ChildProcessTestRunnerAdapterSpec.ts @@ -0,0 +1,84 @@ +import * as sinon from 'sinon'; +import { expect } from 'chai'; +import { RunnerOptions, RunOptions } from 'stryker-api/test_runner'; +import { LogLevel } from 'stryker-api/core'; +import ChildProcessTestRunnerDecorator from '../../../src/test-runner/ChildProcessTestRunnerDecorator'; +import { Mock, mock } from '../../helpers/producers'; +import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; +import LoggingClientContext from '../../../src/logging/LoggingClientContext'; +import ChildProcessTestRunnerWorker from '../../../src/test-runner/ChildProcessTestRunnerWorker'; +import TestRunnerDecorator from '../../../src/test-runner/TestRunnerDecorator'; +import Task from '../../../src/utils/Task'; + +describe(ChildProcessTestRunnerDecorator.name, () => { + let sut: ChildProcessTestRunnerDecorator; + let runnerOptions: RunnerOptions; + let childProcessProxyMock: { + proxy: Mock; + dispose: sinon.SinonStub; + }; + let childProcessProxyCreateStub: sinon.SinonStub; + let loggingContext: LoggingClientContext; + let clock: sinon.SinonFakeTimers; + + beforeEach(() => { + clock = sandbox.useFakeTimers(); + childProcessProxyMock = { + proxy: mock(TestRunnerDecorator), + dispose: sandbox.stub() + }; + childProcessProxyCreateStub = sandbox.stub(ChildProcessProxy, 'create'); + childProcessProxyCreateStub.returns(childProcessProxyMock); + runnerOptions = { + fileNames: [], + port: 42, + strykerOptions: { + plugins: ['foo-plugin', 'bar-plugin'] + } + }; + loggingContext = { port: 4200, level: LogLevel.Fatal }; + sut = new ChildProcessTestRunnerDecorator('realRunner', runnerOptions, 'a working directory', loggingContext); + }); + + it('should create the child process proxy', () => { + expect(childProcessProxyCreateStub).calledWith( + require.resolve('../../../src/test-runner/ChildProcessTestRunnerWorker.js'), + loggingContext, + ['foo-plugin', 'bar-plugin'], + 'a working directory', + ChildProcessTestRunnerWorker, + 'realRunner', runnerOptions + ); + }); + + it('should forward `init` calls', () => { + childProcessProxyMock.proxy.init.resolves(42); + return expect(sut.init()).eventually.eq(42); + }); + + it('should forward `run` calls', async () => { + childProcessProxyMock.proxy.run.resolves(42); + const runOptions: RunOptions = { + timeout: 234 + }; + await expect(sut.run(runOptions)).eventually.eq(42); + expect(childProcessProxyMock.proxy.run).calledWith(runOptions); + }); + + it('should dispose the test runner first on `dispose`', async () => { + childProcessProxyMock.proxy.dispose.resolves(); + await sut.dispose(); + expect(childProcessProxyMock.proxy.dispose) + .calledBefore(childProcessProxyMock.dispose); + }); + + it('should only wait 2 seconds for the test runner to be disposed', async () => { + const testRunnerDisposeTask = new Task(); + childProcessProxyMock.proxy.dispose.returns(testRunnerDisposeTask.promise); + const disposePromise = sut.dispose(); + clock.tick(2001); + await disposePromise; + expect(childProcessProxyMock.dispose).called; + testRunnerDisposeTask.resolve(undefined); + }); +}); \ No newline at end of file diff --git a/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts b/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts deleted file mode 100644 index 5a49298bee..0000000000 --- a/packages/stryker/test/unit/isolated-runner/IsolatedTestRunnerAdapterSpec.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { EmptyAdapterMessage } from './../../../src/isolated-runner/MessageProtocol'; -import * as path from 'path'; -import * as child_process from 'child_process'; -import * as _ from 'lodash'; -import * as sinon from 'sinon'; -import { expect } from 'chai'; -import { RunResult, RunStatus, RunnerOptions } from 'stryker-api/test_runner'; -import IsolatedTestRunnerAdapter from '../../../src/isolated-runner/IsolatedTestRunnerAdapter'; -import { WorkerMessage, RunMessage, ResultMessage } from '../../../src/isolated-runner/MessageProtocol'; -import * as objectUtils from '../../../src/utils/objectUtils'; -import { LogLevel } from 'stryker-api/core'; - -describe('IsolatedTestRunnerAdapter', () => { - let sut: IsolatedTestRunnerAdapter; - let sinonSandbox: sinon.SinonSandbox; - let clock: sinon.SinonFakeTimers; - let killStub: sinon.SinonStub; - let fakeChildProcess: { - kill: sinon.SinonStub; - send: sinon.SinonStub; - on: sinon.SinonStub; - pid: number; - }; - let runnerOptions: RunnerOptions; - - beforeEach(() => { - runnerOptions = { - fileNames: [], - port: 42, - strykerOptions: {} - }; - sinonSandbox = sinon.createSandbox(); - fakeChildProcess = { - kill: sinon.stub(), - send: sinon.stub(), - on: sinon.stub(), - pid: 42 - }; - killStub = sinonSandbox.stub(objectUtils, 'kill'); - sinonSandbox.stub(child_process, 'fork').returns(fakeChildProcess); - clock = sinon.useFakeTimers(); - }); - - describe('when constructed', () => { - - beforeEach(() => { - sut = new IsolatedTestRunnerAdapter('realRunner', runnerOptions, 'a working directory', { port: 4200, level: LogLevel.Fatal }); - }); - - it('should spawn a child process', () => { - let expectedWorkerProcessPath = path.resolve(__dirname + '/../../../src/isolated-runner/') + '/IsolatedTestRunnerAdapterWorker'; - let expectedExecArgv = _.clone(process.execArgv); - _.remove(expectedExecArgv, arg => arg.substr(0, 11) === '--debug-brk'); - expect(child_process.fork).to.have.been.calledWith(expectedWorkerProcessPath, [], { execArgv: expectedExecArgv, silent: true }); - expect(fakeChildProcess.on).to.have.been.calledWith('message'); - }); - - describe('init', () => { - - let initPromise: Promise; - - function arrangeAct() { - initPromise = sut.init(); - clock.tick(500); - receiveResultMessage(); - } - - it('should call "init" on child process', () => { - arrangeAct(); - const expectedMessage: EmptyAdapterMessage = { kind: 'init' }; - expect(fakeChildProcess.send).to.have.been.calledWith(objectUtils.serialize(expectedMessage)); - }); - - - it(' "initDone"', () => { - arrangeAct(); - receiveMessage({ kind: 'initDone', errorMessage: null }); - return expect(initPromise).to.eventually.eq(undefined); - }); - - it('should reject any exceptions', () => { - fakeChildProcess.send.throws(new Error('some error')); - arrangeAct(); - return expect(initPromise).to.be.rejectedWith('some error'); - }); - }); - - describe('run(options)', () => { - const runOptions: { timeout: 2000 } = { timeout: 2000 }; - let runPromise: Promise; - - function act() { - runPromise = sut.run(runOptions); - } - - it('should send run-message to worker', () => { - act(); - const expectedMessage: RunMessage = { - kind: 'run', - runOptions - }; - expect(fakeChildProcess.send).to.have.been.calledWith(objectUtils.serialize(expectedMessage)); - }); - - it('should proxy run response', () => { - const expectedResult: RunResult = { - status: RunStatus.Error, - errorMessages: ['OK, only used for unit testing'], - tests: [] - }; - act(); - receiveMessage({ kind: 'result', result: expectedResult }); - expect(runPromise).to.eventually.be.eq(expectedResult); - }); - - it('should reject any exceptions', () => { - fakeChildProcess.send.throws(new Error('some error')); - act(); - return expect(runPromise).to.be.rejectedWith('some error'); - }); - }); - - describe('dispose()', () => { - - it('should send `dispose` to worker process', () => { - sut.dispose(); - return expect(fakeChildProcess.send).to.have.been.calledWith(objectUtils.serialize({ kind: 'dispose' })); - }); - - describe('and child process responds to dispose', () => { - beforeEach(() => { - const promise = sut.dispose(); - receiveMessage({ kind: 'disposeDone' }); - return promise; - }); - - it('should kill the child process', () => { - expect(killStub).to.have.been.calledWith(42); - }); - }); - - describe('and a timeout occurred', () => { - - beforeEach(() => { - // Wait for worker process takes 2000 ms - const promise = sut.dispose(); - clock.tick(2000); - return promise; - }); - - it('should kill the child process', () => { - expect(killStub).to.have.been.calledWith(42); - }); - }); - }); - it('should reject any exceptions', () => { - fakeChildProcess.send.throws(new Error('some error')); - return expect(sut.run({ timeout: 24 })).to.be.rejectedWith('some error'); - }); - }); - - const receiveResultMessage = () => { - const message: ResultMessage = { kind: 'result', result: { status: RunStatus.Complete, tests: [] } }; - receiveMessage(message); - return message; - }; - - const receiveMessage = (message: WorkerMessage) => { - const callback: (message: WorkerMessage) => void = fakeChildProcess.on.getCall(0).args[1]; - callback(message); - return message; - }; - - afterEach(() => { - clock.restore(); - sinonSandbox.restore(); - }); -}); \ No newline at end of file diff --git a/packages/stryker/test/unit/isolated-runner/RetryDecoratorSpec.ts b/packages/stryker/test/unit/isolated-runner/RetryDecoratorSpec.ts index 212be6b28a..d217dbc0ed 100644 --- a/packages/stryker/test/unit/isolated-runner/RetryDecoratorSpec.ts +++ b/packages/stryker/test/unit/isolated-runner/RetryDecoratorSpec.ts @@ -1,9 +1,10 @@ import { expect } from 'chai'; import { RunResult, RunStatus } from 'stryker-api/test_runner'; -import RetryDecorator from '../../../src/isolated-runner/RetryDecorator'; +import RetryDecorator from '../../../src/test-runner/RetryDecorator'; import TestRunnerMock from '../../helpers/TestRunnerMock'; import { errorToString } from '../../../src/utils/objectUtils'; -import TestRunnerDecorator from '../../../src/isolated-runner/TestRunnerDecorator'; +import TestRunnerDecorator from '../../../src/test-runner/TestRunnerDecorator'; +import ChildProcessCrashedError from '../../../src/child-proxy/ChildProcessCrashedError'; describe('RetryDecorator', () => { let sut: RetryDecorator; @@ -14,11 +15,7 @@ describe('RetryDecorator', () => { let availableTestRunners: TestRunnerMock[]; const options = { timeout: 2 }; const expectedResult = 'something'; - const brokenPipeError: NodeJS.ErrnoException = { - name: '', - code: 'EPIPE', - message: 'Intended error for testing' - }; + const crashedError = new ChildProcessCrashedError(null); beforeEach(() => { testRunner1 = new TestRunnerMock(); @@ -42,7 +39,7 @@ describe('RetryDecorator', () => { }); it('should swallow rejections when inner process crashed', () => { - testRunner1.dispose.rejects(brokenPipeError); + testRunner1.dispose.rejects(crashedError); return expect(sut.dispose()).to.eventually.not.be.ok; }); @@ -66,20 +63,20 @@ describe('RetryDecorator', () => { }); it('should retry on a new test runner if a crash related reject appears', () => { - testRunner1.run.rejects(brokenPipeError); + testRunner1.run.rejects(crashedError); testRunner2.run.resolves(expectedResult); return expect(sut.run(options)).to.eventually.eq(expectedResult); }); it('should retry at most 3 times before rejecting', () => { - testRunner1.run.rejects(brokenPipeError); - testRunner2.run.rejects(brokenPipeError); - testRunner3.run.rejects(brokenPipeError); - testRunner4.run.rejects(brokenPipeError); + testRunner1.run.rejects(crashedError); + testRunner2.run.rejects(crashedError); + testRunner3.run.rejects(crashedError); + testRunner4.run.rejects(crashedError); return sut.run(options).then((runResult: RunResult) => { expect(runResult.status).to.be.eq(RunStatus.Error); expect(runResult.errorMessages).to.be.deep.eq(['Test runner crashed. Tried twice to restart it without any luck. Last time the error message was: ' - + errorToString(brokenPipeError)]); + + errorToString(crashedError)]); expect(availableTestRunners).to.have.lengthOf(0); }); }); diff --git a/packages/stryker/test/unit/isolated-runner/TestRunnerDecoratorSpec.ts b/packages/stryker/test/unit/isolated-runner/TestRunnerDecoratorSpec.ts index 5813b4a5fa..468c194976 100644 --- a/packages/stryker/test/unit/isolated-runner/TestRunnerDecoratorSpec.ts +++ b/packages/stryker/test/unit/isolated-runner/TestRunnerDecoratorSpec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import TestRunnerDecorator from '../../../src/isolated-runner/TestRunnerDecorator'; +import TestRunnerDecorator from '../../../src/test-runner/TestRunnerDecorator'; import TestRunnerMock from '../../helpers/TestRunnerMock'; describe('TestRunnerDecorator', () => { diff --git a/packages/stryker/test/unit/isolated-runner/TimeoutDecoratorSpec.ts b/packages/stryker/test/unit/isolated-runner/TimeoutDecoratorSpec.ts index 8917b30aab..5fc90e55d7 100644 --- a/packages/stryker/test/unit/isolated-runner/TimeoutDecoratorSpec.ts +++ b/packages/stryker/test/unit/isolated-runner/TimeoutDecoratorSpec.ts @@ -1,7 +1,7 @@ import * as sinon from 'sinon'; import { expect } from 'chai'; import { RunStatus } from 'stryker-api/test_runner'; -import TimeoutDecorator from '../../../src/isolated-runner/TimeoutDecorator'; +import TimeoutDecorator from '../../../src/test-runner/TimeoutDecorator'; import { isPromise } from '../../../src/utils/objectUtils'; import TestRunnerMock from '../../helpers/TestRunnerMock'; From 9e91a25f294ddc97481ae21b654374ca2878c6e0 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sun, 22 Jul 2018 17:36:40 -0700 Subject: [PATCH 34/54] test(Test runner): Move unit tests to match source location --- packages/stryker/test/helpers/LoggingServer.ts | 3 ++- .../ChildProcessTestRunnerAdapterSpec.ts | 0 .../{isolated-runner => test-runner}/RetryDecoratorSpec.ts | 0 .../TestRunnerDecoratorSpec.ts | 0 .../{isolated-runner => test-runner}/TimeoutDecoratorSpec.ts | 0 5 files changed, 2 insertions(+), 1 deletion(-) rename packages/stryker/test/unit/{isolated-runner => test-runner}/ChildProcessTestRunnerAdapterSpec.ts (100%) rename packages/stryker/test/unit/{isolated-runner => test-runner}/RetryDecoratorSpec.ts (100%) rename packages/stryker/test/unit/{isolated-runner => test-runner}/TestRunnerDecoratorSpec.ts (100%) rename packages/stryker/test/unit/{isolated-runner => test-runner}/TimeoutDecoratorSpec.ts (100%) diff --git a/packages/stryker/test/helpers/LoggingServer.ts b/packages/stryker/test/helpers/LoggingServer.ts index 9c54971cd6..e20e69eed2 100644 --- a/packages/stryker/test/helpers/LoggingServer.ts +++ b/packages/stryker/test/helpers/LoggingServer.ts @@ -18,7 +18,8 @@ export default class LoggingServer { loggingEvents.forEach(event => this.subscriber && this.subscriber.next(event)); }); socket.on('error', () => { - // Idle + // A client connection was killed unexpectedly. + // This happens during integration tests, this is safe to ignore (log4js does that as well) }); }); this.server.listen(this.port); diff --git a/packages/stryker/test/unit/isolated-runner/ChildProcessTestRunnerAdapterSpec.ts b/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerAdapterSpec.ts similarity index 100% rename from packages/stryker/test/unit/isolated-runner/ChildProcessTestRunnerAdapterSpec.ts rename to packages/stryker/test/unit/test-runner/ChildProcessTestRunnerAdapterSpec.ts diff --git a/packages/stryker/test/unit/isolated-runner/RetryDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts similarity index 100% rename from packages/stryker/test/unit/isolated-runner/RetryDecoratorSpec.ts rename to packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts diff --git a/packages/stryker/test/unit/isolated-runner/TestRunnerDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/TestRunnerDecoratorSpec.ts similarity index 100% rename from packages/stryker/test/unit/isolated-runner/TestRunnerDecoratorSpec.ts rename to packages/stryker/test/unit/test-runner/TestRunnerDecoratorSpec.ts diff --git a/packages/stryker/test/unit/isolated-runner/TimeoutDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/TimeoutDecoratorSpec.ts similarity index 100% rename from packages/stryker/test/unit/isolated-runner/TimeoutDecoratorSpec.ts rename to packages/stryker/test/unit/test-runner/TimeoutDecoratorSpec.ts From 85c9d3a731f0cb0b237588624d5d171924134f5e Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 23 Jul 2018 21:58:13 -0700 Subject: [PATCH 35/54] fix(ChildProcessProxy): Don't wait forever on dispose in worker --- .../stryker/src/child-proxy/ChildProcessProxy.ts | 10 +++++++--- .../unit/child-proxy/ChildProcessProxySpec.ts | 15 ++++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index a825aa3e86..82f531397d 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -17,6 +17,7 @@ export type Promisified = { const BROKEN_PIPE_ERROR_CODE = 'EPIPE'; const IPC_CHANNEL_CLOSED_ERROR_CODE = 'ERR_IPC_CHANNEL_CLOSED'; +const TIMEOUT_FOR_DISPOSE = 2000; export default class ChildProcessProxy { readonly proxy: Promisified; @@ -33,6 +34,7 @@ export default class ChildProcessProxy { private constructor(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, constructorParams: any[]) { this.worker = fork(require.resolve('./ChildProcessProxyWorker'), [autoStart], { silent: true, execArgv: [] }); this.initTask = new Task(); + this.log.debug('Starting %s in a child process', requirePath); this.send({ kind: WorkerMessageKind.Init, loggingContext, @@ -163,8 +165,8 @@ export default class ChildProcessProxy { private handleUnexpectedExit(code: number | null, signal: string) { this.isDisposed = true; - this.log.warn(`Child process [pid ${this.worker.pid}] exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr(this.lastMessagesQueue)}`); this.currentError = new ChildProcessCrashedError(code); + this.log.warn(`Child process [pid ${this.worker.pid}] exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr(this.lastMessagesQueue)}`, this.currentError); this.reportError(this.currentError); function stdoutAndStderr(messages: string[]) { @@ -195,12 +197,14 @@ export default class ChildProcessProxy { if (this.isDisposed) { return Promise.resolve(); } else { - this.disposeTask = new Task(); - this.send({ kind: WorkerMessageKind.Dispose }); + this.log.debug('Disposing of worker process %s', this.worker.pid); const killWorker = () => { + this.log.debug('Kill %s', this.worker.pid); kill(this.worker.pid); this.isDisposed = true; }; + this.disposeTask = new Task(TIMEOUT_FOR_DISPOSE); + this.send({ kind: WorkerMessageKind.Dispose }); return this.disposeTask.promise .then(killWorker) .catch(killWorker); diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 5bc8e1078a..2b52e5d1ec 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -32,8 +32,10 @@ describe('ChildProcessProxy', () => { let childProcessMock: ChildProcessMock; let killStub: sinon.SinonStub; let logMock: Mock; + let clock: sinon.SinonFakeTimers; beforeEach(() => { + clock = sandbox.useFakeTimers(); childProcessMock = new ChildProcessMock(); forkStub = sandbox.stub(childProcess, 'fork'); killStub = sandbox.stub(objectUtils, 'kill'); @@ -148,7 +150,7 @@ describe('ChildProcessProxy', () => { // Act const delayedEcho = sut.proxy.sayHello('echo'); - await tick(); + clock.tick(0); receiveMessage(workerResponse); const result: string = await delayedEcho; @@ -189,6 +191,13 @@ describe('ChildProcessProxy', () => { expect(childProcessMock.send).calledOnce; // init }); + it('should only wait for max 2 seconds before going ahead and killing the child process anyway', async() => { + const disposePromise = sut.dispose(); + clock.tick(2000); + await disposePromise; + expect(killStub).called; + }); + async function actDispose() { const disposePromise = sut.dispose(); receiveMessage({ kind: ParentMessageKind.DisposeCompleted }); @@ -202,10 +211,6 @@ describe('ChildProcessProxy', () => { } }); -function tick() { - return new Promise(res => setTimeout(res, 0)); -} - function createSut(overrides: { requirePath?: string; loggingContext?: LoggingClientContext; From 9d62efe52a87f7a9d03927defbeb5292ed59af0c Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 23 Jul 2018 21:58:43 -0700 Subject: [PATCH 36/54] build: Don't run integration tests in stryker.conf.js --- packages/stryker/stryker.conf.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/stryker/stryker.conf.js b/packages/stryker/stryker.conf.js index e50fe48a8e..c88830dd97 100644 --- a/packages/stryker/stryker.conf.js +++ b/packages/stryker/stryker.conf.js @@ -11,7 +11,8 @@ module.exports = function (config) { 'package.json', 'src/**/*.ts', '!src/**/*.d.ts', - 'test/**/*.ts', + 'test/helpers/**/*.ts', + 'test/unit/**/*.ts', '!test/**/*.d.ts' ], symlinkNodeModules: false, @@ -44,12 +45,13 @@ module.exports = function (config) { testFramework: 'mocha', testRunner: 'mocha', reporter: ['progress', 'html', 'clear-text', 'event-recorder', 'dashboard'], - maxConcurrentTestRunners: 5, + maxConcurrentTestRunners: 4, thresholds: { high: 80, low: 60, break: null }, + fileLogLevel: 'trace', logLevel: 'info', plugins: [ require.resolve('../stryker-mocha-runner/src/index'), From b35cfe64c916947d96b10c52fd6e49f34f9a2da9 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 23 Jul 2018 22:00:20 -0700 Subject: [PATCH 37/54] fix(ChildProcessTestRunnerDecorator): Make resilient against crashes --- .../ChildProcessTestRunnerDecorator.ts | 10 ++++- ...=> ChildProcessTestRunnerDecoratorSpec.ts} | 39 ++++++++++++------- 2 files changed, 33 insertions(+), 16 deletions(-) rename packages/stryker/test/unit/test-runner/{ChildProcessTestRunnerAdapterSpec.ts => ChildProcessTestRunnerDecoratorSpec.ts} (69%) diff --git a/packages/stryker/src/test-runner/ChildProcessTestRunnerDecorator.ts b/packages/stryker/src/test-runner/ChildProcessTestRunnerDecorator.ts index 4fcdbb9004..e122b733cd 100644 --- a/packages/stryker/src/test-runner/ChildProcessTestRunnerDecorator.ts +++ b/packages/stryker/src/test-runner/ChildProcessTestRunnerDecorator.ts @@ -3,6 +3,7 @@ import LoggingClientContext from '../logging/LoggingClientContext'; import ChildProcessProxy from '../child-proxy/ChildProcessProxy'; import ChildProcessTestRunnerWorker from './ChildProcessTestRunnerWorker'; import { sleep } from '../utils/objectUtils'; +import ChildProcessCrashedError from '../child-proxy/ChildProcessCrashedError'; const MAX_WAIT_FOR_DISPOSE = 2000; @@ -35,10 +36,15 @@ export default class ChildProcessTestRunnerDecorator implements TestRunner { } async dispose(): Promise { - + await Promise.race([ // First let the inner test runner dispose - this.worker.proxy.dispose(), + this.worker.proxy.dispose().catch(error => { + // It's OK if the child process is already down. + if (!(error instanceof ChildProcessCrashedError)) { + throw error; + } + }), // ... but don't wait forever on that sleep(MAX_WAIT_FOR_DISPOSE) diff --git a/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerAdapterSpec.ts b/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts similarity index 69% rename from packages/stryker/test/unit/test-runner/ChildProcessTestRunnerAdapterSpec.ts rename to packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts index abbd3a13b6..26b350c9e5 100644 --- a/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerAdapterSpec.ts +++ b/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts @@ -9,6 +9,7 @@ import LoggingClientContext from '../../../src/logging/LoggingClientContext'; import ChildProcessTestRunnerWorker from '../../../src/test-runner/ChildProcessTestRunnerWorker'; import TestRunnerDecorator from '../../../src/test-runner/TestRunnerDecorator'; import Task from '../../../src/utils/Task'; +import ChildProcessCrashedError from '../../../src/child-proxy/ChildProcessCrashedError'; describe(ChildProcessTestRunnerDecorator.name, () => { let sut: ChildProcessTestRunnerDecorator; @@ -65,20 +66,30 @@ describe(ChildProcessTestRunnerDecorator.name, () => { expect(childProcessProxyMock.proxy.run).calledWith(runOptions); }); - it('should dispose the test runner first on `dispose`', async () => { - childProcessProxyMock.proxy.dispose.resolves(); - await sut.dispose(); - expect(childProcessProxyMock.proxy.dispose) - .calledBefore(childProcessProxyMock.dispose); - }); + describe('dispose', () => { + + it('should dispose the test runner before disposing the child process itself on `dispose`', async () => { + childProcessProxyMock.proxy.dispose.resolves(); + await sut.dispose(); + expect(childProcessProxyMock.proxy.dispose) + .calledBefore(childProcessProxyMock.dispose); + }); + + it('should not reject when the child process is down', async () => { + childProcessProxyMock.proxy.dispose.rejects(new ChildProcessCrashedError(1)); + await sut.dispose(); + expect(childProcessProxyMock.dispose).called; + }); + + it('should only wait 2 seconds for the test runner to be disposed', async () => { + const testRunnerDisposeTask = new Task(); + childProcessProxyMock.proxy.dispose.returns(testRunnerDisposeTask.promise); + const disposePromise = sut.dispose(); + clock.tick(2001); + await disposePromise; + expect(childProcessProxyMock.dispose).called; + testRunnerDisposeTask.resolve(undefined); + }); - it('should only wait 2 seconds for the test runner to be disposed', async () => { - const testRunnerDisposeTask = new Task(); - childProcessProxyMock.proxy.dispose.returns(testRunnerDisposeTask.promise); - const disposePromise = sut.dispose(); - clock.tick(2001); - await disposePromise; - expect(childProcessProxyMock.dispose).called; - testRunnerDisposeTask.resolve(undefined); }); }); \ No newline at end of file From 075f84fd81985bb21dac77a9197f971b00c6d882 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 23 Jul 2018 22:01:28 -0700 Subject: [PATCH 38/54] refactor(RetryDecorator): Remove redundent retry logic on dispose --- .../stryker/src/test-runner/RetryDecorator.ts | 38 +++----------- .../unit/test-runner/RetryDecoratorSpec.ts | 49 ++++++++----------- 2 files changed, 27 insertions(+), 60 deletions(-) diff --git a/packages/stryker/src/test-runner/RetryDecorator.ts b/packages/stryker/src/test-runner/RetryDecorator.ts index 76d9c11295..9b63e4a0fb 100644 --- a/packages/stryker/src/test-runner/RetryDecorator.ts +++ b/packages/stryker/src/test-runner/RetryDecorator.ts @@ -1,8 +1,6 @@ import { RunOptions, RunResult, RunStatus } from 'stryker-api/test_runner'; -import { errorToString } from '../utils/objectUtils'; import TestRunnerDecorator from './TestRunnerDecorator'; -import Task from '../utils/Task'; -import ChildProcessCrashedError from '../child-proxy/ChildProcessCrashedError'; +import { errorToString } from '../utils/objectUtils'; const ERROR_MESSAGE = 'Test runner crashed. Tried twice to restart it without any luck. Last time the error message was: '; @@ -10,45 +8,23 @@ const ERROR_MESSAGE = 'Test runner crashed. Tried twice to restart it without an * Wraps a test runner and implements the retry functionality. */ export default class RetryDecorator extends TestRunnerDecorator { - private currentRunTask: Task; - - run(options: RunOptions): Promise { - this.currentRunTask = new Task(); - this.tryRun(options); - return this.currentRunTask.promise; - } - - dispose(): Promise { - return super.dispose().catch(err => { - if (this.innerProcessIsCrashed(err)) { - return null; - } else { - // Oops, not intended to catch this one. Pass through - throw err; - } - }); - } - - private innerProcessIsCrashed(error: any) { - return error instanceof ChildProcessCrashedError; - } - private async tryRun(options: RunOptions, attemptsLeft = 2, lastError?: any) { + async run(options: RunOptions, attemptsLeft = 2, lastError?: Error): Promise { if (attemptsLeft > 0) { try { - let result = await this.innerRunner.run(options); - this.currentRunTask.resolve(result); + return await this.innerRunner.run(options); } catch (error) { await this.recover(); - await this.tryRun(options, attemptsLeft - 1, error); + return this.run(options, attemptsLeft - 1, error); } } else { await this.recover(); - this.currentRunTask.resolve({ status: RunStatus.Error, errorMessages: [ERROR_MESSAGE + errorToString(lastError)], tests: [] }); + return { status: RunStatus.Error, errorMessages: [ERROR_MESSAGE + errorToString(lastError)], tests: [] }; } } - private recover(): Promise { + private async recover(): Promise { + await this.dispose(); this.createInnerRunner(); return this.init(); } diff --git a/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts index a30f4f4b72..529000a96d 100644 --- a/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts +++ b/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { RunResult, RunStatus } from 'stryker-api/test_runner'; +import { RunStatus } from 'stryker-api/test_runner'; import RetryDecorator from '../../../src/test-runner/RetryDecorator'; import TestRunnerMock from '../../helpers/TestRunnerMock'; import { errorToString } from '../../../src/utils/objectUtils'; @@ -22,27 +22,12 @@ describe('RetryDecorator', () => { sut = new RetryDecorator(() => availableTestRunners.shift() || new TestRunnerMock()); }); - describe('init', () => { - it('should not be overridden', () => { - expect(sut.init).to.be.eq(TestRunnerDecorator.prototype.init); - }); + it('should not override `init`', () => { + expect(sut.init).to.be.eq(TestRunnerDecorator.prototype.init); }); - describe('dispose', () => { - it('should pass through when resolved', () => { - testRunner1.dispose.resolves(null); - return expect(sut.dispose()).to.eventually.eq(null); - }); - - it('should swallow rejections when inner process crashed', () => { - testRunner1.dispose.rejects(crashedError); - return expect(sut.dispose()).to.eventually.not.be.ok; - }); - - it('should pass through non-crash related rejections', () => { - testRunner1.dispose.rejects(new Error('someError')); - return expect(sut.dispose()).to.be.rejectedWith('someError'); - }); + it('should not override `dispose`', () => { + expect(sut.dispose).to.be.eq(TestRunnerDecorator.prototype.dispose); }); describe('run', () => { @@ -65,18 +50,24 @@ describe('RetryDecorator', () => { return expect(sut.run(options)).to.eventually.eq(expectedResult); }); - it('should retry at most 1 times before rejecting', () => { - const finalError = new Error('Error'); + it('should dispose a test runner when it rejected, before creating a new one', async () => { + testRunner1.run.rejects(crashedError); + testRunner2.run.resolves(expectedResult); + await sut.run(options); + expect(testRunner1.dispose).calledBefore(testRunner2.init); + }); - testRunner1.run.rejects(new Error('Error')); + it('should retry at most 1 times before rejecting', async () => { + const finalError = new Error('foo'); + + testRunner1.run.rejects(new Error('bar')); testRunner2.run.rejects(finalError); - return sut.run(options).then((runResult: RunResult) => { - expect(runResult.status).to.be.eq(RunStatus.Error); - expect(runResult.errorMessages).to.be.deep.eq(['Test runner crashed. Tried twice to restart it without any luck. Last time the error message was: ' - + errorToString(finalError)]); - expect(availableTestRunners).to.have.lengthOf(0); - }); + const runResult = await sut.run(options); + expect(runResult.status).to.be.eq(RunStatus.Error); + expect(runResult.errorMessages).to.be.deep.eq(['Test runner crashed. Tried twice to restart it without any luck. Last time the error message was: ' + + errorToString(finalError)]); + expect(availableTestRunners).to.have.lengthOf(0); }); }); }); \ No newline at end of file From f060649cb316073242cec0d98d532bf69d8b12ff Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 23 Jul 2018 22:02:01 -0700 Subject: [PATCH 39/54] fix(RetryDecorator): Cleanup unused promise --- .../src/test-runner/TimeoutDecorator.ts | 34 +++++++------------ .../unit/test-runner/TimeoutDecoratorSpec.ts | 8 ----- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/packages/stryker/src/test-runner/TimeoutDecorator.ts b/packages/stryker/src/test-runner/TimeoutDecorator.ts index d72f044c86..ed39ea855e 100644 --- a/packages/stryker/src/test-runner/TimeoutDecorator.ts +++ b/packages/stryker/src/test-runner/TimeoutDecorator.ts @@ -1,10 +1,9 @@ import { RunOptions, RunResult, RunStatus } from 'stryker-api/test_runner'; -import { isPromise } from '../utils/objectUtils'; -import Task from '../utils/Task'; import TestRunnerDecorator from './TestRunnerDecorator'; import { getLogger } from 'stryker-api/logging'; +import { sleep } from '../utils/objectUtils'; -const MAX_WAIT_FOR_DISPOSE = 2500; +const TIMEOUT_EXPIRED = 'timeout_expired'; /** * Wraps a test runner and implements the timeout functionality. @@ -13,30 +12,21 @@ export default class TimeoutDecorator extends TestRunnerDecorator { private readonly log = getLogger(TimeoutDecorator.name); - run(options: RunOptions): Promise { + async run(options: RunOptions): Promise { this.log.debug('Starting timeout timer (%s ms) for a test run', options.timeout); - const runTask = new Task(options.timeout, () => this.handleTimeout()); - runTask.chainTo(super.run(options)); - return runTask.promise; - } - - dispose(): Promise { - return this.proxy(() => super.dispose(), MAX_WAIT_FOR_DISPOSE); - } - - private proxy(action?: () => Promise | void, timeoutMs?: number): Promise { - if (action) { - const maybePromise = action(); - if (isPromise(maybePromise)) { - const task = new Task(timeoutMs); - task.chainTo(maybePromise); - return task.promise; - } + const result = await Promise.race([super.run(options), timeout()]); + if (result === TIMEOUT_EXPIRED) { + return this.handleTimeout(); + } else { + return result; + } + function timeout() { + return sleep(options.timeout).then<'timeout_expired'>(() => TIMEOUT_EXPIRED); } - return Promise.resolve(); } private handleTimeout(): Promise { + this.log.debug('Timeout expired, restarting the ') return this.dispose() .then(() => this.createInnerRunner()) .then(() => this.init()) diff --git a/packages/stryker/test/unit/test-runner/TimeoutDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/TimeoutDecoratorSpec.ts index 5fc90e55d7..fcd7493640 100644 --- a/packages/stryker/test/unit/test-runner/TimeoutDecoratorSpec.ts +++ b/packages/stryker/test/unit/test-runner/TimeoutDecoratorSpec.ts @@ -58,14 +58,6 @@ describe('TimeoutDecorator', () => { describe('dispose', () => { itShouldProxyRequestsForMethod('dispose'); - - it('should wait no longer then 2500 ms', () => { - testRunner1.dispose.returns(new Promise(res => { })); - const disposePromise = sut.dispose(); - clock.tick(2500); - const p = expect(disposePromise).to.eventually.be.eq(undefined); - return p; - }); }); describe('run', () => { From 06e9998a824babdafac99b599eda542b09fa2a85 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 23 Jul 2018 22:35:17 -0700 Subject: [PATCH 40/54] refactor(TimeoutDecorator): Add semicolon --- packages/stryker/src/test-runner/TimeoutDecorator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stryker/src/test-runner/TimeoutDecorator.ts b/packages/stryker/src/test-runner/TimeoutDecorator.ts index ed39ea855e..9819e9ea24 100644 --- a/packages/stryker/src/test-runner/TimeoutDecorator.ts +++ b/packages/stryker/src/test-runner/TimeoutDecorator.ts @@ -26,7 +26,7 @@ export default class TimeoutDecorator extends TestRunnerDecorator { } private handleTimeout(): Promise { - this.log.debug('Timeout expired, restarting the ') + this.log.debug('Timeout expired, restarting the process and reporting timeout'); return this.dispose() .then(() => this.createInnerRunner()) .then(() => this.init()) From dd2ee86c72669af7c7a1037bf2c995af5ca03ac1 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 23 Jul 2018 22:35:42 -0700 Subject: [PATCH 41/54] test(TestRunner): Add integration test for crashing test runner --- .../test-runner/AdditionalTestRunners.ts | 10 +++++++++- .../test-runner/ResilientTestRunnerFactory.it.ts | 13 ++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/stryker/test/integration/test-runner/AdditionalTestRunners.ts b/packages/stryker/test/integration/test-runner/AdditionalTestRunners.ts index ae10b9c88a..3dc85cb3a4 100644 --- a/packages/stryker/test/integration/test-runner/AdditionalTestRunners.ts +++ b/packages/stryker/test/integration/test-runner/AdditionalTestRunners.ts @@ -11,13 +11,20 @@ class CoverageReportingTestRunner implements TestRunner { class TimeBombTestRunner implements TestRunner { constructor() { // Setting a time bomb after 100 ms - setTimeout(() => process.exit(), 100); + setTimeout(() => process.exit(), 500); } run() { return Promise.resolve({ status: RunStatus.Complete, tests: [] }); } } +class ProximityMineTestRunner implements TestRunner { + run() { + process.exit(42); + return Promise.resolve({ status: RunStatus.Complete, tests: [] }); + } +} + class DirectResolvedTestRunner implements TestRunner { run() { (global as any).__coverage__ = 'coverageObject'; @@ -128,5 +135,6 @@ TestRunnerFactory.instance().register('discover-regex', DiscoverRegexTestRunner) TestRunnerFactory.instance().register('direct-resolved', DirectResolvedTestRunner); TestRunnerFactory.instance().register('coverage-reporting', CoverageReportingTestRunner); TestRunnerFactory.instance().register('time-bomb', TimeBombTestRunner); +TestRunnerFactory.instance().register('proximity-mine', ProximityMineTestRunner); TestRunnerFactory.instance().register('async-promise-rejection-handler', AsyncronousPromiseRejectionHandlerTestRunner); TestRunnerFactory.instance().register('reject-init', RejectInitRunner); \ No newline at end of file diff --git a/packages/stryker/test/integration/test-runner/ResilientTestRunnerFactory.it.ts b/packages/stryker/test/integration/test-runner/ResilientTestRunnerFactory.it.ts index f25267da83..f9b6ad424f 100644 --- a/packages/stryker/test/integration/test-runner/ResilientTestRunnerFactory.it.ts +++ b/packages/stryker/test/integration/test-runner/ResilientTestRunnerFactory.it.ts @@ -130,14 +130,21 @@ describe('ResilientTestRunnerFactory integration', function () { expect(result.errorMessages).undefined; }); - it('should be able to recover from a crash', async () => { - // time-bomb will crash after 100 ms + it('should be able to recover from an async crash', async () => { + // time-bomb will crash after 500 ms await arrangeSut('time-bomb'); - await sleep(101); + await sleep(550); const result = await actRun(); expect(RunStatus[result.status]).eq(RunStatus[RunStatus.Complete]); expect(result.errorMessages).undefined; }); + + it('should report if a crash happens twice', async () => { + await arrangeSut('proximity-mine'); + const result = await actRun(); + expect(RunStatus[result.status]).eq(RunStatus[RunStatus.Error]); + expect(result.errorMessages).property('0').contains('Test runner crashed'); + }); it('should handle asynchronously handled promise rejections from the underlying test runner', async () => { const logEvents = loggingServer.event$.pipe(toArray()).toPromise(); From cb63eab1922e3843646c52465e139457b871a8b9 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 23 Jul 2018 23:07:38 -0700 Subject: [PATCH 42/54] refactor(Task): Refactor task to use `Promise.race` Don't reinvent the wheel --- .../src/child-proxy/ChildProcessProxy.ts | 6 +-- packages/stryker/src/utils/Task.ts | 45 +++++++------------ packages/stryker/src/utils/objectUtils.ts | 2 +- .../child-proxy/ChildProcessProxy.it.ts | 2 +- packages/stryker/test/unit/SandboxPoolSpec.ts | 7 ++- .../ChildProcessTestRunnerDecoratorSpec.ts | 2 +- .../unit/transpiler/MutantTranspilerSpec.ts | 6 +-- 7 files changed, 28 insertions(+), 42 deletions(-) diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index 82f531397d..5622777f07 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -4,7 +4,7 @@ import { File } from 'stryker-api/core'; import { getLogger } from 'stryker-api/logging'; import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol'; import { serialize, deserialize, kill, isErrnoException } from '../utils/objectUtils'; -import Task from '../utils/Task'; +import { Task, ExpirableTask } from '../utils/Task'; import LoggingClientContext from '../logging/LoggingClientContext'; import StrykerError from '../utils/StrykerError'; import ChildProcessCrashedError from './ChildProcessCrashedError'; @@ -24,7 +24,7 @@ export default class ChildProcessProxy { private worker: ChildProcess; private initTask: Task; - private disposeTask: Task | undefined; + private disposeTask: ExpirableTask | undefined; private currentError: StrykerError | undefined; private workerTasks: Task[] = []; private log = getLogger(ChildProcessProxy.name); @@ -203,7 +203,7 @@ export default class ChildProcessProxy { kill(this.worker.pid); this.isDisposed = true; }; - this.disposeTask = new Task(TIMEOUT_FOR_DISPOSE); + this.disposeTask = new ExpirableTask(TIMEOUT_FOR_DISPOSE); this.send({ kind: WorkerMessageKind.Dispose }); return this.disposeTask.promise .then(killWorker) diff --git a/packages/stryker/src/utils/Task.ts b/packages/stryker/src/utils/Task.ts index 4e7cae239d..9580864f7a 100644 --- a/packages/stryker/src/utils/Task.ts +++ b/packages/stryker/src/utils/Task.ts @@ -1,59 +1,48 @@ +import { sleep } from './objectUtils'; /** * Wraps a promise in a Task api for convenience. */ -export default class Task { +export class Task { - private _promise: Promise; + protected _promise: Promise; private resolveFn: (value?: T | PromiseLike) => void; private rejectFn: (reason: any) => void; private _isResolved = false; - private timeout: NodeJS.Timer; - constructor(timeoutMs?: number, private timeoutHandler?: () => PromiseLike) { + constructor() { this._promise = new Promise((resolve, reject) => { this.resolveFn = resolve; this.rejectFn = reject; }); - if (timeoutMs) { - this.timeout = setTimeout(() => this.handleTimeout(), timeoutMs); - } - } - - get isResolved() { - return this._isResolved; } get promise() { return this._promise; } - handleTimeout() { - if (this.timeoutHandler) { - this.timeoutHandler().then(val => this.resolve(val)); - } else { - this.resolve(undefined); - } - } - - chainTo(promise: Promise) { - promise.then(value => this.resolve(value), reason => this.reject(reason)); + get isResolved() { + return this._isResolved; } resolve(result: undefined | T | PromiseLike) { - this.resolveTimeout(); + this._isResolved = true; this.resolveFn(result); } reject(reason: any) { - this.resolveTimeout(); + this._isResolved = true; this.rejectFn(reason); } +} - private resolveTimeout() { - if (this.timeout) { - clearTimeout(this.timeout); - } - this._isResolved = true; +/** + * A task that can expire after the given time. + * If that happens, the inner promise is resolved + */ +export class ExpirableTask extends Task { + constructor(timeoutMS: number) { + super(); + this._promise = Promise.race([this._promise, sleep(timeoutMS)]); } } \ No newline at end of file diff --git a/packages/stryker/src/utils/objectUtils.ts b/packages/stryker/src/utils/objectUtils.ts index 40567b8f65..5beb42cf64 100644 --- a/packages/stryker/src/utils/objectUtils.ts +++ b/packages/stryker/src/utils/objectUtils.ts @@ -102,7 +102,7 @@ export function kill(pid: number): Promise { }); } -export function sleep(ms: number) { +export function sleep(ms: number): Promise { return new Promise(res => { setTimeout(res, ms); }); diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index 6cbc01fb06..6751c269c8 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -6,7 +6,7 @@ import { File, LogLevel } from 'stryker-api/core'; import { Logger } from 'stryker-api/logging'; import Echo from './Echo'; import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; -import Task from '../../../src/utils/Task'; +import { Task } from '../../../src/utils/Task'; import LoggingServer from '../../helpers/LoggingServer'; import { filter } from 'rxjs/operators'; import { Mock } from '../../helpers/producers'; diff --git a/packages/stryker/test/unit/SandboxPoolSpec.ts b/packages/stryker/test/unit/SandboxPoolSpec.ts index 694fe0ce68..6984ce3b8a 100644 --- a/packages/stryker/test/unit/SandboxPoolSpec.ts +++ b/packages/stryker/test/unit/SandboxPoolSpec.ts @@ -6,10 +6,11 @@ import { File, LogLevel } from 'stryker-api/core'; import { TestFramework } from 'stryker-api/test_framework'; import Sandbox from '../../src/Sandbox'; import SandboxPool from '../../src/SandboxPool'; -import Task from '../../src/utils/Task'; +import { Task } from '../../src/utils/Task'; import '../helpers/globals'; import { Mock, config, file, mock, testFramework } from '../helpers/producers'; import LoggingClientContext from '../../src/logging/LoggingClientContext'; +import { sleep } from '../../src/utils/objectUtils'; const OVERHEAD_TIME_MS = 42; const LOGGING_CONTEXT: LoggingClientContext = Object.freeze({ @@ -117,8 +118,6 @@ describe('SandboxPool', () => { }); function tick() { - return new Promise(res => { - setTimeout(res, 0); - }); + return sleep(0); } diff --git a/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts index 26b350c9e5..465af335b8 100644 --- a/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts +++ b/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts @@ -8,7 +8,7 @@ import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; import LoggingClientContext from '../../../src/logging/LoggingClientContext'; import ChildProcessTestRunnerWorker from '../../../src/test-runner/ChildProcessTestRunnerWorker'; import TestRunnerDecorator from '../../../src/test-runner/TestRunnerDecorator'; -import Task from '../../../src/utils/Task'; +import { Task } from '../../../src/utils/Task'; import ChildProcessCrashedError from '../../../src/child-proxy/ChildProcessCrashedError'; describe(ChildProcessTestRunnerDecorator.name, () => { diff --git a/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts b/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts index 58943dce1b..2d274128a6 100644 --- a/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts +++ b/packages/stryker/test/unit/transpiler/MutantTranspilerSpec.ts @@ -6,7 +6,7 @@ import ChildProcessProxy from '../../../src/child-proxy/ChildProcessProxy'; import MutantTranspiler from '../../../src/transpiler/MutantTranspiler'; import TranspileResult from '../../../src/transpiler/TranspileResult'; import TranspilerFacade, * as transpilerFacade from '../../../src/transpiler/TranspilerFacade'; -import { errorToString } from '../../../src/utils/objectUtils'; +import { errorToString, sleep } from '../../../src/utils/objectUtils'; import '../../helpers/globals'; import { Mock, config, file, mock, testableMutant } from '../../helpers/producers'; import LoggingClientContext from '../../../src/logging/LoggingClientContext'; @@ -157,9 +157,7 @@ describe('MutantTranspiler', () => { ]; expect(actualResults).deep.eq(expectedResults); }); - const nextTick = () => new Promise(res => { - setTimeout(res, 0); - }); + const nextTick = () => sleep(0); }); }); From 61af88a5bd2695972a4f9831e6b3268f3f46d69e Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Thu, 26 Jul 2018 13:47:49 -0700 Subject: [PATCH 43/54] fix(Test runner): Improved error message when a test runner process went out of memory --- .../child-proxy/ChildProcessCrashedError.ts | 8 +++- .../src/child-proxy/ChildProcessProxy.ts | 46 ++++++++++++------- .../src/child-proxy/OutOfMemoryError.ts | 11 +++++ .../stryker/src/test-runner/RetryDecorator.ts | 7 +++ packages/stryker/src/utils/StrykerError.ts | 2 +- packages/stryker/src/utils/objectUtils.ts | 6 ++- .../child-proxy/ChildProcessProxy.it.ts | 5 ++ .../test/integration/child-proxy/Echo.ts | 7 +++ .../ChildProcessTestRunnerDecoratorSpec.ts | 2 +- .../unit/test-runner/RetryDecoratorSpec.ts | 17 ++++++- 10 files changed, 87 insertions(+), 24 deletions(-) create mode 100644 packages/stryker/src/child-proxy/OutOfMemoryError.ts diff --git a/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts b/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts index ed2f19bedc..71ad7b6fb7 100644 --- a/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts +++ b/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts @@ -1,8 +1,12 @@ import StrykerError from '../utils/StrykerError'; export default class ChildProcessCrashedError extends StrykerError { - constructor(exitCode: number | null, innerError?: Error) { - super(`Child process exited unexpectedly (code ${exitCode === null ? 'unknown' : exitCode})`, innerError); + constructor( + public readonly pid: number, + public readonly exitCode?: number, + message = `Child process exited unexpectedly (code ${exitCode === null ? 'unknown' : exitCode})`, + innerError?: Error) { + super(message, innerError); Error.captureStackTrace(this, ChildProcessCrashedError); // TS recommendation: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work Object.setPrototypeOf(this, ChildProcessCrashedError.prototype); diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index 5622777f07..a3873b1a4d 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -3,11 +3,11 @@ import { fork, ChildProcess } from 'child_process'; import { File } from 'stryker-api/core'; import { getLogger } from 'stryker-api/logging'; import { WorkerMessage, WorkerMessageKind, ParentMessage, autoStart, ParentMessageKind } from './messageProtocol'; -import { serialize, deserialize, kill, isErrnoException } from '../utils/objectUtils'; +import { serialize, deserialize, kill, isErrnoException, padLeft } from '../utils/objectUtils'; import { Task, ExpirableTask } from '../utils/Task'; import LoggingClientContext from '../logging/LoggingClientContext'; -import StrykerError from '../utils/StrykerError'; import ChildProcessCrashedError from './ChildProcessCrashedError'; +import OutOfMemoryError from './OutOfMemoryError'; type MethodPromised = { (...args: any[]): Promise }; @@ -25,10 +25,10 @@ export default class ChildProcessProxy { private worker: ChildProcess; private initTask: Task; private disposeTask: ExpirableTask | undefined; - private currentError: StrykerError | undefined; + private currentError: ChildProcessCrashedError | undefined; private workerTasks: Task[] = []; private log = getLogger(ChildProcessProxy.name); - private lastMessagesQueue: string[] = []; + private recentMessagesQueue: string[] = []; private isDisposed = false; private constructor(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, constructorParams: any[]) { @@ -137,14 +137,14 @@ export default class ChildProcessProxy { private listenToStdoutAndStderr() { const traceEnabled = this.log.isTraceEnabled(); const handleData = (data: Buffer) => { - const messages = data.toString().split('\n').filter(Boolean); - this.lastMessagesQueue.push(...messages); - if (this.lastMessagesQueue.length > 10) { - this.lastMessagesQueue.shift(); + const message = data.toString(); + this.recentMessagesQueue.push(message); + if (this.recentMessagesQueue.length > 10) { + this.recentMessagesQueue.shift(); } if (traceEnabled) { - messages.forEach(message => this.log.trace(message)); + this.log.trace(message); } }; @@ -163,16 +163,28 @@ export default class ChildProcessProxy { .forEach(task => task.reject(error)); } - private handleUnexpectedExit(code: number | null, signal: string) { + private handleUnexpectedExit(code: number, signal: string) { this.isDisposed = true; - this.currentError = new ChildProcessCrashedError(code); - this.log.warn(`Child process [pid ${this.worker.pid}] exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr(this.lastMessagesQueue)}`, this.currentError); + const output = this.recentMessagesQueue.join(os.EOL); + + if (processOutOfMemory()) { + this.currentError = new OutOfMemoryError(this.worker.pid, code); + this.log.warn(`Child process [pid ${this.currentError.pid}] ran out of memory. Stdout and stderr are logged on debug level.`); + this.log.debug(stdoutAndStderr()); + } else { + this.currentError = new ChildProcessCrashedError(this.worker.pid, code); + this.log.warn(`Child process [pid ${this.worker.pid}] exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr()}`, this.currentError); + } + this.reportError(this.currentError); - function stdoutAndStderr(messages: string[]) { - if (messages.length) { - return `Last part of stdout and stderr was: ${os.EOL}${ - messages.map(msg => `\t${msg}`).join(os.EOL)}`; + function processOutOfMemory() { + return output.indexOf('JavaScript heap out of memory') >= 0; + } + + function stdoutAndStderr() { + if (output.length) { + return `Last part of stdout and stderr was: ${os.EOL}${padLeft(output)}`; } else { return 'Stdout and stderr were empty.'; } @@ -182,7 +194,7 @@ export default class ChildProcessProxy { private handleError(error: Error) { if (this.innerProcessIsCrashed(error)) { this.log.warn(`Child process [pid ${this.worker.pid}] has crashed. See other warning messages for more info.`, error); - this.reportError(new ChildProcessCrashedError(null, error)); + this.reportError(new ChildProcessCrashedError(this.worker.pid, undefined, undefined, error)); } else { this.reportError(error); } diff --git a/packages/stryker/src/child-proxy/OutOfMemoryError.ts b/packages/stryker/src/child-proxy/OutOfMemoryError.ts new file mode 100644 index 0000000000..f4d2a87d98 --- /dev/null +++ b/packages/stryker/src/child-proxy/OutOfMemoryError.ts @@ -0,0 +1,11 @@ +import ChildProcessCrashedError from './ChildProcessCrashedError'; + +export default class OutOfMemoryError extends ChildProcessCrashedError { + constructor(pid: number, exitCode: number) { + super(pid, exitCode, `Process ${pid} ran out of memory`); + this.message = `Process `; + Error.captureStackTrace(this, OutOfMemoryError); + // TS recommendation: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work + Object.setPrototypeOf(this, OutOfMemoryError.prototype); + } +} \ No newline at end of file diff --git a/packages/stryker/src/test-runner/RetryDecorator.ts b/packages/stryker/src/test-runner/RetryDecorator.ts index 9b63e4a0fb..62c359686a 100644 --- a/packages/stryker/src/test-runner/RetryDecorator.ts +++ b/packages/stryker/src/test-runner/RetryDecorator.ts @@ -1,6 +1,8 @@ import { RunOptions, RunResult, RunStatus } from 'stryker-api/test_runner'; import TestRunnerDecorator from './TestRunnerDecorator'; import { errorToString } from '../utils/objectUtils'; +import OutOfMemoryError from '../child-proxy/OutOfMemoryError'; +import { getLogger } from 'stryker-api/logging'; const ERROR_MESSAGE = 'Test runner crashed. Tried twice to restart it without any luck. Last time the error message was: '; @@ -9,11 +11,16 @@ const ERROR_MESSAGE = 'Test runner crashed. Tried twice to restart it without an */ export default class RetryDecorator extends TestRunnerDecorator { + log = getLogger(RetryDecorator.name); + async run(options: RunOptions, attemptsLeft = 2, lastError?: Error): Promise { if (attemptsLeft > 0) { try { return await this.innerRunner.run(options); } catch (error) { + if (error instanceof OutOfMemoryError) { + this.log.info('Test runner process [%s] ran out of memory. You probably have a memory leak in your tests. Don\'t worry, Stryker will restart the process, but you might want to investigate this later, because this decreases performance.', error.pid); + } await this.recover(); return this.run(options, attemptsLeft - 1, error); } diff --git a/packages/stryker/src/utils/StrykerError.ts b/packages/stryker/src/utils/StrykerError.ts index 20e7972568..c6d4ad31db 100644 --- a/packages/stryker/src/utils/StrykerError.ts +++ b/packages/stryker/src/utils/StrykerError.ts @@ -1,7 +1,7 @@ import { errorToString } from './objectUtils'; export default class StrykerError extends Error { - constructor(message: string, innerError?: Error) { + constructor(message: string, readonly innerError?: Error) { super(`${message}${innerError ? `. Inner error: ${errorToString(innerError)}` : ''}`); Error.captureStackTrace(this, StrykerError); // TS recommendation: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work diff --git a/packages/stryker/src/utils/objectUtils.ts b/packages/stryker/src/utils/objectUtils.ts index 5beb42cf64..d47e967242 100644 --- a/packages/stryker/src/utils/objectUtils.ts +++ b/packages/stryker/src/utils/objectUtils.ts @@ -93,7 +93,7 @@ export function kill(pid: number): Promise { res(); } }); - + function canIgnore(code: number | undefined) { // https://docs.microsoft.com/en-us/windows/desktop/Debug/system-error-codes--0-499- // these error codes mean the program is _already_ closed. @@ -106,4 +106,8 @@ export function sleep(ms: number): Promise { return new Promise(res => { setTimeout(res, ms); }); +} + +export function padLeft(input: string): string { + return input.split('\n').map(str => '\t' + str).join('\n'); } \ No newline at end of file diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index 6751c269c8..1c35cfdc2b 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -12,6 +12,7 @@ import { filter } from 'rxjs/operators'; import { Mock } from '../../helpers/producers'; import currentLogMock from '../../helpers/logMock'; import { sleep } from '../../../src/utils/objectUtils'; +import OutOfMemoryError from '../../../src/child-proxy/OutOfMemoryError'; describe('ChildProcessProxy', function () { @@ -116,6 +117,10 @@ describe('ChildProcessProxy', function () { await expect(sut.proxy.exit(1)).rejected; await expect(sut.proxy.say()).rejectedWith('Child process exited unexpectedly (code 1)'); }); + + it('should throw an OutOfMemoryError if the process went out-of-memory', async () => { + await expect(sut.proxy.memoryLeak()).rejectedWith(OutOfMemoryError); + }); }); function toLogLevel(level: log4js.Level) { diff --git a/packages/stryker/test/integration/child-proxy/Echo.ts b/packages/stryker/test/integration/child-proxy/Echo.ts index cc41983e30..ca85eab647 100644 --- a/packages/stryker/test/integration/child-proxy/Echo.ts +++ b/packages/stryker/test/integration/child-proxy/Echo.ts @@ -57,4 +57,11 @@ export default class Echo { stderr(...args: string[]) { args.forEach(arg => console.error(arg)); } + + memoryLeak() { + const arr: number[] = []; + while (true) { + arr.push(1); + } + } } \ No newline at end of file diff --git a/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts index 465af335b8..13a87ecd97 100644 --- a/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts +++ b/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts @@ -76,7 +76,7 @@ describe(ChildProcessTestRunnerDecorator.name, () => { }); it('should not reject when the child process is down', async () => { - childProcessProxyMock.proxy.dispose.rejects(new ChildProcessCrashedError(1)); + childProcessProxyMock.proxy.dispose.rejects(new ChildProcessCrashedError(1, 1)); await sut.dispose(); expect(childProcessProxyMock.dispose).called; }); diff --git a/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts index 529000a96d..f13284631c 100644 --- a/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts +++ b/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts @@ -5,19 +5,25 @@ import TestRunnerMock from '../../helpers/TestRunnerMock'; import { errorToString } from '../../../src/utils/objectUtils'; import TestRunnerDecorator from '../../../src/test-runner/TestRunnerDecorator'; import ChildProcessCrashedError from '../../../src/child-proxy/ChildProcessCrashedError'; +import OutOfMemoryError from '../../../src/child-proxy/OutOfMemoryError'; +import { Logger } from 'stryker-api/logging'; +import { Mock } from '../../helpers/producers'; +import currentLogMock from '../../helpers/logMock'; describe('RetryDecorator', () => { let sut: RetryDecorator; let testRunner1: TestRunnerMock; let testRunner2: TestRunnerMock; let availableTestRunners: TestRunnerMock[]; + let logMock: Mock; const options = { timeout: 2 }; const expectedResult = 'something'; - const crashedError = new ChildProcessCrashedError(null); + const crashedError = new ChildProcessCrashedError(42); beforeEach(() => { testRunner1 = new TestRunnerMock(); testRunner2 = new TestRunnerMock(); + logMock = currentLogMock(); availableTestRunners = [testRunner1, testRunner2]; sut = new RetryDecorator(() => availableTestRunners.shift() || new TestRunnerMock()); }); @@ -44,12 +50,19 @@ describe('RetryDecorator', () => { return expect(sut.run(options)).to.eventually.eq(expectedResult); }); - it('should retry on a new test runner if a crash related reject appears', () => { + it('should retry if a `ChildProcessCrashedError` occurred reject appears', () => { testRunner1.run.rejects(crashedError); testRunner2.run.resolves(expectedResult); return expect(sut.run(options)).to.eventually.eq(expectedResult); }); + it('should log and retry when an `OutOfMemoryError` occurred.', async () => { + testRunner1.run.rejects(new OutOfMemoryError(123, 123)); + testRunner2.run.resolves(expectedResult); + await expect(sut.run(options)).to.eventually.eq(expectedResult); + expect(logMock.info).calledWith('Test runner process [%s] ran out of memory. You probably have a memory leak in your tests. Don\'t worry, Stryker will restart the process, but you might want to investigate this later, because this decreases performance.', 123); + }); + it('should dispose a test runner when it rejected, before creating a new one', async () => { testRunner1.run.rejects(crashedError); testRunner2.run.resolves(expectedResult); From 86e7fe2dea4425b18375a1fce6ca771bc87df7ab Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 28 Jul 2018 13:08:58 +0200 Subject: [PATCH 44/54] test(child-process): Await all messages (red build on node 10) --- .../test/integration/child-proxy/ChildProcessProxy.it.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index 1c35cfdc2b..f193d04776 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -102,8 +102,8 @@ describe('ChildProcessProxy', function () { }); it('should log stdout and stderr on warning when a child process crashed', async () => { - sut.proxy.stdout('stdout message'); - sut.proxy.stderr('stderr message'); + await sut.proxy.stdout('stdout message'); + await sut.proxy.stderr('stderr message'); // Give nodejs the chance to flush the stdout and stderr buffers await sleep(10); await expect(sut.proxy.exit(12)).rejected; From 3caa27f915c8491d2b2fa06d9669d3c8e03b4284 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Sat, 28 Jul 2018 13:10:21 +0200 Subject: [PATCH 45/54] fix(child-process): Increase message size, so out-of-memory message is definitely picked up --- .../src/child-proxy/ChildProcessProxy.ts | 5 +++-- .../unit/child-proxy/ChildProcessProxySpec.ts | 21 +++++++++++++++---- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index a3873b1a4d..df869e6b5c 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -18,6 +18,7 @@ export type Promisified = { const BROKEN_PIPE_ERROR_CODE = 'EPIPE'; const IPC_CHANNEL_CLOSED_ERROR_CODE = 'ERR_IPC_CHANNEL_CLOSED'; const TIMEOUT_FOR_DISPOSE = 2000; +const MESSAGE_QUEUE_SIZE = 20; export default class ChildProcessProxy { readonly proxy: Promisified; @@ -139,7 +140,7 @@ export default class ChildProcessProxy { const handleData = (data: Buffer) => { const message = data.toString(); this.recentMessagesQueue.push(message); - if (this.recentMessagesQueue.length > 10) { + if (this.recentMessagesQueue.length > MESSAGE_QUEUE_SIZE) { this.recentMessagesQueue.shift(); } @@ -184,7 +185,7 @@ export default class ChildProcessProxy { function stdoutAndStderr() { if (output.length) { - return `Last part of stdout and stderr was: ${os.EOL}${padLeft(output)}`; + return `Last part of stdout and stderr was:${os.EOL}${padLeft(output)}`; } else { return 'Stdout and stderr were empty.'; } diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 2b52e5d1ec..b4dc9eb817 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -101,22 +101,35 @@ describe('ChildProcessProxy', () => { childProcessMock.stderr.emit('data', 'foo'); childProcessMock.stdout.emit('data', 'bar'); actExit(23, 'SIGTERM'); - expect(logMock.warn).calledWithMatch(`Child process [pid ${childProcessMock.pid}] exited unexpectedly with exit code 23 (SIGTERM). Last part of stdout and stderr was: ${os.EOL + expect(logMock.warn).calledWithMatch(`Child process [pid ${childProcessMock.pid}] exited unexpectedly with exit code 23 (SIGTERM). Last part of stdout and stderr was:${os.EOL }\tfoo${os.EOL}\tbar`); }); - it('should log that no stdout was available', () => { + it('should log that no stdout was available when stdout and stderr are empty', () => { actExit(23, 'SIGTERM'); expect(logMock.warn).calledWith(`Child process [pid ${childProcessMock.pid}] exited unexpectedly with exit code 23 (SIGTERM). Stdout and stderr were empty.`); }); + it('should only log the last 20 messages from stdout and stderr', () => { + const maxNumberOfMessages = 20; + let expectedMessageLog = ''; + for (let i = 0; i < maxNumberOfMessages + 1; i++) { + if (i > 0) { + expectedMessageLog += `${os.EOL}\t${i}`; + } + childProcessMock.stdout.emit('data', i); + } + actExit(24); + expect(logMock.warn).calledWith(`Child process [pid ${childProcessMock.pid}] exited unexpectedly with exit code 24 (SIGINT). Last part of stdout and stderr was:${expectedMessageLog}`); + }); + it('should reject any outstanding worker promises with the error', () => { const expectedError = 'Child process exited unexpectedly (code 646)'; const actualPromise = sut.proxy.say('test'); actExit(646); return expect(actualPromise).rejectedWith(expectedError); }); - + it('should reject any new calls immediately', () => { actExit(646); return expect(sut.proxy.say('')).rejected; @@ -191,7 +204,7 @@ describe('ChildProcessProxy', () => { expect(childProcessMock.send).calledOnce; // init }); - it('should only wait for max 2 seconds before going ahead and killing the child process anyway', async() => { + it('should only wait for max 2 seconds before going ahead and killing the child process anyway', async () => { const disposePromise = sut.dispose(); clock.tick(2000); await disposePromise; From 60360e5829249daf5ea1eda315fca96bb7bf413e Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 30 Jul 2018 07:50:32 +0200 Subject: [PATCH 46/54] refactor(test runner): Cleanup global reference --- .../stryker/src/test-runner/ChildProcessTestRunnerWorker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts b/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts index 759f493e28..a8d91a5fe4 100644 --- a/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts +++ b/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts @@ -33,7 +33,7 @@ export default class ChildProcessTestRunnerWorker implements TestRunner { const result = await this.underlyingTestRunner.run(options); // If the test runner didn't report on coverage, let's try to do it ourselves. if (!result.coverage) { - result.coverage = (Function('return this'))().__coverage__; + result.coverage = (global as any).__coverage__; } if (result.errorMessages) { // errorMessages should be a string[] From 16d29a968d5f51494bd0b3ef1608e1dbfccd091a Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Mon, 30 Jul 2018 07:51:18 +0200 Subject: [PATCH 47/54] refactor(ChildProcessProxy): Remove unnessesary variable --- packages/stryker/src/child-proxy/ChildProcessProxy.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index df869e6b5c..2ac4b77874 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -136,7 +136,6 @@ export default class ChildProcessProxy { } private listenToStdoutAndStderr() { - const traceEnabled = this.log.isTraceEnabled(); const handleData = (data: Buffer) => { const message = data.toString(); this.recentMessagesQueue.push(message); @@ -144,7 +143,7 @@ export default class ChildProcessProxy { this.recentMessagesQueue.shift(); } - if (traceEnabled) { + if (this.log.isTraceEnabled()) { this.log.trace(message); } }; From 44823ad4132e6c0926f4cc62684548e7b67c8ad1 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 31 Jul 2018 10:58:38 +0200 Subject: [PATCH 48/54] fix(child-process): Correctly type the proxy param (since TS 3.0) --- .../stryker/src/child-proxy/ChildProcessProxy.ts | 9 +++++++-- .../test-runner/ChildProcessTestRunnerWorker.ts | 15 +++++---------- .../child-proxy/ChildProcessProxy.it.ts | 2 +- .../unit/child-proxy/ChildProcessProxySpec.ts | 5 +++-- .../stryker/test/unit/child-proxy/HelloClass.ts | 4 ++++ workspace.code-workspace | 2 +- 6 files changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index 2ac4b77874..9378692750 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -9,10 +9,15 @@ import LoggingClientContext from '../logging/LoggingClientContext'; import ChildProcessCrashedError from './ChildProcessCrashedError'; import OutOfMemoryError from './OutOfMemoryError'; -type MethodPromised = { (...args: any[]): Promise }; +interface Func { + (...args: TS): R; +} +interface PromisifiedFunc { + (...args: TS): Promise; +} export type Promisified = { - [K in keyof T]: T[K] extends MethodPromised ? T[K] : T[K] extends Function ? MethodPromised : () => Promise; + [K in keyof T]: T[K] extends PromisifiedFunc ? T[K] : T[K] extends Func ? PromisifiedFunc : () => Promise; }; const BROKEN_PIPE_ERROR_CODE = 'EPIPE'; diff --git a/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts b/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts index a8d91a5fe4..0a88343f2d 100644 --- a/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts +++ b/packages/stryker/src/test-runner/ChildProcessTestRunnerWorker.ts @@ -12,23 +12,18 @@ export default class ChildProcessTestRunnerWorker implements TestRunner { this.underlyingTestRunner = TestRunnerFactory.instance().create(realTestRunnerName, options); } - init(): Promise | void { + async init(): Promise { if (this.underlyingTestRunner.init) { - return this.underlyingTestRunner.init(); - } else { - return; + await this.underlyingTestRunner.init(); } } - dispose() { + async dispose() { if (this.underlyingTestRunner.dispose) { - return this.underlyingTestRunner.dispose(); - } else { - return; + await this.underlyingTestRunner.dispose(); } } - - + async run(options: RunOptions) { const result = await this.underlyingTestRunner.run(options); // If the test runner didn't report on coverage, let's try to do it ourselves. diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index f193d04776..1e829d3155 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -115,7 +115,7 @@ describe('ChildProcessProxy', function () { it('should immediately reject any subsequent calls when the child process exits', async () => { await expect(sut.proxy.exit(1)).rejected; - await expect(sut.proxy.say()).rejectedWith('Child process exited unexpectedly (code 1)'); + await expect(sut.proxy.say('something')).rejectedWith('Child process exited unexpectedly (code 1)'); }); it('should throw an OutOfMemoryError if the process went out-of-memory', async () => { diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index b4dc9eb817..4d2c17c04f 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -89,6 +89,7 @@ describe('ChildProcessProxy', () => { it('should listen for exit calls', () => { createSut(); expect(childProcessMock.listeners('exit')).lengthOf(1); + sut.proxy.sum }); }); @@ -157,12 +158,12 @@ describe('ChildProcessProxy', () => { const expectedWorkerMessage: WorkerMessage = { kind: WorkerMessageKind.Call, correlationId: 0, - methodName: 'sayHello', + methodName: 'say', args: ['echo'] }; // Act - const delayedEcho = sut.proxy.sayHello('echo'); + const delayedEcho = sut.proxy.say('echo'); clock.tick(0); receiveMessage(workerResponse); const result: string = await delayedEcho; diff --git a/packages/stryker/test/unit/child-proxy/HelloClass.ts b/packages/stryker/test/unit/child-proxy/HelloClass.ts index 05e895ecdb..600786ae3f 100644 --- a/packages/stryker/test/unit/child-proxy/HelloClass.ts +++ b/packages/stryker/test/unit/child-proxy/HelloClass.ts @@ -11,6 +11,10 @@ export default class HelloClass { return `hello ${things.join(' and ')}`; } + sum(a: number, b: number) { + return a + b; + } + reject() { return Promise.reject(new Error('Rejected')); } diff --git a/workspace.code-workspace b/workspace.code-workspace index 4dc28f3795..c35dd83078 100644 --- a/workspace.code-workspace +++ b/workspace.code-workspace @@ -50,7 +50,7 @@ } ], "settings": { - "typescript.tsdk": "..\\..\\node_modules\\typescript\\lib", + "typescript.tsdk": "..\\node_modules\\typescript\\lib", "files.exclude": { ".git": true, ".tscache": true, From 36e8984dc84d2bdbf7912b4257dfc7ee3e58d283 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 31 Jul 2018 11:07:15 +0200 Subject: [PATCH 49/54] refactor(child-process): Remove unused statement --- packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 4d2c17c04f..083d87f24b 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -89,7 +89,6 @@ describe('ChildProcessProxy', () => { it('should listen for exit calls', () => { createSut(); expect(childProcessMock.listeners('exit')).lengthOf(1); - sut.proxy.sum }); }); From b99d21a3aed04c680034c2454ad13f5c3fc05352 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 31 Jul 2018 11:57:35 +0200 Subject: [PATCH 50/54] refactor(child-process): Improve test error message --- .../src/child-proxy/ChildProcessCrashedError.ts | 3 ++- packages/stryker/src/child-proxy/ChildProcessProxy.ts | 8 ++++---- packages/stryker/src/child-proxy/OutOfMemoryError.ts | 2 +- packages/stryker/src/utils/Task.ts | 10 +++++----- .../integration/child-proxy/ChildProcessProxy.it.ts | 5 +++-- .../test/unit/child-proxy/ChildProcessProxySpec.ts | 2 +- .../test-runner/ChildProcessTestRunnerDecoratorSpec.ts | 2 +- .../test/unit/test-runner/RetryDecoratorSpec.ts | 2 +- workspace.code-workspace | 2 +- 9 files changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts b/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts index 71ad7b6fb7..c7591e19d3 100644 --- a/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts +++ b/packages/stryker/src/child-proxy/ChildProcessCrashedError.ts @@ -3,8 +3,9 @@ import StrykerError from '../utils/StrykerError'; export default class ChildProcessCrashedError extends StrykerError { constructor( public readonly pid: number, + message: string, public readonly exitCode?: number, - message = `Child process exited unexpectedly (code ${exitCode === null ? 'unknown' : exitCode})`, + public readonly signal?: string, innerError?: Error) { super(message, innerError); Error.captureStackTrace(this, ChildProcessCrashedError); diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index 9378692750..ef4bb4602b 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -164,7 +164,7 @@ export default class ChildProcessProxy { private reportError(error: Error) { this.workerTasks - .filter(task => !task.isResolved) + .filter(task => !task.isCompleted) .forEach(task => task.reject(error)); } @@ -177,8 +177,8 @@ export default class ChildProcessProxy { this.log.warn(`Child process [pid ${this.currentError.pid}] ran out of memory. Stdout and stderr are logged on debug level.`); this.log.debug(stdoutAndStderr()); } else { - this.currentError = new ChildProcessCrashedError(this.worker.pid, code); - this.log.warn(`Child process [pid ${this.worker.pid}] exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr()}`, this.currentError); + this.currentError = new ChildProcessCrashedError(this.worker.pid, `Child process [pid ${this.worker.pid}] exited unexpectedly with exit code ${code} (${signal || 'without signal'}). ${stdoutAndStderr()}`, code, signal); + this.log.warn(this.currentError.message, this.currentError); } this.reportError(this.currentError); @@ -199,7 +199,7 @@ export default class ChildProcessProxy { private handleError(error: Error) { if (this.innerProcessIsCrashed(error)) { this.log.warn(`Child process [pid ${this.worker.pid}] has crashed. See other warning messages for more info.`, error); - this.reportError(new ChildProcessCrashedError(this.worker.pid, undefined, undefined, error)); + this.reportError(new ChildProcessCrashedError(this.worker.pid, `Child process [pid ${this.worker.pid}] has crashed`, undefined, undefined, error)); } else { this.reportError(error); } diff --git a/packages/stryker/src/child-proxy/OutOfMemoryError.ts b/packages/stryker/src/child-proxy/OutOfMemoryError.ts index f4d2a87d98..2bdbe14163 100644 --- a/packages/stryker/src/child-proxy/OutOfMemoryError.ts +++ b/packages/stryker/src/child-proxy/OutOfMemoryError.ts @@ -2,7 +2,7 @@ import ChildProcessCrashedError from './ChildProcessCrashedError'; export default class OutOfMemoryError extends ChildProcessCrashedError { constructor(pid: number, exitCode: number) { - super(pid, exitCode, `Process ${pid} ran out of memory`); + super(pid, `Process ${pid} ran out of memory`, exitCode); this.message = `Process `; Error.captureStackTrace(this, OutOfMemoryError); // TS recommendation: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work diff --git a/packages/stryker/src/utils/Task.ts b/packages/stryker/src/utils/Task.ts index 9580864f7a..a66ec1337c 100644 --- a/packages/stryker/src/utils/Task.ts +++ b/packages/stryker/src/utils/Task.ts @@ -8,7 +8,7 @@ export class Task { protected _promise: Promise; private resolveFn: (value?: T | PromiseLike) => void; private rejectFn: (reason: any) => void; - private _isResolved = false; + private _isCompleted = false; constructor() { this._promise = new Promise((resolve, reject) => { @@ -21,17 +21,17 @@ export class Task { return this._promise; } - get isResolved() { - return this._isResolved; + get isCompleted() { + return this._isCompleted; } resolve(result: undefined | T | PromiseLike) { - this._isResolved = true; + this._isCompleted = true; this.resolveFn(result); } reject(reason: any) { - this._isResolved = true; + this._isCompleted = true; this.rejectFn(reason); } } diff --git a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts index 1e829d3155..b892c01887 100644 --- a/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts +++ b/packages/stryker/test/integration/child-proxy/ChildProcessProxy.it.ts @@ -13,6 +13,7 @@ import { Mock } from '../../helpers/producers'; import currentLogMock from '../../helpers/logMock'; import { sleep } from '../../../src/utils/objectUtils'; import OutOfMemoryError from '../../../src/child-proxy/OutOfMemoryError'; +import ChildProcessCrashedError from '../../../src/child-proxy/ChildProcessCrashedError'; describe('ChildProcessProxy', function () { @@ -98,7 +99,7 @@ describe('ChildProcessProxy', function () { }); it('should reject when the child process exits', () => { - return expect(sut.proxy.exit(42)).rejectedWith('Child process exited unexpectedly (code 42)'); + return expect(sut.proxy.exit(42)).rejectedWith(ChildProcessCrashedError); }); it('should log stdout and stderr on warning when a child process crashed', async () => { @@ -115,7 +116,7 @@ describe('ChildProcessProxy', function () { it('should immediately reject any subsequent calls when the child process exits', async () => { await expect(sut.proxy.exit(1)).rejected; - await expect(sut.proxy.say('something')).rejectedWith('Child process exited unexpectedly (code 1)'); + await expect(sut.proxy.say('something')).rejectedWith(ChildProcessCrashedError); }); it('should throw an OutOfMemoryError if the process went out-of-memory', async () => { diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 083d87f24b..7b4badafb2 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -124,7 +124,7 @@ describe('ChildProcessProxy', () => { }); it('should reject any outstanding worker promises with the error', () => { - const expectedError = 'Child process exited unexpectedly (code 646)'; + const expectedError = 'Child process [pid 4648] exited unexpectedly with exit code 646 (SIGINT).'; const actualPromise = sut.proxy.say('test'); actExit(646); return expect(actualPromise).rejectedWith(expectedError); diff --git a/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts index 13a87ecd97..b4ed5513b6 100644 --- a/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts +++ b/packages/stryker/test/unit/test-runner/ChildProcessTestRunnerDecoratorSpec.ts @@ -76,7 +76,7 @@ describe(ChildProcessTestRunnerDecorator.name, () => { }); it('should not reject when the child process is down', async () => { - childProcessProxyMock.proxy.dispose.rejects(new ChildProcessCrashedError(1, 1)); + childProcessProxyMock.proxy.dispose.rejects(new ChildProcessCrashedError(1, '1')); await sut.dispose(); expect(childProcessProxyMock.dispose).called; }); diff --git a/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts b/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts index f13284631c..d52528bb04 100644 --- a/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts +++ b/packages/stryker/test/unit/test-runner/RetryDecoratorSpec.ts @@ -18,7 +18,7 @@ describe('RetryDecorator', () => { let logMock: Mock; const options = { timeout: 2 }; const expectedResult = 'something'; - const crashedError = new ChildProcessCrashedError(42); + const crashedError = new ChildProcessCrashedError(42, ''); beforeEach(() => { testRunner1 = new TestRunnerMock(); diff --git a/workspace.code-workspace b/workspace.code-workspace index c35dd83078..2e0a5ecff6 100644 --- a/workspace.code-workspace +++ b/workspace.code-workspace @@ -50,7 +50,7 @@ } ], "settings": { - "typescript.tsdk": "..\\node_modules\\typescript\\lib", + "typescript.tsdk": "node_modules\\typescript\\lib", "files.exclude": { ".git": true, ".tscache": true, From 364d2af946c9dc36310d222a4345e40a03405f27 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Tue, 31 Jul 2018 18:01:30 +0200 Subject: [PATCH 51/54] fix(child-process): Make sure to capture enough of stdout and stderr to determine if it ran out of memory. --- .../src/child-proxy/ChildProcessProxy.ts | 18 +++++++---------- packages/stryker/src/utils/StringBuilder.ts | 20 +++++++++++++++++++ .../unit/child-proxy/ChildProcessProxySpec.ts | 13 ------------ 3 files changed, 27 insertions(+), 24 deletions(-) create mode 100644 packages/stryker/src/utils/StringBuilder.ts diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index ef4bb4602b..68e084b8c3 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -8,6 +8,7 @@ import { Task, ExpirableTask } from '../utils/Task'; import LoggingClientContext from '../logging/LoggingClientContext'; import ChildProcessCrashedError from './ChildProcessCrashedError'; import OutOfMemoryError from './OutOfMemoryError'; +import StringBuilder from '../utils/StringBuilder'; interface Func { (...args: TS): R; @@ -23,7 +24,6 @@ export type Promisified = { const BROKEN_PIPE_ERROR_CODE = 'EPIPE'; const IPC_CHANNEL_CLOSED_ERROR_CODE = 'ERR_IPC_CHANNEL_CLOSED'; const TIMEOUT_FOR_DISPOSE = 2000; -const MESSAGE_QUEUE_SIZE = 20; export default class ChildProcessProxy { readonly proxy: Promisified; @@ -34,7 +34,7 @@ export default class ChildProcessProxy { private currentError: ChildProcessCrashedError | undefined; private workerTasks: Task[] = []; private log = getLogger(ChildProcessProxy.name); - private recentMessagesQueue: string[] = []; + private stdoutAndStderrBuilder = new StringBuilder(); private isDisposed = false; private constructor(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, constructorParams: any[]) { @@ -141,15 +141,11 @@ export default class ChildProcessProxy { } private listenToStdoutAndStderr() { - const handleData = (data: Buffer) => { - const message = data.toString(); - this.recentMessagesQueue.push(message); - if (this.recentMessagesQueue.length > MESSAGE_QUEUE_SIZE) { - this.recentMessagesQueue.shift(); - } - + const handleData = (data: Buffer | string) => { + const output = data.toString(); + this.stdoutAndStderrBuilder.append(output); if (this.log.isTraceEnabled()) { - this.log.trace(message); + this.log.trace(output); } }; @@ -170,7 +166,7 @@ export default class ChildProcessProxy { private handleUnexpectedExit(code: number, signal: string) { this.isDisposed = true; - const output = this.recentMessagesQueue.join(os.EOL); + const output = this.stdoutAndStderrBuilder.toString(); if (processOutOfMemory()) { this.currentError = new OutOfMemoryError(this.worker.pid, code); diff --git a/packages/stryker/src/utils/StringBuilder.ts b/packages/stryker/src/utils/StringBuilder.ts new file mode 100644 index 0000000000..d6fdb3649d --- /dev/null +++ b/packages/stryker/src/utils/StringBuilder.ts @@ -0,0 +1,20 @@ +import * as os from 'os'; + +export default class StringBuilder { + private maxSize = 2048; + private currentLength = 0; + private strings: string[] = []; + + append(str: string) { + this.strings.push(str); + this.currentLength += str.length; + while (this.currentLength > this.maxSize && this.strings.length > 0) { + const popped = this.strings.shift() as string; + this.currentLength -= popped.length; + } + } + + toString() { + return this.strings.join(os.EOL); + } +} \ No newline at end of file diff --git a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts index 7b4badafb2..ce964fd27f 100644 --- a/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts +++ b/packages/stryker/test/unit/child-proxy/ChildProcessProxySpec.ts @@ -110,19 +110,6 @@ describe('ChildProcessProxy', () => { expect(logMock.warn).calledWith(`Child process [pid ${childProcessMock.pid}] exited unexpectedly with exit code 23 (SIGTERM). Stdout and stderr were empty.`); }); - it('should only log the last 20 messages from stdout and stderr', () => { - const maxNumberOfMessages = 20; - let expectedMessageLog = ''; - for (let i = 0; i < maxNumberOfMessages + 1; i++) { - if (i > 0) { - expectedMessageLog += `${os.EOL}\t${i}`; - } - childProcessMock.stdout.emit('data', i); - } - actExit(24); - expect(logMock.warn).calledWith(`Child process [pid ${childProcessMock.pid}] exited unexpectedly with exit code 24 (SIGINT). Last part of stdout and stderr was:${expectedMessageLog}`); - }); - it('should reject any outstanding worker promises with the error', () => { const expectedError = 'Child process [pid 4648] exited unexpectedly with exit code 646 (SIGINT).'; const actualPromise = sut.proxy.say('test'); From 71154e8c319d8c1a44dcaa1efe11ab626eac4e71 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Wed, 1 Aug 2018 18:41:06 +0200 Subject: [PATCH 52/54] test(string builder): Implement unit tests --- packages/stryker/src/utils/StringBuilder.ts | 6 ++-- .../test/unit/utils/StringBuilderSpec.ts | 33 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 packages/stryker/test/unit/utils/StringBuilderSpec.ts diff --git a/packages/stryker/src/utils/StringBuilder.ts b/packages/stryker/src/utils/StringBuilder.ts index d6fdb3649d..fc323e5e2a 100644 --- a/packages/stryker/src/utils/StringBuilder.ts +++ b/packages/stryker/src/utils/StringBuilder.ts @@ -1,14 +1,16 @@ import * as os from 'os'; +const DEFAULT_MAX_SIZE = 2048; + export default class StringBuilder { - private maxSize = 2048; private currentLength = 0; private strings: string[] = []; + private readonly maxSize = DEFAULT_MAX_SIZE; append(str: string) { this.strings.push(str); this.currentLength += str.length; - while (this.currentLength > this.maxSize && this.strings.length > 0) { + while (this.currentLength > this.maxSize && this.strings.length > 1) { const popped = this.strings.shift() as string; this.currentLength -= popped.length; } diff --git a/packages/stryker/test/unit/utils/StringBuilderSpec.ts b/packages/stryker/test/unit/utils/StringBuilderSpec.ts new file mode 100644 index 0000000000..aef955073e --- /dev/null +++ b/packages/stryker/test/unit/utils/StringBuilderSpec.ts @@ -0,0 +1,33 @@ +import { expect } from 'chai'; +import { EOL } from 'os'; +import StringBuilder from '../../../src/utils/StringBuilder'; + +describe.only(StringBuilder.name, () => { + + it('should append strings with new lines when `toString()` is called', () => { + const sut = new StringBuilder(); + sut.append('1'); + sut.append('2'); + sut.append('3'); + expect(sut.toString()).eq(`1${EOL}2${EOL}3`); + }); + + const DEFAULT_MAX_CHARACTERS = 2048; + it(`should append a to maximum of ${DEFAULT_MAX_CHARACTERS} characters by default`, () => { + const sut = new StringBuilder(); + for (let i = 0; i < DEFAULT_MAX_CHARACTERS; i++) { + sut.append('.'); + } + sut.append('expected'); + const result = sut.toString(); + expect(result.replace(new RegExp(EOL, 'g'), '')).lengthOf(DEFAULT_MAX_CHARACTERS); + expect(result.endsWith(`.${EOL}.${EOL}.${EOL}expected`)).ok; + }); + + it('should not split the last string, even if it exceeds the max characters', () => { + const input = new Array(DEFAULT_MAX_CHARACTERS + 1).fill('.').join(''); + const sut = new StringBuilder(); + sut.append(input); + expect(sut.toString()).eq(input); + }); +}); \ No newline at end of file From 5b0e9410b6edfa85075d9b045d5881a14f348003 Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Wed, 1 Aug 2018 20:13:57 +0200 Subject: [PATCH 53/54] fix(test): Remove `.only` --- packages/stryker/test/unit/utils/StringBuilderSpec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stryker/test/unit/utils/StringBuilderSpec.ts b/packages/stryker/test/unit/utils/StringBuilderSpec.ts index aef955073e..3b887fb28c 100644 --- a/packages/stryker/test/unit/utils/StringBuilderSpec.ts +++ b/packages/stryker/test/unit/utils/StringBuilderSpec.ts @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { EOL } from 'os'; import StringBuilder from '../../../src/utils/StringBuilder'; -describe.only(StringBuilder.name, () => { +describe(StringBuilder.name, () => { it('should append strings with new lines when `toString()` is called', () => { const sut = new StringBuilder(); From 42d95a47dc0c69a09ec758f5f942fd704abf3caf Mon Sep 17 00:00:00 2001 From: Nico Jansen Date: Thu, 2 Aug 2018 14:25:04 +0200 Subject: [PATCH 54/54] fix(child-process): Remove death by 1000 overloads --- packages/stryker/.vscode/settings.json | 20 +++++++++---------- .../src/child-proxy/ChildProcessProxy.ts | 17 ++++++---------- workspace.code-workspace | 2 +- 3 files changed, 16 insertions(+), 23 deletions(-) diff --git a/packages/stryker/.vscode/settings.json b/packages/stryker/.vscode/settings.json index 8f0f977b69..75776c1ebe 100644 --- a/packages/stryker/.vscode/settings.json +++ b/packages/stryker/.vscode/settings.json @@ -1,15 +1,13 @@ { - "files": { - "exclude": { - ".git": "", - ".tscache": "", - "**/*.js": { - "when": "$(basename).ts" - }, - "**/*.d.ts": true, - "**/*.map": { - "when": "$(basename)" - } + "files.exclude": { + ".git": true, + ".tscache": true, + "**/*.js": { + "when": "$(basename).ts" + }, + "**/*.d.ts": true, + "**/*.map": { + "when": "$(basename)" } } } \ No newline at end of file diff --git a/packages/stryker/src/child-proxy/ChildProcessProxy.ts b/packages/stryker/src/child-proxy/ChildProcessProxy.ts index 68e084b8c3..9bedf101b5 100644 --- a/packages/stryker/src/child-proxy/ChildProcessProxy.ts +++ b/packages/stryker/src/child-proxy/ChildProcessProxy.ts @@ -16,7 +16,9 @@ interface Func { interface PromisifiedFunc { (...args: TS): Promise; } - +interface Constructor { + new (...args: TS): T; +} export type Promisified = { [K in keyof T]: T[K] extends PromisifiedFunc ? T[K] : T[K] extends Func ? PromisifiedFunc : () => Promise; }; @@ -40,7 +42,7 @@ export default class ChildProcessProxy { private constructor(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, constructorParams: any[]) { this.worker = fork(require.resolve('./ChildProcessProxyWorker'), [autoStart], { silent: true, execArgv: [] }); this.initTask = new Task(); - this.log.debug('Starting %s in a child process', requirePath); + this.log.debug('Starting %s in child process %s', requirePath, this.worker.pid); this.send({ kind: WorkerMessageKind.Init, loggingContext, @@ -62,15 +64,8 @@ export default class ChildProcessProxy { /** * Creates a proxy where each function of the object created using the constructorFunction arg is ran inside of a child process */ - static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, constructorFunction: { new(arg: P1): T }, arg: P1): ChildProcessProxy; - /** - * Creates a proxy where each function of the object created using the constructorFunction arg is ran inside of a child process - */ - static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, constructorFunction: { new(arg: P1, arg2: P2): T }, arg1: P1, arg2: P2): ChildProcessProxy; - /** - * Creates a proxy where each function of the object created using the constructorFunction arg is ran inside of a child process - */ - static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, _: { new(...params: any[]): T }, ...constructorArgs: any[]) { + static create(requirePath: string, loggingContext: LoggingClientContext, plugins: string[], workingDirectory: string, _: Constructor, ...constructorArgs: TS): + ChildProcessProxy { return new ChildProcessProxy(requirePath, loggingContext, plugins, workingDirectory, constructorArgs); } diff --git a/workspace.code-workspace b/workspace.code-workspace index 2e0a5ecff6..4dc28f3795 100644 --- a/workspace.code-workspace +++ b/workspace.code-workspace @@ -50,7 +50,7 @@ } ], "settings": { - "typescript.tsdk": "node_modules\\typescript\\lib", + "typescript.tsdk": "..\\..\\node_modules\\typescript\\lib", "files.exclude": { ".git": true, ".tscache": true,