diff --git a/.babelrc b/.babelrc index b2b4161..bd8c2c1 100644 --- a/.babelrc +++ b/.babelrc @@ -8,12 +8,12 @@ "transform-regenerator" ] } - ] + ], + ["@babel/preset-typescript"] ], "plugins": [ - "@babel/plugin-transform-flow-strip-types", [ - "@babel/plugin-proposal-decorators", + "@babel/plugin-proposal-decorators", { "decoratorsBeforeExport": false } diff --git a/.eslintrc b/.eslintrc index ce34327..0b3c3e0 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,28 +1,17 @@ { "parser": "babel-eslint", "extends": [ - "airbnb-base", - "plugin:flowtype/recommended" - ], - "plugins": [ - "flowtype", - "flowtype-errors" + "airbnb-base" ], "env": { "node": true }, - "settings": { - "flowtype": { - "onlyFilesWithFlowAnnotation": true - } - }, "rules": { "arrow-parens": ["error", "always"], "max-len": ["error", 120], "no-duplicate-imports": "off", "no-restricted-syntax": "off", "generator-star-spacing": "off", - "import/no-extraneous-dependencies": ["error", {"peerDependencies": true}], - "flowtype-errors/show-errors": "error" + "import/no-extraneous-dependencies": ["error", {"peerDependencies": true}] } } diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index 932e5ca..0000000 --- a/.flowconfig +++ /dev/null @@ -1,5 +0,0 @@ -[ignore] -./lib/.* -[options] -module.ignore_non_literal_requires=true -suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe diff --git a/examples/debug-webpack4/webpack.config.js b/examples/debug-webpack4/webpack.config.js index a525b3c..ec46f39 100644 --- a/examples/debug-webpack4/webpack.config.js +++ b/examples/debug-webpack4/webpack.config.js @@ -1,8 +1,8 @@ let config = { mode: process.env.NODE_ENV || 'development', - entry: './src/index.js', + entry: './lib/index.js', devServer: { - contentBase: './src' + contentBase: './lib' } }; diff --git a/package.json b/package.json index 3b308a4..be7afab 100644 --- a/package.json +++ b/package.json @@ -17,10 +17,9 @@ "scripts": { "clean-lib": "del-cli \"lib/**\" \"!lib\" \"!lib/reporters\" \"!lib/utils.js\" \"!lib/entry.js\" \"!lib/reporters/base.js\"", "clean-tmp": "del-cli \".tmp/**\"", - "build": "yarn run clean-lib && babel ./src -d lib --source-maps", + "build": "yarn run clean-lib && tsc", "lint": "eslint src test bin --fix", - "flow": "flow", - "test": "yarn run clean-tmp && yarn run build && mocha --timeout 10000 --recursive --require @babel/register \"test/**/*.test.js\"", + "test": "yarn run clean-tmp && yarn run build && ts-mocha --timeout 10000 --recursive --require @babel/register --exit \"test/**/*.test.ts\"", "cover": "cross-env BABEL_ENV=coverage nyc --reporter=lcov --reporter=text npm test", "posttest": "yarn run lint", "docs:clean": "del-cli _book", @@ -31,7 +30,7 @@ "prepublishOnly": "yarn run build && yarn run docs:build", "postpublish": "yarn run docs:deploy", "release": "np", - "watch": "babel ./src -w -d lib" + "watch": "tsc -w" }, "repository": { "type": "git", @@ -56,11 +55,14 @@ "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-decorators": "^7.0.0", "@babel/plugin-proposal-object-rest-spread": "^7.0.0", - "@babel/plugin-transform-flow-strip-types": "^7.0.0", "@babel/plugin-transform-runtime": "^7.0.0", "@babel/preset-env": "^7.0.0", - "@babel/preset-flow": "^7.0.0", + "@babel/preset-typescript": "^7.7.4", "@babel/register": "^7.0.0", + "@babel/runtime": "^7.7.6", + "@types/lodash": "^4.14.149", + "@types/node": "^12.12.17", + "@types/webpack": "^4.41.0", "anymatch": "3.1.1", "babel-eslint": "^9.0.0", "babel-loader": "^8.0.0", @@ -75,11 +77,7 @@ "del-cli": "3.0.0", "eslint": "4.19.1", "eslint-config-airbnb-base": "12.1.0", - "eslint-plugin-flowtype": "4.3.0", - "eslint-plugin-flowtype-errors": "4.1.0", "eslint-plugin-import": "^2.9.0", - "fast-async": "^6.1.2", - "flow-bin": "^0.113.0", "fs-extra": "5.0.0", "gh-pages": "1.2.0", "gitbook-cli": "^2.3.2", @@ -96,6 +94,8 @@ "sinon": "7.5.0", "strip-ansi": "^5.2.0", "tiny-worker": "2.3.0", + "ts-mocha": "^6.0.0", + "typescript": "^3.7.3", "webpack": "4.41.0", "worker-loader": "2.0.0", "write-file-webpack-plugin": "^4.2.0" @@ -130,11 +130,10 @@ ] }, "nyc": { + "extension": [".ts"], "include": [ - "src/**/*.js" - ], - "sourceMap": false, - "instrument": false + "src/**/*.ts" + ] }, "resolutions": { "js-yaml": ">=3.13.0", diff --git a/src/MochaWebpack.js b/src/MochaWebpack.ts similarity index 83% rename from src/MochaWebpack.js rename to src/MochaWebpack.ts index ef50075..9edb49b 100644 --- a/src/MochaWebpack.js +++ b/src/MochaWebpack.ts @@ -1,31 +1,31 @@ -// @flow -import TestRunner from './runner/TestRunner'; -import testRunnerReporter from './runner/testRunnerReporter'; + +import TestRunner from "./runner/TestRunner"; +import testRunnerReporter from "./runner/testRunnerReporter"; export type MochaWebpackOptions = { - cwd: string, - webpackConfig: {}, - bail: boolean, - reporter: string | () => void, - reporterOptions: {}, - ui: string, - fgrep?: string, - grep?: string | RegExp, - invert: boolean, - ignoreLeaks: boolean, - fullStackTrace: boolean, - colors?: boolean, - useInlineDiffs: boolean, - timeout: number, - retries?: number, - slow: number, - asyncOnly: boolean, - delay: boolean, - interactive: boolean, - clearTerminal: boolean, - quiet: boolean, - growl?: boolean, - forbidOnly: boolean, + cwd: string; + webpackConfig: {}; + bail: boolean; + reporter: string | (() => void); + reporterOptions: {}; + ui: string; + fgrep?: string; + grep?: string | RegExp; + invert: boolean; + ignoreLeaks: boolean; + fullStackTrace: boolean; + colors?: boolean; + useInlineDiffs: boolean; + timeout: number; + retries?: number; + slow: number; + asyncOnly: boolean; + delay: boolean; + interactive: boolean; + clearTerminal: boolean; + quiet: boolean; + growl?: boolean; + forbidOnly: boolean; }; export default class MochaWebpack { @@ -35,12 +35,14 @@ export default class MochaWebpack { * @private */ entries: Array = []; + /** * Files to include into the bundle * * @private */ includes: Array = []; + /** * Options * @@ -61,10 +63,10 @@ export default class MochaWebpack { slow: 75, asyncOnly: false, delay: false, - interactive: !!((process.stdout: any).isTTY), + interactive: !!(process.stdout as any).isTTY, clearTerminal: false, quiet: false, - forbidOnly: false, + forbidOnly: false }; /** @@ -75,10 +77,7 @@ export default class MochaWebpack { * @return {MochaWebpack} */ addEntry(file: string): MochaWebpack { - this.entries = [ - ...this.entries, - file, - ]; + this.entries = [...this.entries, file]; return this; } @@ -90,10 +89,7 @@ export default class MochaWebpack { * @return {MochaWebpack} */ addInclude(file: string): MochaWebpack { - this.includes = [ - ...this.includes, - file, - ]; + this.includes = [...this.includes, file]; return this; } @@ -107,7 +103,7 @@ export default class MochaWebpack { cwd(cwd: string): MochaWebpack { this.options = { ...this.options, - cwd, + cwd }; return this; } @@ -122,7 +118,7 @@ export default class MochaWebpack { webpackConfig(config: {} = {}): MochaWebpack { this.options = { ...this.options, - webpackConfig: config, + webpackConfig: config }; return this; } @@ -137,7 +133,7 @@ export default class MochaWebpack { bail(bail: boolean = false): MochaWebpack { this.options = { ...this.options, - bail, + bail }; return this; } @@ -149,11 +145,11 @@ export default class MochaWebpack { * @param {Object} reporterOptions optional options * @return {MochaWebpack} */ - reporter(reporter: string | () => void, reporterOptions: {}): MochaWebpack { + reporter(reporter: string | (() => void), reporterOptions: {}): MochaWebpack { this.options = { ...this.options, reporter, - reporterOptions, + reporterOptions }; return this; } @@ -168,7 +164,7 @@ export default class MochaWebpack { ui(ui: string): MochaWebpack { this.options = { ...this.options, - ui, + ui }; return this; } @@ -183,7 +179,7 @@ export default class MochaWebpack { fgrep(str: string): MochaWebpack { this.options = { ...this.options, - fgrep: str, + fgrep: str }; return this; } @@ -198,7 +194,7 @@ export default class MochaWebpack { grep(pattern: string | RegExp): MochaWebpack { this.options = { ...this.options, - grep: pattern, + grep: pattern }; return this; } @@ -212,7 +208,7 @@ export default class MochaWebpack { invert(): MochaWebpack { this.options = { ...this.options, - invert: true, + invert: true }; return this; } @@ -227,7 +223,7 @@ export default class MochaWebpack { ignoreLeaks(ignore: boolean): MochaWebpack { this.options = { ...this.options, - ignoreLeaks: ignore, + ignoreLeaks: ignore }; return this; } @@ -241,7 +237,7 @@ export default class MochaWebpack { fullStackTrace(): MochaWebpack { this.options = { ...this.options, - fullStackTrace: true, + fullStackTrace: true }; return this; } @@ -256,7 +252,7 @@ export default class MochaWebpack { useColors(colors: boolean): MochaWebpack { this.options = { ...this.options, - colors, + colors }; return this; } @@ -270,7 +266,7 @@ export default class MochaWebpack { quiet(): MochaWebpack { this.options = { ...this.options, - quiet: true, + quiet: true }; return this; } @@ -285,7 +281,7 @@ export default class MochaWebpack { useInlineDiffs(inlineDiffs: boolean): MochaWebpack { this.options = { ...this.options, - useInlineDiffs: inlineDiffs, + useInlineDiffs: inlineDiffs }; return this; } @@ -300,7 +296,7 @@ export default class MochaWebpack { timeout(timeout: number): MochaWebpack { this.options = { ...this.options, - timeout, + timeout }; return this; } @@ -315,7 +311,7 @@ export default class MochaWebpack { retries(count: number): MochaWebpack { this.options = { ...this.options, - retries: count, + retries: count }; return this; } @@ -331,7 +327,7 @@ export default class MochaWebpack { slow(threshold: number): MochaWebpack { this.options = { ...this.options, - slow: threshold, + slow: threshold }; return this; } @@ -345,7 +341,7 @@ export default class MochaWebpack { asyncOnly(): MochaWebpack { this.options = { ...this.options, - asyncOnly: true, + asyncOnly: true }; return this; } @@ -359,7 +355,7 @@ export default class MochaWebpack { delay(): MochaWebpack { this.options = { ...this.options, - delay: true, + delay: true }; return this; } @@ -374,7 +370,7 @@ export default class MochaWebpack { interactive(interactive: boolean): MochaWebpack { this.options = { ...this.options, - interactive, + interactive }; return this; } @@ -389,7 +385,7 @@ export default class MochaWebpack { clearTerminal(clearTerminal: boolean): MochaWebpack { this.options = { ...this.options, - clearTerminal, + clearTerminal }; return this; } @@ -404,7 +400,7 @@ export default class MochaWebpack { growl(): MochaWebpack { this.options = { ...this.options, - growl: true, + growl: true }; return this; } @@ -419,7 +415,7 @@ export default class MochaWebpack { forbidOnly(): MochaWebpack { this.options = { ...this.options, - forbidOnly: true, + forbidOnly: true }; return this; } @@ -437,7 +433,7 @@ export default class MochaWebpack { interactive: this.options.interactive, quiet: this.options.quiet, cwd: this.options.cwd, - clearTerminal: this.options.clearTerminal, + clearTerminal: this.options.clearTerminal }); return runner.run(); } @@ -453,7 +449,7 @@ export default class MochaWebpack { interactive: this.options.interactive, quiet: this.options.quiet, cwd: this.options.cwd, - clearTerminal: this.options.clearTerminal, + clearTerminal: this.options.clearTerminal }); await runner.watch(); } diff --git a/src/cli/index.js b/src/cli/index.ts similarity index 68% rename from src/cli/index.js rename to src/cli/index.ts index d7b5175..0d17574 100644 --- a/src/cli/index.js +++ b/src/cli/index.ts @@ -1,12 +1,12 @@ -import path from 'path'; -import _ from 'lodash'; +import path from "path"; +import _ from "lodash"; -import parseArgv from './parseArgv'; -import { existsFileSync } from '../util/exists'; -import parseConfig from './parseConfig'; -import requireWebpackConfig from './requireWebpackConfig'; -import { ensureGlob, extensionsToGlob } from '../util/glob'; -import createMochaWebpack from '../createMochaWebpack'; +import parseArgv from "./parseArgv"; +import { existsFileSync } from "../util/exists"; +import parseConfig from "./parseConfig"; +import requireWebpackConfig from "./requireWebpackConfig"; +import { ensureGlob, extensionsToGlob } from "../util/glob"; +import { createMochaWebpack } from "../createMochaWebpack"; function resolve(mod) { @@ -33,28 +33,23 @@ async function cli() { const options = _.defaults({}, cliOptions, configOptions, defaultOptions); - options.require.forEach((mod) => { + options.require.forEach(mod => { require(resolve(mod)); // eslint-disable-line global-require, import/no-dynamic-require }); options.include = options.include.map(resolve); - options.webpackConfig = await requireWebpackConfig( - options.webpackConfig, - requiresWebpackConfig, - options.webpackEnv, - options.mode, - ); + options.webpackConfig = await requireWebpackConfig(options.webpackConfig, requiresWebpackConfig, options.webpackEnv, options.mode); const mochaWebpack = createMochaWebpack(); - options.include.forEach((f) => mochaWebpack.addInclude(f)); + options.include.forEach(f => mochaWebpack.addInclude(f)); const extensions = _.get(options.webpackConfig, 'resolve.extensions', ['.js']); const fallbackFileGlob = extensionsToGlob(extensions); const fileGlob = options.glob != null ? options.glob : fallbackFileGlob; - options.files.forEach((f) => mochaWebpack.addEntry(ensureGlob(f, options.recursive, fileGlob))); + options.files.forEach(f => mochaWebpack.addEntry(ensureGlob(f, options.recursive, fileGlob))); mochaWebpack.cwd(process.cwd()); mochaWebpack.webpackConfig(options.webpackConfig); @@ -114,23 +109,20 @@ async function cli() { mochaWebpack.forbidOnly(); } - Promise - .resolve() - .then(() => { - if (options.watch) { - return mochaWebpack.watch(); - } - return mochaWebpack.run(); - }) - .then((failures) => { - exit(options.exit, failures); - }) - .catch((e) => { - if (e) { - console.error(e.stack); // eslint-disable-line - } - exit(options.exit, 1); - }); + // @ts-ignore + await Promise.resolve().then(() => { + if (options.watch) { + return mochaWebpack.watch(); + } + return mochaWebpack.run(); + }).then(failures => { + exit(options.exit, failures); + }).catch(e => { + if (e) { + console.error(e.stack); // eslint-disable-line + } + exit(options.exit, 1); + }); } cli(); diff --git a/src/cli/parseArgv.js b/src/cli/parseArgv.ts similarity index 83% rename from src/cli/parseArgv.js rename to src/cli/parseArgv.ts index 10fb6c3..4e1b54e 100644 --- a/src/cli/parseArgv.js +++ b/src/cli/parseArgv.ts @@ -1,5 +1,5 @@ -import yargs from 'yargs'; -import _ from 'lodash'; +import yargs from "yargs"; +import _ from "lodash"; const BASIC_GROUP = 'Basic options:'; const OUTPUT_GROUP = 'Output options:'; @@ -11,46 +11,46 @@ const options = { type: 'boolean', default: false, describe: 'force all tests to take a callback (async) or return a promise', - group: ADVANCED_GROUP, + group: ADVANCED_GROUP }, colors: { alias: 'c', type: 'boolean', default: undefined, describe: 'force enabling of colors', - group: OUTPUT_GROUP, + group: OUTPUT_GROUP }, quiet: { alias: 'q', type: 'boolean', default: undefined, describe: 'does not show informational messages', - group: OUTPUT_GROUP, + group: OUTPUT_GROUP }, interactive: { type: 'boolean', - default: !!(process.stdout.isTTY), + default: !!process.stdout.isTTY, describe: 'force interactive mode (default enabled in terminal)', - group: OUTPUT_GROUP, + group: OUTPUT_GROUP }, 'clear-terminal': { type: 'boolean', default: false, describe: 'clear current terminal, purging its histroy', - group: OUTPUT_GROUP, + group: OUTPUT_GROUP }, growl: { alias: 'G', type: 'boolean', default: false, describe: 'enable growl notification support', - group: OUTPUT_GROUP, + group: OUTPUT_GROUP }, recursive: { type: 'boolean', default: false, describe: 'include sub directories', - group: ADVANCED_GROUP, + group: ADVANCED_GROUP }, reporter: { alias: 'R', @@ -58,48 +58,48 @@ const options = { describe: 'specify the reporter to use', group: OUTPUT_GROUP, default: 'spec', - requiresArg: true, + requiresArg: true }, 'reporter-options': { alias: 'O', type: 'string', describe: 'reporter-specific options, --reporter-options ', group: OUTPUT_GROUP, - requiresArg: true, + requiresArg: true }, bail: { alias: 'b', type: 'boolean', describe: 'bail after first test failure', group: ADVANCED_GROUP, - default: false, + default: false }, glob: { type: 'string', describe: 'only test files matching (only valid for directory entry)', group: ADVANCED_GROUP, - requiresArg: true, + requiresArg: true }, grep: { alias: 'g', type: 'string', describe: 'only run tests matching ', group: ADVANCED_GROUP, - requiresArg: true, + requiresArg: true }, fgrep: { alias: 'f', type: 'string', describe: 'only run tests containing ', group: ADVANCED_GROUP, - requiresArg: true, + requiresArg: true }, invert: { alias: 'i', type: 'boolean', describe: 'inverts --grep and --fgrep matches', group: ADVANCED_GROUP, - default: false, + default: false }, require: { alias: 'r', @@ -107,14 +107,14 @@ const options = { describe: 'require the given module', group: ADVANCED_GROUP, requiresArg: true, - multiple: true, + multiple: true }, include: { type: 'string', describe: 'include the given module into test bundle', group: ADVANCED_GROUP, requiresArg: true, - multiple: true, + multiple: true }, slow: { alias: 's', @@ -122,7 +122,7 @@ const options = { group: ADVANCED_GROUP, default: 75, defaultDescription: '75 ms', - requiresArg: true, + requiresArg: true }, timeout: { alias: 't', @@ -130,102 +130,98 @@ const options = { group: ADVANCED_GROUP, default: 2000, defaultDescription: '2000 ms', - requiresArg: true, + requiresArg: true }, ui: { alias: 'u', describe: 'specify user-interface (e.g. "bdd", "tdd", "exports", "qunit")', group: BASIC_GROUP, default: 'bdd', - requiresArg: true, + requiresArg: true }, watch: { alias: 'w', type: 'boolean', describe: 'watch files for changes', group: BASIC_GROUP, - default: false, + default: false }, 'check-leaks': { type: 'boolean', describe: 'check for global variable leaks', group: ADVANCED_GROUP, - default: false, + default: false }, 'full-trace': { type: 'boolean', describe: 'display the full stack trace', group: ADVANCED_GROUP, - default: false, + default: false }, 'inline-diffs': { type: 'boolean', describe: 'display actual/expected differences inline within each string', group: ADVANCED_GROUP, - default: false, + default: false }, exit: { type: 'boolean', describe: 'require a clean shutdown of the event loop: mocha will not call process.exit', group: ADVANCED_GROUP, - default: false, + default: false }, retries: { describe: 'set numbers of time to retry a failed test case', group: BASIC_GROUP, - requiresArg: true, + requiresArg: true }, delay: { type: 'boolean', describe: 'wait for async suite definition', group: ADVANCED_GROUP, - default: false, + default: false }, mode: { type: 'string', choices: ['development', 'production'], describe: 'webpack mode to use', group: BASIC_GROUP, - requiresArg: true, + requiresArg: true }, 'webpack-config': { type: 'string', describe: 'path to webpack-config file', group: BASIC_GROUP, requiresArg: true, - default: 'webpack.config.js', + default: 'webpack.config.js' }, 'webpack-env': { describe: 'environment passed to the webpack-config, when it is a function', - group: BASIC_GROUP, + group: BASIC_GROUP }, opts: { type: 'string', describe: 'path to webpack-mocha options file', group: BASIC_GROUP, - requiresArg: true, + requiresArg: true }, 'forbid-only': { type: 'boolean', describe: 'fail if exclusive test(s) encountered', group: ADVANCED_GROUP, - default: false, - }, + default: false + } }; -const paramList = (opts) => _.map(_.keys(opts), _.camelCase); +const paramList = opts => _.map(_.keys(opts), _.camelCase); const parameters = paramList(options); // camel case parameters -const parametersWithMultipleArgs = paramList(_.pickBy(_.mapValues(options, (v) => !!v.requiresArg && v.multiple === true))); // eslint-disable-line max-len +// @ts-ignore +const parametersWithMultipleArgs = paramList(_.pickBy(_.mapValues(options, v => !!v.requiresArg && v.multiple === true))); // eslint-disable-line max-len +// @ts-ignore const groupedAliases = _.values(_.mapValues(options, (value, key) => [_.camelCase(key), key, value.alias].filter(_.identity))); // eslint-disable-line max-len function parse(argv, ignoreDefaults) { - const parsedArgs = yargs() - .help('help') - .alias('help', 'h') - .version() - .options(options) - .strict() - .parse(argv); + const parsedArgs = yargs().help('help').alias('help', 'h').version().options(options).strict().parse(argv); let files = parsedArgs._; @@ -237,7 +233,7 @@ function parse(argv, ignoreDefaults) { const parsedOptions = _.pick(parsedArgs, parameters); // pick all parameters as new object const validOptions = _.omitBy(parsedOptions, _.isUndefined); // remove all undefined values - _.forEach(parametersWithMultipleArgs, (key) => { + _.forEach(parametersWithMultipleArgs, key => { if (_.has(validOptions, key)) { const value = validOptions[key]; if (!Array.isArray(value)) { @@ -251,7 +247,7 @@ function parse(argv, ignoreDefaults) { // see https://github.com/yargs/yargs/issues/229 if (parametersWithMultipleArgs.indexOf(key) === -1 && _.isArray(value)) { const arg = _.kebabCase(key); - const provided = value.map((v) => `--${arg} ${v}`).join(' '); + const provided = value.map(v => `--${arg} ${v}`).join(' '); const expected = `--${arg} ${value[0]}`; throw new Error(`Duplicating arguments for "--${arg}" is not allowed. "${provided}" was provided, but expected "${expected}"`); // eslint-disable-line max-len @@ -263,7 +259,7 @@ function parse(argv, ignoreDefaults) { const reporterOptions = {}; if (validOptions.reporterOptions) { - validOptions.reporterOptions.split(',').forEach((opt) => { + validOptions.reporterOptions.split(',').forEach(opt => { const L = opt.split('='); if (L.length > 2 || L.length === 0) { throw new Error(`invalid reporter option ${opt}`); @@ -291,8 +287,7 @@ function parse(argv, ignoreDefaults) { if (ignoreDefaults) { const userOptions = yargs(argv).argv; const providedKeys = _.keys(userOptions); - const usedAliases = _.flatten(_.filter(groupedAliases, (aliases) => - _.some(aliases, (alias) => providedKeys.indexOf(alias) !== -1))); + const usedAliases = _.flatten(_.filter(groupedAliases, aliases => _.some(aliases, alias => providedKeys.indexOf(alias) !== -1))); if (parsedArgs._.length) { usedAliases.push('files'); diff --git a/src/cli/parseConfig.js b/src/cli/parseConfig.ts similarity index 64% rename from src/cli/parseConfig.js rename to src/cli/parseConfig.ts index eb99d8d..2b8b79f 100644 --- a/src/cli/parseConfig.js +++ b/src/cli/parseConfig.ts @@ -1,6 +1,6 @@ -import fs from 'fs'; -import { existsFileSync } from '../util/exists'; -import parseArgv from './parseArgv'; +import fs from "fs"; +import { existsFileSync } from "../util/exists"; +import parseArgv from "./parseArgv"; const defaultConfig = 'mochapack.opts'; @@ -12,7 +12,7 @@ function handleMissingConfig(config) { return {}; } -const createStripSurroundingChar = (c) => (s) => { +const createStripSurroundingChar = c => s => { if (s.indexOf(c) === 0 && s.lastIndexOf(c) === s.length - 1 && s.indexOf(c) !== s.lastIndexOf(c)) { return s.substring(1, s.length - 1); } @@ -22,7 +22,7 @@ const createStripSurroundingChar = (c) => (s) => { const stripSingleQuotes = createStripSurroundingChar("'"); const stripDoubleQuotes = createStripSurroundingChar('"'); -const removeSurroundingQuotes = (str) => { +const removeSurroundingQuotes = str => { const stripped = stripDoubleQuotes(str); if (stripped !== str) { @@ -32,19 +32,14 @@ const removeSurroundingQuotes = (str) => { return stripSingleQuotes(str); }; -export default function parseConfig(explicitConfig) { +export default function parseConfig(explicitConfig?: any) { const config = explicitConfig || defaultConfig; if (!existsFileSync(config)) { return handleMissingConfig(explicitConfig); } - const argv = fs.readFileSync(config, 'utf8') - .replace(/\\\s/g, '%20') - .split(/\s/) - .filter(Boolean) - .map((value) => value.replace(/%20/g, ' ')) - .map(removeSurroundingQuotes); + const argv = fs.readFileSync(config, 'utf8').replace(/\\\s/g, '%20').split(/\s/).filter(Boolean).map(value => value.replace(/%20/g, ' ')).map(removeSurroundingQuotes); const defaultOptions = parseArgv(argv, true); return defaultOptions; } diff --git a/src/cli/requireWebpackConfig.js b/src/cli/requireWebpackConfig.ts similarity index 88% rename from src/cli/requireWebpackConfig.js rename to src/cli/requireWebpackConfig.ts index e06cadd..e0b5ad5 100644 --- a/src/cli/requireWebpackConfig.js +++ b/src/cli/requireWebpackConfig.ts @@ -1,6 +1,9 @@ -import path from 'path'; -import fs from 'fs'; -import interpret from 'interpret'; +import path from "path"; +import fs from "fs"; +import interpret from "interpret"; +import { Configuration as WebpackConfig } from "webpack"; + +type WebpackConfigMode = 'production' | 'development' | 'none' function sortExtensions(ext1, ext2) { if (ext1 === '.js') { @@ -57,18 +60,17 @@ function registerCompiler(moduleDescriptor) { try { registerCompiler(moduleDescriptor[i]); break; - } catch (e) { - // do nothing + } catch (e) {// do nothing } } } } -export default async function requireWebpackConfig(webpackConfig, required, env, mode) { +export default async function requireWebpackConfig(webpackConfig, required?: boolean, env?: string, mode?: WebpackConfigMode) { const configPath = path.resolve(webpackConfig); const configExtension = getConfigExtension(configPath); let configFound = false; - let config = {}; + let config: WebpackConfig | ((...args: any[]) => Promise) = {}; if (fileExists(configPath)) { // config exists, register compiler for non-js extensions @@ -95,11 +97,12 @@ export default async function requireWebpackConfig(webpackConfig, required, env, if (required) { throw new Error(`Webpack config could not be found: ${webpackConfig}`); } else if (mode != null) { - config.mode = mode; + (config as WebpackConfig).mode = mode; } return config; } + // @ts-ignore config = config.default || config; if (typeof config === 'function') { diff --git a/src/createMochaWebpack.js b/src/createMochaWebpack.js deleted file mode 100644 index 2b6a1b6..0000000 --- a/src/createMochaWebpack.js +++ /dev/null @@ -1,7 +0,0 @@ -// @flow -import MochaWebpack from './MochaWebpack'; - -// module.exports cause of babel 6 -module.exports = function createMochaWebpack(): MochaWebpack { - return new MochaWebpack(); -}; diff --git a/src/createMochaWebpack.ts b/src/createMochaWebpack.ts new file mode 100644 index 0000000..1f6a4c6 --- /dev/null +++ b/src/createMochaWebpack.ts @@ -0,0 +1,7 @@ + +import MochaWebpack from "./MochaWebpack"; + +// module.exports cause of babel 6 +export function createMochaWebpack(): MochaWebpack { + return new MochaWebpack(); +}; diff --git a/src/runner/TestRunner.js b/src/runner/TestRunner.ts similarity index 71% rename from src/runner/TestRunner.js rename to src/runner/TestRunner.ts index 8941c6f..8b30b39 100644 --- a/src/runner/TestRunner.js +++ b/src/runner/TestRunner.ts @@ -1,25 +1,25 @@ -// @flow -import path from 'path'; -import EventEmitter from 'events'; -import _ from 'lodash'; -import chokidar from 'chokidar'; -import minimatch from 'minimatch'; - -import { glob } from '../util/glob'; -import createCompiler from '../webpack/compiler/createCompiler'; -import createWatchCompiler from '../webpack/compiler/createWatchCompiler'; -import registerInMemoryCompiler from '../webpack/compiler/registerInMemoryCompiler'; -import registerReadyCallback from '../webpack/compiler/registerReadyCallback'; -// $FlowFixMe -import { EntryConfig } from '../webpack/loader/entryLoader'; -import configureMocha from './configureMocha'; -import getBuildStats from '../webpack/util/getBuildStats'; -import buildProgressPlugin from '../webpack/plugin/buildProgressPlugin'; - -import type { MochaWebpackOptions } from '../MochaWebpack'; -import type { BuildStats } from '../webpack/util/getBuildStats'; -import type { WatchCompiler } from '../webpack/compiler/createWatchCompiler'; -import type { Compiler, Stats } from '../webpack/types'; + +import path from "path"; +import EventEmitter from "events"; +import _ from "lodash"; +import chokidar from "chokidar"; +import minimatch from "minimatch"; + +import { glob } from "../util/glob"; +import createCompiler from "../webpack/compiler/createCompiler"; +import createWatchCompiler from "../webpack/compiler/createWatchCompiler"; +import registerInMemoryCompiler from "../webpack/compiler/registerInMemoryCompiler"; +import registerReadyCallback from "../webpack/compiler/registerReadyCallback"; + +import { EntryConfig } from "../webpack/loader/entryLoader"; +import configureMocha from "./configureMocha"; +import getBuildStats from "../webpack/util/getBuildStats"; +import buildProgressPlugin from "../webpack/plugin/buildProgressPlugin"; + +import { MochaWebpackOptions } from "../MochaWebpack"; +import { BuildStats } from "../webpack/util/getBuildStats"; +import { WatchCompiler } from "../webpack/compiler/createWatchCompiler"; +import { Configuration as WebpackConfig, Compiler, Stats } from "webpack"; const entryPath = path.resolve(__dirname, '../entry.js'); const entryLoaderPath = path.resolve(__dirname, '../webpack/loader/entryLoader.js'); @@ -28,19 +28,20 @@ const noop = () => undefined; type MochaRunner = { - abort: () => void, + abort: () => void; currentRunnable?: { - retries: (count: number) => void, - enableTimeouts: (enabled: boolean) => void, - timeout: (ms: number) => void, - resetTimeout: (ms: number) => void, - } + retries: (count: number) => void; + enableTimeouts: (enabled: boolean) => void; + timeout: (ms: number) => void; + resetTimeout: (ms: number) => void; + }; }; type Mocha = { - run: (cb: (failures: number) => void) => MochaRunner, + run: (cb: (failures: number) => void) => MochaRunner; }; export default class TestRunner extends EventEmitter { + entries: Array; includes: Array; options: MochaWebpackOptions; @@ -53,24 +54,27 @@ export default class TestRunner extends EventEmitter { this.options = options; } - prepareMocha(webpackConfig: Object, stats: Stats): Mocha { + prepareMocha(webpackConfig: WebpackConfig, stats: Stats): Mocha { const mocha: Mocha = configureMocha(this.options); const outputPath = webpackConfig.output.path; const buildStats: BuildStats = getBuildStats(stats, outputPath); + // @ts-ignore global.__webpackManifest__ = buildStats.affectedModules; // eslint-disable-line // clear up require cache for changed files to make sure that we get the latest changes - buildStats.affectedFiles.forEach((filePath) => { + buildStats.affectedFiles.forEach(filePath => { delete require.cache[filePath]; }); // pass webpack's entry files to mocha - (mocha: any).files = buildStats.entries; + (mocha as any).files = buildStats.entries; return mocha; } async run(): Promise { - const { webpackConfig: config } = await this.createWebpackConfig(); + const { + webpackConfig: config + } = await this.createWebpackConfig(); let failures = 0; const compiler: Compiler = createCompiler(config); @@ -82,7 +86,7 @@ export default class TestRunner extends EventEmitter { const dispose = registerInMemoryCompiler(compiler); try { failures = await new Promise((resolve, reject) => { - registerReadyCallback(compiler, (err: ?(Error | string), webpackStats: ?Stats) => { + registerReadyCallback(compiler, (err: (Error | string) | null, webpackStats: Stats | null) => { this.emit('webpack:ready', err, webpackStats); if (err || !webpackStats) { reject(); @@ -92,7 +96,7 @@ export default class TestRunner extends EventEmitter { const mocha = this.prepareMocha(config, webpackStats); this.emit('mocha:begin'); try { - mocha.run((fails) => { + mocha.run(fails => { this.emit('mocha:finished', fails); resolve(fails); }); @@ -114,13 +118,16 @@ export default class TestRunner extends EventEmitter { } async watch(): Promise { - const { webpackConfig: config, entryConfig } = await this.createWebpackConfig(); + const { + webpackConfig: config, + entryConfig + } = await this.createWebpackConfig(); - let mochaRunner: ?MochaRunner = null; - let stats: ?Stats = null; - let compilationScheduler: ?() => void = null; + let mochaRunner: MochaRunner | null = null; + let stats: Stats | null = null; + let compilationScheduler: () => void | null = null; - const uncaughtExceptionListener = (err) => { + const uncaughtExceptionListener = err => { // mocha catches uncaughtException only while tests are running, // that's why we register a custom error handler to keep this process alive this.emit('uncaughtException', err); @@ -128,14 +135,13 @@ export default class TestRunner extends EventEmitter { const runMocha = () => { try { - // $FlowFixMe const mocha = this.prepareMocha(config, stats); // unregister our custom exception handler (see declaration) process.removeListener('uncaughtException', uncaughtExceptionListener); // run tests this.emit('mocha:begin'); - mochaRunner = mocha.run(_.once((failures) => { + mochaRunner = mocha.run(_.once(failures => { // register custom exception handler to catch all errors that may happen after mocha think tests are done process.on('uncaughtException', uncaughtExceptionListener); @@ -182,7 +188,7 @@ export default class TestRunner extends EventEmitter { } }); // register webpack ready callback - registerReadyCallback(compiler, (err: ?(Error | string), webpackStats: ?Stats) => { + registerReadyCallback(compiler, (err: (Error | string) | null, webpackStats: Stats | null) => { this.emit('webpack:ready', err, webpackStats); if (err) { // wait for fixed tests @@ -192,7 +198,7 @@ export default class TestRunner extends EventEmitter { runMocha(); }); - const watchCompiler: WatchCompiler = createWatchCompiler(compiler, (config: any).watchOptions); + const watchCompiler: WatchCompiler = createWatchCompiler(compiler, (config as any).watchOptions); // start webpack build immediately watchCompiler.watch(); @@ -210,12 +216,12 @@ export default class TestRunner extends EventEmitter { ignored: watchOptions.ignored, usePolling: watchOptions.poll ? true : undefined, interval: pollingInterval, - binaryInterval: pollingInterval, + binaryInterval: pollingInterval }); const restartWebpackBuild = _.debounce(() => watchCompiler.watch(), watchOptions.aggregateTimeout); const fileDeletedOrAdded = (file, deleted) => { - const matchesGlob = this.entries.some((pattern) => minimatch(file, pattern)); + const matchesGlob = this.entries.some(pattern => minimatch(file, pattern)); // Chokidar gives files not matching pattern sometimes, prevent this if (matchesGlob) { const filePath = path.join(this.options.cwd, file); @@ -235,22 +241,24 @@ export default class TestRunner extends EventEmitter { }; // add listener for entry creation & deletion events - watcher.on('add', (file) => fileDeletedOrAdded(file, false)); - watcher.on('unlink', (file) => fileDeletedOrAdded(file, true)); + watcher.on('add', file => fileDeletedOrAdded(file, false)); + watcher.on('unlink', file => fileDeletedOrAdded(file, true)); return new Promise(() => undefined); // never ending story } async createWebpackConfig() { - const { webpackConfig } = this.options; + const { + webpackConfig + } = this.options; const files = await glob(this.entries, { cwd: this.options.cwd, - absolute: true, + absolute: true }); const entryConfig = new EntryConfig(); - files.forEach((f) => entryConfig.addFile(f)); + files.forEach(f => entryConfig.addFile(f)); const tmpPath = path.join(this.options.cwd, '.tmp', 'mochapack', Date.now().toString()); const withCustomPath = _.has(webpackConfig, 'output.path'); @@ -266,42 +274,36 @@ export default class TestRunner extends EventEmitter { const userLoaders = _.get(webpackConfig, 'module.rules', []); userLoaders.unshift({ test: entryPath, - use: [ - { - loader: includeLoaderPath, - options: { - include: this.includes, - }, - }, - { - loader: entryLoaderPath, - options: { - entryConfig, - }, - }, - ], + use: [{ + loader: includeLoaderPath, + options: { + include: this.includes + } + }, { + loader: entryLoaderPath, + options: { + entryConfig + } + }] }); const config = { ...webpackConfig, entry: entryPath, module: { - ...(webpackConfig: any).module, - rules: userLoaders, + ...(webpackConfig as any).module, + rules: userLoaders }, output: { - ...(webpackConfig: any).output, + ...(webpackConfig as any).output, path: outputPath, - publicPath, + publicPath }, - plugins: [ - ...((webpackConfig: any).plugins || []), - ...plugins, - ], + plugins: [...((webpackConfig as any).plugins || []), ...plugins] }; return { webpackConfig: config, - entryConfig, + entryConfig }; } } diff --git a/src/runner/configureMocha.js b/src/runner/configureMocha.ts similarity index 89% rename from src/runner/configureMocha.js rename to src/runner/configureMocha.ts index fdd63ed..3800616 100644 --- a/src/runner/configureMocha.js +++ b/src/runner/configureMocha.ts @@ -1,8 +1,8 @@ -// @flow -import Mocha from 'mocha'; -import loadReporter from './loadReporter'; -import loadUI from './loadUI'; -import type { MochaWebpackOptions } from '../MochaWebpack'; + +import Mocha from "mocha"; +import loadReporter from "./loadReporter"; +import loadUI from "./loadUI"; +import { MochaWebpackOptions } from "../MochaWebpack"; export default function configureMocha(options: MochaWebpackOptions) { @@ -91,4 +91,4 @@ export default function configureMocha(options: MochaWebpackOptions) { mocha.ui(ui); return mocha; -} +} \ No newline at end of file diff --git a/src/runner/loadReporter.js b/src/runner/loadReporter.ts similarity index 80% rename from src/runner/loadReporter.js rename to src/runner/loadReporter.ts index 4214433..ba0c7b0 100644 --- a/src/runner/loadReporter.js +++ b/src/runner/loadReporter.ts @@ -1,8 +1,8 @@ -// @flow -import path from 'path'; -import { reporters } from 'mocha'; -export default function loadReporter(reporter: string | () => void, cwd: string) { +import path from "path"; +import { reporters, Spec } from "mocha"; + +export default function loadReporter(reporter: string | (() => void) | Spec, cwd?: string) { // if reporter is already loaded, just return it if (typeof reporter === 'function') { return reporter; diff --git a/src/runner/loadUI.js b/src/runner/loadUI.ts similarity index 73% rename from src/runner/loadUI.js rename to src/runner/loadUI.ts index 3f487fb..1780f8c 100644 --- a/src/runner/loadUI.js +++ b/src/runner/loadUI.ts @@ -1,8 +1,8 @@ -// @flow -import path from 'path'; -import { interfaces } from 'mocha'; -export default function loadUI(ui: string, cwd: string) { +import path from "path"; +import { interfaces } from "mocha"; + +export default function loadUI(ui: string, cwd?: string) { // try to load built-in ui like 'bdd' if (typeof interfaces[ui] !== 'undefined') { return ui; diff --git a/src/runner/testRunnerReporter.js b/src/runner/testRunnerReporter.ts similarity index 75% rename from src/runner/testRunnerReporter.js rename to src/runner/testRunnerReporter.ts index c4cb526..d28ad35 100644 --- a/src/runner/testRunnerReporter.js +++ b/src/runner/testRunnerReporter.ts @@ -1,34 +1,38 @@ -// @flow -import EventEmitter from 'events'; -import chalk from 'chalk'; -import type { Stats } from '../webpack/types'; -import createStatsFormatter from '../webpack/util/createStatsFormatter'; + +import EventEmitter from "events"; +import chalk from "chalk"; +import { Stats } from "webpack"; +import createStatsFormatter from "../webpack/util/createStatsFormatter"; type ReporterOptions = { - eventEmitter: EventEmitter, - interactive: boolean, - clearTerminal: boolean, - quiet: boolean, - cwd: string, + eventEmitter: EventEmitter; + interactive: boolean; + clearTerminal: boolean; + quiet: boolean; + cwd: string; }; const log = (...args: Array) => { console.log(...args); // eslint-disable-line no-console - console.log();// eslint-disable-line no-console + console.log(); // eslint-disable-line no-console }; -const formatTitleInfo = (title) => chalk.inverse('', title, ''); -const formatTitleWarn = (title) => chalk.black.bgYellow('', title, ''); -const formatTitleError = (title) => chalk.white.bold.bgRed('', title, ''); +const formatTitleInfo = title => chalk.inverse('', title, ''); +const formatTitleWarn = title => chalk.black.bgYellow('', title, ''); +const formatTitleError = title => chalk.white.bold.bgRed('', title, ''); class Reporter { + added: Array; removed: Array; options: ReporterOptions; - formatStats: (stats: Stats) => { warnings: Array, errors: Array }; + formatStats: (stats: Stats) => {warnings: Array;errors: Array;}; constructor(options: ReporterOptions) { - const { cwd, eventEmitter } = options; + const { + cwd, + eventEmitter + } = options; this.options = options; this.added = []; @@ -61,13 +65,11 @@ class Reporter { static displayErrors(severity: string, errors: Array) { const errorCount = errors.length; - const message = severity === 'error' ? - `Failed to compile with ${chalk.red(`${errorCount} ${severity}(s)`)}` : - `Compiled with ${chalk.yellow(`${errorCount} ${severity}(s)`)}`; + const message = severity === 'error' ? `Failed to compile with ${chalk.red(`${errorCount} ${severity}(s)`)}` : `Compiled with ${chalk.yellow(`${errorCount} ${severity}(s)`)}`; const titleColor = severity === 'error' ? formatTitleError : formatTitleWarn; log(titleColor('WEBPACK'), message); - errors.forEach((err) => log(err)); + errors.forEach(err => log(err)); } onUncaughtException = (err: Error) => { @@ -84,12 +86,12 @@ class Reporter { this.clearTerminal(); if (this.added.length > 0) { this.logInfo(formatTitleInfo('MOCHA'), 'The following test entry files were added:'); - this.logInfo(this.added.map((f) => `+ ${f}`).join('\n')); + this.logInfo(this.added.map(f => `+ ${f}`).join('\n')); } if (this.removed.length > 0) { this.logInfo(formatTitleInfo('MOCHA'), 'The following test entry files were removed:'); - this.logInfo(this.removed.map((f) => `- ${f}`).join('\n')); + this.logInfo(this.removed.map(f => `- ${f}`).join('\n')); } this.logInfo(formatTitleInfo('WEBPACK'), 'Compiling...'); @@ -101,10 +103,16 @@ class Reporter { onWebpackReady = (err?: Error, stats?: Stats) => { this.clearTerminal(); if (stats != null) { - const { errors, warnings } = this.formatStats(stats); + const { + errors, + warnings + } = this.formatStats(stats); if (errors.length === 0 && warnings.length === 0) { - const { startTime, endTime } = stats; + const { + startTime, + endTime + } = stats; const compileTime = endTime - startTime; this.logInfo(formatTitleInfo('WEBPACK'), `Compiled successfully in ${chalk.green(`${compileTime}ms`)}`); return; diff --git a/src/util/exists.js b/src/util/exists.ts similarity index 72% rename from src/util/exists.js rename to src/util/exists.ts index 1b47253..04a4028 100644 --- a/src/util/exists.js +++ b/src/util/exists.ts @@ -1,11 +1,11 @@ -// @flow -import fs from 'fs'; + +import fs from "fs"; /* eslint-disable import/prefer-default-export */ export function existsFileSync(file: string): boolean { try { - fs.accessSync(file, fs.F_OK); + fs.accessSync(file, fs.constants.F_OK); return true; } catch (e) { return false; diff --git a/src/util/glob.js b/src/util/glob.ts similarity index 71% rename from src/util/glob.js rename to src/util/glob.ts index 620a1a9..3e0f0d9 100644 --- a/src/util/glob.js +++ b/src/util/glob.ts @@ -1,16 +1,13 @@ -// @flow -import path from 'path'; -import globby from 'globby'; -import isGlob from 'is-glob'; -import globParent from 'glob-parent'; -import normalizePath from 'normalize-path'; -const isDirectory = (filePath) => path.extname(filePath).length === 0; +import path from "path"; +import globby from "globby"; +import isGlob from "is-glob"; +import globParent from "glob-parent"; +import normalizePath from "normalize-path"; -export const glob = async ( - patterns: Array, - options: {}, -): Promise> => globby(patterns, options); +const isDirectory = filePath => path.extname(filePath).length === 0; + +export const glob = async (patterns: Array, options: {}): Promise> => globby(patterns, options); export const ensureGlob = (entry: string, recursive: boolean = false, pattern: string = '*.js'): string => { const normalized = normalizePath(entry); @@ -43,4 +40,4 @@ export const extensionsToGlob = (extensions: Array) => { return `*${filtered[0]}`; } return `*{${filtered.join(',')}}`; -}; +}; \ No newline at end of file diff --git a/src/util/paths.js b/src/util/paths.ts similarity index 80% rename from src/util/paths.js rename to src/util/paths.ts index f9034f4..9d5d871 100644 --- a/src/util/paths.js +++ b/src/util/paths.ts @@ -1,8 +1,7 @@ -// @flow -import { join, posix, win32 } from 'path'; + +import { join, posix, win32 } from "path"; // eslint-disable-next-line import/prefer-default-export export function ensureAbsolutePath(path: string, basePath: string) { return posix.isAbsolute(path) || win32.isAbsolute(path) ? path : join(basePath, path); -} - +} \ No newline at end of file diff --git a/src/util/registerRequireHook.js b/src/util/registerRequireHook.ts similarity index 84% rename from src/util/registerRequireHook.js rename to src/util/registerRequireHook.ts index d3e89f1..2e1ff76 100644 --- a/src/util/registerRequireHook.js +++ b/src/util/registerRequireHook.ts @@ -1,9 +1,10 @@ -// @flow + + /* eslint-disable no-underscore-dangle */ // see https://github.com/nodejs/node/blob/master/lib/module.js -// $FlowFixMe -import Module from 'module'; + +import Module from "module"; // the module in which the require() call originated let requireCaller; @@ -11,8 +12,10 @@ let requireCaller; let pathResolvers = []; // keep original Module._resolveFilename +// @ts-ignore const originalResolveFilename = Module._resolveFilename; // override Module._resolveFilename +// @ts-ignore Module._resolveFilename = function _resolveFilename(...parameters) { const parent = parameters[1]; // store require() caller (the module in which this require() call originated) @@ -21,8 +24,10 @@ Module._resolveFilename = function _resolveFilename(...parameters) { }; // keep original Module._findPath +// @ts-ignore const originalFindPath = Module._findPath; // override Module._findPath +// @ts-ignore Module._findPath = function _findPath(...parameters) { const request = parameters[0]; @@ -44,10 +49,7 @@ Module._findPath = function _findPath(...parameters) { }; -export default function registerRequireHook( - dotExt: string, - resolve: (path: string, parent: Module) => { path: ?string, source: ?string }, -) { +export default function registerRequireHook(dotExt: string, resolve: (path: string, parent: Module) => {path: string | null;source: string | null;}) { // cache source code after resolving to avoid another access to the fs const sourceCache = {}; // store all files that were affected by this hook @@ -55,7 +57,10 @@ export default function registerRequireHook( const resolvePath = (path, parent) => { // get CommonJS module source code for this require() call - const { path: resolvedPath, source } = resolve(path, parent); + const { + path: resolvedPath, + source + } = resolve(path, parent); // if no CommonJS module source code returned - skip this require() hook if (resolvedPath == null) { @@ -72,7 +77,7 @@ export default function registerRequireHook( return resolvedPath; }; - const resolveSource = (path) => { + const resolveSource = path => { const source = sourceCache[path]; delete sourceCache[path]; return source; @@ -82,13 +87,16 @@ export default function registerRequireHook( // keep original extension loader + // @ts-ignore const originalLoader = Module._extensions[dotExt]; // override extension loader + // @ts-ignore Module._extensions[dotExt] = (module, filename) => { const source = resolveSource(filename); if (typeof source === 'undefined') { // load the file with the original loader + // @ts-ignore (originalLoader || Module._extensions['.js'])(module, filename); return; } @@ -100,9 +108,10 @@ export default function registerRequireHook( }; return function unmout() { - pathResolvers = pathResolvers.filter((r) => r !== resolvePath); + pathResolvers = pathResolvers.filter(r => r !== resolvePath); + // @ts-ignore Module._extensions[dotExt] = originalLoader; - Object.keys(affectedFiles).forEach((path) => { + Object.keys(affectedFiles).forEach(path => { delete require.cache[path]; delete sourceCache[path]; delete affectedFiles[path]; diff --git a/src/webpack/compiler/createCompiler.js b/src/webpack/compiler/createCompiler.ts similarity index 62% rename from src/webpack/compiler/createCompiler.js rename to src/webpack/compiler/createCompiler.ts index 18469a4..28b1189 100644 --- a/src/webpack/compiler/createCompiler.js +++ b/src/webpack/compiler/createCompiler.ts @@ -1,6 +1,5 @@ -// @flow -import webpack from 'webpack'; -import type { Compiler } from '../types'; + +import webpack, { Compiler } from "webpack"; export default function createCompiler(webpackConfig: {}): Compiler { const compiler = webpack(webpackConfig); diff --git a/src/webpack/compiler/createWatchCompiler.js b/src/webpack/compiler/createWatchCompiler.ts similarity index 82% rename from src/webpack/compiler/createWatchCompiler.js rename to src/webpack/compiler/createWatchCompiler.ts index d490c2e..c686bfd 100644 --- a/src/webpack/compiler/createWatchCompiler.js +++ b/src/webpack/compiler/createWatchCompiler.ts @@ -1,17 +1,17 @@ -// @flow -import _ from 'lodash'; -import Watching from 'webpack/lib/Watching'; -import type { Compiler } from '../types'; + +import _ from "lodash"; +import Watching from "webpack/lib/Watching"; +import { Compiler } from "webpack"; export type WatchCompiler = { - watch: () => void, - pause: () => void, + watch: () => void; + pause: () => void; getWatchOptions: () => { - aggregateTimeout: number, - ignored?: RegExp | string, - poll?: number | boolean, - }, -} + aggregateTimeout: number; + ignored?: RegExp | string; + poll?: number | boolean; + }; +}; const noop = () => undefined; export default function createWatchCompiler(compiler: Compiler, watchOptions: {}): WatchCompiler { @@ -25,12 +25,13 @@ export default function createWatchCompiler(compiler: Compiler, watchOptions: {} if (watchCompiler === null) { watchCompiler = createWatcher(); } else { + // @ts-ignore const times = compiler.watchFileSystem.watcher.getTimes(); // check if we can store some collected file timestamps // the non-empty check is necessary as the times will be reseted after .close() // and we don't want to reset already existing timestamps if (Object.keys(times).length > 0) { - const timesMap = new Map(Object.keys(times).map((key) => [key, times[key]])); + const timesMap = new Map(Object.keys(times).map(key => [key, times[key]])); // set already collected file timestamps to cache compiled files // webpack will do this only after a file change, but that will not happen when we add or delete files // and this means that we have to test the whole test suite again ... @@ -51,6 +52,6 @@ export default function createWatchCompiler(compiler: Compiler, watchOptions: {} getWatchOptions() { // 200 is the default value by webpack return _.get(watchCompiler, 'watchOptions', { aggregateTimeout: 200 }); - }, + } }; } diff --git a/src/webpack/compiler/registerInMemoryCompiler.js b/src/webpack/compiler/registerInMemoryCompiler.ts similarity index 70% rename from src/webpack/compiler/registerInMemoryCompiler.js rename to src/webpack/compiler/registerInMemoryCompiler.ts index be456af..48b4b86 100644 --- a/src/webpack/compiler/registerInMemoryCompiler.js +++ b/src/webpack/compiler/registerInMemoryCompiler.ts @@ -1,10 +1,10 @@ -// @flow -import path from 'path'; -import sourceMapSupport from 'source-map-support'; -import MemoryFileSystem from 'memory-fs'; -import registerRequireHook from '../../util/registerRequireHook'; -import { ensureAbsolutePath } from '../../util/paths'; -import type { Compiler, Stats } from '../types'; + +import path from "path"; +import sourceMapSupport from "source-map-support"; +import MemoryFileSystem from "memory-fs"; +import registerRequireHook from "../../util/registerRequireHook"; +import { ensureAbsolutePath } from "../../util/paths"; +import { Compiler, Stats } from "webpack"; export default function registerInMemoryCompiler(compiler: Compiler) { // register memory fs to webpack @@ -17,13 +17,12 @@ export default function registerInMemoryCompiler(compiler: Compiler) { assetMap.clear(); if (!stats.hasErrors()) { - Object.keys(stats.compilation.assets) - .forEach((assetPath) => assetMap.set(ensureAbsolutePath(assetPath, compiler.options.output.path), true)); + Object.keys(stats.compilation.assets).forEach(assetPath => assetMap.set(ensureAbsolutePath(assetPath, compiler.options.output.path), true)); } }); // provide file reader to read from memory fs - let readFile = (filePath) => { + let readFile = filePath => { if (assetMap.has(filePath)) { try { const code = memoryFs.readFileSync(filePath, 'utf8'); @@ -42,7 +41,9 @@ export default function registerInMemoryCompiler(compiler: Compiler) { let resolvedPath = filePath; if (code === null && requireCaller != null) { - const { filename } = requireCaller; + const { + filename + } = requireCaller; if (filename != null) { // if that didn't work, resolve the file relative to it's parent resolvedPath = path.resolve(path.dirname(filename), filePath); @@ -60,11 +61,11 @@ export default function registerInMemoryCompiler(compiler: Compiler) { emptyCacheBetweenOperations: true, handleUncaughtExceptions: false, environment: 'node', - retrieveFile: (f) => readFile(f), // wrapper function to fake an unmount function + retrieveFile: f => readFile(f) // wrapper function to fake an unmount function }); return function unmount() { unmountHook(); - readFile = (filePath) => null; // eslint-disable-line no-unused-vars + readFile = filePath => null; // eslint-disable-line no-unused-vars }; } diff --git a/src/webpack/compiler/registerReadyCallback.js b/src/webpack/compiler/registerReadyCallback.ts similarity index 75% rename from src/webpack/compiler/registerReadyCallback.js rename to src/webpack/compiler/registerReadyCallback.ts index d9dc395..f21a6a9 100644 --- a/src/webpack/compiler/registerReadyCallback.js +++ b/src/webpack/compiler/registerReadyCallback.ts @@ -1,7 +1,7 @@ -// @flow -import type { Compiler, Stats } from '../types'; -export default function registerReadyCallback(compiler: Compiler, cb: (err: ?(Error | string), stats: ?Stats) => void) { +import { Compiler, Stats } from "webpack"; + +export default function registerReadyCallback(compiler: Compiler, cb: (err: (Error | string) | null, stats: Stats | null) => void) { compiler.hooks.failed.tap('mochapack', cb); compiler.hooks.done.tap('mochapack', (stats: Stats) => { if (stats.hasErrors()) { diff --git a/src/webpack/loader/entryLoader.js b/src/webpack/loader/entryLoader.ts similarity index 61% rename from src/webpack/loader/entryLoader.js rename to src/webpack/loader/entryLoader.ts index 7a5b60f..4abdc40 100644 --- a/src/webpack/loader/entryLoader.js +++ b/src/webpack/loader/entryLoader.ts @@ -1,9 +1,10 @@ -// @flow -import loaderUtils from 'loader-utils'; -import normalizePath from 'normalize-path'; -import createEntry from '../util/createEntry'; -class EntryConfig { +import loaderUtils from "loader-utils"; +import normalizePath from "normalize-path"; +import createEntry from "../util/createEntry"; + +export class EntryConfig { + files: Array; constructor() { @@ -17,7 +18,7 @@ class EntryConfig { removeFile(file: string): void { const normalizedFile = normalizePath(file); - this.files = this.files.filter((f) => f !== normalizedFile); + this.files = this.files.filter(f => f !== normalizedFile); } getFiles(): Array { @@ -25,16 +26,14 @@ class EntryConfig { } } -const entryLoader = function entryLoader() { +export const entryLoader = function entryLoader() { const loaderOptions = loaderUtils.getOptions(this); const config: EntryConfig = loaderOptions.entryConfig; // Remove all dependencies of the loader result this.clearDependencies(); - const dependencies: Array = config - .getFiles() - .map((file) => loaderUtils.stringifyRequest(this, file)); + const dependencies: Array = config.getFiles().map(file => loaderUtils.stringifyRequest(this, file)); // add all entries as dependencies dependencies.forEach(this.addDependency.bind(this)); @@ -45,6 +44,4 @@ const entryLoader = function entryLoader() { this.callback(null, sourceCode, null); }; - -module.exports = entryLoader; -module.exports.EntryConfig = EntryConfig; +export default entryLoader; diff --git a/src/webpack/loader/includeFilesLoader.js b/src/webpack/loader/includeFilesLoader.ts similarity index 58% rename from src/webpack/loader/includeFilesLoader.js rename to src/webpack/loader/includeFilesLoader.ts index 2c591e4..8fb5c0e 100644 --- a/src/webpack/loader/includeFilesLoader.js +++ b/src/webpack/loader/includeFilesLoader.ts @@ -1,5 +1,5 @@ -// @flow -import loaderUtils from 'loader-utils'; + +import loaderUtils from "loader-utils"; // Note: no export default here cause of Babel 6 module.exports = function includeFilesLoader(sourceCode: string) { @@ -9,18 +9,13 @@ module.exports = function includeFilesLoader(sourceCode: string) { const loaderOptions = loaderUtils.getOptions(this); if (loaderOptions.include && loaderOptions.include.length) { - const includes = loaderOptions.include - .map((modPath) => `require(${loaderUtils.stringifyRequest(this, modPath)});`) - .join('\n'); + const includes = loaderOptions.include.map(modPath => `require(${loaderUtils.stringifyRequest(this, modPath)});`).join('\n'); - const code = [ - includes, - sourceCode, - ].join('\n'); + const code = [includes, sourceCode].join('\n'); this.callback(null, code, null); return; } this.callback(null, sourceCode, null); -}; +}; \ No newline at end of file diff --git a/src/webpack/plugin/buildProgressPlugin.js b/src/webpack/plugin/buildProgressPlugin.ts similarity index 67% rename from src/webpack/plugin/buildProgressPlugin.js rename to src/webpack/plugin/buildProgressPlugin.ts index 65ef55c..82b1486 100644 --- a/src/webpack/plugin/buildProgressPlugin.js +++ b/src/webpack/plugin/buildProgressPlugin.ts @@ -1,20 +1,20 @@ -import chalk from 'chalk'; -import ProgressBar from 'progress'; -import { ProgressPlugin } from 'webpack'; +import chalk from "chalk"; +import ProgressBar from "progress"; +import { ProgressPlugin } from "webpack"; export default function buildProgressPlugin() { const bar = new ProgressBar(` [:bar] ${chalk.bold(':percent')} (${chalk.dim(':msg')})`, { total: 100, complete: '=', incomplete: ' ', - width: 25, + width: 25 }); return new ProgressPlugin((percent, msg) => { bar.update(percent, { - msg: percent === 1 ? 'completed' : msg, + msg: percent === 1 ? 'completed' : msg }); if (percent === 1) { bar.terminate(); } }); -} +} \ No newline at end of file diff --git a/src/webpack/types.js b/src/webpack/types.js deleted file mode 100644 index 690aacc..0000000 --- a/src/webpack/types.js +++ /dev/null @@ -1,118 +0,0 @@ -// @flow - -export type SourceMap = { - sources: Array, - version: number, - mappings: any, - sourcesContent: any, -}; - -/** - * webpack/lib/Compiler.js - */ -export type Compiler = { - plugin: (hook: string, fn: () => void) => void, - run: (cb: () => void) => void, - watch: (watchOptions: {}, cb: () => void) => void, - outputFileSystem: any, - watchFileSystem: any, - hooks: any, - fileTimestamps: {}, - contextTimestamps: {}, - options: { - output: { - path: string, - }, - }, -} - -/** - * webpack/lib/Module.js - */ -export type Module = { - id: number, - rawRequest: string, - built: boolean, - dependencies: Array<{ module: Module }>, - readableIdentifier: ?any, - chunks: Array, // eslint-disable-line no-use-before-define - getChunks: () => Array, // eslint-disable-line no-use-before-define - blocks: Array // eslint-disable-line no-use-before-define -}; - -/** - * Webpack build error or warning - */ -export type WebpackError = Error & { - message: string, - file?: ?string, - module?: ?Module -}; - - -/** - * webpack/lib/Chunk.js - */ -export type Chunk = { - id: number | string, - modules: Array, - chunks: Array, - parents: Array, - files: Array, - isOnlyInitial: () => boolean, - getModules: () => Array, -}; - -/** - * webpack/lib/ChunkGroup.js - */ -export type ChunkGroup = { - chunks: Array, -}; - -/** - * webpack/lib/DependenciesBlock.js - * webpack/lib/AsyncDependenciesBlock.js - */ -export type DependenciesBlock = { - chunkGroup?: ChunkGroup, -}; - -/** - * webpack/lib/Compilation.js - */ -export type Compilation = { - compiler: Compiler, - plugin: (hook: string, fn: () => void) => void, - modules: Module[], - chunks: Chunk[], - chunkGroups: ChunkGroup[], - errors: Array, - warnings: Array, - assets: { - [key: string]: { - size: () => number, - source: () => string, - map: () => SourceMap, - }, - } -}; - - -/** - * webpack/lib/Stats.js - */ -export type Stats = { - compilation: Compilation, - startTime: number, - endTime: number, - toString: (options: Object) => string, - toJson: (options: ?Object) => { - startTime: number, - endTime: number, - errors: Array, - warnings: Array, - }, - hasWarnings: () => boolean, - hasErrors: () => boolean, -}; diff --git a/src/webpack/types.ts b/src/webpack/types.ts new file mode 100644 index 0000000..721eb91 --- /dev/null +++ b/src/webpack/types.ts @@ -0,0 +1,80 @@ +import { Compiler } from "webpack"; + +export type SourceMap = { + sources: Array; + version: number; + mappings: any; + sourcesContent: any; +}; + +/** + * webpack/lib/Module.js + */ +export type Module = { + id: number; + rawRequest: string; + built: boolean; + dependencies: Array<{module: Module;}>; + readableIdentifier: any | null; + chunks: Array; // eslint-disable-line no-use-before-define + getChunks: () => Array; // eslint-disable-line no-use-before-define + blocks: Array; // eslint-disable-line no-use-before-define +}; + +/** + * Webpack build error or warning + */ +export type WebpackError = Error & { + message: string; + file?: string | null; + module?: Module | null; +}; + + +/** + * webpack/lib/Chunk.js + */ +export type Chunk = { + id: number | string; + modules: Array; + chunks: Array; + parents: Array; + files: Array; + isOnlyInitial: () => boolean; + getModules: () => Array; +}; + +/** + * webpack/lib/ChunkGroup.js + */ +export type ChunkGroup = { + chunks: Array; +}; + +/** + * webpack/lib/DependenciesBlock.js + * webpack/lib/AsyncDependenciesBlock.js + */ +export type DependenciesBlock = { + chunkGroup?: ChunkGroup; +}; + +/** + * webpack/lib/Compilation.js + */ +export type Compilation = { + compiler: Compiler; + plugin: (hook: string, fn: () => void) => void; + modules: Module[]; + chunks: Chunk[]; + chunkGroups: ChunkGroup[]; + errors: Array; + warnings: Array; + assets: { + [key: string]: { + size: () => number; + source: () => string; + map: () => SourceMap; + }; + }; +}; diff --git a/src/webpack/util/createEntry.js b/src/webpack/util/createEntry.js deleted file mode 100644 index 343917c..0000000 --- a/src/webpack/util/createEntry.js +++ /dev/null @@ -1,16 +0,0 @@ -// @flow - -export default function createEntry(filePaths: Array): string { - return [ - '// runtime helper', - 'function inManifest(id) { return global.__webpackManifest__.indexOf(id) >= 0;}', - 'function run(id) { __webpack_require__(id);}', - '', - '// modules to execute goes here', - 'var ids = [', - filePaths.map((path) => `require.resolve(${path})`).join(','), - '];', - '', - 'ids.filter(inManifest).forEach(run)', - ].join('\n'); -} diff --git a/src/webpack/util/createEntry.ts b/src/webpack/util/createEntry.ts new file mode 100644 index 0000000..47a9395 --- /dev/null +++ b/src/webpack/util/createEntry.ts @@ -0,0 +1,5 @@ + + +export default function createEntry(filePaths: Array): string { + return ['// runtime helper', 'function inManifest(id) { return global.__webpackManifest__.indexOf(id) >= 0;}', 'function run(id) { __webpack_require__(id);}', '', '// modules to execute goes here', 'var ids = [', filePaths.map(path => `require.resolve(${path})`).join(','), '];', '', 'ids.filter(inManifest).forEach(run)'].join('\n'); +} \ No newline at end of file diff --git a/src/webpack/util/createStatsFormatter.js b/src/webpack/util/createStatsFormatter.ts similarity index 73% rename from src/webpack/util/createStatsFormatter.js rename to src/webpack/util/createStatsFormatter.ts index ab1b4b1..af9c64e 100644 --- a/src/webpack/util/createStatsFormatter.js +++ b/src/webpack/util/createStatsFormatter.ts @@ -1,11 +1,12 @@ -// @flow -import { EOL } from 'os'; -import chalk from 'chalk'; -import RequestShortener from 'webpack/lib/RequestShortener'; -import { formatErrorMessage, stripLoaderFromPath } from './formatUtil'; -import type { WebpackError, Stats } from '../types'; -const createGetFile = (requestShortener: RequestShortener) => (e: WebpackError): ?string => { +import { EOL } from "os"; +import chalk from "chalk"; +import { Stats } from "webpack"; +import RequestShortener from "webpack/lib/RequestShortener"; +import { formatErrorMessage, stripLoaderFromPath } from "./formatUtil"; +import { WebpackError } from "../types"; + +const createGetFile = (requestShortener: RequestShortener) => (e: WebpackError): string | null => { /* istanbul ignore if */ if (e.file) { // webpack does this also, so there must be case when this happens @@ -14,20 +15,20 @@ const createGetFile = (requestShortener: RequestShortener) => (e: WebpackError): // if we got a module, build a file path to the module without loader information return stripLoaderFromPath(e.module.readableIdentifier(requestShortener)); } + /* istanbul ignore next */ return null; }; // helper to transform strings in errors -const ensureWebpackErrors = (errors: Array): Array => errors - .map((e: string | WebpackError) => { - /* istanbul ignore if */ - if (typeof e === 'string') { - // webpack does this also, so there must be case when this happens - return (({ message: e }: any): WebpackError); - } - return e; - }); +const ensureWebpackErrors = (errors: Array): Array => errors.map((e: string | WebpackError) => { + /* istanbul ignore if */ + if (typeof e === 'string') { + // webpack does this also, so there must be case when this happens + return (({ message: e } as any) as WebpackError); + } + return e; +}); const prependWarning = (message: string) => `${chalk.yellow('Warning')} ${message}`; const prependError = (message: string) => `${chalk.red('Error')} ${message}`; @@ -60,12 +61,12 @@ export default function createStatsFormatter(rootPath: string) { return lines.join(EOL); }; - return function statsFormatter(stats: Stats): { errors: Array, warnings: Array } { + return function statsFormatter(stats: Stats): {errors: Array;warnings: Array;} { const { compilation } = stats; return { errors: ensureWebpackErrors(compilation.errors).map(formatError).map(prependError), - warnings: ensureWebpackErrors(compilation.warnings).map(formatError).map(prependWarning), + warnings: ensureWebpackErrors(compilation.warnings).map(formatError).map(prependWarning) }; }; } diff --git a/src/webpack/util/formatUtil.js b/src/webpack/util/formatUtil.ts similarity index 69% rename from src/webpack/util/formatUtil.js rename to src/webpack/util/formatUtil.ts index cdc7fda..d084f5f 100644 --- a/src/webpack/util/formatUtil.js +++ b/src/webpack/util/formatUtil.ts @@ -1,11 +1,11 @@ -// @flow -import { EOL } from 'os'; -import _ from 'lodash'; + +import { EOL } from "os"; +import _ from "lodash"; const syntaxErrorLabel = 'Syntax error:'; // we replace all EOL combinations with \n and replace to work in a consistent way -const replaceEol = (message) => message.replace(/\r?\n/g, '\n'); +const replaceEol = message => message.replace(/\r?\n/g, '\n'); // undo eol replacements const useValidEol = (message: string) => message.replace('\n', EOL); @@ -15,11 +15,7 @@ const stripStackTrace = (message: string) => message.replace(/^\s*at\s.*\(.+\)\n const cleanUpModuleNotFoundMessage = (message: string) => { if (message.indexOf('Module not found:') === 0) { - return message - .replace('Cannot resolve \'file\' or \'directory\' ', '') - .replace('Cannot resolve module ', '') - .replace('Error: Can\'t resolve ', '') - .replace('Error: ', ''); + return message.replace('Cannot resolve \'file\' or \'directory\' ', '').replace('Cannot resolve module ', '').replace('Error: Can\'t resolve ', '').replace('Error: ', ''); } return message; }; @@ -44,29 +40,20 @@ const cleanUpBuildError = (message: string) => { message = lines.join('\n'); // eslint-disable-line no-param-reassign } - return message - .replace('Module build failed: SyntaxError:', syntaxErrorLabel) // babel-loader error - .replace('Module build failed:', ''); // otherwise remove it as it's already clear that this is an module error + return message.replace('Module build failed: SyntaxError:', syntaxErrorLabel) // babel-loader error + .replace('Module build failed:', ''); // otherwise remove it as it's already clear that this is an module error } return message; }; // removes new line characters at the end of message -const cleanUpUnwantedEol = (message) => message.replace(/\s*\n\s*$/, ''); +const cleanUpUnwantedEol = message => message.replace(/\s*\n\s*$/, ''); // indent all lines by 2 spaces -const indent = (message: string) => message.split('\n').map((l) => ` ${l}`).join('\n'); +const indent = (message: string) => message.split('\n').map(l => ` ${l}`).join('\n'); // gets executed from top to bottom -export const formatErrorMessage: (message: string) => string = _.flow([ - replaceEol, - stripStackTrace, - cleanUpModuleNotFoundMessage, - cleanUpBuildError, - cleanUpUnwantedEol, - indent, - useValidEol, -]); +export const formatErrorMessage: (message: string) => string = _.flow([replaceEol, stripStackTrace, cleanUpModuleNotFoundMessage, cleanUpBuildError, cleanUpUnwantedEol, indent, useValidEol]); export const stripLoaderFromPath = (file: string) => { // Remove webpack-specific loader notation from filename. @@ -78,5 +65,4 @@ export const stripLoaderFromPath = (file: string) => { return file.substr(file.lastIndexOf('!') + 1); } return file; -}; - +}; \ No newline at end of file diff --git a/src/webpack/util/getAffectedModuleIds.js b/src/webpack/util/getAffectedModuleIds.ts similarity index 79% rename from src/webpack/util/getAffectedModuleIds.js rename to src/webpack/util/getAffectedModuleIds.ts index 932be9a..cabdd75 100644 --- a/src/webpack/util/getAffectedModuleIds.js +++ b/src/webpack/util/getAffectedModuleIds.ts @@ -1,10 +1,12 @@ -// @flow -import type { Module, Chunk } from '../types'; -type ModuleMap = { [key: string | number]: Module }; +import { Module, Chunk } from "../types"; + +type ModuleMap = { + [key: string ]: Module; +}; type ModuleUsageMap = { // child id - [key: string | number]: ModuleMap, + [key: string ]: ModuleMap; }; const isBuilt = (module: Module): boolean => module.built; const getId = (module: any): number | string => module.id; @@ -58,7 +60,7 @@ const buildModuleUsageMap = (chunks: Array, modules: Array): Modu // } // const moduleUsageMap: ModuleUsageMap = modules.reduce((memo, module: Module) => { - module.dependencies.forEach((dependency) => { + module.dependencies.forEach(dependency => { const dependentModule = dependency.module; if (!dependentModule) { @@ -92,24 +94,19 @@ const buildModuleUsageMap = (chunks: Array, modules: Array): Modu // detect modules with code split points (e.g. require.ensure) and enhance moduleUsageMap with that information modules.forEach((module: Module) => { - module.blocks - // chunkGroup can be invalid in in some cases - .filter((block) => block.chunkGroup != null) - .forEach((block) => { - // loop through all generated chunks by this module - // $FlowFixMe - flow thinks that block.chunkGroup could be null - block.chunkGroup.chunks.map(getId).forEach((chunkId) => { - // and mark all modules of this chunk as a direct dependency of the original module - Object - .values((chunkModuleMap[chunkId]: ModuleMap)) - .forEach((childModule: any) => { - if (typeof moduleUsageMap[childModule.id] === 'undefined') { - moduleUsageMap[childModule.id] = {}; - } - moduleUsageMap[childModule.id][module.id] = module; - }); + module.blocks // chunkGroup can be invalid in in some cases + .filter(block => block.chunkGroup != null).forEach(block => { + // loop through all generated chunks by this module + block.chunkGroup.chunks.map(getId).forEach(chunkId => { + // and mark all modules of this chunk as a direct dependency of the original module + Object.values((chunkModuleMap[chunkId] as ModuleMap)).forEach((childModule: any) => { + if (typeof moduleUsageMap[childModule.id] === 'undefined') { + moduleUsageMap[childModule.id] = {}; + } + moduleUsageMap[childModule.id][module.id] = module; }); }); + }); }); return moduleUsageMap; diff --git a/src/webpack/util/getBuildStats.js b/src/webpack/util/getBuildStats.ts similarity index 60% rename from src/webpack/util/getBuildStats.js rename to src/webpack/util/getBuildStats.ts index 21c961f..3209e20 100644 --- a/src/webpack/util/getBuildStats.js +++ b/src/webpack/util/getBuildStats.ts @@ -1,26 +1,31 @@ -// @flow -import path from 'path'; -import sortChunks from './sortChunks'; -import getAffectedModuleIds from './getAffectedModuleIds'; -import type { Chunk, Module, Stats } from '../types'; +import path from "path"; +import sortChunks from "./sortChunks"; +import getAffectedModuleIds from "./getAffectedModuleIds"; + +import { Chunk, Module } from "../types"; +import { Stats } from "webpack"; export type BuildStats = { - affectedModules: Array, - affectedFiles: Array, - entries: Array, + affectedModules: Array; + affectedFiles: Array; + entries: Array; }; export default function getBuildStats(stats: Stats, outputPath: string): BuildStats { - const { chunks, chunkGroups, modules } = stats.compilation; + const { + chunks, + chunkGroups, + modules + } = stats.compilation; const sortedChunks = sortChunks(chunks, chunkGroups); const affectedModules = getAffectedModuleIds(chunks, modules); const entries = []; const js = []; - const pathHelper = (f) => path.join(outputPath, f); + const pathHelper = f => path.join(outputPath, f); sortedChunks.forEach((chunk: Chunk) => { @@ -32,9 +37,8 @@ export default function getBuildStats(stats: Stats, outputPath: string): BuildSt entries.push(entry); } - if (chunk.getModules().some((module: Module) => affectedModules.indexOf(module.id) !== -1) - ) { - files.forEach((file) => { + if (chunk.getModules().some((module: Module) => affectedModules.indexOf(module.id) !== -1)) { + files.forEach(file => { if (/\.js$/.test(file)) { js.push(file); } @@ -45,7 +49,7 @@ export default function getBuildStats(stats: Stats, outputPath: string): BuildSt const buildStats: BuildStats = { affectedModules, affectedFiles: js.map(pathHelper), - entries: entries.map(pathHelper), + entries: entries.map(pathHelper) }; return buildStats; diff --git a/src/webpack/util/sortChunks.js b/src/webpack/util/sortChunks.js deleted file mode 100644 index 1a89e1f..0000000 --- a/src/webpack/util/sortChunks.js +++ /dev/null @@ -1,29 +0,0 @@ -import toposort from 'toposort'; -// see https://github.com/jantimon/html-webpack-plugin/blob/8131d8bb1dc9b185b3c1709264a3baf32ef799bc/lib/chunksorter.js - -export default function sortChunks(chunks, chunkGroups) { - // We build a map (chunk-id -> chunk) for faster access during graph building. - const nodeMap = {}; - - chunks.forEach((chunk) => { - nodeMap[chunk.id] = chunk; - }); - - // Add an edge for each parent (parent -> child) - const edges = chunkGroups.reduce((result, chunkGroup) => - result.concat(Array.from(chunkGroup.parentsIterable, (parentGroup) => [parentGroup, chunkGroup])), []); - const sortedGroups = toposort.array(chunkGroups, edges); - // flatten chunkGroup into chunks - const sortedChunks = sortedGroups - .reduce((result, chunkGroup) => result.concat(chunkGroup.chunks), []) - .map((chunk) => // use the chunk from the list passed in, since it may be a filtered list - nodeMap[chunk.id]) - .filter((chunk, index, self) => { - // make sure exists (ie excluded chunks not in nodeMap) - const exists = !!chunk; - // make sure we have a unique list - const unique = self.indexOf(chunk) === index; - return exists && unique; - }); - return sortedChunks; -} diff --git a/src/webpack/util/sortChunks.ts b/src/webpack/util/sortChunks.ts new file mode 100644 index 0000000..afc9ce9 --- /dev/null +++ b/src/webpack/util/sortChunks.ts @@ -0,0 +1,25 @@ +import toposort from "toposort"; +// see https://github.com/jantimon/html-webpack-plugin/blob/8131d8bb1dc9b185b3c1709264a3baf32ef799bc/lib/chunksorter.js + +export default function sortChunks(chunks, chunkGroups) { + // We build a map (chunk-id -> chunk) for faster access during graph building. + const nodeMap = {}; + + chunks.forEach(chunk => { + nodeMap[chunk.id] = chunk; + }); + + // Add an edge for each parent (parent -> child) + const edges = chunkGroups.reduce((result, chunkGroup) => result.concat(Array.from(chunkGroup.parentsIterable, parentGroup => [parentGroup, chunkGroup])), []); + const sortedGroups = toposort.array(chunkGroups, edges); + // flatten chunkGroup into chunks + const sortedChunks = sortedGroups.reduce((result, chunkGroup) => result.concat(chunkGroup.chunks), []).map(chunk => // use the chunk from the list passed in, since it may be a filtered list + nodeMap[chunk.id]).filter((chunk, index, self) => { + // make sure exists (ie excluded chunks not in nodeMap) + const exists = !!chunk; + // make sure we have a unique list + const unique = self.indexOf(chunk) === index; + return exists && unique; + }); + return sortedChunks; +} \ No newline at end of file diff --git a/test/fixture/customMochaReporter.js b/test/fixture/customMochaReporter.js index 6fd4ffa..159a6f2 100644 --- a/test/fixture/customMochaReporter.js +++ b/test/fixture/customMochaReporter.js @@ -1,4 +1,4 @@ -module.exports = function reporter(runner) { +module.exports = function customMochaReporter(runner) { runner.on('start', () => { console.log('customMochaReporter started'); // eslint-disable-line }); diff --git a/test/integration/cli/code-splitting.test.js b/test/integration/cli/code-splitting.test.ts similarity index 95% rename from test/integration/cli/code-splitting.test.js rename to test/integration/cli/code-splitting.test.ts index 1a1f109..8a0e89b 100644 --- a/test/integration/cli/code-splitting.test.js +++ b/test/integration/cli/code-splitting.test.ts @@ -1,10 +1,11 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import path from 'path'; -import normalizePath from 'normalize-path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import path from "path"; +import normalizePath from "normalize-path"; +import { exec } from "./util/childProcess"; const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); diff --git a/test/integration/cli/config.test.js b/test/integration/cli/config.test.ts similarity index 90% rename from test/integration/cli/config.test.js rename to test/integration/cli/config.test.ts index f1e6f2f..ac4ea69 100644 --- a/test/integration/cli/config.test.js +++ b/test/integration/cli/config.test.ts @@ -1,9 +1,10 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import path from 'path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import path from "path"; +import { exec } from "./util/childProcess"; const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); @@ -11,7 +12,7 @@ const testSimple = path.join(fixtureDir, 'simple/simple.js'); describe('cli --webpack-config', function () { it('does not throw for missing default config', function (done) { - exec(`node ${binPath} "${testSimple}"`, (err) => { + exec(`node ${binPath} "${testSimple}"`, err => { assert.isNull(err); done(); }); @@ -45,4 +46,4 @@ describe('cli --webpack-config', function () { done(); }); }); -}); +}); \ No newline at end of file diff --git a/test/integration/cli/custom-output-path.test.js b/test/integration/cli/custom-output-path.test.ts similarity index 86% rename from test/integration/cli/custom-output-path.test.js rename to test/integration/cli/custom-output-path.test.ts index 7cfff6e..e618ad8 100644 --- a/test/integration/cli/custom-output-path.test.js +++ b/test/integration/cli/custom-output-path.test.ts @@ -1,11 +1,12 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback, max-len */ -import { assert } from 'chai'; -import path from 'path'; -import fs from 'fs'; -import del from 'del'; -import normalizePath from 'normalize-path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import path from "path"; +import fs from "fs"; +import del from "del"; +import normalizePath from "normalize-path"; +import { exec } from "./util/childProcess"; const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); diff --git a/test/integration/cli/entry.test.js b/test/integration/cli/entry.test.ts similarity index 82% rename from test/integration/cli/entry.test.js rename to test/integration/cli/entry.test.ts index 6a01db8..3d84d8a 100644 --- a/test/integration/cli/entry.test.js +++ b/test/integration/cli/entry.test.ts @@ -1,16 +1,17 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback, max-len */ -import { assert } from 'chai'; -import _ from 'lodash'; -import fs from 'fs-extra'; -import del from 'del'; -import path from 'path'; -import anymatch from 'anymatch'; -import normalizePath from 'normalize-path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import _ from "lodash"; +import fs from "fs-extra"; +import del from "del"; +import path from "path"; +import anymatch from "anymatch"; +import normalizePath from "normalize-path"; +import { exec } from "./util/childProcess"; -const escapePath = (p) => p.replace(/\\/gm, '\\\\'); +const escapePath = p => p.replace(/\\/gm, '\\\\'); function createTest(filePath, passing) { const content = ` @@ -66,7 +67,7 @@ describe('cli - entry', function () { }); it('handles failed module with syntax errors', function (done) { - exec(`node ${binPath} --mode development "${this.corruptedTest}"`, (err) => { + exec(`node ${binPath} --mode development "${this.corruptedTest}"`, err => { assert.isNotNull(err); assert.isAbove(err.code, 0); done(); @@ -74,7 +75,7 @@ describe('cli - entry', function () { }); it('handles module with runtime errors', function (done) { - exec(`node ${binPath} --mode development "${this.runtimeErrorTest}"`, (err) => { + exec(`node ${binPath} --mode development "${this.runtimeErrorTest}"`, err => { assert.isNotNull(err); assert.isAbove(err.code, 0); done(); @@ -124,7 +125,7 @@ describe('cli - entry', function () { }); it('handles failed module with syntax errors', function (done) { - exec(`node ${binPath} --mode development "${this.corruptedTest}" "${this.corruptedTest2}"`, (err) => { + exec(`node ${binPath} --mode development "${this.corruptedTest}" "${this.corruptedTest2}"`, err => { assert.isNotNull(err); assert.isAbove(err.code, 0); done(); @@ -179,7 +180,7 @@ describe('cli - entry', function () { }); context('glob pattern as option', function () { - const testFiles = _.range(1, 30).map((x) => { + const testFiles = _.range(1, 30).map(x => { if (parseInt(x / 10, 10) === 0) { if (x <= 4) { return path.join(fixtureDirTmp, `passing-test-${x}.js`); @@ -194,7 +195,7 @@ describe('cli - entry', function () { }).map(normalizePath); before(function () { - testFiles.forEach((file) => { + testFiles.forEach(file => { if (file.indexOf('passing-test') !== -1) { createTest(file, true); } else if (file.indexOf('failing-test') !== -1) { @@ -205,13 +206,11 @@ describe('cli - entry', function () { }); }); - const corruptedPatterns = [ - path.join(fixtureDirTmp, 'corrupted-*.js'), - ].map(normalizePath); + const corruptedPatterns = [path.join(fixtureDirTmp, 'corrupted-*.js')].map(normalizePath); - corruptedPatterns.forEach((pattern) => { + corruptedPatterns.forEach(pattern => { it(`handles corrupted modules with pattern '${pattern}'`, function (done) { - exec(`node ${binPath} --mode development "${pattern}"`, (err) => { + exec(`node ${binPath} --mode development "${pattern}"`, err => { assert.isNotNull(err); assert.isAbove(err.code, 0); done(); @@ -219,20 +218,16 @@ describe('cli - entry', function () { }); }); - const passingPatterns = [ - path.join(fixtureDirTmp, 'passing-*.js'), - path.join(fixtureDirTmp, 'passing-*-1.js'), - path.join(fixtureDirTmp, '**/passing-*.js'), - ].map(normalizePath); + const passingPatterns = [path.join(fixtureDirTmp, 'passing-*.js'), path.join(fixtureDirTmp, 'passing-*-1.js'), path.join(fixtureDirTmp, '**/passing-*.js')].map(normalizePath); - passingPatterns.forEach((pattern) => { + passingPatterns.forEach(pattern => { const matcher = anymatch(pattern); const files = testFiles.filter(matcher); it(`runs ${files.length} passing tests of ${testFiles.length} with pattern '${pattern}'`, function (done) { exec(`node ${binPath} --mode development "${pattern}"`, (err, output) => { assert.isNull(err); - files.forEach((file) => { + files.forEach(file => { assert.include(output, file); }); assert.include(output, `${files.length} passing`); @@ -241,13 +236,9 @@ describe('cli - entry', function () { }); }); - const failingPatterns = [ - path.join(fixtureDirTmp, 'failing-*.js'), - path.join(fixtureDirTmp, 'failing-*-7.js'), - path.join(fixtureDirTmp, 'failing-*-@(5|6).js'), - ].map(normalizePath); + const failingPatterns = [path.join(fixtureDirTmp, 'failing-*.js'), path.join(fixtureDirTmp, 'failing-*-7.js'), path.join(fixtureDirTmp, 'failing-*-@(5|6).js')].map(normalizePath); - failingPatterns.forEach((pattern) => { + failingPatterns.forEach(pattern => { const matcher = anymatch(pattern); const files = testFiles.filter(matcher); @@ -255,7 +246,7 @@ describe('cli - entry', function () { exec(`node ${binPath} --mode development "${pattern}"`, (err, output) => { assert.isNotNull(err); assert.strictEqual(err.code, files.length); - files.forEach((file) => { + files.forEach(file => { assert.include(output, file); }); @@ -266,20 +257,16 @@ describe('cli - entry', function () { }); }); - const multiPassingPatterns = [ - path.join(fixtureDirTmp, 'passing-*-1.js'), - path.join(fixtureDirTmp, 'passing-*-2.js'), - path.join(fixtureDirTmp, 'passing-*-3.js'), - ].map(normalizePath); + const multiPassingPatterns = [path.join(fixtureDirTmp, 'passing-*-1.js'), path.join(fixtureDirTmp, 'passing-*-2.js'), path.join(fixtureDirTmp, 'passing-*-3.js')].map(normalizePath); - const pattern = multiPassingPatterns.map((str) => `"${str}"`).join(' '); + const pattern = multiPassingPatterns.map(str => `"${str}"`).join(' '); const matcher = anymatch(multiPassingPatterns); const files = testFiles.filter(matcher); it(`runs ${files.length} passing tests of ${testFiles.length} with pattern '${pattern}'`, function (done) { exec(`node ${binPath} --mode development ${pattern}`, (err, output) => { assert.isNull(err); - files.forEach((file) => { + files.forEach(file => { assert.include(output, file); }); assert.include(output, `${files.length} passing`); @@ -297,11 +284,11 @@ describe('cli - entry', function () { context('directory with passing tests', function () { before(function () { - this.testFiles = _.range(1, 10).map((x) => { + this.testFiles = _.range(1, 10).map(x => { const subdir = subdirectories[x % 3]; return path.join(fixtureDirTmp, subdir, `passing-test-${x}.js`); }).map(normalizePath); - this.testFiles.forEach((file) => createTest(file, true)); + this.testFiles.forEach(file => createTest(file, true)); }); it('runs all tests in directory\'', function (done) { @@ -310,7 +297,7 @@ describe('cli - entry', function () { exec(`node ${binPath} --mode development "${fixtureDirTmp}"`, (err, output) => { assert.isNull(err); - files.forEach((file) => { + files.forEach(file => { assert.include(output, file); }); assert.include(output, `${files.length} passing`); @@ -323,7 +310,7 @@ describe('cli - entry', function () { const files = this.testFiles.filter(matcher); exec(`node ${binPath} --mode development --glob "*-test-3.js" "${fixtureDirTmp}"`, (err, output) => { assert.isNull(err); - files.forEach((file) => { + files.forEach(file => { assert.include(output, file); }); assert.include(output, `${files.length} passing`); @@ -338,7 +325,7 @@ describe('cli - entry', function () { exec(`node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, (err, output) => { assert.isNull(err); - files.forEach((file) => { + files.forEach(file => { assert.include(output, file); }); assert.include(output, `${files.length} passing`); @@ -353,11 +340,11 @@ describe('cli - entry', function () { context('directory with failing tests', function () { before(function () { - this.testFiles = _.range(1, 10).map((x) => { + this.testFiles = _.range(1, 10).map(x => { const subdir = subdirectories[x % 3]; return path.join(fixtureDirTmp, subdir, `failing-test-${x}.js`); }).map(normalizePath); - this.testFiles.forEach((file) => createTest(file, false)); + this.testFiles.forEach(file => createTest(file, false)); }); it('runs all tests in directory\'', function (done) { @@ -367,7 +354,7 @@ describe('cli - entry', function () { exec(`node ${binPath} --mode development "${fixtureDirTmp}"`, (err, output) => { assert.isNotNull(err); assert.strictEqual(err.code, files.length); - files.forEach((file) => { + files.forEach(file => { assert.include(output, file); }); @@ -384,7 +371,7 @@ describe('cli - entry', function () { exec(`node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, (err, output) => { assert.isNotNull(err); assert.strictEqual(err.code, files.length); - files.forEach((file) => { + files.forEach(file => { assert.include(output, file); }); @@ -401,15 +388,15 @@ describe('cli - entry', function () { context('directory with corrupted modules', function () { before(function () { - this.testFiles = _.range(1, 10).map((x) => { + this.testFiles = _.range(1, 10).map(x => { const subdir = subdirectories[x % 3]; return path.join(fixtureDirTmp, subdir, `corrupted-test-${x}.js`); - }).map((file) => normalizePath(file)); - this.testFiles.forEach((file) => createCorruptedTest(file)); + }).map(file => normalizePath(file)); + this.testFiles.forEach(file => createCorruptedTest(file)); }); it('fails before running tests of directory', function (done) { - exec(`node ${binPath} --mode development "${fixtureDirTmp}"`, (err) => { + exec(`node ${binPath} --mode development "${fixtureDirTmp}"`, err => { assert.isNotNull(err); assert.isAbove(err.code, 0); done(); @@ -417,7 +404,7 @@ describe('cli - entry', function () { }); it('fails before running tests of directory directory & subdirectories\'', function (done) { - exec(`node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, (err) => { + exec(`node ${binPath} --mode development --recursive "${fixtureDirTmp}"`, err => { assert.isNotNull(err); assert.isAbove(err.code, 0); done(); @@ -436,33 +423,29 @@ describe('cli - entry', function () { this.index = 0; this.configPath = path.join(fixtureDir, 'config', 'config.resolve-extensions.js'); this.testDir = path.join(fixtureDirTmp, 'resolve-test'); - this.testFiles = ['ts', 'tsx', 'js', 'jsx'] - .map((ext) => { - const file = path.join(this.testDir, `passing-test-${this.index}.${ext}`); - this.index += 1; - return file; - }) - .map((file) => normalizePath(file)); - - this.ignoredFiles = ['coffee'] - .map((ext) => { - const file = path.join(this.testDir, `passing-test-${this.index}.${ext}`); - this.index += 1; - return file; - }) - .map((file) => normalizePath(file)); - - this.testFiles.forEach((file) => createTest(file, true)); - this.ignoredFiles.forEach((file) => createTest(file, true)); + this.testFiles = ['ts', 'tsx', 'js', 'jsx'].map(ext => { + const file = path.join(this.testDir, `passing-test-${this.index}.${ext}`); + this.index += 1; + return file; + }).map(file => normalizePath(file)); + + this.ignoredFiles = ['coffee'].map(ext => { + const file = path.join(this.testDir, `passing-test-${this.index}.${ext}`); + this.index += 1; + return file; + }).map(file => normalizePath(file)); + + this.testFiles.forEach(file => createTest(file, true)); + this.ignoredFiles.forEach(file => createTest(file, true)); }); it('resolve.extensions will be used for module resolution when no --glob is given', function (done) { exec(`node ${binPath} --mode development --webpack-config "${this.configPath}" "${this.testDir}"`, (err, output) => { assert.isNull(err); - this.testFiles.forEach((file) => { + this.testFiles.forEach(file => { assert.include(output, file); }); - this.ignoredFiles.forEach((file) => { + this.ignoredFiles.forEach(file => { assert.notInclude(output, file); }); assert.include(output, `${this.testFiles.length} passing`); @@ -475,7 +458,7 @@ describe('cli - entry', function () { const files = this.testFiles.filter(matcher); exec(`node ${binPath} --mode development --webpack-config "${this.configPath}" --glob "*.js" "${this.testDir}"`, (err, output) => { assert.isNull(err); - files.forEach((file) => { + files.forEach(file => { assert.include(output, file); }); assert.include(output, `${files.length} passing`); @@ -487,4 +470,4 @@ describe('cli - entry', function () { return del([].concat(this.testFiles, this.ignoredFiles)); }); }); -}); +}); \ No newline at end of file diff --git a/test/integration/cli/forbidOnly.test.js b/test/integration/cli/forbidOnly.test.ts similarity index 81% rename from test/integration/cli/forbidOnly.test.js rename to test/integration/cli/forbidOnly.test.ts index 0b53e32..4b12778 100644 --- a/test/integration/cli/forbidOnly.test.js +++ b/test/integration/cli/forbidOnly.test.ts @@ -1,9 +1,10 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import path from 'path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import path from "path"; +import { exec } from "./util/childProcess"; const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); @@ -11,9 +12,9 @@ const test = path.join(fixtureDir, 'only/simple-only.js'); describe('cli --forbid-only', function () { it('gets really angry if there is an only in the test', function (done) { - exec(`node ${binPath} --mode development --forbid-only "${test}"`, (err) => { + exec(`node ${binPath} --mode development --forbid-only "${test}"`, err => { assert.isNotNull(err); done(); }); }); -}); +}); \ No newline at end of file diff --git a/test/integration/cli/include.test.js b/test/integration/cli/include.test.ts similarity index 91% rename from test/integration/cli/include.test.js rename to test/integration/cli/include.test.ts index 3931672..2a94cef 100644 --- a/test/integration/cli/include.test.js +++ b/test/integration/cli/include.test.ts @@ -1,9 +1,10 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import path from 'path'; -import { assert } from 'chai'; -import { exec } from './util/childProcess'; +import path from "path"; +import { assert } from "chai"; +import { exec } from "./util/childProcess"; const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); @@ -21,7 +22,7 @@ function test(entry, options, cb) { } function testInclude(entry, includes, cb) { - const options = includes.map((value) => `--include ${value}`); + const options = includes.map(value => `--include ${value}`); test(entry, options, cb); } @@ -91,10 +92,10 @@ describe('cli --include', function () { }); it('include node_module', function (done) { - testInclude(path.join(testDir, 'test.js'), ['chai'], (err) => { + testInclude(path.join(testDir, 'test.js'), ['chai'], err => { assert.isNull(err); done(); }); }); }); -}); +}); \ No newline at end of file diff --git a/test/integration/cli/interactive.test.js b/test/integration/cli/interactive.test.ts similarity index 84% rename from test/integration/cli/interactive.test.js rename to test/integration/cli/interactive.test.ts index e11e2cb..e999437 100644 --- a/test/integration/cli/interactive.test.js +++ b/test/integration/cli/interactive.test.ts @@ -1,9 +1,10 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import path from 'path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import path from "path"; +import { exec } from "./util/childProcess"; const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); @@ -17,4 +18,4 @@ describe('cli --interactive', function () { done(); }); }); -}); +}); \ No newline at end of file diff --git a/test/integration/cli/quiet.test.js b/test/integration/cli/quiet.test.ts similarity index 91% rename from test/integration/cli/quiet.test.js rename to test/integration/cli/quiet.test.ts index 37f3e81..4020b3a 100644 --- a/test/integration/cli/quiet.test.js +++ b/test/integration/cli/quiet.test.ts @@ -1,9 +1,10 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import path from 'path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import path from "path"; +import { exec } from "./util/childProcess"; const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); @@ -35,4 +36,4 @@ describe('cli --quiet', function () { done(); }); }); -}); +}); \ No newline at end of file diff --git a/test/integration/cli/reporter.test.js b/test/integration/cli/reporter.test.ts similarity index 91% rename from test/integration/cli/reporter.test.js rename to test/integration/cli/reporter.test.ts index 40c1f21..609beee 100644 --- a/test/integration/cli/reporter.test.js +++ b/test/integration/cli/reporter.test.ts @@ -1,9 +1,10 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import path from 'path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import path from "path"; +import { exec } from "./util/childProcess"; const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); @@ -29,7 +30,7 @@ describe('cli --reporter', function () { }); it('shows notifications with --growl', function (done) { - exec(`node ${binPath} --mode development --growl "${test}"`, (err) => { + exec(`node ${binPath} --mode development --growl "${test}"`, err => { assert.isNull(err); done(); }); diff --git a/test/integration/cli/ui.test.js b/test/integration/cli/ui.test.ts similarity index 91% rename from test/integration/cli/ui.test.js rename to test/integration/cli/ui.test.ts index 9dc9263..8a26ed9 100644 --- a/test/integration/cli/ui.test.js +++ b/test/integration/cli/ui.test.ts @@ -1,9 +1,10 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import path from 'path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import path from "path"; +import { exec } from "./util/childProcess"; const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); @@ -35,4 +36,4 @@ describe('cli --ui', function () { done(); }); }); -}); +}); \ No newline at end of file diff --git a/test/integration/cli/util/childProcess.js b/test/integration/cli/util/childProcess.js deleted file mode 100644 index e93f25c..0000000 --- a/test/integration/cli/util/childProcess.js +++ /dev/null @@ -1,15 +0,0 @@ -import { exec as execProcess } from 'child_process'; - -export function exec(command, cb) { // eslint-disable-line import/prefer-default-export - let data = ''; - const ps = execProcess(command, (err) => { - cb(err, data !== '' ? data : null); - }); - - ps.stdout.on('data', (d) => { - data += d; - }); - ps.stderr.on('data', (d) => { - data += d; - }); -} diff --git a/test/integration/cli/util/childProcess.ts b/test/integration/cli/util/childProcess.ts new file mode 100644 index 0000000..20ba3c7 --- /dev/null +++ b/test/integration/cli/util/childProcess.ts @@ -0,0 +1,15 @@ +import { exec as execProcess } from "child_process"; + +export function exec(command, cb) {// eslint-disable-line import/prefer-default-export + let data = ''; + const ps = execProcess(command, err => { + cb(err, data !== '' ? data : null); + }); + + ps.stdout.on('data', d => { + data += d; + }); + ps.stderr.on('data', d => { + data += d; + }); +} \ No newline at end of file diff --git a/test/integration/cli/version.test.js b/test/integration/cli/version.test.ts similarity index 75% rename from test/integration/cli/version.test.js rename to test/integration/cli/version.test.ts index f3eadc8..c769cf7 100644 --- a/test/integration/cli/version.test.js +++ b/test/integration/cli/version.test.ts @@ -1,10 +1,11 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import path from 'path'; -import { exec } from './util/childProcess'; -import { version } from '../../../package.json'; +import { assert } from "chai"; +import path from "path"; +import { exec } from "./util/childProcess"; +import { version } from "../../../package.json"; const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); @@ -20,4 +21,4 @@ describe('cli - version', function () { done(); }); }); -}); +}); \ No newline at end of file diff --git a/test/integration/cli/watch.test.ts b/test/integration/cli/watch.test.ts new file mode 100644 index 0000000..dc45cc0 --- /dev/null +++ b/test/integration/cli/watch.test.ts @@ -0,0 +1,518 @@ +/* eslint-env node, mocha */ + +/* eslint-disable func-names, max-len */ + +import { assert } from "chai"; +import path from "path"; +import { spawn } from "child_process"; +import del from "del"; +import fs from "fs-extra"; + +const fixtureDir = path.join(process.cwd(), '.tmp/fixture'); + +const deleteTest = fileName => del(path.join(fixtureDir, fileName)); + +const createTest = (fileName, testName, passing) => { + const content = ` + var assert = require('assert'); + describe('${fileName} - ${testName}', function () { + it('runs test', function () { + assert.ok(${passing}); + }); + }); + `; + fs.outputFileSync(path.join(fixtureDir, fileName), content); +}; + +function createSyntaxErrorTest(fileName, testName) { + const content = ` + var assert = require('assert'); + describe('${fileName} - ${testName}', function () { + it('runs test', function () { + assert.ok(false); + }); + `; + fs.outputFileSync(path.join(fixtureDir, fileName), content); +} + +function createUncaughtErrorTest(fileName, testName) { + const content = ` + describe('${fileName} - ${testName}', function () { + it('runs test', function () { + setTimeout(function () { + done(); // done is undefined -> uncaught error + }, 1000); + }); + }); + `; + fs.outputFileSync(path.join(fixtureDir, fileName), content); +} + +function createErrorFile(fileName, testName) { + const content = ` + throw new Error('Error ${fileName} ${testName}'); + `; + fs.outputFileSync(path.join(fixtureDir, fileName), content); +} + +const createLongRunningTest = (fileName, testName) => { + const content = ` + var assert = require('assert'); + describe('${fileName} - ${testName} - 1', function () { + it('runs test 1' , function (done) { + this.timeout(3000); + console.log('starting ${testName} - 1'); + setTimeout(function() { + console.log('finished ${testName} - 1'); + done(); + }, 2000); + }); + }); + + describe('${fileName} - ${testName}', function () { + it('runs test 2' , function (done) { + this.timeout(3000); + console.log('starting ${testName} - 2'); + setTimeout(function() { + console.log('finished ${testName} - 2'); + done(); + }, 2000); + }); + }); + `; + fs.outputFileSync(path.join(fixtureDir, fileName), content); +}; + +const createNeverEndingTest = (fileName, testName) => { + const content = ` + var assert = require('assert'); + describe('${fileName} - ${testName} - 1', function () { + it('runs test 1' , function (done) { + console.log('starting ${testName}'); + }); + }); + `; + fs.outputFileSync(path.join(fixtureDir, fileName), content); +}; + + +const waitFor = (condition, timeoutInMs) => new Promise((resolve, reject) => { + const startTime = Date.now(); + const endTime = startTime + timeoutInMs; + + const remainingTime = () => Math.max(endTime - Date.now(), 0); + const timeoutDelay = () => Math.min(remainingTime(), 500); + + const run = () => { + let result = false; + let error = null; + try { + result = condition(); + } catch (e) { + error = e; + result = false; + } + + if (result !== false && error === null) { + resolve(); + } else if (remainingTime() > 0) { + setTimeout(run, timeoutDelay()); + } else if (error != null) { + reject(error); + } else { + reject(new Error(`Condition not met within time: ${condition.toString()}`)); + } + }; + setTimeout(run, timeoutDelay()); +}); + +const spawnMochaWebpack = (...args) => { + let data = ''; + const binPath = path.relative(process.cwd(), path.join('bin', 'mochapack')); + + const child = spawn('node', [binPath, '--mode', 'development', ...args]); + const receiveData = d => { + data += d.toString(); + }; + + child.stdout.on('data', receiveData); + child.stderr.on('data', receiveData); + + return { + get log() { + return data; + }, + clearLog() { + data = ''; + }, + kill() { + child.stdout.removeListener('data', receiveData); + child.stderr.removeListener('data', receiveData); + child.kill(); + } + }; +}; + +// eslint-disable-next-line +// FIXME These tests have proven unreliable in the past and are thus disabled +xdescribe('cli --watch', function () { + // Retry all tests in this suite up to 4 times + this.retries(4); + + beforeEach(function () { + this.testGlob = path.join(fixtureDir, '*.js'); + this.entryGlob = path.relative(process.cwd(), this.testGlob); + }); + + it('should log syntax error and wait until that is fixed before running tests', function () { + this.timeout(10000); + const testFile = 'test1.js'; + const testId = Date.now(); + createSyntaxErrorTest(testFile, testId); + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, 'Unexpected token'), 5000)) // output matched our condition + .then(() => { + assert.notInclude(mw.log, testId); + assert.notInclude(mw.log, 'failing'); + assert.notInclude(mw.log, 'passing'); + + // clear log to receive only changes + mw.clearLog(); + + // fix test + const updatedTestId = testId + 100; + createTest(testFile, updatedTestId, true); + return updatedTestId; + }) // wait until the output matches our condition + .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition + .then(() => { + // check if test was updated + assert.notInclude(mw.log, testId); + }).catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should catch other errors outside of tests', function () { + this.timeout(10000); + const testFile = 'test1.js'; + const testId = Date.now(); + createErrorFile(testFile, testId); + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, `Error ${testFile}`), 5000)) // output matched our condition + .then(() => { + assert.include(mw.log, 'Exception occurred while loading your tests'); + assert.include(mw.log, testId); + + // clear log to receive only changes + mw.clearLog(); + + // fix test + const updatedTestId = testId + 100; + createTest(testFile, updatedTestId, true); + return updatedTestId; + }) // wait until the output matches our condition + .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition + .then(() => { + // check if test was updated + assert.notInclude(mw.log, testId); + }).catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should catch uncaught errors that occur after tests are done', function () { + this.timeout(10000); + const testFile = 'test1.js'; + const testId = Date.now(); + createUncaughtErrorTest(testFile, testId); + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, 'UNCAUGHT EXCEPTION'), 5000)) // output matched our condition + .then(() => { + assert.include(mw.log, 'Exception occurred after running tests'); + assert.include(mw.log, '1 passing'); + assert.include(mw.log, testFile); + assert.include(mw.log, testId); + + // clear log to receive only changes + mw.clearLog(); + + // fix test + const updatedTestId = testId + 100; + createTest(testFile, updatedTestId, true); + return updatedTestId; + }) // wait until the output matches our condition + .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition + .then(() => { + // check if test was updated + assert.notInclude(mw.log, testId); + }).catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should run a test', function () { + this.timeout(5000); + const testFile = 'test1.js'; + const testId = Date.now(); + createTest(testFile, testId, true); + + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, testId) && assert.include(mw.log, '1 passing'), 5000)).catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should run a test again when it changes', function () { + this.timeout(15000); + const testFile = 'test1.js'; + const testId = Date.now(); + createTest(testFile, testId, true); + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, testId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition + .then(() => { + // clear log to receive only changes + mw.clearLog(); + + // update test + const updatedTestId = testId + 100; + createTest(testFile, updatedTestId, true); + return updatedTestId; + }) // wait until the output matches our condition + .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition + .then(() => { + // check if test was updated + assert.notInclude(mw.log, testId); + }).catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should run only the changed test again when it changes', function () { + this.timeout(15000); + const testFile1 = 'test1.js'; + const testFile2 = 'test2.js'; + const testId1 = Date.now() + 1; + const testId2 = testId1 + 2; + createTest(testFile1, testId1, true); + createTest(testFile2, testId2, true); + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, '2 passing'), 5000)) // output matched our condition + .then(() => { + // check if both tests were tested + assert.include(mw.log, testId1); + assert.include(mw.log, testFile1); + assert.include(mw.log, testId2); + assert.include(mw.log, testFile2); + + // clear log to receive only changes + mw.clearLog(); + + // update test + const updatedTestId = testId2 + 100; + createTest(testFile2, updatedTestId, true); + return updatedTestId; + }) // wait until the output matches our condition + .then(updatedTestId => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition + .then(() => { + // check if just updated test was tested again + assert.notInclude(mw.log, testFile1); + assert.notInclude(mw.log, testId1); + }).catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should abort test suite when a file changes while running tests and then test again', function () { + this.timeout(15000); + const testFile = 'test1.js'; + const testId = Date.now(); + const updatedTestId = testId + 100; + createLongRunningTest(testFile, testId); + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the first async test start + .then(() => waitFor(() => assert.include(mw.log, `starting ${testId} - 1`), 5000)).then(() => { + // check if tests were not ready yet + assert.notInclude(mw.log, `starting ${testId} - 2`); + assert.notInclude(mw.log, `finished ${testId} - 2`); + + // clear log to receive only changes + mw.clearLog(); + + // update test + createTest(testFile, updatedTestId, true); + }) // wait until tests were aborted + .then(() => waitFor(() => assert.include(mw.log, '0 passing'), 5000)).then(() => { + // check if tests were aborted + assert.notInclude(mw.log, `finished ${testId} - 2`); + }) // wait until tests were tested again + .then(() => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)).catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should also abort tests that will never finish (e.g. by mistake) when timeouts are disabled and run tests again', function () { + this.timeout(15000); + const testFile = 'test1.js'; + const testId = Date.now(); + const updatedTestId = testId + 100; + createNeverEndingTest(testFile, testId); + const mw = spawnMochaWebpack('--timeout', 0, '--watch', this.entryGlob); + + return Promise.resolve() // wait until the first async test start + .then(() => waitFor(() => assert.include(mw.log, `starting ${testId}`), 5000)).then(() => { + // clear log to receive only changes + mw.clearLog(); + + // update test + createTest(testFile, updatedTestId, true); + }) // wait until tests were aborted + .then(() => waitFor(() => assert.include(mw.log, 'Tests aborted'), 5000)).then(() => { + // check if tests were aborted + assert.notInclude(mw.log, `finished ${testId} - 2`); + }) // wait until tests were tested again + .then(() => waitFor(() => assert.include(mw.log, updatedTestId) && assert.include(mw.log, '1 passing'), 5000)).catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should recognize new test entries that match the pattern', function () { + this.timeout(10000); + const testFile1 = 'test1.js'; + const testId1 = Date.now() + 1; + const testFile2 = 'test2.js'; + const testId2 = testId1 + 2; + createTest(testFile1, testId1, true); + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, testId1) && assert.include(mw.log, '1 passing'), 5000)) // output matched our condition + .then(() => { + // clear log to receive only changes + mw.clearLog(); + // create new test + createTest(testFile2, testId2, true); + }) // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, testId2) && assert.include(mw.log, '1 passing'), 5000)).then(() => { + assert.notInclude(mw.log, testId1); + assert.notInclude(mw.log, testFile1); + }) // output matched our condition + .catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should recognize multiple new test entries that match the pattern', function () { + this.timeout(10000); + const testFile1 = 'test1.js'; + const testId1 = Date.now() + 1; + const testFile2 = 'test2.js'; + const testId2 = testId1 + 2; + const testFile3 = 'test3.js'; + const testId3 = testId2 + 3; + createTest(testFile1, testId1, true); + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, '1 passing'), 5000)) // output matched our condition + .then(() => { + assert.include(mw.log, testId1); + assert.include(mw.log, testFile1); + + // clear log to receive only changes + mw.clearLog(); + + // create new tests + createTest(testFile2, testId2, true); + createTest(testFile3, testId3, true); + }) // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, testId2) && assert.include(mw.log, testId3) && assert.include(mw.log, '2 passing'), 5000)).then(() => { + assert.notInclude(mw.log, testId1); + assert.notInclude(mw.log, testFile1); + }) // output matched our condition + .catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + it('should recognize deleted test entries that match the pattern', function () { + this.timeout(10000); + const testFile1 = 'test1.js'; + const testFile2 = 'test2.js'; + const testId1 = Date.now() + 1; + const testId2 = Date.now() + 2; + createTest(testFile1, testId1, true); + createTest(testFile2, testId2, true); + const mw = spawnMochaWebpack('--watch', this.entryGlob); + + return Promise.resolve() // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, '2 passing'), 5000)) // output matched our condition + .then(() => { + assert.include(mw.log, testId1); + assert.include(mw.log, testFile1); + assert.include(mw.log, testId2); + assert.include(mw.log, testFile2); + + // clear log to receive only changes + mw.clearLog(); + + // delete test + deleteTest(testFile2); + }) // wait until the output matches our condition + .then(() => waitFor(() => assert.include(mw.log, 'passing'), 5000)).then(() => { + assert.notInclude(mw.log, testId2); + }).catch(e => e).then(e => { + // finally, kill watch process + mw.kill(); + // maybe rethrow error + assert.ifError(e); + }); + }); + + afterEach(function () { + return del(this.testGlob); + }); +}); \ No newline at end of file diff --git a/test/integration/cli/webworker.test.js b/test/integration/cli/webworker.test.ts similarity index 75% rename from test/integration/cli/webworker.test.js rename to test/integration/cli/webworker.test.ts index 6f9ba4f..fb8f14d 100644 --- a/test/integration/cli/webworker.test.js +++ b/test/integration/cli/webworker.test.ts @@ -1,13 +1,14 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import path from 'path'; -import normalizePath from 'normalize-path'; -import { exec } from './util/childProcess'; +import { assert } from "chai"; +import path from "path"; +import normalizePath from "normalize-path"; +import { exec } from "./util/childProcess"; const fixtureDir = path.relative(process.cwd(), path.join(__dirname, 'fixture')); -const binPath = path.relative(process.cwd(), path.join('bin', '_mocha')); +const binPath = path.relative(process.cwd(), path.resolve('bin', '_mocha')); describe('webworker', function () { before(function () { @@ -21,4 +22,4 @@ describe('webworker', function () { done(); }); }); -}); +}); \ No newline at end of file diff --git a/test/integration/statsFormatter/mock/json-loader.js b/test/integration/statsFormatter/mock/json-loader.ts similarity index 98% rename from test/integration/statsFormatter/mock/json-loader.js rename to test/integration/statsFormatter/mock/json-loader.ts index a5de00b..8edc8ea 100644 --- a/test/integration/statsFormatter/mock/json-loader.js +++ b/test/integration/statsFormatter/mock/json-loader.ts @@ -5,4 +5,4 @@ */ module.exports = function mockJsonLoader() { throw new SyntaxError('Unexpected token'); -}; +}; \ No newline at end of file diff --git a/test/integration/statsFormatter/statsCasesFixture/babel-loader-syntax-error/entry.js b/test/integration/statsFormatter/statsCasesFixture/babel-loader-syntax-error/entry.ts.txt similarity index 100% rename from test/integration/statsFormatter/statsCasesFixture/babel-loader-syntax-error/entry.js rename to test/integration/statsFormatter/statsCasesFixture/babel-loader-syntax-error/entry.ts.txt diff --git a/test/integration/statsFormatter/statsCasesFixture/babel-loader-syntax-error/errors.webpack-4.node-12.txt b/test/integration/statsFormatter/statsCasesFixture/babel-loader-syntax-error/errors.webpack-4.node-12.txt new file mode 100644 index 0000000..1f5e378 --- /dev/null +++ b/test/integration/statsFormatter/statsCasesFixture/babel-loader-syntax-error/errors.webpack-4.node-12.txt @@ -0,0 +1,9 @@ +Error in ./entry.js + + Module build failed (from Cdir/node_modules/babel-loader/lib/index.js): + SyntaxError: Xdir/babel-loader-syntax-error/entry.js: Unexpected token (2:0) + + 1 | const x = { + > 2 | + | ^ + at Cdir/node_modules/@babel/core/lib/transform.js:34:34 \ No newline at end of file diff --git a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.js b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.js deleted file mode 100644 index 5b786b1..0000000 --- a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.js +++ /dev/null @@ -1 +0,0 @@ -import './src/critical-dependencies'; diff --git a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.ts b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.ts new file mode 100644 index 0000000..d6dbf90 --- /dev/null +++ b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/entry.ts @@ -0,0 +1 @@ +import "./src/critical-dependencies"; \ No newline at end of file diff --git a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.js b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.js deleted file mode 100644 index b29685a..0000000 --- a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.js +++ /dev/null @@ -1 +0,0 @@ -if (global.test) test(require); diff --git a/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.ts b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.ts new file mode 100644 index 0000000..dee187c --- /dev/null +++ b/test/integration/statsFormatter/statsCasesFixture/critical-dependencies-warning/src/critical-dependencies.ts @@ -0,0 +1 @@ +if (global.test) test(require); \ No newline at end of file diff --git a/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.js b/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.js deleted file mode 100644 index 74f07de..0000000 --- a/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.js +++ /dev/null @@ -1 +0,0 @@ -import './main.css'; diff --git a/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.ts b/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.ts new file mode 100644 index 0000000..f2b9eb2 --- /dev/null +++ b/test/integration/statsFormatter/statsCasesFixture/css-strip-loader/entry.ts @@ -0,0 +1 @@ +import "./main.css"; \ No newline at end of file diff --git a/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.js b/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.js deleted file mode 100644 index 9cc985d..0000000 --- a/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.js +++ /dev/null @@ -1 +0,0 @@ -import 'xxx-does-not-exist-xxx'; diff --git a/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.ts b/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.ts new file mode 100644 index 0000000..bb29849 --- /dev/null +++ b/test/integration/statsFormatter/statsCasesFixture/module-not-found-error/entry.ts @@ -0,0 +1 @@ +import "xxx-does-not-exist-xxx"; \ No newline at end of file diff --git a/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.js b/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.js deleted file mode 100644 index f1ad40f..0000000 --- a/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.js +++ /dev/null @@ -1 +0,0 @@ -import './main.scss'; diff --git a/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.ts b/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.ts new file mode 100644 index 0000000..a615168 --- /dev/null +++ b/test/integration/statsFormatter/statsCasesFixture/sass-loader-module-not-found-error/entry.ts @@ -0,0 +1 @@ +import "./main.scss"; \ No newline at end of file diff --git a/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.js b/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.js deleted file mode 100644 index f1ad40f..0000000 --- a/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.js +++ /dev/null @@ -1 +0,0 @@ -import './main.scss'; diff --git a/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.ts b/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.ts new file mode 100644 index 0000000..a615168 --- /dev/null +++ b/test/integration/statsFormatter/statsCasesFixture/sass-loader-syntax-error/entry.ts @@ -0,0 +1 @@ +import "./main.scss"; \ No newline at end of file diff --git a/test/integration/statsFormatter/statsFormatter.test.js b/test/integration/statsFormatter/statsFormatter.test.ts similarity index 70% rename from test/integration/statsFormatter/statsFormatter.test.js rename to test/integration/statsFormatter/statsFormatter.test.ts index 40943ca..3c4c5b0 100644 --- a/test/integration/statsFormatter/statsFormatter.test.js +++ b/test/integration/statsFormatter/statsFormatter.test.ts @@ -1,26 +1,27 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import fs from 'fs-extra'; -import path from 'path'; +import fs from "fs-extra"; +import path from "path"; -import _ from 'lodash'; -import stripAnsi from 'strip-ansi'; -import webpack from 'webpack'; -import { version as WEBPACK_VERSION } from 'webpack/package.json'; -import MemoryFileSystem from 'memory-fs'; -import { assert } from 'chai'; -import createStatsFormatter from '../../../src/webpack/util/createStatsFormatter'; +import _ from "lodash"; +import stripAnsi from "strip-ansi"; +import webpack from "webpack"; +import { version as WEBPACK_VERSION } from "webpack/package.json"; +import MemoryFileSystem from "memory-fs"; +import { assert } from "chai"; +import createStatsFormatter from "../../../src/webpack/util/createStatsFormatter"; const webpackMajorVersion = WEBPACK_VERSION.charAt(0); const base = path.join(__dirname, 'statsCasesFixture'); -const tests = fs.readdirSync(base).filter((testName) => fs.existsSync(path.join(base, testName, 'entry.js'))); +const tests = fs.readdirSync(base).filter(testName => fs.existsSync(path.join(base, testName, 'entry.js'))); const webpackConfig = { mode: 'development', output: { path: path.join(__dirname, '/dist'), - filename: 'bundle.js', + filename: 'bundle.js' }, module: { rules: [ @@ -43,23 +44,23 @@ const webpackConfig = { }, }; -describe('statFormatter', function () { +describe('statsFormatter', function () { before(function () { if (process.platform === 'win32') { this.skip(); } }); - tests.forEach((testName) => { + tests.forEach(testName => { const testDirPath = path.join(base, testName); const entryPath = path.join(testDirPath, 'entry.js'); // make os & location independent messages without colors const ensureConsistentCompare = _.flow([ - stripAnsi, - (message) => message.replace(/\r?\n/g, '\n'), - (message) => message.replace(new RegExp(testDirPath, 'g'), `Xdir/${testName}`), - (message) => message.replace(new RegExp(process.cwd(), 'g'), 'Cdir'), + stripAnsi, + message => message.replace(/\r?\n/g, '\n'), + message => message.replace(new RegExp(testDirPath, 'g'), `Xdir/${testName}`), + message => message.replace(new RegExp(process.cwd(), 'g'), 'Cdir') ]); it(`should print correct stats for ${path.basename(testDirPath)}`, function (done) { @@ -69,7 +70,7 @@ describe('statFormatter', function () { const config = { ...webpackConfig, context: testDirPath, - entry: `./${path.basename(entryPath)}`, + entry: `./${path.basename(entryPath)}` }; const memoryFs = new MemoryFileSystem(); @@ -83,7 +84,10 @@ describe('statFormatter', function () { return; } - const { warnings, errors } = formatter(stats); + const { + warnings, + errors + } = formatter(stats); assert.isArray(warnings, 'statsFormatter should return an Array of warnings'); assert.lengthOf(warnings, stats.compilation.warnings.length, 'Length of warnings should match original length'); @@ -93,8 +97,13 @@ describe('statFormatter', function () { const warningsContent = ensureConsistentCompare(warnings.join('\n')); const errorsContent = ensureConsistentCompare(errors.join('\n')); + let fixtureNodeId = ''; + if (path.basename(testDirPath) === 'babel-loader-syntax-error') { + const nodeMajorVersion = process.version.split('.')[0].replace('v', ''); + fixtureNodeId = parseInt(nodeMajorVersion, 10) <= 11 ? '' : `.node-${nodeMajorVersion}`; + } const expectedWarningsPath = path.join(testDirPath, `warnings.webpack-${webpackMajorVersion}.txt`); - const expectedErrorsPath = path.join(testDirPath, `errors.webpack-${webpackMajorVersion}.txt`); + const expectedErrorsPath = path.join(testDirPath, `errors.webpack-${webpackMajorVersion}${fixtureNodeId}.txt`); if (!fs.existsSync(expectedWarningsPath) || !fs.existsSync(expectedErrorsPath)) { fs.outputFileSync(expectedWarningsPath, warningsContent); diff --git a/test/unit/MochaWebpack.test.js b/test/unit/MochaWebpack.test.ts similarity index 98% rename from test/unit/MochaWebpack.test.js rename to test/unit/MochaWebpack.test.ts index 59a137b..26063f4 100644 --- a/test/unit/MochaWebpack.test.js +++ b/test/unit/MochaWebpack.test.ts @@ -1,7 +1,8 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback, max-len */ -import { assert } from 'chai'; -import MochaWebpack from '../../src/MochaWebpack'; +import { assert } from "chai"; +import MochaWebpack from "../../src/MochaWebpack"; describe('MochaWebpack', function () { it('should create a instance of MochaWebpack', function () { @@ -30,10 +31,10 @@ describe('MochaWebpack', function () { slow: 75, asyncOnly: false, delay: false, - interactive: !!(process.stdout.isTTY), + interactive: !!process.stdout.isTTY, clearTerminal: false, quiet: false, - forbidOnly: false, + forbidOnly: false }; assert.deepEqual(mochaWebpack.options, expected); }); @@ -92,7 +93,7 @@ describe('MochaWebpack', function () { it('webpackConfig()', function () { const oldOptions = this.mochaWebpack.options; const webpackConfig = { - loaders: [], + loaders: [] }; const returnValue = this.mochaWebpack.webpackConfig(webpackConfig); @@ -117,7 +118,7 @@ describe('MochaWebpack', function () { const oldOptions = this.mochaWebpack.options; const reporter = 'test'; const reporterOptions = { - foo: 'bar', + foo: 'bar' }; const returnValue = this.mochaWebpack.reporter(reporter, reporterOptions); diff --git a/test/unit/cli/fixture/webpackConfig/webpack.config-ts.ts b/test/unit/cli/fixture/webpackConfig/webpack.config-ts.ts index 3b414f5..c72a81b 100644 --- a/test/unit/cli/fixture/webpackConfig/webpack.config-ts.ts +++ b/test/unit/cli/fixture/webpackConfig/webpack.config-ts.ts @@ -1,5 +1,6 @@ interface Config { + mode: string; target: string; } const config: Config = { diff --git a/test/unit/cli/parseArgv.test.js b/test/unit/cli/parseArgv.test.ts similarity index 82% rename from test/unit/cli/parseArgv.test.js rename to test/unit/cli/parseArgv.test.ts index dea3b02..d1de0a8 100644 --- a/test/unit/cli/parseArgv.test.js +++ b/test/unit/cli/parseArgv.test.ts @@ -1,15 +1,14 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import parseArgv from '../../../src/cli/parseArgv'; +import { assert } from "chai"; +import parseArgv from "../../../src/cli/parseArgv"; describe('parseArgv', function () { beforeEach(function () { this.parseArgv = parseArgv; - this.argv = [ - 'src', - ]; + this.argv = ['src']; }); context('duplicated arguments', function () { @@ -63,7 +62,7 @@ describe('parseArgv', function () { const files = ['--recursive', 'test/bin/fixture']; assert.deepEqual(this.parseArgv(files, true), { recursive: true, - files: ['test/bin/fixture'], + files: ['test/bin/fixture'] }); }); @@ -71,7 +70,7 @@ describe('parseArgv', function () { const argv = ['--webpack-config', 'webpack-config.js']; assert.deepEqual(this.parseArgv(argv, true), { - webpackConfig: 'webpack-config.js', + webpackConfig: 'webpack-config.js' }); }); @@ -80,7 +79,7 @@ describe('parseArgv', function () { assert.deepEqual(this.parseArgv(argv, true), { webpackConfig: 'webpack-config.js', - files: ['test/bin/fixture'], + files: ['test/bin/fixture'] }); }); }); @@ -128,7 +127,9 @@ describe('parseArgv', function () { context('async-only', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -154,7 +155,9 @@ describe('parseArgv', function () { context('colors', function () { it('uses undefined as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -195,7 +198,9 @@ describe('parseArgv', function () { context('growl', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -222,7 +227,9 @@ describe('parseArgv', function () { context('recursive', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -249,7 +256,9 @@ describe('parseArgv', function () { context('reporter-options', function () { it('uses {} as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -259,13 +268,7 @@ describe('parseArgv', function () { assert.deepEqual(parsedArgv.reporterOptions, {}); }); - const parameters = [ - { given: ['--reporter-options', 'foo=bar,quux'], expected: { foo: 'bar', quux: true } }, - { given: ['--reporter-options', 'foo=bar,quux,bar=foo'], expected: { foo: 'bar', quux: true, bar: 'foo' } }, - { given: ['--reporter-options', 'foo=bar,quux,bar=foo'], expected: { foo: 'bar', quux: true, bar: 'foo' } }, - { given: ['--O', 'foo=bar'], expected: { foo: 'bar' } }, - { given: ['-O', 'foo=bar'], expected: { foo: 'bar' } }, - ]; + const parameters = [{ given: ['--reporter-options', 'foo=bar,quux'], expected: { foo: 'bar', quux: true } }, { given: ['--reporter-options', 'foo=bar,quux,bar=foo'], expected: { foo: 'bar', quux: true, bar: 'foo' } }, { given: ['--reporter-options', 'foo=bar,quux,bar=foo'], expected: { foo: 'bar', quux: true, bar: 'foo' } }, { given: ['--O', 'foo=bar'], expected: { foo: 'bar' } }, { given: ['-O', 'foo=bar'], expected: { foo: 'bar' } }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -285,7 +288,9 @@ describe('parseArgv', function () { context('reporter', function () { it('uses "spec" as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -294,11 +299,7 @@ describe('parseArgv', function () { assert.propertyVal(parsedArgv, 'reporter', 'spec'); }); - const parameters = [ - { given: ['--reporter', 'dot'], expected: 'dot' }, - { given: ['--R', 'dot'], expected: 'dot' }, - { given: ['-R', 'dot'], expected: 'dot' }, - ]; + const parameters = [{ given: ['--reporter', 'dot'], expected: 'dot' }, { given: ['--R', 'dot'], expected: 'dot' }, { given: ['-R', 'dot'], expected: 'dot' }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -317,7 +318,9 @@ describe('parseArgv', function () { context('bail', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -344,7 +347,9 @@ describe('parseArgv', function () { context('grep', function () { it('has no default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -354,11 +359,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--grep', 'test'], expected: 'test' }, - { given: ['--g', 'test'], expected: 'test' }, - { given: ['-g', 'test'], expected: 'test' }, - ]; + const parameters = [{ given: ['--grep', 'test'], expected: 'test' }, { given: ['--g', 'test'], expected: 'test' }, { given: ['-g', 'test'], expected: 'test' }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -377,7 +378,9 @@ describe('parseArgv', function () { context('fgrep', function () { it('has no default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -387,11 +390,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--fgrep', 'test'], expected: 'test' }, - { given: ['--f', 'test'], expected: 'test' }, - { given: ['-f', 'test'], expected: 'test' }, - ]; + const parameters = [{ given: ['--fgrep', 'test'], expected: 'test' }, { given: ['--f', 'test'], expected: 'test' }, { given: ['-f', 'test'], expected: 'test' }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -410,7 +409,9 @@ describe('parseArgv', function () { context('invert', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -437,7 +438,9 @@ describe('parseArgv', function () { context('require', function () { it('uses [] as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -448,12 +451,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--require', 'test'], expected: ['test'] }, - { given: ['--require', 'test', '--require', 'test2'], expected: ['test', 'test2'] }, - { given: ['--r', 'test'], expected: ['test'] }, - { given: ['-r', 'test'], expected: ['test'] }, - ]; + const parameters = [{ given: ['--require', 'test'], expected: ['test'] }, { given: ['--require', 'test', '--require', 'test2'], expected: ['test', 'test2'] }, { given: ['--r', 'test'], expected: ['test'] }, { given: ['-r', 'test'], expected: ['test'] }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -473,7 +471,9 @@ describe('parseArgv', function () { context('include', function () { it('uses [] as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -484,10 +484,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--include', 'test'], expected: ['test'] }, - { given: ['--include', 'test', '--include', 'test2'], expected: ['test', 'test2'] }, - ]; + const parameters = [{ given: ['--include', 'test'], expected: ['test'] }, { given: ['--include', 'test', '--include', 'test2'], expected: ['test', 'test2'] }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -507,7 +504,9 @@ describe('parseArgv', function () { context('slow', function () { it('uses 75 as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -517,13 +516,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--slow', '1000'], expected: 1000 }, - { given: ['--slow', '-1'], expected: -1 }, - { given: ['--s', '1000'], expected: 1000 }, - { given: ['-s', '1000'], expected: 1000 }, - { given: ['-s', '-1'], expected: -1 }, - ]; + const parameters = [{ given: ['--slow', '1000'], expected: 1000 }, { given: ['--slow', '-1'], expected: -1 }, { given: ['--s', '1000'], expected: 1000 }, { given: ['-s', '1000'], expected: 1000 }, { given: ['-s', '-1'], expected: -1 }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -542,7 +535,9 @@ describe('parseArgv', function () { context('timeout', function () { it('uses 2000 as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -552,11 +547,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--timeout', '1000'], expected: 1000 }, - { given: ['--t', '1000'], expected: 1000 }, - { given: ['-t', '1000'], expected: 1000 }, - ]; + const parameters = [{ given: ['--timeout', '1000'], expected: 1000 }, { given: ['--t', '1000'], expected: 1000 }, { given: ['-t', '1000'], expected: 1000 }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -575,7 +566,9 @@ describe('parseArgv', function () { context('ui', function () { it('uses "bdd" as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -585,11 +578,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--ui', 'tdd'], expected: 'tdd' }, - { given: ['--u', 'tdd'], expected: 'tdd' }, - { given: ['-u', 'tdd'], expected: 'tdd' }, - ]; + const parameters = [{ given: ['--ui', 'tdd'], expected: 'tdd' }, { given: ['--u', 'tdd'], expected: 'tdd' }, { given: ['-u', 'tdd'], expected: 'tdd' }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -608,7 +597,9 @@ describe('parseArgv', function () { context('watch', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -635,7 +626,9 @@ describe('parseArgv', function () { context('check-leaks', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -662,7 +655,9 @@ describe('parseArgv', function () { context('full-trace', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -689,7 +684,9 @@ describe('parseArgv', function () { context('inline-diffs', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -716,7 +713,9 @@ describe('parseArgv', function () { context('exit', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -743,7 +742,9 @@ describe('parseArgv', function () { context('retries', function () { it('has no default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -753,9 +754,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--retries', '2'], expected: 2 }, - ]; + const parameters = [{ given: ['--retries', '2'], expected: 2 }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -774,7 +773,9 @@ describe('parseArgv', function () { context('delay', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -801,7 +802,9 @@ describe('parseArgv', function () { context('webpack-config', function () { it('has default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -811,9 +814,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--webpack-config', 'webpack-config.js'], expected: 'webpack-config.js' }, - ]; + const parameters = [{ given: ['--webpack-config', 'webpack-config.js'], expected: 'webpack-config.js' }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -832,7 +833,9 @@ describe('parseArgv', function () { context('webpack-env', function () { it('has no default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -841,15 +844,10 @@ describe('parseArgv', function () { assert.notProperty(parsedArgv, 'webpackEnv'); }); - const parameters = [ - { given: ['--webpack-env', 'production'], expected: 'production' }, - { given: ['--webpack-env.env', 'production'], expected: { env: 'production' } }, - { given: ['--webpack-env.anotherEnv', 'test'], expected: { anotherEnv: 'test' } }, - { - given: ['--webpack-env.env', 'production', '--webpack-env.anotherEnv', 'test'], - expected: { env: 'production', anotherEnv: 'test' }, - }, - ]; + const parameters = [{ given: ['--webpack-env', 'production'], expected: 'production' }, { given: ['--webpack-env.env', 'production'], expected: { env: 'production' } }, { given: ['--webpack-env.anotherEnv', 'test'], expected: { anotherEnv: 'test' } }, { + given: ['--webpack-env.env', 'production', '--webpack-env.anotherEnv', 'test'], + expected: { env: 'production', anotherEnv: 'test' } + }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { // given @@ -867,7 +865,9 @@ describe('parseArgv', function () { context('opts', function () { it('has no default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -877,9 +877,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--opts', 'path/to/other.opts'], expected: 'path/to/other.opts' }, - ]; + const parameters = [{ given: ['--opts', 'path/to/other.opts'], expected: 'path/to/other.opts' }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -898,7 +896,9 @@ describe('parseArgv', function () { context('mode', function () { it('has no default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); @@ -908,10 +908,7 @@ describe('parseArgv', function () { }); - const parameters = [ - { given: ['--mode', 'development'], expected: 'development' }, - { given: ['--mode', 'production'], expected: 'production' }, - ]; + const parameters = [{ given: ['--mode', 'development'], expected: 'development' }, { given: ['--mode', 'production'], expected: 'production' }]; for (const parameter of parameters) { it(`parses ${parameter.given.join(' ')}`, function () { @@ -930,7 +927,9 @@ describe('parseArgv', function () { context('forbid-only', function () { it('uses false as default value', function () { // given - const { argv } = this; + const { + argv + } = this; // when const parsedArgv = this.parseArgv(argv); diff --git a/test/unit/cli/parseConfig.test.js b/test/unit/cli/parseConfig.test.ts similarity index 88% rename from test/unit/cli/parseConfig.test.js rename to test/unit/cli/parseConfig.test.ts index 6b7c87f..70ba8f7 100644 --- a/test/unit/cli/parseConfig.test.js +++ b/test/unit/cli/parseConfig.test.ts @@ -1,10 +1,11 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import path from 'path'; -import fs from 'fs-extra'; -import { assert } from 'chai'; -import parseConfig from '../../../src/cli/parseConfig'; +import path from "path"; +import fs from "fs-extra"; +import { assert } from "chai"; +import parseConfig from "../../../src/cli/parseConfig"; const optsTestCasesPath = path.join(__dirname, 'fixture', 'config', 'optsTestCases'); const optsTestCases = fs.readdirSync(optsTestCasesPath); @@ -32,7 +33,7 @@ describe('parseConfig', function () { assert.throws(fn, /Options file 'missing-config.opts' not found/); }); - optsTestCases.forEach((testDirName) => { + optsTestCases.forEach(testDirName => { const testDirPath = path.join(optsTestCasesPath, testDirName); const optsFilePath = path.join(testDirPath, 'mochapack.opts'); const expectedResultsPath = path.join(testDirPath, 'expected.json'); diff --git a/test/unit/cli/requireWebpackConfig.test.js b/test/unit/cli/requireWebpackConfig.test.ts similarity index 62% rename from test/unit/cli/requireWebpackConfig.test.js rename to test/unit/cli/requireWebpackConfig.test.ts index ef181d4..a99fd2d 100644 --- a/test/unit/cli/requireWebpackConfig.test.js +++ b/test/unit/cli/requireWebpackConfig.test.ts @@ -1,50 +1,49 @@ /* eslint-env node, mocha */ -import path from 'path'; -import { assert } from 'chai'; -import { rejects } from 'assert'; -import requireWebpackConfig from '../../../src/cli/requireWebpackConfig'; +import path from "path"; +import { assert } from "chai"; +import { rejects } from "assert"; +import requireWebpackConfig from "../../../src/cli/requireWebpackConfig"; describe('requireWebpackConfig', () => { - const getConfigPath = (extension, suffix = 'config-test') => - path.join(__dirname, 'fixture', 'webpackConfig', `webpack.${suffix}${extension}`); + const getConfigPath = (extension, suffix = 'config-test') => path.join(__dirname, 'fixture', 'webpackConfig', `webpack.${suffix}${extension}`); const expectedConfigPath = path.join(__dirname, 'fixture', 'webpackConfig', 'expected.json'); const expectedConfig = require(expectedConfigPath); // eslint-disable-line global-require, import/no-dynamic-require it('requires plain JavaScript Webpack config file', async () => { const configPath = getConfigPath('.js'); - assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig); + assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); }); (process.platform === 'win32' ? it.skip : it)('requires symlinked config file', async () => { const configPath = getConfigPath('.js', 'config-symlink'); - assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig); + assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); }); it('requires Babel Webpack config file', async () => { const configPath = getConfigPath('.babel.js'); - assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig); + assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); }); it('requires CoffeeScript Webpack config file', async () => { const configPath = getConfigPath('.coffee'); - assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig); + assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); }); it('requires CoffeeScript Webpack config file with config.js', async () => { const configPath = getConfigPath('.js', 'config'); - assert.deepEqual(await requireWebpackConfig(configPath), expectedConfig); + assert.deepEqual((await requireWebpackConfig(configPath)), expectedConfig); }); it('supports config that exports a function', async () => { const configPath = getConfigPath('.js', 'config-function'); - assert.deepEqual(await requireWebpackConfig(configPath, false, 'test'), expectedConfig); + assert.deepEqual((await requireWebpackConfig(configPath, false, 'test')), expectedConfig); }); it('supports config that exports a Promise', async () => { const configPath = getConfigPath('.js', 'config-promise'); - assert.deepEqual(await requireWebpackConfig(configPath, false, 'test'), expectedConfig); + assert.deepEqual((await requireWebpackConfig(configPath, false, 'test')), expectedConfig); }); it('throws error when multi compiler config is given', async () => { @@ -55,14 +54,11 @@ describe('requireWebpackConfig', () => { it('throws error when not found when required', async () => { const configPath = getConfigPath('.js', 'config-xxx'); - await rejects( - () => requireWebpackConfig(configPath, true), - { message: `Webpack config could not be found: ${configPath}` }, - ); + await rejects(() => requireWebpackConfig(configPath, true), { message: `Webpack config could not be found: ${configPath}` }); }); it('return empty config when not found and not required', async () => { const configPath = getConfigPath('.xxx', 'config-xxx'); - assert.deepEqual(await requireWebpackConfig(configPath), {}); + assert.deepEqual((await requireWebpackConfig(configPath)), {}); }); }); diff --git a/test/unit/createMochaWebpack.test.js b/test/unit/createMochaWebpack.test.ts similarity index 72% rename from test/unit/createMochaWebpack.test.js rename to test/unit/createMochaWebpack.test.ts index 95966f3..4d37751 100644 --- a/test/unit/createMochaWebpack.test.js +++ b/test/unit/createMochaWebpack.test.ts @@ -1,8 +1,9 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import MochaWebpack from '../../src/MochaWebpack'; -import createMochaWebpack from '../../src/createMochaWebpack'; +import { assert } from "chai"; +import MochaWebpack from "../../src/MochaWebpack"; +import { createMochaWebpack } from "../../src/createMochaWebpack"; describe('createMochaWebpack', function () { it('should create a instance of MochaWebpack', function () { diff --git a/test/unit/runner/configureMocha.test.js b/test/unit/runner/configureMocha.test.ts similarity index 89% rename from test/unit/runner/configureMocha.test.js rename to test/unit/runner/configureMocha.test.ts index 1e0963e..58474b3 100644 --- a/test/unit/runner/configureMocha.test.js +++ b/test/unit/runner/configureMocha.test.ts @@ -1,10 +1,11 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import { sandbox } from 'sinon'; -import Mocha from 'mocha'; +import { assert } from "chai"; +import { sandbox } from "sinon"; +import Mocha from "mocha"; -import configureMocha from '../../../src/runner/configureMocha'; +import configureMocha from "../../../src/runner/configureMocha"; describe('configureMocha', function () { @@ -22,7 +23,7 @@ describe('configureMocha', function () { slow: 75, asyncOnly: false, delay: false, - forbidOnly: true, + forbidOnly: true }; this.sandbox = sandbox.create(); this.spyReporter = this.sandbox.spy(Mocha.prototype, 'reporter'); @@ -45,7 +46,7 @@ describe('configureMocha', function () { it('should call reporter()', function () { configureMocha({ - ...this.options, + ...this.options }); const reporter = Mocha.reporters[this.options.reporter]; @@ -56,7 +57,7 @@ describe('configureMocha', function () { it('should call useColors()', function () { configureMocha({ - ...this.options, + ...this.options }); assert.isTrue(this.spyUseColors.called, 'useColors() should be called'); @@ -65,7 +66,7 @@ describe('configureMocha', function () { it('should call useInlineDiffs()', function () { configureMocha({ - ...this.options, + ...this.options }); assert.isTrue(this.spyUseInlineDiffs.called, 'useInlineDiffs() should be called'); @@ -75,7 +76,7 @@ describe('configureMocha', function () { it('should call enableTimeouts()', function () { configureMocha({ ...this.options, - timeout: 0, + timeout: 0 }); assert.isTrue(this.spyEnableTimeouts.called, 'enableTimeouts() should be called'); @@ -86,7 +87,7 @@ describe('configureMocha', function () { configureMocha({ ...this.options, grep: 'dddd', - fgrep: 'dddd', + fgrep: 'dddd' }); assert.isTrue(this.spyGrep.called, 'grep() should be called'); @@ -95,14 +96,14 @@ describe('configureMocha', function () { it('should set growl', function () { configureMocha({ ...this.options, - growl: undefined, + growl: undefined }); assert.isFalse(this.spyGrowl.called, 'growl() should not be called'); configureMocha({ ...this.options, - growl: true, + growl: true }); assert.isTrue(this.spyGrowl.called, 'growl() should be called'); @@ -111,7 +112,7 @@ describe('configureMocha', function () { it('should call forbidOnly()', function () { configureMocha({ ...this.options, - timeout: 0, + timeout: 0 }); assert.isTrue(this.spyForbidOnly.called, 'spyForbidOnly() should be called'); diff --git a/test/unit/runner/loadReporter.test.js b/test/unit/runner/loadReporter.test.ts similarity index 88% rename from test/unit/runner/loadReporter.test.js rename to test/unit/runner/loadReporter.test.ts index 3c98831..14add99 100644 --- a/test/unit/runner/loadReporter.test.js +++ b/test/unit/runner/loadReporter.test.ts @@ -1,11 +1,12 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import spec from 'mocha/lib/reporters/spec'; -import progress from 'mocha/lib/reporters/progress'; +import { assert } from "chai"; +import spec from "mocha/lib/reporters/spec"; +import progress from "mocha/lib/reporters/progress"; -import customMochaReporter from '../../fixture/customMochaReporter'; -import loadReporter from '../../../src/runner/loadReporter'; +import customMochaReporter from "../../fixture/customMochaReporter"; +import loadReporter from "../../../src/runner/loadReporter"; const customMochaReporterPath = require.resolve('../../fixture/customMochaReporter'); diff --git a/test/unit/runner/loadUI.test.js b/test/unit/runner/loadUI.test.ts similarity index 94% rename from test/unit/runner/loadUI.test.js rename to test/unit/runner/loadUI.test.ts index eb925e7..d97c2fb 100644 --- a/test/unit/runner/loadUI.test.js +++ b/test/unit/runner/loadUI.test.ts @@ -1,8 +1,9 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import path from 'path'; -import { assert } from 'chai'; -import loadUI from '../../../src/runner/loadUI'; +import path from "path"; +import { assert } from "chai"; +import loadUI from "../../../src/runner/loadUI"; const customMochaReporterPath = require.resolve('../../fixture/customMochaReporter.js'); diff --git a/test/unit/util/glob.test.js b/test/unit/util/glob.test.ts similarity index 96% rename from test/unit/util/glob.test.js rename to test/unit/util/glob.test.ts index 27c42f2..64b30de 100644 --- a/test/unit/util/glob.test.js +++ b/test/unit/util/glob.test.ts @@ -1,7 +1,8 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import { ensureGlob, extensionsToGlob } from '../../../src/util/glob'; +import { assert } from "chai"; +import { ensureGlob, extensionsToGlob } from "../../../src/util/glob"; describe('glob', function () { context('ensureGlob', function () { diff --git a/test/unit/util/registerRequireHook.test.js b/test/unit/util/registerRequireHook.test.ts similarity index 84% rename from test/unit/util/registerRequireHook.test.js rename to test/unit/util/registerRequireHook.test.ts index af81d4f..4a68b02 100644 --- a/test/unit/util/registerRequireHook.test.js +++ b/test/unit/util/registerRequireHook.test.ts @@ -1,8 +1,9 @@ /* eslint-env node, mocha */ + /* eslint-disable func-names, prefer-arrow-callback */ -import { assert } from 'chai'; -import registerRequireHook from '../../../src/util/registerRequireHook'; -import fakemodule from './fixture/fakeModule'; +import { assert } from "chai"; +import registerRequireHook from "../../../src/util/registerRequireHook"; +import fakemodule from "./fixture/fakeModule"; const fakeModulePath = require.resolve('./fixture/fakeModule'); @@ -19,7 +20,9 @@ describe('registerRequireHook', function () { it('requires from memory', function () { const dispose = registerRequireHook('.js', (filePath, requireCaller) => { if (filePath === fakeModulePath) { - const { filename } = requireCaller; + const { + filename + } = requireCaller; assert.equal(filename, __filename); return { path: filePath, source: 'module.exports = "from-memory";' }; } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..f58fb60 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "declaration": true, + "esModuleInterop": true, + "module": "commonjs", + "moduleResolution": "node", + "outDir": "lib", + "resolveJsonModule": true, + "sourceMap": true, + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.test.ts" + ] +} diff --git a/yarn.lock b/yarn.lock index ea09d32..43a5d01 100644 --- a/yarn.lock +++ b/yarn.lock @@ -340,13 +340,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-syntax-flow@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.7.4.tgz#6d91b59e1a0e4c17f36af2e10dd64ef220919d7b" - integrity sha512-2AMAWl5PsmM5KPkB22cvOkUyWk6MjUaqhHNU5nSPUl/ns3j5qLfw2SuYP5RbVZ0tfLvePr4zUScbICtDP2CUNw== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-json-strings@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.7.4.tgz#86e63f7d2e22f9e27129ac4e83ea989a382e86cc" @@ -375,6 +368,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-syntax-typescript@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.7.4.tgz#5d037ffa10f3b25a16f32570ebbe7a8c2efa304b" + integrity sha512-77blgY18Hud4NM1ggTA8xVT/dBENQf17OpiToSa2jSmEY3fWXD2jwrdVlO4kq5yzUTeF15WSQ6b4fByNvJcjpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-transform-arrow-functions@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.7.4.tgz#76309bd578addd8aee3b379d809c802305a98a12" @@ -457,14 +457,6 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.7.4" "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-flow-strip-types@^7.0.0", "@babel/plugin-transform-flow-strip-types@^7.7.4": - version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.7.4.tgz#cc73f85944782df1d77d80977bc097920a8bf31a" - integrity sha512-w9dRNlHY5ElNimyMYy0oQowvQpwt/PRHI0QS98ZJCTZU2bvSnKXo5zEiD5u76FBPigTm8TkqzmnUTg16T7qbkA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.7.4" - "@babel/plugin-transform-for-of@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.7.4.tgz#248800e3a5e507b1f103d8b4ca998e77c63932bc" @@ -629,6 +621,15 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-typescript@^7.7.4": + version "7.7.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.7.4.tgz#2974fd05f4e85c695acaf497f432342de9fc0636" + integrity sha512-X8e3tcPEKnwwPVG+vP/vSqEShkwODOEeyQGod82qrIuidwIrfnsGn11qPM1jBLF4MqguTXXYzm58d0dY+/wdpg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.7.4" + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-syntax-typescript" "^7.7.4" + "@babel/plugin-transform-unicode-regex@^7.7.4": version "7.7.4" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.7.4.tgz#a3c0f65b117c4c81c5b6484f2a5e7b95346b83ae" @@ -694,13 +695,13 @@ js-levenshtein "^1.1.3" semver "^5.5.0" -"@babel/preset-flow@^7.0.0": +"@babel/preset-typescript@^7.7.4": version "7.7.4" - resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.7.4.tgz#99c1349b6fd7132783196de181e6b32d0949427e" - integrity sha512-6LbUqcHD8BcRtXMOp5bc5nJeU8RlKh6q5U8TgZeCrf9ebBdW8Wyy5ujAUnbJfmzQ56Kkq5XtwErC/5+5RHyFYA== + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.7.4.tgz#780059a78e6fa7f7a4c87f027292a86b31ce080a" + integrity sha512-rqrjxfdiHPsnuPur0jKrIIGQCIgoTWMTjlbWE69G4QJ6TIOVnnRnIJhUxNTL/VwDmEAVX08Tq3B1nirer5341w== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.7.4" + "@babel/plugin-transform-typescript" "^7.7.4" "@babel/register@^7.0.0": version "7.7.4" @@ -721,10 +722,10 @@ core-js "^2.6.5" regenerator-runtime "^0.13.2" -"@babel/runtime@^7.4.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.2.tgz#c3d6e41b304ef10dcf13777a33e7694ec4a9a6dd" - integrity sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg== +"@babel/runtime@^7.7.6": + version "7.7.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.7.6.tgz#d18c511121aff1b4f2cd1d452f1bac9601dd830f" + integrity sha512-BWAJxpNVa0QlE5gZdWjSxXtemZyZ9RmrmVozxt3NUXeZhVIJ5ANyqmMc0JDrivBZyxUuQvFxlvH4OWWOogGfUw== dependencies: regenerator-runtime "^0.13.2" @@ -830,6 +831,11 @@ dependencies: defer-to-connect "^1.0.1" +"@types/anymatch@*": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@types/anymatch/-/anymatch-1.3.1.tgz#336badc1beecb9dacc38bea2cf32adf627a8421a" + integrity sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA== + "@types/events@*": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" @@ -844,6 +850,16 @@ "@types/minimatch" "*" "@types/node" "*" +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + +"@types/lodash@^4.14.149": + version "4.14.149" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" + integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -854,11 +870,54 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.9.tgz#ffeee23afdc19ab16e979338e7b536fdebbbaeaf" integrity sha512-+YB9FtyxXGyD54p8rXwWaN1EWEyar5L58GlGWgtH2I9rGmLGBQcw63+0jw+ujqVavNuO47S1ByAjm9zdHMnskw== +"@types/node@^12.12.17": + version "12.12.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.17.tgz#191b71e7f4c325ee0fb23bc4a996477d92b8c39b" + integrity sha512-Is+l3mcHvs47sKy+afn2O1rV4ldZFU7W8101cNlOd+MRbjM4Onida8jSZnJdTe/0Pcf25g9BNIUsuugmE6puHA== + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== +"@types/source-list-map@*": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" + integrity sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA== + +"@types/tapable@*": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/tapable/-/tapable-1.0.4.tgz#b4ffc7dc97b498c969b360a41eee247f82616370" + integrity sha512-78AdXtlhpCHT0K3EytMpn4JNxaf5tbqbLcbIRoQIHzpTIyjpxLQKRoxU55ujBXAtg3Nl2h/XWvfDa9dsMOd0pQ== + +"@types/uglify-js@*": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/uglify-js/-/uglify-js-3.0.4.tgz#96beae23df6f561862a830b4288a49e86baac082" + integrity sha512-SudIN9TRJ+v8g5pTG8RRCqfqTMNqgWCKKd3vtynhGzkIIjxaicNAMuY5TRadJ6tzDu3Dotf3ngaMILtmOdmWEQ== + dependencies: + source-map "^0.6.1" + +"@types/webpack-sources@*": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@types/webpack-sources/-/webpack-sources-0.1.5.tgz#be47c10f783d3d6efe1471ff7f042611bd464a92" + integrity sha512-zfvjpp7jiafSmrzJ2/i3LqOyTYTuJ7u1KOXlKgDlvsj9Rr0x7ZiYu5lZbXwobL7lmsRNtPXlBfmaUD8eU2Hu8w== + dependencies: + "@types/node" "*" + "@types/source-list-map" "*" + source-map "^0.6.1" + +"@types/webpack@^4.41.0": + version "4.41.0" + resolved "https://registry.yarnpkg.com/@types/webpack/-/webpack-4.41.0.tgz#b813a044d8b0dec7dfcd7622fdbe327bde06eb9a" + integrity sha512-tWkdf9nO0zFgAY/EumUKwrDUhraHKDqCPhwfFR/R8l0qnPdgb9le0Gzhvb7uzVpouuDGBgiE//ZdY+5jcZy2TA== + dependencies: + "@types/anymatch" "*" + "@types/node" "*" + "@types/tapable" "*" + "@types/uglify-js" "*" + "@types/webpack-sources" "*" + source-map "^0.6.0" + "@webassemblyjs/ast@1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359" @@ -1033,11 +1092,6 @@ abbrev@~1.0.9: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= -acorn-es7-plugin@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/acorn-es7-plugin/-/acorn-es7-plugin-1.1.7.tgz#f2ee1f3228a90eead1245f9ab1922eb2e71d336b" - integrity sha1-8u4fMiipDurRJF+asZIusucdM2s= - acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" @@ -1045,16 +1099,16 @@ acorn-jsx@^3.0.0: dependencies: acorn "^3.0.4" -"acorn@>= 2.5.2 <= 5.7.3", acorn@^5.5.0: - version "5.7.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" - integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== - acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" integrity sha1-ReN/s56No/JbruP/U2niu18iAXo= +acorn@^5.5.0: + version "5.7.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" + integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== + acorn@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.1.tgz#3ed8422d6dec09e6121cc7a843ca86a330a86b51" @@ -1333,7 +1387,7 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -arrify@^1.0.1: +arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= @@ -1846,7 +1900,7 @@ buffer-fill@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= -buffer-from@^1.0.0: +buffer-from@^1.0.0, buffer-from@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== @@ -2945,7 +2999,7 @@ dezalgo@^1.0.0, dezalgo@^1.0.1, dezalgo@^1.0.2, dezalgo@~1.0.3: asap "^2.0.0" wrappy "1" -diff@3.5.0, diff@^3.5.0: +diff@3.5.0, diff@^3.1.0, diff@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== @@ -3231,22 +3285,6 @@ eslint-module-utils@^2.4.0: debug "^2.6.8" pkg-dir "^2.0.0" -eslint-plugin-flowtype-errors@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype-errors/-/eslint-plugin-flowtype-errors-4.1.0.tgz#6edb0837001f70001ceeb33f0541bd2b8eb8e6c8" - integrity sha512-79Hy4ITWwXF7J8/N7jZG6PN6O+kL8oUCZgQaPf4eT8UvSI0x10WACEDzfxJgG1qW3/FN/lT6U1e7K/7fpIWPKw== - dependencies: - "@babel/runtime" "^7.4.2" - find-up "^3.0.0" - slash "^2.0.0" - -eslint-plugin-flowtype@4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-4.3.0.tgz#06d0837ac341caf369e7e6dbb112dd7fd21acf17" - integrity sha512-elvqoadMHnYqSYN1YXn02DR7SFW8Kc2CLe8na3m2GdQPQhIY+BgCd2quVJ1AbW3aO0zcyE9loVJ7Szy8A/xlMA== - dependencies: - lodash "^4.17.15" - eslint-plugin-import@^2.9.0: version "2.18.2" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz#02f1180b90b077b33d447a17a2326ceb400aceb6" @@ -3521,14 +3559,6 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= -fast-async@^6.1.2: - version "6.3.8" - resolved "https://registry.yarnpkg.com/fast-async/-/fast-async-6.3.8.tgz#031b9e1d5a84608b117b3e7c999ad477ed2b08a2" - integrity sha512-TjlooyqrYm/gOXjD2UHNwfrWkvTbzU105Nk4bvcRTeRoL+wIeK6rqbqDg3CN9z5p37cE2iXhP6SxQFz8OVIaUg== - dependencies: - nodent-compiler "^3.2.10" - nodent-runtime ">=3.2.1" - fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" @@ -3719,11 +3749,6 @@ flat@^4.1.0: dependencies: is-buffer "~2.0.3" -flow-bin@^0.113.0: - version "0.113.0" - resolved "https://registry.yarnpkg.com/flow-bin/-/flow-bin-0.113.0.tgz#6457d250dbc6f71ca51e75f00a96d23cde5d987a" - integrity sha512-76uE2LGNe50wm+Jup8Np4FBcMbyy5V2iE+K25PPIYLaEMGHrL1jnQfP9L0hTzA5oh2ZJlexRLMlaPqIYIKH9nw== - flush-write-stream@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" @@ -5877,6 +5902,11 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" +make-error@^1.1.1: + version "1.3.5" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.5.tgz#efe4e81f6db28cadd605c70f29c831b58ef776c8" + integrity sha512-c3sIjNUow0+8swNwVpqoH4YCShKNFkMaw6oH1mNS2haDZQqkeZFlHS3dhoeEbKKmJB4vXpJucU6oH75aDYeE9g== + make-fetch-happen@^2.4.13: version "2.6.0" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-2.6.0.tgz#8474aa52198f6b1ae4f3094c04e8370d35ea8a38" @@ -6486,26 +6516,11 @@ node-uuid@~1.4.7: resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" integrity sha1-sEDrCSOWivq/jTL7HxfxFn/auQc= -nodent-compiler@^3.2.10: - version "3.2.11" - resolved "https://registry.yarnpkg.com/nodent-compiler/-/nodent-compiler-3.2.11.tgz#8f4bc703d7d8d0e563f5e09ea22efdce04dbaf9b" - integrity sha512-rfDrGWdgIJYomPUzR8nXiWNuIhJ7cVodPeZP3Ho65LEycuaX2uVNZ0ytpcfrmUKzdFeLRtye9+pHe8OynPZuPQ== - dependencies: - acorn ">= 2.5.2 <= 5.7.3" - acorn-es7-plugin "^1.1.7" - nodent-transform "^3.2.9" - source-map "^0.5.7" - -nodent-runtime@>=3.2.1, nodent-runtime@^3.2.1: +nodent-runtime@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/nodent-runtime/-/nodent-runtime-3.2.1.tgz#9e2755d85e39f764288f0d4752ebcfe3e541e00e" integrity sha512-7Ws63oC+215smeKJQCxzrK21VFVlCFBkwl0MOObt0HOpVQXs3u483sAmtkF33nNqZ5rSOQjB76fgyPBmAUrtCA== -nodent-transform@^3.2.9: - version "3.2.9" - resolved "https://registry.yarnpkg.com/nodent-transform/-/nodent-transform-3.2.9.tgz#ec11a6116b5476e60bc212371cf6b8e4c74f40b6" - integrity sha512-4a5FH4WLi+daH/CGD5o/JWRR8W5tlCkd3nrDSkxbOzscJTyTUITltvOJeQjg3HJ1YgEuNyiPhQbvbtRjkQBByQ== - "nopt@2 || 3", nopt@~3.0.6: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -8820,7 +8835,7 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.13, source-map-support@^0.5.16, source-map-support@~0.5.12: +source-map-support@^0.5.13, source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.12: version "0.5.16" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== @@ -9479,6 +9494,39 @@ trim-right@^1.0.1: dependencies: glob "^7.1.2" +ts-mocha@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-6.0.0.tgz#40b8c5462ffce6f5dcee5ff729655b2958f26e50" + integrity sha512-ZCtJK8WXxHNbFNjvUKQIXZby/+ybQQkaBcM/3QhBQUfwjpdGFE9F6iWsHhF5ifQNFV/lWiOODi2VMD5AyPcQyg== + dependencies: + ts-node "7.0.1" + optionalDependencies: + tsconfig-paths "^3.5.0" + +ts-node@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" + integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== + dependencies: + arrify "^1.0.0" + buffer-from "^1.1.0" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.5.6" + yn "^2.0.0" + +tsconfig-paths@^3.5.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" + integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + tslib@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" @@ -9533,6 +9581,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@^3.7.3: + version "3.7.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.3.tgz#b36840668a16458a7025b9eabfad11b66ab85c69" + integrity sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw== + uglify-js@^3.1.4: version "3.6.0" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.0.tgz#704681345c53a8b2079fb6cec294b05ead242ff5" @@ -10107,3 +10160,8 @@ yargs@^7.0.0: which-module "^1.0.0" y18n "^3.2.1" yargs-parser "^5.0.0" + +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + integrity sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=