diff --git a/.eslintignore b/.eslintignore index 577dfdb51a1..4a85947e5b9 100644 --- a/.eslintignore +++ b/.eslintignore @@ -16,8 +16,9 @@ test/**/**/dist/ test/**/**/**/dist/ test/**/**/index.js test/binCases/config-location/webpack-babel-config/bin/es6.js -packages/**/*.js +packages/**/lib packages/utils/validate-identifier.ts -lib/utils/interactive.js \ No newline at end of file +lib/utils/interactive.js +test/typescript/webpack.config.ts diff --git a/package.json b/package.json index f2f17530ddf..1ceb3c7e0cf 100644 --- a/package.json +++ b/package.json @@ -23,21 +23,18 @@ "bundler", "web" ], - "files": [ - "lib", - "bin/cli.js" - ], "workspaces": [ "./packages/*" ], "scripts": { "bootstrap": "lerna bootstrap", - "build": "tsc", + "build": "node scripts/buildPackages.js", "clean:all": "rimraf node_modules packages/*/{node_modules}", "commit": "git-cz", "docs": "typedoc", "format": "eslint --fix . --ext .js,.ts", "lint": "eslint . --ext .js,.ts", + "lint:fix": "eslint . --ext .js,.ts --fix", "pretest": "yarn build && yarn lint", "reportCoverage": "nyc report --reporter=json && codecov -f coverage/coverage-final.json --disable=gcov", "smoketest": "smoketests/smoketests.sh", diff --git a/packages/generate-loader/.gitignore b/packages/generate-loader/.gitignore index a6c7c2852d0..8a04eb86df7 100644 --- a/packages/generate-loader/.gitignore +++ b/packages/generate-loader/.gitignore @@ -1 +1,2 @@ *.js +lib/ diff --git a/packages/generate-loader/src/_index.js.tpl b/packages/generate-loader/lib/_index.js.tpl similarity index 100% rename from packages/generate-loader/src/_index.js.tpl rename to packages/generate-loader/lib/_index.js.tpl diff --git a/packages/generate-loader/src/cjs.js.tpl b/packages/generate-loader/lib/cjs.js.tpl similarity index 100% rename from packages/generate-loader/src/cjs.js.tpl rename to packages/generate-loader/lib/cjs.js.tpl diff --git a/packages/generate-loader/package.json b/packages/generate-loader/package.json index b4cb8b57920..6fe688a926c 100644 --- a/packages/generate-loader/package.json +++ b/packages/generate-loader/package.json @@ -2,7 +2,8 @@ "name": "@webpack-cli/generate-loader", "version": "1.0.1-alpha.0", "description": "A scaffold for generating a loader", - "main": "index.js", + "main": "lib/index.js", + "types": "lib/index.d.ts", "directories": { "example": "examples", "test": "test" @@ -24,5 +25,10 @@ "scripts": { "build": "tsc", "watch": "npm run build && tsc -w" - } + }, + "files": [ + "lib", + "templates", + "examples" + ] } diff --git a/packages/generate-loader/index.ts b/packages/generate-loader/src/index.ts similarity index 60% rename from packages/generate-loader/index.ts rename to packages/generate-loader/src/index.ts index 8f280fc6226..0e37a46ba94 100644 --- a/packages/generate-loader/index.ts +++ b/packages/generate-loader/src/index.ts @@ -1,5 +1,5 @@ -import LoaderGenerator from "@webpack-cli/generators/loader-generator"; -import * as yeoman from "yeoman-environment"; +import { loaderGenerator } from "@webpack-cli/generators"; +import yeoman from "yeoman-environment"; /** * Runs a yeoman generator to create a new webpack loader project @@ -10,7 +10,7 @@ export default function loaderCreator(): void { const env = yeoman.createEnv(); const generatorName = "webpack-loader-generator"; - env.registerStub(LoaderGenerator, generatorName); + env.registerStub(loaderGenerator, generatorName); env.run(generatorName); } diff --git a/packages/generate-loader/tsconfig.json b/packages/generate-loader/tsconfig.json index 8b1269a36b6..9a8c2d505a1 100644 --- a/packages/generate-loader/tsconfig.json +++ b/packages/generate-loader/tsconfig.json @@ -1,3 +1,12 @@ -{ - "extends": "../../tsconfig.packages.json" -} +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"], + "references": [ + {"path": "../generators"} + ] +} diff --git a/packages/generate-plugin/.gitignore b/packages/generate-plugin/.gitignore index a6c7c2852d0..8a04eb86df7 100644 --- a/packages/generate-plugin/.gitignore +++ b/packages/generate-plugin/.gitignore @@ -1 +1,2 @@ *.js +lib/ diff --git a/packages/generate-plugin/src/_index.js.tpl b/packages/generate-plugin/lib/_index.js.tpl similarity index 100% rename from packages/generate-plugin/src/_index.js.tpl rename to packages/generate-plugin/lib/_index.js.tpl diff --git a/packages/generate-plugin/src/cjs.js.tpl b/packages/generate-plugin/lib/cjs.js.tpl similarity index 100% rename from packages/generate-plugin/src/cjs.js.tpl rename to packages/generate-plugin/lib/cjs.js.tpl diff --git a/packages/generate-plugin/package.json b/packages/generate-plugin/package.json index e3259394e03..3588b1f4b9e 100644 --- a/packages/generate-plugin/package.json +++ b/packages/generate-plugin/package.json @@ -2,7 +2,7 @@ "name": "@webpack-cli/generate-plugin", "version": "1.0.1-alpha.0", "description": "A scaffold for generating a plugin", - "main": "index.js", + "main": "src/index.js", "directories": { "example": "examples", "test": "test" @@ -24,5 +24,10 @@ "scripts": { "build": "tsc", "watch": "npm run build && tsc -w" - } + }, + "files": [ + "lib", + "templates", + "examples" + ] } diff --git a/packages/generate-plugin/index.ts b/packages/generate-plugin/src/index.ts similarity index 60% rename from packages/generate-plugin/index.ts rename to packages/generate-plugin/src/index.ts index 50448da6713..829936f3640 100644 --- a/packages/generate-plugin/index.ts +++ b/packages/generate-plugin/src/index.ts @@ -1,5 +1,5 @@ -import PluginGenerator from "@webpack-cli/generators/plugin-generator"; -import * as yeoman from "yeoman-environment"; +import { pluginGenerator } from "@webpack-cli/generators"; +import yeoman from "yeoman-environment"; /** * Runs a yeoman generator to create a new webpack plugin project @@ -10,7 +10,7 @@ export default function pluginCreator(): void { const env = yeoman.createEnv(); const generatorName = "webpack-plugin-generator"; - env.registerStub(PluginGenerator, generatorName); + env.registerStub(pluginGenerator, generatorName); env.run(generatorName); } diff --git a/packages/generate-plugin/tsconfig.json b/packages/generate-plugin/tsconfig.json index 8b1269a36b6..534b7fbe0bf 100644 --- a/packages/generate-plugin/tsconfig.json +++ b/packages/generate-plugin/tsconfig.json @@ -1,3 +1,10 @@ -{ - "extends": "../../tsconfig.packages.json" -} +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"], + "references": [{ "path": "../generators" }] +} diff --git a/packages/generators/.gitignore b/packages/generators/.gitignore index b3cdf36cae7..3c16bb63d13 100644 --- a/packages/generators/.gitignore +++ b/packages/generators/.gitignore @@ -3,3 +3,4 @@ !*.test.js !/**/*.test.js !/templates/*.js +lib/ diff --git a/packages/generators/__tests__/init-generator.test.ts b/packages/generators/__tests__/init-generator.test.ts index 9bd9ad38ab8..0b294ab2554 100644 --- a/packages/generators/__tests__/init-generator.test.ts +++ b/packages/generators/__tests__/init-generator.test.ts @@ -4,7 +4,7 @@ import { run } from 'yeoman-test'; // fixme: unstable describe('init generator', () => { it('generates a webpack project config', async () => { - const outputDir = await run(join(__dirname, '../init-generator')).withPrompts({ + const outputDir = await run(join(__dirname, '../src/init-generator')).withPrompts({ multiEntries: false, singularEntry: 'src/index2', outputDir: 'dist2', diff --git a/packages/generators/__tests__/loader-generator.test.ts b/packages/generators/__tests__/loader-generator.test.ts index 55707ac105c..70dfdb8c354 100644 --- a/packages/generators/__tests__/loader-generator.test.ts +++ b/packages/generators/__tests__/loader-generator.test.ts @@ -2,7 +2,7 @@ import { join } from 'path'; import { run } from 'yeoman-test'; import assert from 'yeoman-assert'; -import { makeLoaderName } from '../loader-generator'; +import { makeLoaderName } from '../src/loader-generator'; describe('loader generator', () => { it.skip('generates a default loader', async () => { diff --git a/packages/generators/__tests__/plugin-generator.test.ts b/packages/generators/__tests__/plugin-generator.test.ts index aa4641279ea..e0cbc533efb 100644 --- a/packages/generators/__tests__/plugin-generator.test.ts +++ b/packages/generators/__tests__/plugin-generator.test.ts @@ -2,7 +2,7 @@ import { join } from 'path'; import { run } from 'yeoman-test'; import assert from 'yeoman-assert'; -import { generatePluginName } from '../utils'; +import { generatePluginName } from '../src/utils'; describe('plugin generator', () => { it.skip('generates a default plugin', async () => { diff --git a/packages/generators/addon-generator.ts b/packages/generators/addon-generator.ts deleted file mode 100644 index c287fedba90..00000000000 --- a/packages/generators/addon-generator.ts +++ /dev/null @@ -1,80 +0,0 @@ -import * as mkdirp from "mkdirp"; -import * as path from "path"; -import * as Generator from "yeoman-generator"; - -import * as copyUtils from "@webpack-cli/utils/copy-utils"; - -/** - * Creates a Yeoman Generator that generates a project conforming - * to webpack-defaults. - * - * @param {Generator.Questions} prompts An array of Yeoman prompt objects - * - * @param {string} templateDir Absolute path to template directory - * - * @param {string[]} copyFiles An array of file paths (relative to `./templates`) - * of files to be copied to the generated project. File paths should be of the - * form `path/to/file.js.tpl`. - * - * @param {string[]} copyTemplateFiles An array of file paths (relative to - * `./templates`) of files to be copied to the generated project. Template - * file paths should be of the form `path/to/_file.js.tpl`. - * - * @param {Function} templateFn A function that is passed a generator instance and - * returns an object containing data to be supplied to the template files. - * - * @returns {Generator} A class extending Generator - */ -const addonGenerator = ( - prompts: Generator.Questions, - templateDir: string, - copyFiles: string[], - copyTemplateFiles: string[], - templateFn: Function -): typeof Generator => - class AddonGenerator extends Generator { - public props: Generator.Question; - public copy: (value: string, index: number, array: string[]) => void; - public copyTpl: (value: string, index: number, array: string[]) => void; - - public prompting(): Promise { - return this.prompt(prompts).then((props: Generator.Question): void => { - this.props = props; - }); - } - - public default(): void { - const currentDirName = path.basename(this.destinationPath()); - if (currentDirName !== this.props.name) { - this.log(` - Your project must be inside a folder named ${this.props.name} - I will create this folder for you. - `); - mkdirp(this.props.name, (err: object): void => { - if (err) console.error("Failed to create directory", err); - }); - const pathToProjectDir: string = this.destinationPath(this.props.name); - this.destinationRoot(pathToProjectDir); - } - } - - public writing(): void { - this.copy = copyUtils.generatorCopy(this, templateDir); - this.copyTpl = copyUtils.generatorCopyTpl(this, templateDir, templateFn(this)); - - copyFiles.forEach(this.copy); - copyTemplateFiles.forEach(this.copyTpl); - } - - public install(): void { - this.npmInstall(["webpack-defaults", "bluebird"], { - "save-dev": true - }); - } - - public end(): void { - this.spawnCommand("npm", ["run", "defaults"]); - } - }; - -export default addonGenerator; diff --git a/packages/generators/package.json b/packages/generators/package.json index aa8d9e8e3b0..c884a5f9480 100644 --- a/packages/generators/package.json +++ b/packages/generators/package.json @@ -2,7 +2,8 @@ "name": "@webpack-cli/generators", "version": "1.0.1-alpha.0", "description": "Webpack-CLI generators", - "main": "index.js", + "main": "lib/index.js", + "types": "lib/index.d.ts", "keywords": [], "author": "", "license": "MIT", @@ -12,7 +13,8 @@ "dependencies": { "@webpack-cli/utils": "^1.0.1-alpha.0", "@webpack-cli/webpack-scaffold": "^1.0.1-alpha.0", - "chalk": "2.4.2", + "@webpack-cli/package-utils": "^1.0.0", + "chalk": "3.0.0", "glob-all": "3.1.0", "inquirer-autocomplete-prompt": "1.0.1", "lodash": "4.17.15", @@ -21,6 +23,7 @@ "webpack": "4.x.x", "webpack-dev-server": "3.8.0", "yeoman-generator": "4.5.0" + }, "peerDependencies": { "webpack": "4.x.x" @@ -42,5 +45,9 @@ "scripts": { "build": "tsc", "watch": "npm run build && tsc -w" - } + }, + "files": [ + "lib", + "templates" + ] } diff --git a/packages/generators/src/addon-generator.ts b/packages/generators/src/addon-generator.ts new file mode 100644 index 00000000000..b9ef59e69c3 --- /dev/null +++ b/packages/generators/src/addon-generator.ts @@ -0,0 +1,80 @@ +import mkdirp from 'mkdirp'; +import path from 'path'; +import Generator from 'yeoman-generator'; +import { generatorCopy, generatorCopyTpl } from '@webpack-cli/utils'; + +/** + * Creates a Yeoman Generator that generates a project conforming + * to webpack-defaults. + * + * @param {Generator.Questions} prompts An array of Yeoman prompt objects + * + * @param {string} templateDir Absolute path to template directory + * + * @param {string[]} copyFiles An array of file paths (relative to `./templates`) + * of files to be copied to the generated project. File paths should be of the + * form `path/to/file.js.tpl`. + * + * @param {string[]} copyTemplateFiles An array of file paths (relative to + * `./templates`) of files to be copied to the generated project. Template + * file paths should be of the form `path/to/_file.js.tpl`. + * + * @param {Function} templateFn A function that is passed a generator instance and + * returns an object containing data to be supplied to the template files. + * + * @returns {Generator} A class extending Generator + */ +const addonGenerator = ( + prompts: Generator.Questions, + templateDir: string, + copyFiles: string[], + copyTemplateFiles: string[], + templateFn: Function, +): typeof Generator => { + return class extends Generator { + public props: Generator.Question; + public copy: (value: string, index: number, array: string[]) => void; + public copyTpl: (value: string, index: number, array: string[]) => void; + + public prompting(): Promise { + return this.prompt(prompts).then((props: Generator.Question): void => { + this.props = props; + }); + } + + public default(): void { + const currentDirName = path.basename(this.destinationPath()); + if (currentDirName !== this.props.name) { + this.log(` + Your project must be inside a folder named ${this.props.name} + I will create this folder for you. + `); + mkdirp(this.props.name, (err: object): void => { + if (err) console.error('Failed to create directory', err); + }); + const pathToProjectDir: string = this.destinationPath(this.props.name); + this.destinationRoot(pathToProjectDir); + } + } + + public writing(): void { + this.copy = generatorCopy(this, templateDir); + this.copyTpl = generatorCopyTpl(this, templateDir, templateFn(this)); + + copyFiles.forEach(this.copy); + copyTemplateFiles.forEach(this.copyTpl); + } + + public install(): void { + this.npmInstall(['webpack-defaults', 'bluebird'], { + 'save-dev': true, + }); + } + + public end(): void { + this.spawnCommand('npm', ['run', 'defaults']); + } + }; +}; + +export default addonGenerator; diff --git a/packages/generators/index.ts b/packages/generators/src/index.ts similarity index 100% rename from packages/generators/index.ts rename to packages/generators/src/index.ts diff --git a/packages/generators/init-generator.ts b/packages/generators/src/init-generator.ts similarity index 92% rename from packages/generators/init-generator.ts rename to packages/generators/src/init-generator.ts index 3ff8df4674a..7a07f7a122a 100644 --- a/packages/generators/init-generator.ts +++ b/packages/generators/src/init-generator.ts @@ -1,9 +1,8 @@ import chalk from "chalk"; -import * as logSymbols from "log-symbols"; -import * as Generator from "yeoman-generator"; -import * as path from "path"; - -import { getPackageManager } from "@webpack-cli/utils/package-manager"; +import logSymbols from "log-symbols"; +import Generator from "yeoman-generator"; +import path from "path"; +import { getPackageManager } from "@webpack-cli/package-utils"; import { Confirm, Input, List } from "@webpack-cli/webpack-scaffold"; import { @@ -259,17 +258,17 @@ export default class InitGenerator extends Generator { if (this.langType === "ES6") { this.fs.copyTpl( - path.resolve(__dirname, "./templates/.babelrc"), + path.resolve(__dirname, "../templates/.babelrc"), this.destinationPath(".babelrc"), {} ); } - const packageJsonTemplatePath = "./templates/package.json.js"; + const packageJsonTemplatePath = "../templates/package.json.js"; this.fs.extendJSON(this.destinationPath("package.json"), require(packageJsonTemplatePath)(this.usingDefaults)); const generateEntryFile = (entryPath: string, name: string): void => { entryPath = entryPath.replace(/'/g, ""); - this.fs.copyTpl(path.resolve(__dirname, "./templates/index.js"), this.destinationPath(entryPath), { name }); + this.fs.copyTpl(path.resolve(__dirname, "../templates/index.js"), this.destinationPath(entryPath), { name }); }; // Generate entry file/files @@ -281,12 +280,12 @@ export default class InitGenerator extends Generator { } // Generate README - this.fs.copyTpl(path.resolve(__dirname, "./templates/README.md"), this.destinationPath("README.md"), {}); + this.fs.copyTpl(path.resolve(__dirname, "../templates/README.md"), this.destinationPath("README.md"), {}); // Generate HTML template file, copy the default service worker if (this.usingDefaults) { this.fs.copyTpl( - path.resolve(__dirname, "./templates/template.html"), + path.resolve(__dirname, "../templates/template.html"), this.destinationPath("index.html"), {} ); @@ -295,7 +294,7 @@ export default class InitGenerator extends Generator { // Generate tsconfig if (this.langType === LangType.Typescript) { - const tsConfigTemplatePath = "./templates/tsconfig.json.js"; + const tsConfigTemplatePath = "../templates/tsconfig.json.js"; this.fs.extendJSON(this.destinationPath("tsconfig.json"), require(tsConfigTemplatePath)); } } diff --git a/packages/generators/loader-generator.ts b/packages/generators/src/loader-generator.ts similarity index 95% rename from packages/generators/loader-generator.ts rename to packages/generators/src/loader-generator.ts index e36dab18f4d..f594a93e14f 100644 --- a/packages/generators/loader-generator.ts +++ b/packages/generators/src/loader-generator.ts @@ -1,6 +1,5 @@ -import * as _ from "lodash"; -import * as path from "path"; - +import _ from "lodash"; +import path from "path"; import addonGenerator from "./addon-generator"; /** diff --git a/packages/generators/plugin-generator.ts b/packages/generators/src/plugin-generator.ts similarity index 93% rename from packages/generators/plugin-generator.ts rename to packages/generators/src/plugin-generator.ts index 22a0295332e..36147b64d51 100644 --- a/packages/generators/plugin-generator.ts +++ b/packages/generators/src/plugin-generator.ts @@ -1,6 +1,5 @@ -import * as _ from "lodash"; -import * as path from "path"; - +import _ from "lodash"; +import path from "path"; import addonGenerator from "./addon-generator"; /** diff --git a/packages/generators/types/index.ts b/packages/generators/src/types/index.ts similarity index 100% rename from packages/generators/types/index.ts rename to packages/generators/src/types/index.ts diff --git a/packages/generators/update-generator.ts b/packages/generators/src/update-generator.ts similarity index 55% rename from packages/generators/update-generator.ts rename to packages/generators/src/update-generator.ts index f5c3060de66..83e32c6dbda 100644 --- a/packages/generators/update-generator.ts +++ b/packages/generators/src/update-generator.ts @@ -1,3 +1,3 @@ -import * as Generator from "yeoman-generator"; +import Generator from "yeoman-generator"; export default class UpdateGenerator extends Generator {} diff --git a/packages/generators/utils/entry.ts b/packages/generators/src/utils/entry.ts similarity index 98% rename from packages/generators/utils/entry.ts rename to packages/generators/src/utils/entry.ts index a57538c54da..10321a1ad60 100644 --- a/packages/generators/utils/entry.ts +++ b/packages/generators/src/utils/entry.ts @@ -1,4 +1,4 @@ -import * as Generator from "yeoman-generator"; +import Generator from "yeoman-generator"; import { Input, InputValidate } from "@webpack-cli/webpack-scaffold"; import validate from "./validate"; diff --git a/packages/generators/utils/index.ts b/packages/generators/src/utils/index.ts similarity index 100% rename from packages/generators/utils/index.ts rename to packages/generators/src/utils/index.ts diff --git a/packages/generators/utils/languageSupport.ts b/packages/generators/src/utils/languageSupport.ts similarity index 100% rename from packages/generators/utils/languageSupport.ts rename to packages/generators/src/utils/languageSupport.ts diff --git a/packages/generators/utils/optionsSchema.json b/packages/generators/src/utils/optionsSchema.json similarity index 100% rename from packages/generators/utils/optionsSchema.json rename to packages/generators/src/utils/optionsSchema.json diff --git a/packages/generators/utils/plugins.ts b/packages/generators/src/utils/plugins.ts similarity index 100% rename from packages/generators/utils/plugins.ts rename to packages/generators/src/utils/plugins.ts diff --git a/packages/generators/utils/styleSupport.ts b/packages/generators/src/utils/styleSupport.ts similarity index 100% rename from packages/generators/utils/styleSupport.ts rename to packages/generators/src/utils/styleSupport.ts diff --git a/packages/generators/utils/tooltip.ts b/packages/generators/src/utils/tooltip.ts similarity index 100% rename from packages/generators/utils/tooltip.ts rename to packages/generators/src/utils/tooltip.ts diff --git a/packages/generators/utils/validate.ts b/packages/generators/src/utils/validate.ts similarity index 100% rename from packages/generators/utils/validate.ts rename to packages/generators/src/utils/validate.ts diff --git a/packages/generators/utils/webpackConfig.ts b/packages/generators/src/utils/webpackConfig.ts similarity index 100% rename from packages/generators/utils/webpackConfig.ts rename to packages/generators/src/utils/webpackConfig.ts diff --git a/packages/generators/templates/package.json.js b/packages/generators/templates/package.json.js index f1db2f046fe..95f84661e6e 100644 --- a/packages/generators/templates/package.json.js +++ b/packages/generators/templates/package.json.js @@ -1,5 +1,6 @@ +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type module.exports = usingDefaults => { - let scripts = { + const scripts = { build: "webpack" }; if (usingDefaults) { diff --git a/packages/generators/tsconfig.json b/packages/generators/tsconfig.json index 9707d6cc9de..03a222fce7c 100644 --- a/packages/generators/tsconfig.json +++ b/packages/generators/tsconfig.json @@ -1,6 +1,10 @@ -{ - "extends": "../../tsconfig.packages.json", - "compilerOptions": { - "allowJs": true - } -} +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"], + "references": [{ "path": "../utils" }, { "path": "../webpack-scaffold" }, { "path": "../package-utils" }] +} diff --git a/packages/info/.gitignore b/packages/info/.gitignore index a6c7c2852d0..8a04eb86df7 100644 --- a/packages/info/.gitignore +++ b/packages/info/.gitignore @@ -1 +1,2 @@ *.js +lib/ diff --git a/packages/info/__tests__/index.test.ts b/packages/info/__tests__/index.test.ts index d0c1e95c002..7fbfe686086 100644 --- a/packages/info/__tests__/index.test.ts +++ b/packages/info/__tests__/index.test.ts @@ -1,4 +1,4 @@ -import { informationType } from "../index"; +import { informationType } from "../src"; describe("infoSystem", () => { it("should return the information of the system", async () => { diff --git a/packages/info/package.json b/packages/info/package.json index b3b0a6ce993..1fa58d18c7e 100644 --- a/packages/info/package.json +++ b/packages/info/package.json @@ -2,7 +2,8 @@ "name": "@webpack-cli/info", "version": "1.0.1-alpha.0", "description": "Outputs info about system and webpack config", - "main": "index.js", + "main": "lib/index.js", + "type": "lib/index.d.ts", "author": "", "license": "MIT", "publishConfig": { @@ -10,7 +11,7 @@ }, "dependencies": { "@types/yargs": "13.0.0", - "chalk": "2.4.2", + "chalk": "3.0.0", "cli-table3": "0.5.1", "envinfo": "7.3.1", "prettyjson": "1.2.1", @@ -23,5 +24,8 @@ "scripts": { "build": "tsc", "watch": "npm run build && tsc -w" - } + }, + "files": [ + "lib" + ] } diff --git a/packages/info/commands.ts b/packages/info/src/commands.ts similarity index 100% rename from packages/info/commands.ts rename to packages/info/src/commands.ts diff --git a/packages/info/configParser.ts b/packages/info/src/configParser.ts similarity index 93% rename from packages/info/configParser.ts rename to packages/info/src/configParser.ts index 1ce02ca406e..b0d840e36b5 100644 --- a/packages/info/configParser.ts +++ b/packages/info/src/configParser.ts @@ -1,6 +1,6 @@ -import * as path from 'path'; -import chalk from 'chalk'; -import * as prettyjson from 'prettyjson'; +import path from 'path'; +import chalk = require('chalk'); +import prettyjson from 'prettyjson'; export function getNameFromPath(fullPath: string): string { const filename = fullPath.replace(/^.*[\\\/]/, ''); diff --git a/packages/info/index.ts b/packages/info/src/index.ts similarity index 97% rename from packages/info/index.ts rename to packages/info/src/index.ts index 37fec97a81e..410eb351790 100644 --- a/packages/info/index.ts +++ b/packages/info/src/index.ts @@ -1,6 +1,6 @@ -import chalk from 'chalk'; -import * as envinfo from 'envinfo'; -import * as process from 'process'; +import chalk = require('chalk'); +import envinfo from 'envinfo'; +import process from 'process'; import { argv } from './options'; import { AVAILABLE_COMMANDS, AVAILABLE_FORMATS, IGNORE_FLAGS } from './commands'; diff --git a/packages/info/options.ts b/packages/info/src/options.ts similarity index 96% rename from packages/info/options.ts rename to packages/info/src/options.ts index 1677fc51ab5..5683baece95 100644 --- a/packages/info/options.ts +++ b/packages/info/src/options.ts @@ -1,4 +1,4 @@ -import * as yargs from "yargs"; +import yargs from "yargs"; export const argv = yargs .option("system", { alias: "s", diff --git a/packages/info/renderTable.ts b/packages/info/src/renderTable.ts similarity index 89% rename from packages/info/renderTable.ts rename to packages/info/src/renderTable.ts index c650e005a02..9431f720bb4 100644 --- a/packages/info/renderTable.ts +++ b/packages/info/src/renderTable.ts @@ -1,4 +1,4 @@ -import * as Table from "cli-table3"; +import Table from "cli-table3"; import chalk from "chalk"; export function renderTable(data, fileName): string { const table = new Table({ diff --git a/packages/info/tsconfig.json b/packages/info/tsconfig.json index 8b1269a36b6..fd0ff87aea4 100644 --- a/packages/info/tsconfig.json +++ b/packages/info/tsconfig.json @@ -1,3 +1,9 @@ -{ - "extends": "../../tsconfig.packages.json" -} +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"] +} diff --git a/packages/init/.gitignore b/packages/init/.gitignore index 6d6c6e81408..c3af857904e 100644 --- a/packages/init/.gitignore +++ b/packages/init/.gitignore @@ -1,2 +1 @@ -*.js -types/*.js +lib/ diff --git a/packages/init/init.ts b/packages/init/init.ts deleted file mode 100644 index 1b6a056994e..00000000000 --- a/packages/init/init.ts +++ /dev/null @@ -1,82 +0,0 @@ -import chalk from "chalk"; -import * as j from "jscodeshift"; -import pEachSeries = require("p-each-series"); -import * as path from "path"; - -import propTypes from "@webpack-cli/utils/prop-types"; -import astTransform from "@webpack-cli/utils/recursive-parser"; -import runPrettier from "@webpack-cli/utils/run-prettier"; - -import { Node } from "./types/NodePath"; -import { Error } from "./types"; -import { Configuration, WebpackProperties } from "./types/Transform"; - -/** - * - * Maps back transforms that needs to be run using the configuration - * provided. - * - * @param {Object} transformObject - An Object with all transformations - * @param {Object} config - Configuration to transform - * @returns {Array} - An array with the transformations to be run - */ - -const mapOptionsToTransform = (config: Configuration): string[] => - Object.keys(config.webpackOptions).filter((key: string): boolean => propTypes.has(key)); - -/** - * - * Runs the transformations from an object we get from yeoman - * - * @param {Object} webpackProperties - Configuration to transform - * @param {String} action - Action to be done on the given ast - * @returns {Promise} - A promise that writes each transform, runs prettier - * and writes the file - */ - -export default function runTransform(webpackProperties: WebpackProperties, action: string): void { - // webpackOptions.name sent to nameTransform if match - const webpackConfig: string[] = Object.keys(webpackProperties).filter( - (p: string): boolean => p !== "configFile" && p !== "configPath" - ); - - const initActionNotDefined = (action && action !== "init") || false; - - webpackConfig.forEach( - (scaffoldPiece: string): Promise => { - const config: Configuration = webpackProperties[scaffoldPiece]; - const transformations = mapOptionsToTransform(config); - const ast = j(initActionNotDefined ? webpackProperties.configFile : "module.exports = {}"); - const transformAction: string | null = action || null; - - return pEachSeries(transformations, (f: string): boolean | Node => { - return astTransform(j, ast, config.webpackOptions[f], transformAction, f); - }) - .then((): void | PromiseLike => { - let configurationName = "webpack.config.js"; - if (config.configName) { - configurationName = `webpack.${config.configName}.js`; - } - - const outputPath = initActionNotDefined - ? webpackProperties.configPath - : path.join(process.cwd(), configurationName); - - const source: string = ast.toSource({ - quote: "single" - }); - - runPrettier(outputPath, source); - }) - .catch((err: Error): void => { - console.error(err.message ? err.message : err); - }); - } - ); - - let successMessage = `Congratulations! Your new webpack configuration file has been created!`; - if (initActionNotDefined && webpackProperties.config.item) { - successMessage = `Congratulations! ${webpackProperties.config.item} has been ${action}ed!`; - } - process.stdout.write("\n" + chalk.green(`${successMessage}\n`)); -} diff --git a/packages/init/package.json b/packages/init/package.json index 79c9a238169..b8005a1e107 100644 --- a/packages/init/package.json +++ b/packages/init/package.json @@ -11,7 +11,7 @@ "dependencies": { "@webpack-cli/generators": "^1.0.1-alpha.0", "@webpack-cli/utils": "^1.0.1-alpha.0", - "chalk": "2.4.2", + "chalk": "3.0.0", "jscodeshift": "0.6.4", "p-each-series": "2.1.0" }, @@ -23,5 +23,8 @@ "scripts": { "build": "tsc", "watch": "npm run build && tsc -w" - } + }, + "files": [ + "lib" + ] } diff --git a/packages/init/index.ts b/packages/init/src/index.ts similarity index 71% rename from packages/init/index.ts rename to packages/init/src/index.ts index 00509913f4f..e07d1939ed4 100644 --- a/packages/init/index.ts +++ b/packages/init/src/index.ts @@ -1,6 +1,5 @@ -import defaultGenerator from '@webpack-cli/generators/init-generator'; -import modifyConfigHelper from '@webpack-cli/utils/modify-config-helper'; -import npmPackagesExists from '@webpack-cli/utils/npm-packages-exists'; +import { initGenerator } from '@webpack-cli/generators'; +import { modifyHelperUtil, npmPackagesExists } from '@webpack-cli/utils'; const AUTO_PREFIX = '--auto'; @@ -19,7 +18,7 @@ export default function initializeInquirer(...args: string[]): Function | void { const packages = args; const includesDefaultPrefix = packages.includes(AUTO_PREFIX); if (packages.length === 0 || includesDefaultPrefix) { - return modifyConfigHelper('init', defaultGenerator, null, null, includesDefaultPrefix); + return modifyHelperUtil('init', initGenerator, null, null, includesDefaultPrefix); } return npmPackagesExists(packages); } diff --git a/packages/init/src/init.ts b/packages/init/src/init.ts new file mode 100644 index 00000000000..1b9a170480b --- /dev/null +++ b/packages/init/src/init.ts @@ -0,0 +1,74 @@ +import chalk = require('chalk'); +import j from 'jscodeshift'; +import pEachSeries = require('p-each-series'); +import path from 'path'; +import { PROP_TYPES, runPrettier, recursiveTransform } from '@webpack-cli/utils'; +import { Node } from './types/NodePath'; +import { Error } from './types'; +import { Configuration, WebpackProperties } from './types/Transform'; + +/** + * + * Maps back transforms that needs to be run using the configuration + * provided. + * + * @param {Object} transformObject - An Object with all transformations + * @param {Object} config - Configuration to transform + * @returns {Array} - An array with the transformations to be run + */ + +const mapOptionsToTransform = (config: Configuration): string[] => + Object.keys(config.webpackOptions).filter((key: string): boolean => PROP_TYPES.has(key)); + +/** + * + * Runs the transformations from an object we get from yeoman + * + * @param {Object} webpackProperties - Configuration to transform + * @param {String} action - Action to be done on the given ast + * @returns {Promise} - A promise that writes each transform, runs prettier + * and writes the file + */ + +export default function runTransform(webpackProperties: WebpackProperties, action: string): void { + // webpackOptions.name sent to nameTransform if match + const webpackConfig: string[] = Object.keys(webpackProperties).filter((p: string): boolean => p !== 'configFile' && p !== 'configPath'); + + const initActionNotDefined = (action && action !== 'init') || false; + + webpackConfig.forEach( + (scaffoldPiece: string): Promise => { + const config: Configuration = webpackProperties[scaffoldPiece]; + const transformations = mapOptionsToTransform(config); + const ast = j(initActionNotDefined ? webpackProperties.configFile : 'module.exports = {}'); + const transformAction: string | null = action || null; + + return pEachSeries(transformations, (f: string): boolean | Node => { + return recursiveTransform(j, ast, config.webpackOptions[f], transformAction, f); + }) + .then((): void | PromiseLike => { + let configurationName = 'webpack.config.js'; + if (config.configName) { + configurationName = `webpack.${config.configName}.js`; + } + + const outputPath = initActionNotDefined ? webpackProperties.configPath : path.join(process.cwd(), configurationName); + + const source: string = ast.toSource({ + quote: 'single', + }); + + runPrettier(outputPath, source); + }) + .catch((err: Error): void => { + console.error(err.message ? err.message : err); + }); + }, + ); + + let successMessage = `Congratulations! Your new webpack configuration file has been created!`; + if (initActionNotDefined && webpackProperties.config.item) { + successMessage = `Congratulations! ${webpackProperties.config.item} has been ${action}ed!`; + } + process.stdout.write('\n' + chalk.green(`${successMessage}\n`)); +} diff --git a/packages/init/types/NodePath.ts b/packages/init/src/types/NodePath.ts similarity index 100% rename from packages/init/types/NodePath.ts rename to packages/init/src/types/NodePath.ts diff --git a/packages/init/types/Transform.ts b/packages/init/src/types/Transform.ts similarity index 100% rename from packages/init/types/Transform.ts rename to packages/init/src/types/Transform.ts diff --git a/packages/init/types/index.ts b/packages/init/src/types/index.ts similarity index 100% rename from packages/init/types/index.ts rename to packages/init/src/types/index.ts diff --git a/packages/init/tsconfig.json b/packages/init/tsconfig.json index 8b1269a36b6..e79ddebf0aa 100644 --- a/packages/init/tsconfig.json +++ b/packages/init/tsconfig.json @@ -1,3 +1,10 @@ -{ - "extends": "../../tsconfig.packages.json" -} +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"], + "references": [{ "path": "../generators" }, { "path": "../utils" }] +} diff --git a/packages/logger/.eslintrc b/packages/logger/.eslintrc new file mode 100644 index 00000000000..e8b8b926974 --- /dev/null +++ b/packages/logger/.eslintrc @@ -0,0 +1,10 @@ +{ + "root": true, + "extends": [ + "plugin:@typescript-eslint/recommended", + "prettier", + "prettier/@typescript-eslint" + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], +} diff --git a/packages/logger/.gitignore b/packages/logger/.gitignore new file mode 100644 index 00000000000..c3af857904e --- /dev/null +++ b/packages/logger/.gitignore @@ -0,0 +1 @@ +lib/ diff --git a/packages/logger/README.md b/packages/logger/README.md new file mode 100644 index 00000000000..0d0dfe07cfd --- /dev/null +++ b/packages/logger/README.md @@ -0,0 +1,11 @@ +# `@webpack-cli/logger` + +> TODO: description + +## Usage + +``` +const logger = require('@webpack-cli/logger'); + +// TODO: DEMONSTRATE API +``` diff --git a/packages/logger/package.json b/packages/logger/package.json new file mode 100644 index 00000000000..ade62b0956c --- /dev/null +++ b/packages/logger/package.json @@ -0,0 +1,37 @@ +{ + "name": "@webpack-cli/logger", + "version": "1.0.0", + "description": "webpack CLI logger instance", + "keywords": [ + "webpack", + "webpack-cli", + "logger" + ], + "author": "emanuele ", + "homepage": "https://github.com/ematipico/webpack-cli#readme", + "license": "MIT", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "directories": { + "test": "__tests__" + }, + "files": [ + "src" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ematipico/webpack-cli.git" + }, + "scripts": { + "test": "echo \"Error: run tests from root\" && exit 1" + }, + "bugs": { + "url": "https://github.com/ematipico/webpack-cli/issues" + }, + "peerDependencies": { + "webpack": "^4.41.6" + } +} diff --git a/packages/logger/src/index.ts b/packages/logger/src/index.ts new file mode 100644 index 00000000000..52bbfcffa25 --- /dev/null +++ b/packages/logger/src/index.ts @@ -0,0 +1,6 @@ +import logging from 'webpack/lib/logging/runtime'; + +// Get a logger +const logger = logging.getLogger('webpack-cli'); + +export { logger }; diff --git a/packages/logger/tsconfig.json b/packages/logger/tsconfig.json new file mode 100644 index 00000000000..fd0ff87aea4 --- /dev/null +++ b/packages/logger/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"] +} diff --git a/packages/migrate/.gitignore b/packages/migrate/.gitignore index 04d5044e769..c3af857904e 100644 --- a/packages/migrate/.gitignore +++ b/packages/migrate/.gitignore @@ -1,6 +1 @@ -/*.js -/**/*.js -!*.test.js -!/**/*.test.js -!/**/__testfixtures__/*.js -!/**/__snapshots__/*.js +lib/ diff --git a/packages/migrate/bannerPlugin/__tests__/__snapshots__/bannerPlugin.test.ts.snap b/packages/migrate/__tests__/bannerPlugin/__snapshots__/bannerPlugin.test.ts.snap similarity index 61% rename from packages/migrate/bannerPlugin/__tests__/__snapshots__/bannerPlugin.test.ts.snap rename to packages/migrate/__tests__/bannerPlugin/__snapshots__/bannerPlugin.test.ts.snap index 1d2652250e2..30d5fa15421 100644 --- a/packages/migrate/bannerPlugin/__tests__/__snapshots__/bannerPlugin.test.ts.snap +++ b/packages/migrate/__tests__/bannerPlugin/__snapshots__/bannerPlugin.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`bannerPlugin transforms correctly using "bannerPlugin-0" data 1`] = ` +exports[`banner plugin bannerPlugin transforms correctly using "bannerPlugin-0" data 1`] = ` "module.exports = { plugins: [ new webpack.BannerPlugin({ @@ -13,7 +13,7 @@ exports[`bannerPlugin transforms correctly using "bannerPlugin-0" data 1`] = ` " `; -exports[`bannerPlugin transforms correctly using "bannerPlugin-1" data 1`] = ` +exports[`banner plugin bannerPlugin transforms correctly using "bannerPlugin-1" data 1`] = ` "// Should do nothing if there is no banner plugin module.exports = { plugins: [] @@ -21,7 +21,7 @@ module.exports = { " `; -exports[`bannerPlugin transforms correctly using "bannerPlugin-2" data 1`] = ` +exports[`banner plugin bannerPlugin transforms correctly using "bannerPlugin-2" data 1`] = ` "// Only transform if it uses the old format module.exports = { plugins: [ diff --git a/packages/migrate/bannerPlugin/__tests__/__testfixtures__/bannerPlugin-0.input.js b/packages/migrate/__tests__/bannerPlugin/__testfixtures__/bannerPlugin-0.input.js similarity index 100% rename from packages/migrate/bannerPlugin/__tests__/__testfixtures__/bannerPlugin-0.input.js rename to packages/migrate/__tests__/bannerPlugin/__testfixtures__/bannerPlugin-0.input.js diff --git a/packages/migrate/bannerPlugin/__tests__/__testfixtures__/bannerPlugin-1.input.js b/packages/migrate/__tests__/bannerPlugin/__testfixtures__/bannerPlugin-1.input.js similarity index 100% rename from packages/migrate/bannerPlugin/__tests__/__testfixtures__/bannerPlugin-1.input.js rename to packages/migrate/__tests__/bannerPlugin/__testfixtures__/bannerPlugin-1.input.js diff --git a/packages/migrate/bannerPlugin/__tests__/__testfixtures__/bannerPlugin-2.input.js b/packages/migrate/__tests__/bannerPlugin/__testfixtures__/bannerPlugin-2.input.js similarity index 100% rename from packages/migrate/bannerPlugin/__tests__/__testfixtures__/bannerPlugin-2.input.js rename to packages/migrate/__tests__/bannerPlugin/__testfixtures__/bannerPlugin-2.input.js diff --git a/packages/migrate/__tests__/bannerPlugin/bannerPlugin.test.ts b/packages/migrate/__tests__/bannerPlugin/bannerPlugin.test.ts new file mode 100644 index 00000000000..507761fb69f --- /dev/null +++ b/packages/migrate/__tests__/bannerPlugin/bannerPlugin.test.ts @@ -0,0 +1,13 @@ +import defineTest from "../../../utils/__tests__/defineTest"; +import { join } from "path"; + +const dirName: string = join(__dirname); + +describe('banner plugin', function() { + { + defineTest(dirName, "bannerPlugin", "bannerPlugin-0"); + defineTest(dirName, "bannerPlugin", "bannerPlugin-1"); + defineTest(dirName, "bannerPlugin", "bannerPlugin-2"); + } +}); + diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__snapshots__/commonsChunkPlugin.test.ts.snap b/packages/migrate/__tests__/commonsChunkPlugin/__snapshots__/commonsChunkPlugin.test.ts.snap similarity index 83% rename from packages/migrate/commonsChunkPlugin/__tests__/__snapshots__/commonsChunkPlugin.test.ts.snap rename to packages/migrate/__tests__/commonsChunkPlugin/__snapshots__/commonsChunkPlugin.test.ts.snap index edc282c874b..593db1cc8cd 100644 --- a/packages/migrate/commonsChunkPlugin/__tests__/__snapshots__/commonsChunkPlugin.test.ts.snap +++ b/packages/migrate/__tests__/commonsChunkPlugin/__snapshots__/commonsChunkPlugin.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-0" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-0" data 1`] = ` "module.exports = { entry: { app: './src/app.js', @@ -30,7 +30,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-0" da " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-1" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-1" data 1`] = ` "module.exports = { entry: { vendor: './src/vendors.js', @@ -58,7 +58,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-1" da " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-2" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-2" data 1`] = ` "module.exports = { entry: { vendor: './src/vendors.js', @@ -80,7 +80,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-2" da " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-3" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-3" data 1`] = ` "module.exports = { optimizations: { splitChunks: { @@ -98,7 +98,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-3" da " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-4" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-4" data 1`] = ` "module.exports = { entry: { main: './src/index.js', @@ -121,7 +121,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-4" da " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-5" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-5" data 1`] = ` "module.exports = { entry: { main: './src/index.js', @@ -147,7 +147,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-5" da " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6a" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6a" data 1`] = ` "module.exports = { entry: { main: './src/index.js', @@ -176,7 +176,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6a" d " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6b" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6b" data 1`] = ` "module.exports = { entry: { main: './src/index.js', @@ -209,7 +209,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6b" d " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6c" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6c" data 1`] = ` "module.exports = { entry: { main: './src/index.js', @@ -242,7 +242,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6c" d " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6d" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6d" data 1`] = ` "module.exports = { entry: { main: './src/index.js', @@ -278,7 +278,7 @@ exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-6d" d " `; -exports[`commonsChunkPlugin transforms correctly using "commonsChunkPlugin-7" data 1`] = ` +exports[`commons chunk plugin commonsChunkPlugin transforms correctly using "commonsChunkPlugin-7" data 1`] = ` "module.exports = { entry: { main: './src/index.js', diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-0.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-0.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-0.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-0.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-1.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-1.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-1.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-1.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-2.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-2.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-2.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-2.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-3.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-3.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-3.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-3.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-4.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-4.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-4.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-4.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-5.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-5.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-5.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-5.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-6a.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-6a.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-6a.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-6a.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-6b.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-6b.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-6b.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-6b.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-6c.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-6c.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-6c.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-6c.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-6d.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-6d.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-6d.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-6d.input.js diff --git a/packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-7.input.js b/packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-7.input.js similarity index 100% rename from packages/migrate/commonsChunkPlugin/__tests__/__testfixtures__/commonsChunkPlugin-7.input.js rename to packages/migrate/__tests__/commonsChunkPlugin/__testfixtures__/commonsChunkPlugin-7.input.js diff --git a/packages/migrate/__tests__/commonsChunkPlugin/commonsChunkPlugin.test.ts b/packages/migrate/__tests__/commonsChunkPlugin/commonsChunkPlugin.test.ts new file mode 100644 index 00000000000..8937f1ce244 --- /dev/null +++ b/packages/migrate/__tests__/commonsChunkPlugin/commonsChunkPlugin.test.ts @@ -0,0 +1,21 @@ +import defineTest from "../../../utils/__tests__/defineTest"; +import { join } from "path"; +const dirName: string = join(__dirname); + +describe('commons chunk plugin', function() { + { + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-0"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-1"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-2"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-3"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-4"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-5"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-6a"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-6b"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-6c"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-6d"); + defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-7"); + + } +}); + diff --git a/packages/migrate/extractTextPlugin/__tests__/__snapshots__/extractTextPlugin.test.ts.snap b/packages/migrate/__tests__/extractTextPlugin/__snapshots__/extractTextPlugin.test.ts.snap similarity index 84% rename from packages/migrate/extractTextPlugin/__tests__/__snapshots__/extractTextPlugin.test.ts.snap rename to packages/migrate/__tests__/extractTextPlugin/__snapshots__/extractTextPlugin.test.ts.snap index fe042da4a2c..4e2ee40db6c 100644 --- a/packages/migrate/extractTextPlugin/__tests__/__snapshots__/extractTextPlugin.test.ts.snap +++ b/packages/migrate/__tests__/extractTextPlugin/__snapshots__/extractTextPlugin.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`extractTextPlugin transforms correctly 1`] = ` +exports[`extractTextPlugin extractTextPlugin transforms correctly 1`] = ` "const ExtractTextPlugin = require(\\"extract-text-webpack-plugin\\"); module.exports = { diff --git a/packages/migrate/extractTextPlugin/__tests__/__testfixtures__/extractTextPlugin.input.js b/packages/migrate/__tests__/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js similarity index 100% rename from packages/migrate/extractTextPlugin/__tests__/__testfixtures__/extractTextPlugin.input.js rename to packages/migrate/__tests__/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js diff --git a/packages/migrate/__tests__/extractTextPlugin/extractTextPlugin.test.ts b/packages/migrate/__tests__/extractTextPlugin/extractTextPlugin.test.ts new file mode 100644 index 00000000000..899ec10510c --- /dev/null +++ b/packages/migrate/__tests__/extractTextPlugin/extractTextPlugin.test.ts @@ -0,0 +1,10 @@ +import defineTest from '../../../utils/__tests__/defineTest'; +import { join } from 'path'; + +const dirName: string = join(__dirname); + +describe('extractTextPlugin', function() { + { + defineTest(dirName, 'extractTextPlugin'); + } +}); diff --git a/packages/migrate/loaderOptionsPlugin/__tests__/__snapshots__/loaderOptionsPlugin.test.ts.snap b/packages/migrate/__tests__/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.ts.snap similarity index 66% rename from packages/migrate/loaderOptionsPlugin/__tests__/__snapshots__/loaderOptionsPlugin.test.ts.snap rename to packages/migrate/__tests__/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.ts.snap index cb72fbea538..6d0877f5f11 100644 --- a/packages/migrate/loaderOptionsPlugin/__tests__/__snapshots__/loaderOptionsPlugin.test.ts.snap +++ b/packages/migrate/__tests__/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`loaderOptionsPlugin transforms correctly using "loaderOptionsPlugin-0" data 1`] = ` +exports[`loaderOptionsPlugin loaderOptionsPlugin transforms correctly using "loaderOptionsPlugin-0" data 1`] = ` "// Do not create LoaderOptionsPlugin is not necessary module.exports = { plugins: [ @@ -10,7 +10,7 @@ module.exports = { " `; -exports[`loaderOptionsPlugin transforms correctly using "loaderOptionsPlugin-1" data 1`] = ` +exports[`loaderOptionsPlugin loaderOptionsPlugin transforms correctly using "loaderOptionsPlugin-1" data 1`] = ` "module.exports = { plugins: [ new webpack.optimize.UglifyJsPlugin(), @@ -24,7 +24,7 @@ exports[`loaderOptionsPlugin transforms correctly using "loaderOptionsPlugin-1" " `; -exports[`loaderOptionsPlugin transforms correctly using "loaderOptionsPlugin-2" data 1`] = ` +exports[`loaderOptionsPlugin loaderOptionsPlugin transforms correctly using "loaderOptionsPlugin-2" data 1`] = ` "// Don't modify LoaderOptionsPlugin module.exports = { plugins: [ @@ -37,7 +37,7 @@ module.exports = { " `; -exports[`loaderOptionsPlugin transforms correctly using "loaderOptionsPlugin-3" data 1`] = ` +exports[`loaderOptionsPlugin loaderOptionsPlugin transforms correctly using "loaderOptionsPlugin-3" data 1`] = ` "// Don't modify LoaderOptionsPlugin const ExtractTextPlugin = require('extract-text-webpack-plugin'); diff --git a/packages/migrate/loaderOptionsPlugin/__tests__/__testfixtures__/loaderOptionsPlugin-0.input.js b/packages/migrate/__tests__/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin-0.input.js similarity index 100% rename from packages/migrate/loaderOptionsPlugin/__tests__/__testfixtures__/loaderOptionsPlugin-0.input.js rename to packages/migrate/__tests__/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin-0.input.js diff --git a/packages/migrate/loaderOptionsPlugin/__tests__/__testfixtures__/loaderOptionsPlugin-1.input.js b/packages/migrate/__tests__/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin-1.input.js similarity index 100% rename from packages/migrate/loaderOptionsPlugin/__tests__/__testfixtures__/loaderOptionsPlugin-1.input.js rename to packages/migrate/__tests__/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin-1.input.js diff --git a/packages/migrate/loaderOptionsPlugin/__tests__/__testfixtures__/loaderOptionsPlugin-2.input.js b/packages/migrate/__tests__/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin-2.input.js similarity index 100% rename from packages/migrate/loaderOptionsPlugin/__tests__/__testfixtures__/loaderOptionsPlugin-2.input.js rename to packages/migrate/__tests__/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin-2.input.js diff --git a/packages/migrate/loaderOptionsPlugin/__tests__/__testfixtures__/loaderOptionsPlugin-3.input.js b/packages/migrate/__tests__/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin-3.input.js similarity index 100% rename from packages/migrate/loaderOptionsPlugin/__tests__/__testfixtures__/loaderOptionsPlugin-3.input.js rename to packages/migrate/__tests__/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin-3.input.js diff --git a/packages/migrate/__tests__/loaderOptionsPlugin/loaderOptionsPlugin.test.ts b/packages/migrate/__tests__/loaderOptionsPlugin/loaderOptionsPlugin.test.ts new file mode 100644 index 00000000000..07aa556fecf --- /dev/null +++ b/packages/migrate/__tests__/loaderOptionsPlugin/loaderOptionsPlugin.test.ts @@ -0,0 +1,13 @@ +import defineTest from "../../../utils/__tests__/defineTest"; +import { join } from "path"; + +const dirName: string = join(__dirname); +describe('loaderOptionsPlugin', function() { + { + defineTest(dirName, "loaderOptionsPlugin", "loaderOptionsPlugin-0"); + defineTest(dirName, "loaderOptionsPlugin", "loaderOptionsPlugin-1"); + defineTest(dirName, "loaderOptionsPlugin", "loaderOptionsPlugin-2"); + defineTest(dirName, "loaderOptionsPlugin", "loaderOptionsPlugin-3"); + } +}); + diff --git a/packages/migrate/loaders/__tests__/__snapshots__/loaders.test.ts.snap b/packages/migrate/__tests__/loaders/__snapshots__/loaders.test.ts.snap similarity index 84% rename from packages/migrate/loaders/__tests__/__snapshots__/loaders.test.ts.snap rename to packages/migrate/__tests__/loaders/__snapshots__/loaders.test.ts.snap index e12d1d75875..5fb72ae39e0 100644 --- a/packages/migrate/loaders/__tests__/__snapshots__/loaders.test.ts.snap +++ b/packages/migrate/__tests__/loaders/__snapshots__/loaders.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`loaders transforms correctly using "loaders-0" data 1`] = ` +exports[`loaders loaders transforms correctly using "loaders-0" data 1`] = ` "module.exports = [ { module: { @@ -117,7 +117,7 @@ exports[`loaders transforms correctly using "loaders-0" data 1`] = ` " `; -exports[`loaders transforms correctly using "loaders-1" data 1`] = ` +exports[`loaders loaders transforms correctly using "loaders-1" data 1`] = ` "module.exports = { module: { rules: [ @@ -141,7 +141,7 @@ exports[`loaders transforms correctly using "loaders-1" data 1`] = ` " `; -exports[`loaders transforms correctly using "loaders-2" data 1`] = ` +exports[`loaders loaders transforms correctly using "loaders-2" data 1`] = ` "module.exports = { module: { rules: [ @@ -162,7 +162,7 @@ exports[`loaders transforms correctly using "loaders-2" data 1`] = ` " `; -exports[`loaders transforms correctly using "loaders-3" data 1`] = ` +exports[`loaders loaders transforms correctly using "loaders-3" data 1`] = ` "module.exports = { module: { rules: [ @@ -180,7 +180,7 @@ exports[`loaders transforms correctly using "loaders-3" data 1`] = ` " `; -exports[`loaders transforms correctly using "loaders-4" data 1`] = ` +exports[`loaders loaders transforms correctly using "loaders-4" data 1`] = ` "module.exports = { module: { rules: [ @@ -198,7 +198,7 @@ exports[`loaders transforms correctly using "loaders-4" data 1`] = ` " `; -exports[`loaders transforms correctly using "loaders-5" data 1`] = ` +exports[`loaders loaders transforms correctly using "loaders-5" data 1`] = ` "module.exports = { module: { rules: [{ @@ -219,7 +219,7 @@ exports[`loaders transforms correctly using "loaders-5" data 1`] = ` " `; -exports[`loaders transforms correctly using "loaders-6" data 1`] = ` +exports[`loaders loaders transforms correctly using "loaders-6" data 1`] = ` "module.exports = { module: { rules: [{ @@ -240,7 +240,7 @@ exports[`loaders transforms correctly using "loaders-6" data 1`] = ` " `; -exports[`loaders transforms correctly using "loaders-7" data 1`] = ` +exports[`loaders loaders transforms correctly using "loaders-7" data 1`] = ` "module.exports = { module: { rules: [ @@ -263,7 +263,7 @@ exports[`loaders transforms correctly using "loaders-7" data 1`] = ` " `; -exports[`loaders transforms correctly using "loaders-8" data 1`] = ` +exports[`loaders loaders transforms correctly using "loaders-8" data 1`] = ` "module.exports = { module: { rules: [ diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-0.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-0.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-0.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-0.input.js diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-1.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-1.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-1.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-1.input.js diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-2.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-2.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-2.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-2.input.js diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-3.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-3.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-3.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-3.input.js diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-4.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-4.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-4.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-4.input.js diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-5.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-5.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-5.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-5.input.js diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-6.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-6.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-6.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-6.input.js diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-7.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-7.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-7.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-7.input.js diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-8.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-8.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-8.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-8.input.js diff --git a/packages/migrate/loaders/__tests__/__testfixtures__/loaders-9.input.js b/packages/migrate/__tests__/loaders/__testfixtures__/loaders-9.input.js similarity index 100% rename from packages/migrate/loaders/__tests__/__testfixtures__/loaders-9.input.js rename to packages/migrate/__tests__/loaders/__testfixtures__/loaders-9.input.js diff --git a/packages/migrate/__tests__/loaders/loaders.test.ts b/packages/migrate/__tests__/loaders/loaders.test.ts new file mode 100644 index 00000000000..a303f63e773 --- /dev/null +++ b/packages/migrate/__tests__/loaders/loaders.test.ts @@ -0,0 +1,20 @@ +import defineTest from "../../../utils/__tests__/defineTest"; +import { join } from "path"; + +const dirName: string = join(__dirname); + +describe('loaders', function() { + { + defineTest(dirName, "loaders", "loaders-0"); + defineTest(dirName, "loaders", "loaders-1"); + defineTest(dirName, "loaders", "loaders-2"); + defineTest(dirName, "loaders", "loaders-3"); + defineTest(dirName, "loaders", "loaders-4"); + defineTest(dirName, "loaders", "loaders-5"); + defineTest(dirName, "loaders", "loaders-6"); + defineTest(dirName, "loaders", "loaders-7"); + defineTest(dirName, "loaders", "loaders-8"); + } +}); + + diff --git a/packages/migrate/__tests__/migrate.test.ts b/packages/migrate/__tests__/migrate.test.ts index f367e19ee34..5e76dc2e17b 100644 --- a/packages/migrate/__tests__/migrate.test.ts +++ b/packages/migrate/__tests__/migrate.test.ts @@ -1,4 +1,4 @@ -import { transform, transformations } from "../migrate"; +import { transform, transformations } from "../src/migrate"; const input = ` module.exports = { diff --git a/packages/migrate/__tests__/moduleConcatenationPlugin/__snapshots__/moduleConcatenationPlugin.test.ts.snap b/packages/migrate/__tests__/moduleConcatenationPlugin/__snapshots__/moduleConcatenationPlugin.test.ts.snap new file mode 100644 index 00000000000..76320d16f65 --- /dev/null +++ b/packages/migrate/__tests__/moduleConcatenationPlugin/__snapshots__/moduleConcatenationPlugin.test.ts.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`moduleConcatenationPlugin moduleConcatenationPlugin transforms correctly using "moduleConcatenationPlugin-0" data 1`] = ` +"module.exports = { + optimizations: { + concatenateModules: true + } +}; +" +`; + +exports[`moduleConcatenationPlugin moduleConcatenationPlugin transforms correctly using "moduleConcatenationPlugin-1" data 1`] = ` +"module.exports = { + optimizations: { + splitChunks: false, + concatenateModules: true + }, + plugins: [new Foo()] +}; +" +`; + +exports[`moduleConcatenationPlugin moduleConcatenationPlugin transforms correctly using "moduleConcatenationPlugin-2" data 1`] = ` +"module.exports = { + optimizations: { + concatenateModules: true + }, + plugins: [new Foo()] +}; +" +`; diff --git a/packages/migrate/moduleConcatenationPlugin/__tests__/__testfixtures__/moduleConcatenationPlugin-0.input.js b/packages/migrate/__tests__/moduleConcatenationPlugin/__testfixtures__/moduleConcatenationPlugin-0.input.js similarity index 100% rename from packages/migrate/moduleConcatenationPlugin/__tests__/__testfixtures__/moduleConcatenationPlugin-0.input.js rename to packages/migrate/__tests__/moduleConcatenationPlugin/__testfixtures__/moduleConcatenationPlugin-0.input.js diff --git a/packages/migrate/moduleConcatenationPlugin/__tests__/__testfixtures__/moduleConcatenationPlugin-1.input.js b/packages/migrate/__tests__/moduleConcatenationPlugin/__testfixtures__/moduleConcatenationPlugin-1.input.js similarity index 100% rename from packages/migrate/moduleConcatenationPlugin/__tests__/__testfixtures__/moduleConcatenationPlugin-1.input.js rename to packages/migrate/__tests__/moduleConcatenationPlugin/__testfixtures__/moduleConcatenationPlugin-1.input.js diff --git a/packages/migrate/moduleConcatenationPlugin/__tests__/__testfixtures__/moduleConcatenationPlugin-2.input.js b/packages/migrate/__tests__/moduleConcatenationPlugin/__testfixtures__/moduleConcatenationPlugin-2.input.js similarity index 100% rename from packages/migrate/moduleConcatenationPlugin/__tests__/__testfixtures__/moduleConcatenationPlugin-2.input.js rename to packages/migrate/__tests__/moduleConcatenationPlugin/__testfixtures__/moduleConcatenationPlugin-2.input.js diff --git a/packages/migrate/__tests__/moduleConcatenationPlugin/moduleConcatenationPlugin.test.ts b/packages/migrate/__tests__/moduleConcatenationPlugin/moduleConcatenationPlugin.test.ts new file mode 100644 index 00000000000..56764547e32 --- /dev/null +++ b/packages/migrate/__tests__/moduleConcatenationPlugin/moduleConcatenationPlugin.test.ts @@ -0,0 +1,12 @@ +import defineTest from '../../../utils/__tests__/defineTest'; +import { join } from 'path'; + +const dirName: string = join(__dirname); + +describe('moduleConcatenationPlugin', function() { + { + defineTest(dirName, 'moduleConcatenationPlugin', 'moduleConcatenationPlugin-0'); + defineTest(dirName, 'moduleConcatenationPlugin', 'moduleConcatenationPlugin-1'); + defineTest(dirName, 'moduleConcatenationPlugin', 'moduleConcatenationPlugin-2'); + } +}); diff --git a/packages/migrate/namedModulesPlugin/__tests__/__snapshots__/namedModulesPlugin.test.ts.snap b/packages/migrate/__tests__/namedModulesPlugin/__snapshots__/namedModulesPlugin.test.ts.snap similarity index 52% rename from packages/migrate/namedModulesPlugin/__tests__/__snapshots__/namedModulesPlugin.test.ts.snap rename to packages/migrate/__tests__/namedModulesPlugin/__snapshots__/namedModulesPlugin.test.ts.snap index c637d5c41e8..5aea9ec1444 100644 --- a/packages/migrate/namedModulesPlugin/__tests__/__snapshots__/namedModulesPlugin.test.ts.snap +++ b/packages/migrate/__tests__/namedModulesPlugin/__snapshots__/namedModulesPlugin.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`namedModulesPlugin transforms correctly using "namedModulesPlugin-0" data 1`] = ` +exports[`namedModulesPlugin namedModulesPlugin transforms correctly using "namedModulesPlugin-0" data 1`] = ` "module.export = { optimizations: { namedModules: true @@ -9,7 +9,7 @@ exports[`namedModulesPlugin transforms correctly using "namedModulesPlugin-0" da " `; -exports[`namedModulesPlugin transforms correctly using "namedModulesPlugin-1" data 1`] = ` +exports[`namedModulesPlugin namedModulesPlugin transforms correctly using "namedModulesPlugin-1" data 1`] = ` "module.export = { optimizations: { splitChunks: false, @@ -20,7 +20,7 @@ exports[`namedModulesPlugin transforms correctly using "namedModulesPlugin-1" da " `; -exports[`namedModulesPlugin transforms correctly using "namedModulesPlugin-2" data 1`] = ` +exports[`namedModulesPlugin namedModulesPlugin transforms correctly using "namedModulesPlugin-2" data 1`] = ` "module.export = { optimizations: { namedModules: true diff --git a/packages/migrate/namedModulesPlugin/__tests__/__testfixtures__/namedModulesPlugin-0.input.js b/packages/migrate/__tests__/namedModulesPlugin/__testfixtures__/namedModulesPlugin-0.input.js similarity index 100% rename from packages/migrate/namedModulesPlugin/__tests__/__testfixtures__/namedModulesPlugin-0.input.js rename to packages/migrate/__tests__/namedModulesPlugin/__testfixtures__/namedModulesPlugin-0.input.js diff --git a/packages/migrate/namedModulesPlugin/__tests__/__testfixtures__/namedModulesPlugin-1.input.js b/packages/migrate/__tests__/namedModulesPlugin/__testfixtures__/namedModulesPlugin-1.input.js similarity index 100% rename from packages/migrate/namedModulesPlugin/__tests__/__testfixtures__/namedModulesPlugin-1.input.js rename to packages/migrate/__tests__/namedModulesPlugin/__testfixtures__/namedModulesPlugin-1.input.js diff --git a/packages/migrate/namedModulesPlugin/__tests__/__testfixtures__/namedModulesPlugin-2.input.js b/packages/migrate/__tests__/namedModulesPlugin/__testfixtures__/namedModulesPlugin-2.input.js similarity index 100% rename from packages/migrate/namedModulesPlugin/__tests__/__testfixtures__/namedModulesPlugin-2.input.js rename to packages/migrate/__tests__/namedModulesPlugin/__testfixtures__/namedModulesPlugin-2.input.js diff --git a/packages/migrate/__tests__/namedModulesPlugin/namedModulesPlugin.test.ts b/packages/migrate/__tests__/namedModulesPlugin/namedModulesPlugin.test.ts new file mode 100644 index 00000000000..27b272afb4d --- /dev/null +++ b/packages/migrate/__tests__/namedModulesPlugin/namedModulesPlugin.test.ts @@ -0,0 +1,13 @@ +import defineTest from "../../../utils/__tests__/defineTest"; +import { join } from "path"; + +const dirName: string = join(__dirname); + +describe('namedModulesPlugin', function() { + { + defineTest(dirName, "namedModulesPlugin", "namedModulesPlugin-0"); + defineTest(dirName, "namedModulesPlugin", "namedModulesPlugin-1"); + defineTest(dirName, "namedModulesPlugin", "namedModulesPlugin-2"); + } +}); + diff --git a/packages/migrate/noEmitOnErrorsPlugin/__tests__/__snapshots__/noEmitOnErrorsPlugin.test.ts.snap b/packages/migrate/__tests__/noEmitOnErrorsPlugin/__snapshots__/noEmitOnErrorsPlugin.test.ts.snap similarity index 51% rename from packages/migrate/noEmitOnErrorsPlugin/__tests__/__snapshots__/noEmitOnErrorsPlugin.test.ts.snap rename to packages/migrate/__tests__/noEmitOnErrorsPlugin/__snapshots__/noEmitOnErrorsPlugin.test.ts.snap index 6febeb7012a..c5f215b09da 100644 --- a/packages/migrate/noEmitOnErrorsPlugin/__tests__/__snapshots__/noEmitOnErrorsPlugin.test.ts.snap +++ b/packages/migrate/__tests__/noEmitOnErrorsPlugin/__snapshots__/noEmitOnErrorsPlugin.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`noEmitOnErrorsPlugin transforms correctly using "noEmitOnErrorsPlugin-0" data 1`] = ` +exports[`noEmitOnErrorsPlugin noEmitOnErrorsPlugin transforms correctly using "noEmitOnErrorsPlugin-0" data 1`] = ` "module.exports = { optimizations: { noEmitOnErrors: true @@ -9,7 +9,7 @@ exports[`noEmitOnErrorsPlugin transforms correctly using "noEmitOnErrorsPlugin-0 " `; -exports[`noEmitOnErrorsPlugin transforms correctly using "noEmitOnErrorsPlugin-1" data 1`] = ` +exports[`noEmitOnErrorsPlugin noEmitOnErrorsPlugin transforms correctly using "noEmitOnErrorsPlugin-1" data 1`] = ` "module.exports = { optimizations: { splitChunks: false, @@ -20,7 +20,7 @@ exports[`noEmitOnErrorsPlugin transforms correctly using "noEmitOnErrorsPlugin-1 " `; -exports[`noEmitOnErrorsPlugin transforms correctly using "noEmitOnErrorsPlugin-2" data 1`] = ` +exports[`noEmitOnErrorsPlugin noEmitOnErrorsPlugin transforms correctly using "noEmitOnErrorsPlugin-2" data 1`] = ` "module.exports = { optimizations: { noEmitOnErrors: true diff --git a/packages/migrate/noEmitOnErrorsPlugin/__tests__/__testfixtures__/noEmitOnErrorsPlugin-0.input.js b/packages/migrate/__tests__/noEmitOnErrorsPlugin/__testfixtures__/noEmitOnErrorsPlugin-0.input.js similarity index 100% rename from packages/migrate/noEmitOnErrorsPlugin/__tests__/__testfixtures__/noEmitOnErrorsPlugin-0.input.js rename to packages/migrate/__tests__/noEmitOnErrorsPlugin/__testfixtures__/noEmitOnErrorsPlugin-0.input.js diff --git a/packages/migrate/noEmitOnErrorsPlugin/__tests__/__testfixtures__/noEmitOnErrorsPlugin-1.input.js b/packages/migrate/__tests__/noEmitOnErrorsPlugin/__testfixtures__/noEmitOnErrorsPlugin-1.input.js similarity index 100% rename from packages/migrate/noEmitOnErrorsPlugin/__tests__/__testfixtures__/noEmitOnErrorsPlugin-1.input.js rename to packages/migrate/__tests__/noEmitOnErrorsPlugin/__testfixtures__/noEmitOnErrorsPlugin-1.input.js diff --git a/packages/migrate/noEmitOnErrorsPlugin/__tests__/__testfixtures__/noEmitOnErrorsPlugin-2.input.js b/packages/migrate/__tests__/noEmitOnErrorsPlugin/__testfixtures__/noEmitOnErrorsPlugin-2.input.js similarity index 100% rename from packages/migrate/noEmitOnErrorsPlugin/__tests__/__testfixtures__/noEmitOnErrorsPlugin-2.input.js rename to packages/migrate/__tests__/noEmitOnErrorsPlugin/__testfixtures__/noEmitOnErrorsPlugin-2.input.js diff --git a/packages/migrate/__tests__/noEmitOnErrorsPlugin/noEmitOnErrorsPlugin.test.ts b/packages/migrate/__tests__/noEmitOnErrorsPlugin/noEmitOnErrorsPlugin.test.ts new file mode 100644 index 00000000000..c2c690da37a --- /dev/null +++ b/packages/migrate/__tests__/noEmitOnErrorsPlugin/noEmitOnErrorsPlugin.test.ts @@ -0,0 +1,12 @@ +import defineTest from '../../../utils/__tests__/defineTest'; +import { join } from 'path'; + +const dirName: string = join(__dirname); + +describe('noEmitOnErrorsPlugin', function() { + { + defineTest(dirName, 'noEmitOnErrorsPlugin', 'noEmitOnErrorsPlugin-0'); + defineTest(dirName, 'noEmitOnErrorsPlugin', 'noEmitOnErrorsPlugin-1'); + defineTest(dirName, 'noEmitOnErrorsPlugin', 'noEmitOnErrorsPlugin-2'); + } +}); diff --git a/packages/migrate/outputPath/__tests__/__snapshots__/outputPath.test.ts.snap b/packages/migrate/__tests__/outputPath/__snapshots__/outputPath.test.ts.snap similarity index 53% rename from packages/migrate/outputPath/__tests__/__snapshots__/outputPath.test.ts.snap rename to packages/migrate/__tests__/outputPath/__snapshots__/outputPath.test.ts.snap index faf8dd2b327..ceb019922fc 100644 --- a/packages/migrate/outputPath/__tests__/__snapshots__/outputPath.test.ts.snap +++ b/packages/migrate/__tests__/outputPath/__snapshots__/outputPath.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`outputPath transforms correctly using "outputPath-0" data 1`] = ` +exports[`outputPath outputPath transforms correctly using "outputPath-0" data 1`] = ` "module.exports = { output: { path: path.join(__dirname, \\"dist\\"), @@ -9,7 +9,7 @@ exports[`outputPath transforms correctly using "outputPath-0" data 1`] = ` " `; -exports[`outputPath transforms correctly using "outputPath-1" data 1`] = ` +exports[`outputPath outputPath transforms correctly using "outputPath-1" data 1`] = ` "module.exports = { output: { path: path.join(__dirname, \\"dist\\") @@ -18,7 +18,7 @@ exports[`outputPath transforms correctly using "outputPath-1" data 1`] = ` " `; -exports[`outputPath transforms correctly using "outputPath-2" data 1`] = ` +exports[`outputPath outputPath transforms correctly using "outputPath-2" data 1`] = ` "module.exports = { output: { path: path.join(__dirname, \\"dist\\") diff --git a/packages/migrate/outputPath/__tests__/__testfixtures__/outputPath-0.input.js b/packages/migrate/__tests__/outputPath/__testfixtures__/outputPath-0.input.js similarity index 100% rename from packages/migrate/outputPath/__tests__/__testfixtures__/outputPath-0.input.js rename to packages/migrate/__tests__/outputPath/__testfixtures__/outputPath-0.input.js diff --git a/packages/migrate/outputPath/__tests__/__testfixtures__/outputPath-1.input.js b/packages/migrate/__tests__/outputPath/__testfixtures__/outputPath-1.input.js similarity index 100% rename from packages/migrate/outputPath/__tests__/__testfixtures__/outputPath-1.input.js rename to packages/migrate/__tests__/outputPath/__testfixtures__/outputPath-1.input.js diff --git a/packages/migrate/outputPath/__tests__/__testfixtures__/outputPath-2.input.js b/packages/migrate/__tests__/outputPath/__testfixtures__/outputPath-2.input.js similarity index 100% rename from packages/migrate/outputPath/__tests__/__testfixtures__/outputPath-2.input.js rename to packages/migrate/__tests__/outputPath/__testfixtures__/outputPath-2.input.js diff --git a/packages/migrate/__tests__/outputPath/outputPath.test.ts b/packages/migrate/__tests__/outputPath/outputPath.test.ts new file mode 100644 index 00000000000..91808deb05d --- /dev/null +++ b/packages/migrate/__tests__/outputPath/outputPath.test.ts @@ -0,0 +1,12 @@ +import defineTest from '../../../utils/__tests__/defineTest'; +import { join } from 'path'; + +const dirName: string = join(__dirname); + +describe('outputPath', function() { + { + defineTest(dirName, 'outputPath', 'outputPath-0'); + defineTest(dirName, 'outputPath', 'outputPath-1'); + defineTest(dirName, 'outputPath', 'outputPath-2'); + } +}); diff --git a/packages/migrate/removeDeprecatedPlugins/__tests__/__snapshots__/removeDeprecatedPlugins.test.ts.snap b/packages/migrate/__tests__/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.ts.snap similarity index 50% rename from packages/migrate/removeDeprecatedPlugins/__tests__/__snapshots__/removeDeprecatedPlugins.test.ts.snap rename to packages/migrate/__tests__/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.ts.snap index 62b69a6e5de..5955bd27226 100644 --- a/packages/migrate/removeDeprecatedPlugins/__tests__/__snapshots__/removeDeprecatedPlugins.test.ts.snap +++ b/packages/migrate/__tests__/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.ts.snap @@ -1,23 +1,23 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-0" data 1`] = ` +exports[`remove deprecated plugin removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-0" data 1`] = ` "module.exports = {}; " `; -exports[`removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-1" data 1`] = ` +exports[`remove deprecated plugin removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-1" data 1`] = ` "module.exports = {}; " `; -exports[`removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-2" data 1`] = ` +exports[`remove deprecated plugin removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-2" data 1`] = ` "module.exports = { plugins: [new webpack.optimize.UglifyJsPlugin()] }; " `; -exports[`removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-3" data 1`] = ` +exports[`remove deprecated plugin removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-3" data 1`] = ` "// This should throw module.exports = config => { @@ -29,7 +29,7 @@ module.exports = config => { " `; -exports[`removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-4" data 1`] = ` +exports[`remove deprecated plugin removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-4" data 1`] = ` "// This should throw const webpack = require(\\"webpack\\"); diff --git a/packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-0.input.js b/packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-0.input.js similarity index 100% rename from packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-0.input.js rename to packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-0.input.js diff --git a/packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-1.input.js b/packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-1.input.js similarity index 100% rename from packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-1.input.js rename to packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-1.input.js diff --git a/packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-2.input.js b/packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-2.input.js similarity index 100% rename from packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-2.input.js rename to packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-2.input.js diff --git a/packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-3.input.js b/packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-3.input.js similarity index 100% rename from packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-3.input.js rename to packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-3.input.js diff --git a/packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-4.input.js b/packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-4.input.js similarity index 100% rename from packages/migrate/removeDeprecatedPlugins/__tests__/__testfixtures__/removeDeprecatedPlugins-4.input.js rename to packages/migrate/__tests__/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-4.input.js diff --git a/packages/migrate/__tests__/removeDeprecatedPlugins/removeDeprecatedPlugins.test.ts b/packages/migrate/__tests__/removeDeprecatedPlugins/removeDeprecatedPlugins.test.ts new file mode 100644 index 00000000000..44fb21360be --- /dev/null +++ b/packages/migrate/__tests__/removeDeprecatedPlugins/removeDeprecatedPlugins.test.ts @@ -0,0 +1,15 @@ +import defineTest from "../../../utils/__tests__/defineTest"; +import { join } from "path"; + +const dirName: string = join(__dirname); + +describe('remove deprecated plugin', function() { + { + defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-0"); + defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-1"); + defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-2"); + defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-3"); + defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-4"); + } +}); + diff --git a/packages/migrate/removeJsonLoader/__tests__/__snapshots__/removeJsonLoader.test.ts.snap b/packages/migrate/__tests__/removeJsonLoader/__snapshots__/removeJsonLoader.test.ts.snap similarity index 57% rename from packages/migrate/removeJsonLoader/__tests__/__snapshots__/removeJsonLoader.test.ts.snap rename to packages/migrate/__tests__/removeJsonLoader/__snapshots__/removeJsonLoader.test.ts.snap index cb5cf219f5e..fbdf946613a 100644 --- a/packages/migrate/removeJsonLoader/__tests__/__snapshots__/removeJsonLoader.test.ts.snap +++ b/packages/migrate/__tests__/removeJsonLoader/__snapshots__/removeJsonLoader.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`removeJsonLoader transforms correctly using "removeJsonLoader-0" data 1`] = ` +exports[`removeJsonLoader removeJsonLoader transforms correctly using "removeJsonLoader-0" data 1`] = ` "module.exports = { module: { rules: [ @@ -18,7 +18,7 @@ exports[`removeJsonLoader transforms correctly using "removeJsonLoader-0" data 1 " `; -exports[`removeJsonLoader transforms correctly using "removeJsonLoader-1" data 1`] = ` +exports[`removeJsonLoader removeJsonLoader transforms correctly using "removeJsonLoader-1" data 1`] = ` "module.exports = { module: { rules: [ @@ -34,7 +34,7 @@ exports[`removeJsonLoader transforms correctly using "removeJsonLoader-1" data 1 " `; -exports[`removeJsonLoader transforms correctly using "removeJsonLoader-2" data 1`] = ` +exports[`removeJsonLoader removeJsonLoader transforms correctly using "removeJsonLoader-2" data 1`] = ` "module.exports = { module: { rules: [] @@ -43,7 +43,7 @@ exports[`removeJsonLoader transforms correctly using "removeJsonLoader-2" data 1 " `; -exports[`removeJsonLoader transforms correctly using "removeJsonLoader-3" data 1`] = ` +exports[`removeJsonLoader removeJsonLoader transforms correctly using "removeJsonLoader-3" data 1`] = ` "module.exports = { module: { rules: [] diff --git a/packages/migrate/removeJsonLoader/__tests__/__testfixtures__/removeJsonLoader-0.input.js b/packages/migrate/__tests__/removeJsonLoader/__testfixtures__/removeJsonLoader-0.input.js similarity index 100% rename from packages/migrate/removeJsonLoader/__tests__/__testfixtures__/removeJsonLoader-0.input.js rename to packages/migrate/__tests__/removeJsonLoader/__testfixtures__/removeJsonLoader-0.input.js diff --git a/packages/migrate/removeJsonLoader/__tests__/__testfixtures__/removeJsonLoader-1.input.js b/packages/migrate/__tests__/removeJsonLoader/__testfixtures__/removeJsonLoader-1.input.js similarity index 100% rename from packages/migrate/removeJsonLoader/__tests__/__testfixtures__/removeJsonLoader-1.input.js rename to packages/migrate/__tests__/removeJsonLoader/__testfixtures__/removeJsonLoader-1.input.js diff --git a/packages/migrate/removeJsonLoader/__tests__/__testfixtures__/removeJsonLoader-2.input.js b/packages/migrate/__tests__/removeJsonLoader/__testfixtures__/removeJsonLoader-2.input.js similarity index 100% rename from packages/migrate/removeJsonLoader/__tests__/__testfixtures__/removeJsonLoader-2.input.js rename to packages/migrate/__tests__/removeJsonLoader/__testfixtures__/removeJsonLoader-2.input.js diff --git a/packages/migrate/removeJsonLoader/__tests__/__testfixtures__/removeJsonLoader-3.input.js b/packages/migrate/__tests__/removeJsonLoader/__testfixtures__/removeJsonLoader-3.input.js similarity index 100% rename from packages/migrate/removeJsonLoader/__tests__/__testfixtures__/removeJsonLoader-3.input.js rename to packages/migrate/__tests__/removeJsonLoader/__testfixtures__/removeJsonLoader-3.input.js diff --git a/packages/migrate/__tests__/removeJsonLoader/removeJsonLoader.test.ts b/packages/migrate/__tests__/removeJsonLoader/removeJsonLoader.test.ts new file mode 100644 index 00000000000..a52d19e59ce --- /dev/null +++ b/packages/migrate/__tests__/removeJsonLoader/removeJsonLoader.test.ts @@ -0,0 +1,14 @@ +import defineTest from "../../../utils/__tests__/defineTest"; +import { join } from "path"; + +const dirName: string = join(__dirname); + +describe('removeJsonLoader', function() { + { + defineTest(dirName, "removeJsonLoader", "removeJsonLoader-0"); + defineTest(dirName, "removeJsonLoader", "removeJsonLoader-1"); + defineTest(dirName, "removeJsonLoader", "removeJsonLoader-2"); + defineTest(dirName, "removeJsonLoader", "removeJsonLoader-3"); + } +}); + diff --git a/packages/migrate/resolve/__tests__/__snapshots__/resolve.test.ts.snap b/packages/migrate/__tests__/resolve/__snapshots__/resolve.test.ts.snap similarity index 87% rename from packages/migrate/resolve/__tests__/__snapshots__/resolve.test.ts.snap rename to packages/migrate/__tests__/resolve/__snapshots__/resolve.test.ts.snap index c96bb8462fc..8c95bc6fa11 100644 --- a/packages/migrate/resolve/__tests__/__snapshots__/resolve.test.ts.snap +++ b/packages/migrate/__tests__/resolve/__snapshots__/resolve.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`resolve transforms correctly 1`] = ` +exports[`resolve resolve transforms correctly 1`] = ` "const path = require(\\"path\\"); const rootPath = path.resolve(\\"/src\\"); module.exports = [ diff --git a/packages/migrate/resolve/__tests__/__testfixtures__/resolve.input.js b/packages/migrate/__tests__/resolve/__testfixtures__/resolve.input.js similarity index 100% rename from packages/migrate/resolve/__tests__/__testfixtures__/resolve.input.js rename to packages/migrate/__tests__/resolve/__testfixtures__/resolve.input.js diff --git a/packages/migrate/__tests__/resolve/resolve.test.ts b/packages/migrate/__tests__/resolve/resolve.test.ts new file mode 100644 index 00000000000..3fe39376e12 --- /dev/null +++ b/packages/migrate/__tests__/resolve/resolve.test.ts @@ -0,0 +1,11 @@ +import defineTest from "../../../utils/__tests__/defineTest"; +import { join } from "path"; + +const dirName: string = join(__dirname); + +describe('resolve', function() { + { + defineTest(dirName, "resolve"); + + } +}); diff --git a/packages/migrate/uglifyJsPlugin/__tests__/__snapshots__/uglifyJsPlugin.test.ts.snap b/packages/migrate/__tests__/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.ts.snap similarity index 78% rename from packages/migrate/uglifyJsPlugin/__tests__/__snapshots__/uglifyJsPlugin.test.ts.snap rename to packages/migrate/__tests__/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.ts.snap index 5559fd99aa5..5f584a014f8 100644 --- a/packages/migrate/uglifyJsPlugin/__tests__/__snapshots__/uglifyJsPlugin.test.ts.snap +++ b/packages/migrate/__tests__/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-0" data 1`] = ` +exports[`uglifyJsPluginu uglifyJsPlugin transforms correctly using "uglifyJsPlugin-0" data 1`] = ` "module.exports = { optimization: { minimize: true @@ -9,7 +9,7 @@ exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-0" data 1`] = " `; -exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-1" data 1`] = ` +exports[`uglifyJsPluginu uglifyJsPlugin transforms correctly using "uglifyJsPlugin-1" data 1`] = ` "const TerserPlugin = require('terser-webpack-plugin'); module.exports = { devtool: \\"source-map\\", @@ -25,7 +25,7 @@ module.exports = { " `; -exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-2" data 1`] = ` +exports[`uglifyJsPluginu uglifyJsPlugin transforms correctly using "uglifyJsPlugin-2" data 1`] = ` "const TerserPlugin = require('terser-webpack-plugin'); module.exports = { devtool: \\"source-map\\", @@ -41,7 +41,7 @@ module.exports = { " `; -exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-3" data 1`] = ` +exports[`uglifyJsPluginu uglifyJsPlugin transforms correctly using "uglifyJsPlugin-3" data 1`] = ` "module.exports = { devtool: 'eval', @@ -77,7 +77,7 @@ exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-3" data 1`] = " `; -exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-4" data 1`] = ` +exports[`uglifyJsPluginu uglifyJsPlugin transforms correctly using "uglifyJsPlugin-4" data 1`] = ` "const TerserPlugin = require('terser-webpack-plugin'); module.exports = { devtool: 'eval', diff --git a/packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-0.input.js b/packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-0.input.js similarity index 100% rename from packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-0.input.js rename to packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-0.input.js diff --git a/packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-1.input.js b/packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-1.input.js similarity index 100% rename from packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-1.input.js rename to packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-1.input.js diff --git a/packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-2.input.js b/packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-2.input.js similarity index 100% rename from packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-2.input.js rename to packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-2.input.js diff --git a/packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-3.input.js b/packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-3.input.js similarity index 100% rename from packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-3.input.js rename to packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-3.input.js diff --git a/packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-4.input.js b/packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-4.input.js similarity index 100% rename from packages/migrate/uglifyJsPlugin/__tests__/__testfixtures__/uglifyJsPlugin-4.input.js rename to packages/migrate/__tests__/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-4.input.js diff --git a/packages/migrate/__tests__/uglifyJsPlugin/uglifyJsPlugin.test.ts b/packages/migrate/__tests__/uglifyJsPlugin/uglifyJsPlugin.test.ts new file mode 100644 index 00000000000..4963df96828 --- /dev/null +++ b/packages/migrate/__tests__/uglifyJsPlugin/uglifyJsPlugin.test.ts @@ -0,0 +1,14 @@ +import defineTest from '../../../utils/__tests__/defineTest'; +import { join } from 'path'; + +const dirName: string = join(__dirname); + +describe('uglifyJsPluginu', function() { + { + defineTest(dirName, 'uglifyJsPlugin', 'uglifyJsPlugin-0'); + defineTest(dirName, 'uglifyJsPlugin', 'uglifyJsPlugin-1'); + defineTest(dirName, 'uglifyJsPlugin', 'uglifyJsPlugin-2'); + defineTest(dirName, 'uglifyJsPlugin', 'uglifyJsPlugin-3'); + defineTest(dirName, 'uglifyJsPlugin', 'uglifyJsPlugin-4'); + } +}); diff --git a/packages/migrate/bannerPlugin/__tests__/bannerPlugin.test.ts b/packages/migrate/bannerPlugin/__tests__/bannerPlugin.test.ts deleted file mode 100644 index f7382096901..00000000000 --- a/packages/migrate/bannerPlugin/__tests__/bannerPlugin.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "bannerPlugin", "bannerPlugin-0"); -defineTest(dirName, "bannerPlugin", "bannerPlugin-1"); -defineTest(dirName, "bannerPlugin", "bannerPlugin-2"); diff --git a/packages/migrate/bannerPlugin/bannerPlugin.ts b/packages/migrate/bannerPlugin/bannerPlugin.ts deleted file mode 100644 index 5c1647e7e68..00000000000 --- a/packages/migrate/bannerPlugin/bannerPlugin.ts +++ /dev/null @@ -1,28 +0,0 @@ -import * as utils from "@webpack-cli/utils/ast-utils"; - -import { JSCodeshift, Node } from "../types/NodePath"; - -/** - * - * Transform for BannerPlugin arguments. Consolidates first and second argument (if - * both are present) into single options object. - * - * @param {Object} j - jscodeshift top-level import - * @param {Node} ast - jscodeshift ast to transform - * @returns {Node} ast - jscodeshift ast - */ - -export default function(j: JSCodeshift, ast: Node): Node { - return utils.findPluginsByName(j, ast, ["webpack.BannerPlugin"]).forEach((path: Node): void => { - const args: Node[] = (path.value as Node).arguments; // any node - // If the first argument is a literal replace it with object notation - // See https://webpack.js.org/guides/migrating/#bannerplugin-breaking-change - if (args && args.length > 1 && args[0].type === j.Literal.name) { - // and remove the first argument - (path.value as Node).arguments = [(path.value as Node).arguments[1]]; - utils.createOrUpdatePluginByName(j, path.parent, "webpack.BannerPlugin", { - banner: args[0].value - }); - } - }); -} diff --git a/packages/migrate/commonsChunkPlugin/__tests__/commonsChunkPlugin.test.ts b/packages/migrate/commonsChunkPlugin/__tests__/commonsChunkPlugin.test.ts deleted file mode 100644 index 80ec6de5f7e..00000000000 --- a/packages/migrate/commonsChunkPlugin/__tests__/commonsChunkPlugin.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-0"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-1"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-2"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-3"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-4"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-5"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-6a"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-6b"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-6c"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-6d"); -defineTest(dirName, "commonsChunkPlugin", "commonsChunkPlugin-7"); diff --git a/packages/migrate/extractTextPlugin/__tests__/extractTextPlugin.test.ts b/packages/migrate/extractTextPlugin/__tests__/extractTextPlugin.test.ts deleted file mode 100644 index 4e866fb005f..00000000000 --- a/packages/migrate/extractTextPlugin/__tests__/extractTextPlugin.test.ts +++ /dev/null @@ -1,5 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); -defineTest(dirName, "extractTextPlugin"); diff --git a/packages/migrate/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.ts b/packages/migrate/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.ts deleted file mode 100644 index d827273f340..00000000000 --- a/packages/migrate/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "loaderOptionsPlugin", "loaderOptionsPlugin-0"); -defineTest(dirName, "loaderOptionsPlugin", "loaderOptionsPlugin-1"); -defineTest(dirName, "loaderOptionsPlugin", "loaderOptionsPlugin-2"); -defineTest(dirName, "loaderOptionsPlugin", "loaderOptionsPlugin-3"); diff --git a/packages/migrate/loaders/__tests__/loaders.test.ts b/packages/migrate/loaders/__tests__/loaders.test.ts deleted file mode 100644 index 052103e79ef..00000000000 --- a/packages/migrate/loaders/__tests__/loaders.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "loaders", "loaders-0"); -defineTest(dirName, "loaders", "loaders-1"); -defineTest(dirName, "loaders", "loaders-2"); -defineTest(dirName, "loaders", "loaders-3"); -defineTest(dirName, "loaders", "loaders-4"); -defineTest(dirName, "loaders", "loaders-5"); -defineTest(dirName, "loaders", "loaders-6"); -defineTest(dirName, "loaders", "loaders-7"); -defineTest(dirName, "loaders", "loaders-8"); diff --git a/packages/migrate/moduleConcatenationPlugin/__tests__/__snapshots__/moduleConcatenationPlugin.test.ts.snap b/packages/migrate/moduleConcatenationPlugin/__tests__/__snapshots__/moduleConcatenationPlugin.test.ts.snap deleted file mode 100644 index 5a974551a29..00000000000 --- a/packages/migrate/moduleConcatenationPlugin/__tests__/__snapshots__/moduleConcatenationPlugin.test.ts.snap +++ /dev/null @@ -1,31 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`moduleConcatenationPlugin transforms correctly using "moduleConcatenationPlugin-0" data 1`] = ` -"module.exports = { - optimizations: { - concatenateModules: true - } -}; -" -`; - -exports[`moduleConcatenationPlugin transforms correctly using "moduleConcatenationPlugin-1" data 1`] = ` -"module.exports = { - optimizations: { - splitChunks: false, - concatenateModules: true - }, - plugins: [new Foo()] -}; -" -`; - -exports[`moduleConcatenationPlugin transforms correctly using "moduleConcatenationPlugin-2" data 1`] = ` -"module.exports = { - optimizations: { - concatenateModules: true - }, - plugins: [new Foo()] -}; -" -`; diff --git a/packages/migrate/moduleConcatenationPlugin/__tests__/moduleConcatenationPlugin.test.ts b/packages/migrate/moduleConcatenationPlugin/__tests__/moduleConcatenationPlugin.test.ts deleted file mode 100644 index 69fcf1c07a0..00000000000 --- a/packages/migrate/moduleConcatenationPlugin/__tests__/moduleConcatenationPlugin.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "moduleConcatenationPlugin", "moduleConcatenationPlugin-0"); -defineTest(dirName, "moduleConcatenationPlugin", "moduleConcatenationPlugin-1"); -defineTest(dirName, "moduleConcatenationPlugin", "moduleConcatenationPlugin-2"); diff --git a/packages/migrate/namedModulesPlugin/__tests__/namedModulesPlugin.test.ts b/packages/migrate/namedModulesPlugin/__tests__/namedModulesPlugin.test.ts deleted file mode 100644 index ed0ffe9d7d3..00000000000 --- a/packages/migrate/namedModulesPlugin/__tests__/namedModulesPlugin.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "namedModulesPlugin", "namedModulesPlugin-0"); -defineTest(dirName, "namedModulesPlugin", "namedModulesPlugin-1"); -defineTest(dirName, "namedModulesPlugin", "namedModulesPlugin-2"); diff --git a/packages/migrate/noEmitOnErrorsPlugin/__tests__/noEmitOnErrorsPlugin.test.ts b/packages/migrate/noEmitOnErrorsPlugin/__tests__/noEmitOnErrorsPlugin.test.ts deleted file mode 100644 index a1e43ea1021..00000000000 --- a/packages/migrate/noEmitOnErrorsPlugin/__tests__/noEmitOnErrorsPlugin.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "noEmitOnErrorsPlugin", "noEmitOnErrorsPlugin-0"); -defineTest(dirName, "noEmitOnErrorsPlugin", "noEmitOnErrorsPlugin-1"); -defineTest(dirName, "noEmitOnErrorsPlugin", "noEmitOnErrorsPlugin-2"); diff --git a/packages/migrate/outputPath/__tests__/outputPath.test.ts b/packages/migrate/outputPath/__tests__/outputPath.test.ts deleted file mode 100644 index 1d5141154bb..00000000000 --- a/packages/migrate/outputPath/__tests__/outputPath.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "outputPath", "outputPath-0"); -defineTest(dirName, "outputPath", "outputPath-1"); -defineTest(dirName, "outputPath", "outputPath-2"); diff --git a/packages/migrate/outputPath/outputPath.ts b/packages/migrate/outputPath/outputPath.ts deleted file mode 100644 index def0fee03c6..00000000000 --- a/packages/migrate/outputPath/outputPath.ts +++ /dev/null @@ -1,67 +0,0 @@ -import * as utils from "@webpack-cli/utils/ast-utils"; - -import { JSCodeshift, Node } from "../types/NodePath"; - -function replaceWithPath(j: JSCodeshift, p: Node, pathVarName: string): Node { - const convertedPath: Node = j.callExpression( - j.memberExpression(j.identifier(pathVarName), j.identifier("join"), false), - [j.identifier("__dirname"), p.value as Node] - ); - - return convertedPath; -} - -/** - * - * Transform which adds `path.join` call to `output.path` literals - * - * @param {Object} j - jscodeshift top-level import - * @param {Node} ast - jscodeshift ast to transform - * @returns {Node} ast - jscodeshift ast - */ -export default function(j: JSCodeshift, ast: Node): Node | void { - const literalOutputPath: Node = ast - .find(j.ObjectExpression) - .filter((p: Node): boolean => utils.safeTraverse(p, ["parentPath", "value", "key", "name"]) === "output") - .find(j.Property) - .filter( - (p: Node): boolean => - utils.safeTraverse(p, ["value", "key", "name"]) === "path" && - utils.safeTraverse(p, ["value", "value", "type"]) === "Literal" - ); - - if (literalOutputPath) { - let pathVarName = "path"; - let isPathPresent = false; - const pathDeclaration: Node = ast - .find(j.VariableDeclarator) - .filter((p: Node): boolean => utils.safeTraverse(p, ["value", "init", "callee", "name"]) === "require") - .filter( - (p: Node): boolean => - utils.safeTraverse(p, ["value", "init", "arguments"]) && - // TODO: to fix when we have proper typing (@types/jscodeshift) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (p.value as any).init.arguments.reduce((isPresent: boolean, a: Node): boolean => { - return (a.type === "Literal" && a.value === "path") || isPresent; - }, false) - ); - - if (pathDeclaration) { - isPathPresent = true; - pathDeclaration.forEach((p: Node): void => { - pathVarName = utils.safeTraverse(p, ["value", "id", "name"]) as string; - }); - } - const finalPathName = pathVarName; - literalOutputPath.find(j.Literal).replaceWith((p: Node): Node => replaceWithPath(j, p, finalPathName)); - - if (!isPathPresent) { - const pathRequire: Node = utils.getRequire(j, "path", "path"); - return ast - .find(j.Program) - .replaceWith((p: Node): Node => j.program([].concat(pathRequire).concat((p.value as Node).body))); - } - } - - return ast; -} diff --git a/packages/migrate/package.json b/packages/migrate/package.json index 5b74a866bc9..a3f62bf04dc 100644 --- a/packages/migrate/package.json +++ b/packages/migrate/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@webpack-cli/utils": "^1.0.1-alpha.0", - "chalk": "2.4.2", + "chalk": "3.0.0", "diff": "4.0.1", "inquirer": "6.5.1", "jscodeshift": "0.6.4", @@ -24,7 +24,6 @@ "webpack": "4.x.x" }, "devDependencies": { - "@types/chalk": "2.2.0", "@types/diff": "4.0.2", "@types/inquirer": "6.5.0", "@types/listr": "0.14.2", @@ -40,5 +39,8 @@ "test": "jest", "build": "tsc", "watch": "npm run build && tsc -w" - } + }, + "files": [ + "lib" + ] } diff --git a/packages/migrate/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.test.ts b/packages/migrate/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.test.ts deleted file mode 100644 index 2e4285f1b77..00000000000 --- a/packages/migrate/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-0"); -defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-1"); -defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-2"); -defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-3"); -defineTest(dirName, "removeDeprecatedPlugins", "removeDeprecatedPlugins-4"); diff --git a/packages/migrate/removeJsonLoader/__tests__/removeJsonLoader.test.ts b/packages/migrate/removeJsonLoader/__tests__/removeJsonLoader.test.ts deleted file mode 100644 index 33274324889..00000000000 --- a/packages/migrate/removeJsonLoader/__tests__/removeJsonLoader.test.ts +++ /dev/null @@ -1,9 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "removeJsonLoader", "removeJsonLoader-0"); -defineTest(dirName, "removeJsonLoader", "removeJsonLoader-1"); -defineTest(dirName, "removeJsonLoader", "removeJsonLoader-2"); -defineTest(dirName, "removeJsonLoader", "removeJsonLoader-3"); diff --git a/packages/migrate/removeJsonLoader/removeJsonLoader.ts b/packages/migrate/removeJsonLoader/removeJsonLoader.ts deleted file mode 100644 index 1fcd9c379cb..00000000000 --- a/packages/migrate/removeJsonLoader/removeJsonLoader.ts +++ /dev/null @@ -1,77 +0,0 @@ -import * as utils from "@webpack-cli/utils/ast-utils"; - -import { JSCodeshift, Node } from "../types/NodePath"; - -type TransformCallback = (astNode: Node) => void; - -/** - * - * Transform which removes the json loader from all possible declarations - * - * @param {Object} j - jscodeshift top-level import - * @param {Node} ast - jscodeshift ast to transform - * @returns {Node} ast - jscodeshift ast - */ - -export default function(j: JSCodeshift, ast: Node): Node { - /** - * - * Remove the loader with name `name` from the given NodePath - * - * @param {Node} path - ast to remove the loader from - * @param {String} name - the name of the loader to remove - * @returns {void} - */ - - function removeLoaderByName(path: Node, name: string): void { - const loadersNode = (path.value as Node).value as Node; - - switch (loadersNode.type) { - case j.ArrayExpression.name: { - const loaders: Node[] = loadersNode.elements.map( - (p: Node): Node => { - return utils.safeTraverse(p, ["properties", "0", "value", "value"]) as Node; - } - ); - - const loaderIndex: number = loaders.indexOf(name); - if (loaders.length && loaderIndex > -1) { - // Remove loader from the array - loaders.splice(loaderIndex, 1); - // and from AST - loadersNode.elements.splice(loaderIndex, 1); - } - - // If there are no loaders left, remove the whole Rule object - if (loaders.length === 0) { - j(path.parent).remove(); - } - break; - } - case j.Literal.name: { - // If only the loader with the matching name was used - // we can remove the whole Property node completely - if (loadersNode.value === name) { - j(path.parent).remove(); - } - break; - } - } - } - - function removeLoaders(astNode: Node): void { - astNode - .find(j.Property, { key: { name: "use" } }) - .forEach((path: Node): void => removeLoaderByName(path, "json-loader")); - - astNode - .find(j.Property, { key: { name: "loader" } }) - .forEach((path: Node): void => removeLoaderByName(path, "json-loader")); - } - - const transforms: TransformCallback[] = [removeLoaders]; - - transforms.forEach((t: TransformCallback): void => t(ast)); - - return ast; -} diff --git a/packages/migrate/resolve/__tests__/resolve.test.ts b/packages/migrate/resolve/__tests__/resolve.test.ts deleted file mode 100644 index 82349cbc543..00000000000 --- a/packages/migrate/resolve/__tests__/resolve.test.ts +++ /dev/null @@ -1,5 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); -defineTest(dirName, "resolve"); diff --git a/packages/migrate/src/bannerPlugin/bannerPlugin.ts b/packages/migrate/src/bannerPlugin/bannerPlugin.ts new file mode 100644 index 00000000000..f2ee59a18e3 --- /dev/null +++ b/packages/migrate/src/bannerPlugin/bannerPlugin.ts @@ -0,0 +1,28 @@ +import { createOrUpdatePluginByName, findPluginsByName } from '@webpack-cli/utils'; + +import { JSCodeshift, Node } from '../types/NodePath'; + +/** + * + * Transform for BannerPlugin arguments. Consolidates first and second argument (if + * both are present) into single options object. + * + * @param {Object} j - jscodeshift top-level import + * @param {Node} ast - jscodeshift ast to transform + * @returns {Node} ast - jscodeshift ast + */ + +export default function(j: JSCodeshift, ast: Node): Node { + return findPluginsByName(j, ast, ['webpack.BannerPlugin']).forEach((path: Node): void => { + const args: Node[] = (path.value as Node).arguments; // any node + // If the first argument is a literal replace it with object notation + // See https://webpack.js.org/guides/migrating/#bannerplugin-breaking-change + if (args && args.length > 1 && args[0].type === j.Literal.name) { + // and remove the first argument + (path.value as Node).arguments = [(path.value as Node).arguments[1]]; + createOrUpdatePluginByName(j, path.parent, 'webpack.BannerPlugin', { + banner: args[0].value, + }); + } + }); +} diff --git a/packages/migrate/commonsChunkPlugin/commonsChunkPlugin.ts b/packages/migrate/src/commonsChunkPlugin/commonsChunkPlugin.ts similarity index 99% rename from packages/migrate/commonsChunkPlugin/commonsChunkPlugin.ts rename to packages/migrate/src/commonsChunkPlugin/commonsChunkPlugin.ts index 22110532e10..655fd034dff 100644 --- a/packages/migrate/commonsChunkPlugin/commonsChunkPlugin.ts +++ b/packages/migrate/src/commonsChunkPlugin/commonsChunkPlugin.ts @@ -5,7 +5,7 @@ import { findAndRemovePluginByName, findPluginsByName, findRootNodesByName -} from "@webpack-cli/utils/ast-utils"; +} from "@webpack-cli/utils"; import { JSCodeshift, Node } from "../types/NodePath"; diff --git a/packages/migrate/extractTextPlugin/extractTextPlugin.ts b/packages/migrate/src/extractTextPlugin/extractTextPlugin.ts similarity index 85% rename from packages/migrate/extractTextPlugin/extractTextPlugin.ts rename to packages/migrate/src/extractTextPlugin/extractTextPlugin.ts index 565ff11c3ce..bea252ce5ed 100644 --- a/packages/migrate/extractTextPlugin/extractTextPlugin.ts +++ b/packages/migrate/src/extractTextPlugin/extractTextPlugin.ts @@ -1,4 +1,4 @@ -import * as utils from "@webpack-cli/utils/ast-utils"; +import { createProperty, findVariableToPlugin, isType } from '@webpack-cli/utils'; import { JSCodeshift, Node } from "../types/NodePath"; @@ -35,19 +35,19 @@ export default function(j: JSCodeshift, ast: Node): void | Node { const changeArguments = (path: Node): Node => { const args: Node[] = (path.value as Node).arguments; - const literalArgs: Node[] = args.filter((p: Node): boolean => utils.isType(p, "Literal")); + const literalArgs: Node[] = args.filter((p: Node): boolean => isType(p, "Literal")); if (literalArgs && literalArgs.length > 1) { const newArgs: object = j.objectExpression( literalArgs.map( (p: Node, index: number): Node => - utils.createProperty(j, index === 0 ? "fallback" : "use", p.value as Node) + createProperty(j, index === 0 ? "fallback" : "use", p.value as Node) ) ); (path.value as Node).arguments = [newArgs]; } return path; }; - const name: string = utils.findVariableToPlugin(j, ast, "extract-text-webpack-plugin"); + const name: string = findVariableToPlugin(j, ast, "extract-text-webpack-plugin"); if (!name) { return ast; } diff --git a/packages/migrate/index.ts b/packages/migrate/src/index.ts similarity index 95% rename from packages/migrate/index.ts rename to packages/migrate/src/index.ts index 0aa755c92fd..c85c403accf 100644 --- a/packages/migrate/index.ts +++ b/packages/migrate/src/index.ts @@ -1,19 +1,17 @@ import chalk from "chalk"; -import * as diff from "diff"; -import * as fs from "fs"; -import * as inquirer from "inquirer"; -import * as Listr from "listr"; +import diff from "diff"; +import fs from "fs"; +import inquirer from "inquirer"; +import Listr from "listr"; import pLazy = require("p-lazy"); -import * as path from "path"; +import path from "path"; // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore import { validate, WebpackOptionsValidationError } from "webpack"; - -import runPrettier from "@webpack-cli/utils/run-prettier"; - +import { runPrettier } from "@webpack-cli/utils"; import { transformations } from "./migrate"; import { Node } from "./types/NodePath"; -import * as jscodeshift from "jscodeshift"; +import jscodeshift from "jscodeshift"; declare let process: { cwd: Function; diff --git a/packages/migrate/loaderOptionsPlugin/loaderOptionsPlugin.ts b/packages/migrate/src/loaderOptionsPlugin/loaderOptionsPlugin.ts similarity index 96% rename from packages/migrate/loaderOptionsPlugin/loaderOptionsPlugin.ts rename to packages/migrate/src/loaderOptionsPlugin/loaderOptionsPlugin.ts index 4c41b49cda0..84c451cb737 100644 --- a/packages/migrate/loaderOptionsPlugin/loaderOptionsPlugin.ts +++ b/packages/migrate/src/loaderOptionsPlugin/loaderOptionsPlugin.ts @@ -1,6 +1,6 @@ import isEmpty = require("lodash/isEmpty"); -import { createOrUpdatePluginByName, findPluginsByName, safeTraverse } from "@webpack-cli/utils/ast-utils"; +import { createOrUpdatePluginByName, findPluginsByName, safeTraverse } from "@webpack-cli/utils"; import { JSCodeshift, Node } from "../types/NodePath"; diff --git a/packages/migrate/loaders/loaders.ts b/packages/migrate/src/loaders/loaders.ts similarity index 89% rename from packages/migrate/loaders/loaders.ts rename to packages/migrate/src/loaders/loaders.ts index ff35c534842..2eb660ba338 100644 --- a/packages/migrate/loaders/loaders.ts +++ b/packages/migrate/src/loaders/loaders.ts @@ -1,4 +1,4 @@ -import * as utils from "@webpack-cli/utils/ast-utils"; +import { createLiteral, createProperty, findObjWithOneOfKeys, safeTraverse } from '@webpack-cli/utils'; import { JSCodeshift, Node } from "../types/NodePath"; @@ -73,7 +73,7 @@ export default function(j: JSCodeshift, ast: Node): Node { if (arrElement.type === j.Literal.name) { // Replace with `{ loader: LOADER }` Object return j.objectExpression([ - utils.createProperty(j, "loader", arrElement.value as Node) + createProperty(j, "loader", arrElement.value as Node) ]); } // otherwise keep the existing element @@ -88,7 +88,7 @@ export default function(j: JSCodeshift, ast: Node): Node { pair.value = j.arrayExpression( (literalValue.value as string).split("!").map( (loader: string): Node => { - return j.objectExpression([utils.createProperty(j, "loader", loader)]); + return j.objectExpression([createProperty(j, "loader", loader)]); } ) ); @@ -119,10 +119,10 @@ export default function(j: JSCodeshift, ast: Node): Node { const param: string[] = option.split("="); const key: string = param[0]; const val: string | boolean = param[1] || true; // No value in query string means it is truthy value - return j.objectProperty(j.identifier(key), utils.createLiteral(j, val)); + return j.objectProperty(j.identifier(key), createLiteral(j, val)); } ); - const loaderProp: Node = utils.createProperty(j, "loader", loader); + const loaderProp: Node = createProperty(j, "loader", loader); const queryProp: Node = j.property("init", j.identifier("options"), j.objectExpression(options)); return j.objectExpression([loaderProp, queryProp]); }; @@ -138,7 +138,7 @@ export default function(j: JSCodeshift, ast: Node): Node { const findLoaderWithQueryString = (p: Node): boolean => { return (p.value as Node).properties.reduce((predicate: boolean, prop: Node): boolean => { return ( - (utils.safeTraverse(prop, ["value", "value", "indexOf"]) && + (safeTraverse(prop, ["value", "value", "indexOf"]) && ((prop.value as Node).value as string).indexOf("?") > -1) || predicate ); @@ -156,7 +156,7 @@ export default function(j: JSCodeshift, ast: Node): Node { const checkForLoader = (path: Node): boolean => (path.value as Node).name === "loaders" && - utils.safeTraverse(path, ["parent", "parent", "parent", "node", "key", "name"]) === "module"; + safeTraverse(path, ["parent", "parent", "parent", "node", "key", "name"]) === "module"; /** * Puts pre- or postLoader into `loaders` object and adds the appropriate `enforce` property @@ -178,7 +178,7 @@ export default function(j: JSCodeshift, ast: Node): Node { if (keyName !== "loaders") { const enforceVal: string = keyName === "preLoaders" ? "pre" : "post"; (prop.value as Node).elements.map((elem: Node): void => { - elem.properties.push(utils.createProperty(j, "enforce", enforceVal)); + elem.properties.push(createProperty(j, "enforce", enforceVal)); if (loaders && loaders.type === "ArrayExpression") { loaders.elements.push(elem); } else { @@ -204,7 +204,7 @@ export default function(j: JSCodeshift, ast: Node): Node { const prepostLoaders = (): Node => ast .find(j.ObjectExpression) - .filter((p: Node): boolean => utils.findObjWithOneOfKeys(p, ["preLoaders", "postLoaders"])) + .filter((p: Node): boolean => findObjWithOneOfKeys(p, ["preLoaders", "postLoaders"])) .forEach(fitIntoLoaders); /** @@ -228,10 +228,10 @@ export default function(j: JSCodeshift, ast: Node): Node { const loadersToArrayExpression = (): Node | void => ast .find(j.ObjectExpression) - .filter((path: Node): boolean => utils.findObjWithOneOfKeys(path, ["loader", "loaders"])) + .filter((path: Node): boolean => findObjWithOneOfKeys(path, ["loader", "loaders"])) .filter( (path: Node): boolean => - utils.safeTraverse(path, ["parent", "parent", "node", "key", "name"]) === "rules" + safeTraverse(path, ["parent", "parent", "node", "key", "name"]) === "rules" ) .forEach(createArrayExpressionFromArray); @@ -260,7 +260,7 @@ export default function(j: JSCodeshift, ast: Node): Node { const loaderWithQueryParam = (): Node => ast .find(j.ObjectExpression) - .filter((p: Node): boolean => utils.findObjWithOneOfKeys(p, ["loader"])) + .filter((p: Node): boolean => findObjWithOneOfKeys(p, ["loader"])) .filter(findLoaderWithQueryString) .replaceWith(createLoaderWithQuery); @@ -299,7 +299,7 @@ export default function(j: JSCodeshift, ast: Node): Node { (path.value as Node).properties.forEach((prop: Node): void => { if ( prop.key.name === "loader" && - utils.safeTraverse(prop, ["value", "value"]) && + safeTraverse(prop, ["value", "value"]) && !((prop.value as Node).value as string).endsWith("-loader") ) { prop.value = j.literal(((prop.value as Node).value as string) + "-loader"); @@ -349,7 +349,7 @@ export default function(j: JSCodeshift, ast: Node): Node { const moveOptionsToUse = (): Node => ast .find(j.ObjectExpression) - .filter((p: Node): boolean => utils.findObjWithOneOfKeys(p, ["use"])) + .filter((p: Node): boolean => findObjWithOneOfKeys(p, ["use"])) .forEach(fitOptionsToUse); const transforms = [ diff --git a/packages/migrate/migrate.ts b/packages/migrate/src/migrate.ts similarity index 99% rename from packages/migrate/migrate.ts rename to packages/migrate/src/migrate.ts index f39326aeb61..02bb20319a1 100644 --- a/packages/migrate/migrate.ts +++ b/packages/migrate/src/migrate.ts @@ -1,7 +1,6 @@ -import * as jscodeshift from "jscodeshift"; +import jscodeshift from "jscodeshift"; import pEachSeries = require("p-each-series"); import pLazy = require("p-lazy"); - import bannerPluginTransform from "./bannerPlugin/bannerPlugin"; import commonsChunkPluginTransform from "./commonsChunkPlugin/commonsChunkPlugin"; import extractTextPluginTransform from "./extractTextPlugin/extractTextPlugin"; diff --git a/packages/migrate/moduleConcatenationPlugin/moduleConcatenationPlugin.ts b/packages/migrate/src/moduleConcatenationPlugin/moduleConcatenationPlugin.ts similarity index 95% rename from packages/migrate/moduleConcatenationPlugin/moduleConcatenationPlugin.ts rename to packages/migrate/src/moduleConcatenationPlugin/moduleConcatenationPlugin.ts index 658d2c1359f..caa25803940 100644 --- a/packages/migrate/moduleConcatenationPlugin/moduleConcatenationPlugin.ts +++ b/packages/migrate/src/moduleConcatenationPlugin/moduleConcatenationPlugin.ts @@ -1,4 +1,4 @@ -import { addOrUpdateConfigObject, findAndRemovePluginByName } from "@webpack-cli/utils/ast-utils"; +import { addOrUpdateConfigObject, findAndRemovePluginByName } from "@webpack-cli/utils"; import { JSCodeshift, Node } from "../types/NodePath"; diff --git a/packages/migrate/namedModulesPlugin/namedModulesPlugin.ts b/packages/migrate/src/namedModulesPlugin/namedModulesPlugin.ts similarity index 95% rename from packages/migrate/namedModulesPlugin/namedModulesPlugin.ts rename to packages/migrate/src/namedModulesPlugin/namedModulesPlugin.ts index 34faab3cd4b..fd73fdd045e 100644 --- a/packages/migrate/namedModulesPlugin/namedModulesPlugin.ts +++ b/packages/migrate/src/namedModulesPlugin/namedModulesPlugin.ts @@ -1,4 +1,4 @@ -import { addOrUpdateConfigObject, findAndRemovePluginByName } from "@webpack-cli/utils/ast-utils"; +import { addOrUpdateConfigObject, findAndRemovePluginByName } from "@webpack-cli/utils"; import { JSCodeshift, Node } from "../types/NodePath"; diff --git a/packages/migrate/noEmitOnErrorsPlugin/noEmitOnErrorsPlugin.ts b/packages/migrate/src/noEmitOnErrorsPlugin/noEmitOnErrorsPlugin.ts similarity index 95% rename from packages/migrate/noEmitOnErrorsPlugin/noEmitOnErrorsPlugin.ts rename to packages/migrate/src/noEmitOnErrorsPlugin/noEmitOnErrorsPlugin.ts index 567d688a47c..283cc3c880c 100644 --- a/packages/migrate/noEmitOnErrorsPlugin/noEmitOnErrorsPlugin.ts +++ b/packages/migrate/src/noEmitOnErrorsPlugin/noEmitOnErrorsPlugin.ts @@ -1,4 +1,4 @@ -import { addOrUpdateConfigObject, findAndRemovePluginByName } from "@webpack-cli/utils/ast-utils"; +import { addOrUpdateConfigObject, findAndRemovePluginByName } from "@webpack-cli/utils"; import { JSCodeshift, Node } from "../types/NodePath"; /** diff --git a/packages/migrate/src/outputPath/outputPath.ts b/packages/migrate/src/outputPath/outputPath.ts new file mode 100644 index 00000000000..cd8bcab03d7 --- /dev/null +++ b/packages/migrate/src/outputPath/outputPath.ts @@ -0,0 +1,64 @@ +import { getRequire, safeTraverse } from '@webpack-cli/utils'; + +import { JSCodeshift, Node } from '../types/NodePath'; + +function replaceWithPath(j: JSCodeshift, p: Node, pathVarName: string): Node { + const convertedPath: Node = j.callExpression(j.memberExpression(j.identifier(pathVarName), j.identifier('join'), false), [ + j.identifier('__dirname'), + p.value as Node, + ]); + + return convertedPath; +} + +/** + * + * Transform which adds `path.join` call to `output.path` literals + * + * @param {Object} j - jscodeshift top-level import + * @param {Node} ast - jscodeshift ast to transform + * @returns {Node} ast - jscodeshift ast + */ +export default function(j: JSCodeshift, ast: Node): Node | void { + const literalOutputPath: Node = ast + .find(j.ObjectExpression) + .filter((p: Node): boolean => safeTraverse(p, ['parentPath', 'value', 'key', 'name']) === 'output') + .find(j.Property) + .filter( + (p: Node): boolean => + safeTraverse(p, ['value', 'key', 'name']) === 'path' && safeTraverse(p, ['value', 'value', 'type']) === 'Literal', + ); + + if (literalOutputPath) { + let pathVarName = 'path'; + let isPathPresent = false; + const pathDeclaration: Node = ast + .find(j.VariableDeclarator) + .filter((p: Node): boolean => safeTraverse(p, ['value', 'init', 'callee', 'name']) === 'require') + .filter( + (p: Node): boolean => + safeTraverse(p, ['value', 'init', 'arguments']) && + // TODO: to fix when we have proper typing (@types/jscodeshift) + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (p.value as any).init.arguments.reduce((isPresent: boolean, a: Node): boolean => { + return (a.type === 'Literal' && a.value === 'path') || isPresent; + }, false), + ); + + if (pathDeclaration) { + isPathPresent = true; + pathDeclaration.forEach((p: Node): void => { + pathVarName = safeTraverse(p, ['value', 'id', 'name']) as string; + }); + } + const finalPathName = pathVarName; + literalOutputPath.find(j.Literal).replaceWith((p: Node): Node => replaceWithPath(j, p, finalPathName)); + + if (!isPathPresent) { + const pathRequire: Node = getRequire(j, 'path', 'path'); + return ast.find(j.Program).replaceWith((p: Node): Node => j.program([].concat(pathRequire).concat((p.value as Node).body))); + } + } + + return ast; +} diff --git a/packages/migrate/removeDeprecatedPlugins/removeDeprecatedPlugins.ts b/packages/migrate/src/removeDeprecatedPlugins/removeDeprecatedPlugins.ts similarity index 76% rename from packages/migrate/removeDeprecatedPlugins/removeDeprecatedPlugins.ts rename to packages/migrate/src/removeDeprecatedPlugins/removeDeprecatedPlugins.ts index 4770ae36ffb..c2e5dd6d900 100644 --- a/packages/migrate/removeDeprecatedPlugins/removeDeprecatedPlugins.ts +++ b/packages/migrate/src/removeDeprecatedPlugins/removeDeprecatedPlugins.ts @@ -1,6 +1,6 @@ import chalk from "chalk"; -import * as utils from "@webpack-cli/utils/ast-utils"; +import { findPluginsByName, isType, safeTraverse } from '@webpack-cli/utils'; import { JSCodeshift, Node } from "../types/NodePath"; @@ -22,15 +22,15 @@ export default function(j: JSCodeshift, ast: Node): Node { "webpack.optimize.DedupePlugin" ]; - return utils.findPluginsByName(j, ast, deprecatedPlugingsList).forEach((path: Node): void => { + return findPluginsByName(j, ast, deprecatedPlugingsList).forEach((path: Node): void => { // For now we only support the case where plugins are defined in an Array - const arrayPath = utils.safeTraverse(path, ["parent", "value"]) as Node; + const arrayPath = safeTraverse(path, ["parent", "value"]) as Node; - if (arrayPath && utils.isType(arrayPath, "ArrayExpression")) { + if (arrayPath && isType(arrayPath, "ArrayExpression")) { // Check how many plugins are defined and // if there is only last plugin left remove `plugins: []` node // - const arrayElementsPath = utils.safeTraverse(arrayPath, ["elements"]) as Node[]; + const arrayElementsPath = safeTraverse(arrayPath, ["elements"]) as Node[]; if (arrayElementsPath && arrayElementsPath.length === 1) { j(path.parent.parent).remove(); } else { diff --git a/packages/migrate/src/removeJsonLoader/removeJsonLoader.ts b/packages/migrate/src/removeJsonLoader/removeJsonLoader.ts new file mode 100644 index 00000000000..ce088c29c4b --- /dev/null +++ b/packages/migrate/src/removeJsonLoader/removeJsonLoader.ts @@ -0,0 +1,73 @@ +import { safeTraverse } from '@webpack-cli/utils'; + +import { JSCodeshift, Node } from '../types/NodePath'; + +type TransformCallback = (astNode: Node) => void; + +/** + * + * Transform which removes the json loader from all possible declarations + * + * @param {Object} j - jscodeshift top-level import + * @param {Node} ast - jscodeshift ast to transform + * @returns {Node} ast - jscodeshift ast + */ + +export default function(j: JSCodeshift, ast: Node): Node { + /** + * + * Remove the loader with name `name` from the given NodePath + * + * @param {Node} path - ast to remove the loader from + * @param {String} name - the name of the loader to remove + * @returns {void} + */ + + function removeLoaderByName(path: Node, name: string): void { + const loadersNode = (path.value as Node).value as Node; + + switch (loadersNode.type) { + case j.ArrayExpression.name: { + const loaders: Node[] = loadersNode.elements.map( + (p: Node): Node => { + return safeTraverse(p, ['properties', '0', 'value', 'value']) as Node; + }, + ); + + const loaderIndex: number = loaders.indexOf(name); + if (loaders.length && loaderIndex > -1) { + // Remove loader from the array + loaders.splice(loaderIndex, 1); + // and from AST + loadersNode.elements.splice(loaderIndex, 1); + } + + // If there are no loaders left, remove the whole Rule object + if (loaders.length === 0) { + j(path.parent).remove(); + } + break; + } + case j.Literal.name: { + // If only the loader with the matching name was used + // we can remove the whole Property node completely + if (loadersNode.value === name) { + j(path.parent).remove(); + } + break; + } + } + } + + function removeLoaders(astNode: Node): void { + astNode.find(j.Property, { key: { name: 'use' } }).forEach((path: Node): void => removeLoaderByName(path, 'json-loader')); + + astNode.find(j.Property, { key: { name: 'loader' } }).forEach((path: Node): void => removeLoaderByName(path, 'json-loader')); + } + + const transforms: TransformCallback[] = [removeLoaders]; + + transforms.forEach((t: TransformCallback): void => t(ast)); + + return ast; +} diff --git a/packages/migrate/resolve/resolve.ts b/packages/migrate/src/resolve/resolve.ts similarity index 100% rename from packages/migrate/resolve/resolve.ts rename to packages/migrate/src/resolve/resolve.ts diff --git a/packages/migrate/types/NodePath.ts b/packages/migrate/src/types/NodePath.ts similarity index 100% rename from packages/migrate/types/NodePath.ts rename to packages/migrate/src/types/NodePath.ts diff --git a/packages/migrate/uglifyJsPlugin/uglifyJsPlugin.ts b/packages/migrate/src/uglifyJsPlugin/uglifyJsPlugin.ts similarity index 98% rename from packages/migrate/uglifyJsPlugin/uglifyJsPlugin.ts rename to packages/migrate/src/uglifyJsPlugin/uglifyJsPlugin.ts index 47513eeea56..37b31190e74 100644 --- a/packages/migrate/uglifyJsPlugin/uglifyJsPlugin.ts +++ b/packages/migrate/src/uglifyJsPlugin/uglifyJsPlugin.ts @@ -4,7 +4,7 @@ import { findPluginsByName, getRequire, safeTraverse -} from "@webpack-cli/utils/ast-utils"; +} from "@webpack-cli/utils"; import { JSCodeshift, Node } from "../types/NodePath"; diff --git a/packages/migrate/tsconfig.json b/packages/migrate/tsconfig.json index 8b1269a36b6..e99a11c762b 100644 --- a/packages/migrate/tsconfig.json +++ b/packages/migrate/tsconfig.json @@ -1,3 +1,12 @@ -{ - "extends": "../../tsconfig.packages.json" -} +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"], + "references": [ + {"path": "../utils"} + ] +} diff --git a/packages/migrate/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.ts b/packages/migrate/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.ts deleted file mode 100644 index d5e3ddbaf97..00000000000 --- a/packages/migrate/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import defineTest from "@webpack-cli/utils/defineTest"; -import { join } from "path"; - -const dirName: string = join(__dirname, ".."); - -defineTest(dirName, "uglifyJsPlugin", "uglifyJsPlugin-0"); -defineTest(dirName, "uglifyJsPlugin", "uglifyJsPlugin-1"); -defineTest(dirName, "uglifyJsPlugin", "uglifyJsPlugin-2"); -defineTest(dirName, "uglifyJsPlugin", "uglifyJsPlugin-3"); -defineTest(dirName, "uglifyJsPlugin", "uglifyJsPlugin-4"); diff --git a/packages/package-utils/.eslintrc b/packages/package-utils/.eslintrc new file mode 100644 index 00000000000..e8b8b926974 --- /dev/null +++ b/packages/package-utils/.eslintrc @@ -0,0 +1,10 @@ +{ + "root": true, + "extends": [ + "plugin:@typescript-eslint/recommended", + "prettier", + "prettier/@typescript-eslint" + ], + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], +} diff --git a/packages/package-utils/.gitignore b/packages/package-utils/.gitignore new file mode 100644 index 00000000000..c3af857904e --- /dev/null +++ b/packages/package-utils/.gitignore @@ -0,0 +1 @@ +lib/ diff --git a/packages/package-utils/README.md b/packages/package-utils/README.md new file mode 100644 index 00000000000..6b781a5f484 --- /dev/null +++ b/packages/package-utils/README.md @@ -0,0 +1,11 @@ +# `@webpack-cli/package-utils` + +> TODO: description + +## Usage + +``` +const packageUtils = require('@webpack-cli/package-utils'); + +// TODO: DEMONSTRATE API +``` diff --git a/packages/package-utils/__tests__/index.test.ts b/packages/package-utils/__tests__/index.test.ts new file mode 100644 index 00000000000..bb67a82eae2 --- /dev/null +++ b/packages/package-utils/__tests__/index.test.ts @@ -0,0 +1,11 @@ +'use strict'; + +import { packageExists } from '../src'; + +describe('@webpack-cli/package-utils', () => { + it('should check existence of package', () => { + const exists = packageExists('@webpack-cli/info'); + + expect(exists).toBeTruthy(); + }); +}); diff --git a/packages/package-utils/package.json b/packages/package-utils/package.json new file mode 100644 index 00000000000..42224014172 --- /dev/null +++ b/packages/package-utils/package.json @@ -0,0 +1,47 @@ +{ + "name": "@webpack-cli/package-utils", + "version": "1.0.0", + "description": "A module to help managing packages and modules inside webpack CLI", + "keywords": [ + "webpack", + "webpack-cli", + "node", + "package", + "utils", + "npm", + "yarn" + ], + "author": "emanuele ", + "homepage": "https://github.com/ematipico/webpack-cli#readme", + "license": "MIT", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "directories": { + "test": "__tests__" + }, + "files": [ + "lib" + ], + "publishConfig": { + "registry": "https://registry.yarnpkg.com" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/ematipico/webpack-cli.git" + }, + "scripts": { + "test": "echo \"Error: run tests from root\" && exit 1" + }, + "bugs": { + "url": "https://github.com/ematipico/webpack-cli/issues" + }, + "dependencies": { + "execa": "^4.0.0", + "chalk": "^3.0.0", + "enquirer": "^2.3.4", + "@webpack-cli/logger": "1.0.0" + }, + "devDependencies": { + "typescript": "^3.8.2" + } +} diff --git a/packages/package-utils/src/index.ts b/packages/package-utils/src/index.ts new file mode 100644 index 00000000000..f4e2de5cfe0 --- /dev/null +++ b/packages/package-utils/src/index.ts @@ -0,0 +1,5 @@ +export * from './packageUtils' +export * from './processUtils' + + + diff --git a/packages/package-utils/src/packageUtils.ts b/packages/package-utils/src/packageUtils.ts new file mode 100644 index 00000000000..47fffb0dcc8 --- /dev/null +++ b/packages/package-utils/src/packageUtils.ts @@ -0,0 +1,98 @@ +import fs from 'fs'; +import path from 'path'; +import { sync } from 'execa'; +import spawn from 'cross-spawn'; +import chalk = require('chalk'); +import { prompt } from 'enquirer'; +import { runCommand } from './processUtils'; + +/** + * + * Returns the name of package manager to use, + * preferring yarn over npm if available + * + * @returns {String} - The package manager name + */ + +type PackageName = 'npm' | 'yarn'; + +export function getPackageManager(): PackageName { + const hasLocalYarn = fs.existsSync(path.resolve(process.cwd(), 'yarn.lock')); + try { + if (hasLocalYarn) { + return 'yarn'; + } else if (sync('yarn', [' --version'], { stdio: 'ignore' }).stderr) { + return 'yarn'; + } else { + return 'npm'; + } + } catch (e) { + return 'npm'; + } +} + +/** + * + * Returns the path to globally installed + * npm packages, depending on the available + * package manager determined by `getPackageManager` + * + * @returns {String} path - Path to global node_modules folder + */ +export function getPathToGlobalPackages(): string { + const manager: string = getPackageManager(); + + if (manager === 'yarn') { + try { + const yarnDir = spawn + .sync('yarn', ['global', 'dir']) + .stdout.toString() + .trim(); + return path.join(yarnDir, 'node_modules'); + } catch (e) { + // Default to the global npm path below + } + } + + return require('global-modules'); +} + +export function packageExists(packageName: string): boolean { + try { + require(packageName); + return true; + } catch (err) { + return false; + } +} + +/** + * + * @param packageName + * @param preMessage Message to show before the question + */ +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +export async function promptInstallation(packageName: string, preMessage?: Function) { + const packageManager = getPackageManager(); + const options = [packageManager === 'yarn' ? 'add' : 'install', '-D', packageName]; + + const commandToBeRun = `${packageManager} ${options.join(' ')}`; + if (preMessage) { + preMessage(); + } + const question = `Would you like to install ${packageName}? (That will run ${chalk.green(commandToBeRun)})`; + const { installConfirm } = await prompt([ + { + type: 'confirm', + name: 'installConfirm', + message: question, + initial: 'Y', + }, + ]); + if (installConfirm) { + await runCommand(commandToBeRun); + return packageExists(packageName); + } + // eslint-disable-next-line require-atomic-updates + process.exitCode = -1; +} diff --git a/packages/package-utils/src/processUtils.ts b/packages/package-utils/src/processUtils.ts new file mode 100644 index 00000000000..a85324f5bdc --- /dev/null +++ b/packages/package-utils/src/processUtils.ts @@ -0,0 +1,52 @@ +import execa, { ExecaSyncReturnValue, sync } from 'execa'; +import { getPackageManager, getPathToGlobalPackages } from './packageUtils'; +import path from 'path'; +import fs from 'fs'; + +/** + * + * Spawns a new process using the respective package manager + * + * @param {String} pkg - The dependency to be installed + * @param {Boolean} isNew - indicates if it needs to be updated or installed + * @returns {Function} spawn - Installs the package + */ + +function spawnWithArg(pkg: string, isNew: boolean): ExecaSyncReturnValue { + const packageManager: string = getPackageManager(); + let options = []; + + if (packageManager === 'npm') { + options = [isNew ? 'install' : 'update', '-g', pkg]; + } else { + options = ['global', isNew ? 'add' : 'upgrade', pkg]; + } + + return sync(packageManager, options, { + stdio: 'inherit', + }); +} + +/** + * + * Spawns a new process + * + */ +export function spawnChild(pkg: string): ExecaSyncReturnValue { + const rootPath: string = getPathToGlobalPackages(); + const pkgPath: string = path.resolve(rootPath, pkg); + const isNew = !fs.existsSync(pkgPath); + + return spawnWithArg(pkg, isNew); +} + +export async function runCommand(command, args = []): Promise { + try { + await execa(command, args, { + stdio: 'inherit', + shell: true, + }); + } catch (e) { + throw new Error(e); + } +} diff --git a/packages/package-utils/tsconfig.json b/packages/package-utils/tsconfig.json new file mode 100644 index 00000000000..fe4ccf4dffe --- /dev/null +++ b/packages/package-utils/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"], + "references": [ + {"path": "../logger"} + ] +} diff --git a/packages/serve/.gitignore b/packages/serve/.gitignore index 98c957c64d7..ba2eef410b8 100644 --- a/packages/serve/.gitignore +++ b/packages/serve/.gitignore @@ -1,2 +1,3 @@ *.js.map *.js +lib/ diff --git a/test/serve/args-to-camel-case.test.js b/packages/serve/__tests__/args-to-camel-case.test.ts similarity index 75% rename from test/serve/args-to-camel-case.test.js rename to packages/serve/__tests__/args-to-camel-case.test.ts index c10e3e733d2..d0be1fae037 100644 --- a/test/serve/args-to-camel-case.test.js +++ b/packages/serve/__tests__/args-to-camel-case.test.ts @@ -1,6 +1,6 @@ 'use strict'; -const argsToCamelCase = require('../../packages/serve/args-to-camel-case'); +import argsToCamelCase from '../src/args-to-camel-case' describe('args-to-camel-case helper', () => { it('converts arguments with multiple dashes to camel case', () => { @@ -14,6 +14,6 @@ describe('args-to-camel-case helper', () => { multiWordArg2: 'hello world', argument: 0, }; - expect(argsToCamelCase.default(obj)).toEqual(result); + expect(argsToCamelCase(obj)).toEqual(result); }); }); diff --git a/packages/serve/package.json b/packages/serve/package.json index 49ef9fb1e2c..71968b01451 100644 --- a/packages/serve/package.json +++ b/packages/serve/package.json @@ -2,17 +2,20 @@ "name": "@webpack-cli/serve", "version": "1.0.1-alpha.0", "description": "", - "main": "index.js", - "types": "index.d.ts", + "main": "./lib/index.js", + "types": "./lib/index.d.ts", "keywords": [], "publishConfig": { "access": "public" }, + "files": [ + "lib" + ], "author": "", "license": "MIT", "dependencies": { "@webpack-cli/utils": "^1.0.1-alpha.0", - "chalk": "2.4.2", + "chalk": "3.0.0", "cross-spawn": "6.0.5", "inquirer": "6.5.1", "webpack-dev-server": "^3.9.0", diff --git a/packages/serve/args-to-camel-case.ts b/packages/serve/src/args-to-camel-case.ts similarity index 100% rename from packages/serve/args-to-camel-case.ts rename to packages/serve/src/args-to-camel-case.ts diff --git a/packages/serve/index.ts b/packages/serve/src/index.ts similarity index 82% rename from packages/serve/index.ts rename to packages/serve/src/index.ts index 8f1241ba38c..f9d6c6eef00 100644 --- a/packages/serve/index.ts +++ b/packages/serve/src/index.ts @@ -1,7 +1,7 @@ import { devServer } from "webpack-dev-server/bin/cli-flags"; -import * as WebpackCLI from "webpack-cli"; -import * as startDevServer from "./startDevServer"; -import * as argsToCamelCase from "./args-to-camel-case"; +import WebpackCLI from "webpack-cli"; +import startDevServer from "./startDevServer"; +import argsToCamelCase from "./args-to-camel-case"; /** * @@ -21,12 +21,12 @@ export default function serve(...args): void { // see: https://github.com/75lb/command-line-args/blob/master/doc/option-definition.md#optiondefaultoption--boolean const devServerArgs = cli.commandLineArgs(devServer, { argv: args, partial: true }); const webpackArgs = cli.commandLineArgs(core, { argv: devServerArgs._unknown || [], stopAtFirstUnknown: false }); - const finalArgs = argsToCamelCase.default(devServerArgs._all || {}); + const finalArgs = argsToCamelCase(devServerArgs._all || {}); // pass along the 'hot' argument to the dev server if it exists if (webpackArgs && webpackArgs._all && typeof webpackArgs._all.hot !== 'undefined') { finalArgs['hot'] = webpackArgs._all.hot; } cli.getCompiler(webpackArgs, core).then((compiler): void => { - startDevServer.default(compiler, finalArgs); + startDevServer(compiler, finalArgs); }); } diff --git a/packages/serve/startDevServer.ts b/packages/serve/src/startDevServer.ts similarity index 92% rename from packages/serve/startDevServer.ts rename to packages/serve/src/startDevServer.ts index 6a448550d60..8b7daa871d3 100644 --- a/packages/serve/startDevServer.ts +++ b/packages/serve/src/startDevServer.ts @@ -1,4 +1,4 @@ -import * as Server from "webpack-dev-server/lib/Server"; +import Server from "webpack-dev-server/lib/Server"; /** * @@ -6,8 +6,8 @@ import * as Server from "webpack-dev-server/lib/Server"; * * @param {Object} compiler - a webpack compiler * @param {Object} options - devServer options - * - * @returns {Void} + * + * @returns {Void} */ export default function startDevServer(compiler, options): void { const firstWpOpt = compiler.compilers diff --git a/packages/serve/tsconfig.json b/packages/serve/tsconfig.json index b767d00084e..9f70d73f8e0 100644 --- a/packages/serve/tsconfig.json +++ b/packages/serve/tsconfig.json @@ -1,3 +1,10 @@ -{ - "extends": "../../tsconfig.packages.json" -} +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"], + "references": [{ "path": "../utils" }] +} diff --git a/packages/utils/.gitignore b/packages/utils/.gitignore index 04d5044e769..c3af857904e 100644 --- a/packages/utils/.gitignore +++ b/packages/utils/.gitignore @@ -1,6 +1 @@ -/*.js -/**/*.js -!*.test.js -!/**/*.test.js -!/**/__testfixtures__/*.js -!/**/__snapshots__/*.js +lib/ diff --git a/packages/utils/__tests__/.eslintrc b/packages/utils/__tests__/.eslintrc index 5d4340a351d..d172911a863 100644 --- a/packages/utils/__tests__/.eslintrc +++ b/packages/utils/__tests__/.eslintrc @@ -1,7 +1,7 @@ { - "root": true, - "extends": ["../.eslintrc"], - "rules": { - "@typescript-eslint/explicit-function-return-type": ["off"] - } + "root": true, + "extends": ["../.eslintrc"], + "rules": { + "@typescript-eslint/explicit-function-return-type": ["off"] + } } diff --git a/packages/utils/__tests__/__snapshots__/recursive-parser.test.ts.snap b/packages/utils/__tests__/__snapshots__/recursive-parser.test.ts.snap deleted file mode 100644 index 282542a0fd7..00000000000 --- a/packages/utils/__tests__/__snapshots__/recursive-parser.test.ts.snap +++ /dev/null @@ -1,380 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`add transforms correctly using "fixture-2" data 1`] = ` -"const webpack = require(\\"webpack\\"); - -module.exports = { - entry: { - objects: \\"are\\", - - super: [ - \\"yeah\\", - { - test: new RegExp(/\\\\.(js|vue)$/), - loader: \\"'eslint-loader'\\", - enforce: \\"'pre'\\", - include: [\\"customObj\\", \\"'Stringy'\\"], - options: { - formatter: \\"'oki'\\", - updateMe: \\"sure\\" - } - } - ], - - nice: \\"':)'\\", - foo: \\"Promise.resolve()\\", - man: \\"() => duper\\", - mode: \\"yaaa\\", - foo: Promise.resolve(), - man: () => nice!!, - mode: super-man, - nice: '=)', - objects: are not, - - super: [op, { - enforce: 'pre', - include: [asd, 'Stringy'], - loader: 'pia-loader', - - options: { - formatter: 'nao' - }, - - test: /\\\\.(wasm|c)$/ - }] - } -} -" -`; - -exports[`init transforms correctly using "fixture-1" data 1`] = ` -"module.exports = { - entry: { - foo: Promise.resolve(), - man: () => duper, - nice: ':)', - objects: are, - - super: [yeah, { - enforce: 'pre', - include: [customObj, 'Stringy'], - loader: 'eslint-loader', - - options: { - formatter: 'someOption' - }, - - test: /\\\\.(js|vue)$/ - }] - } -};" -`; - -exports[`remove transforms correctly using "fixture-3" data 1`] = ` -"module.exports = { - entry: { - a: \\"a.js\\", - b: \\"taddda\\", - }, - mode: \\"prod\\", - devServer: { - port: 9000, - }, - devtool: \\"eval\\", - plugins: [ - \\"plugin1\\", - \\"plugin2\\", - \\"plugin3\\", - ], - resolve: { - aliasFields: [\\"'browser'\\", \\"wars\\"], - descriptionFiles: [\\"'a'\\", \\"b\\", \\"'c'\\"], - enforceExtension: false, - enforceModuleExtension: false, - extensions: [\\"hey\\", \\"ho\\"], - mainFields: [\\"main\\", \\"'story'\\"], - mainFiles: [\\"'noMainFileHere'\\", \\"iGuess\\"], - modules: [\\"one\\", \\"'two'\\"], - unsafeCache: false, - - resolveLoader: { - modules: [\\"'node_modules'\\", \\"mode_nodules\\"], - extensions: [\\"jsVal\\", \\"'.json'\\"], - mainFields: [\\"loader\\", \\"'main'\\"], - moduleExtensions: [\\"'-loader'\\", \\"value\\"] - }, - - plugins: [\\"somePlugin\\", \\"'stringVal'\\"], - symlinks: true - }, - module: { - noParse: function(content) { - return /jquery|lodash/.test(content); - }, - rules: [ - { - loader: \\"eslint-loader\\", - options: { - formatter: \\"someOption\\" - } - }, - { - loader: \\"vue-loader\\", - options: \\"vueObject\\" - }, - { - loader: \\"babel-loader\\", - include: \\"asdf\\" - } - ] - } -}; -" -`; - -exports[`remove transforms correctly using "fixture-3" data 2`] = ` -"module.exports = { - entry: { - a: \\"a.js\\", - b: \\"taddda\\", - }, - mode: \\"prod\\", - devServer: { - port: 9000, - }, - devtool: \\"eval\\", - plugins: [\\"plugin1\\", \\"plugin3\\"], - resolve: { - alias: { - inject: \\"{{#if_eq build 'standalone'}}\\", - hello: \\"'world'\\", - inject_1: \\"{{/if_eq}}\\", - world: \\"hello\\" - }, - aliasFields: [\\"'browser'\\", \\"wars\\"], - descriptionFiles: [\\"'a'\\", \\"b\\", \\"'c'\\"], - enforceExtension: false, - enforceModuleExtension: false, - extensions: [\\"hey\\", \\"ho\\"], - mainFields: [\\"main\\", \\"'story'\\"], - mainFiles: [\\"'noMainFileHere'\\", \\"iGuess\\"], - modules: [\\"one\\", \\"'two'\\"], - unsafeCache: false, - resolveLoader: { - modules: [\\"'node_modules'\\", \\"mode_nodules\\"], - extensions: [\\"jsVal\\", \\"'.json'\\"], - mainFields: [\\"loader\\", \\"'main'\\"], - moduleExtensions: [\\"'-loader'\\", \\"value\\"] - }, - plugins: [\\"somePlugin\\", \\"'stringVal'\\"], - symlinks: true - }, - module: { - noParse: function(content) { - return /jquery|lodash/.test(content); - }, - rules: [ - { - loader: \\"eslint-loader\\", - options: { - formatter: \\"someOption\\" - } - }, - { - loader: \\"vue-loader\\", - options: \\"vueObject\\" - }, - { - loader: \\"babel-loader\\", - include: \\"asdf\\" - } - ] - } -}; -" -`; - -exports[`remove transforms correctly using "fixture-3" data 3`] = ` -"module.exports = { - entry: { - a: \\"a.js\\", - b: \\"taddda\\", - }, - mode: \\"prod\\", - devServer: { - port: 9000, - }, - devtool: \\"eval\\", - plugins: [ - \\"plugin1\\", - \\"plugin2\\", - \\"plugin3\\", - ], - resolve: { - alias: { - inject: \\"{{#if_eq build 'standalone'}}\\", - hello: \\"'world'\\", - inject_1: \\"{{/if_eq}}\\", - world: \\"hello\\" - }, - aliasFields: [\\"'browser'\\", \\"wars\\"], - descriptionFiles: [\\"'a'\\", \\"b\\", \\"'c'\\"], - enforceExtension: false, - enforceModuleExtension: false, - extensions: [\\"hey\\", \\"ho\\"], - mainFields: [\\"main\\", \\"'story'\\"], - mainFiles: [\\"'noMainFileHere'\\", \\"iGuess\\"], - modules: [\\"one\\", \\"'two'\\"], - unsafeCache: false, - resolveLoader: { - modules: [\\"'node_modules'\\", \\"mode_nodules\\"], - extensions: [\\"jsVal\\", \\"'.json'\\"], - mainFields: [\\"loader\\", \\"'main'\\"], - moduleExtensions: [\\"'-loader'\\", \\"value\\"] - }, - plugins: [\\"somePlugin\\", \\"'stringVal'\\"], - symlinks: true - }, - module: { - rules: [ - { - loader: \\"eslint-loader\\", - options: { - formatter: \\"someOption\\" - } - }, - { - loader: \\"vue-loader\\", - options: \\"vueObject\\" - }, - { - loader: \\"babel-loader\\", - include: \\"asdf\\" - } - ] - } -}; -" -`; - -exports[`remove transforms correctly using "fixture-3" data 4`] = ` -"module.exports = { - entry: { - b: \\"taddda\\" - }, - mode: \\"prod\\", - devServer: { - port: 9000, - }, - devtool: \\"eval\\", - plugins: [ - \\"plugin1\\", - \\"plugin2\\", - \\"plugin3\\", - ], - resolve: { - alias: { - inject: \\"{{#if_eq build 'standalone'}}\\", - hello: \\"'world'\\", - inject_1: \\"{{/if_eq}}\\", - world: \\"hello\\" - }, - aliasFields: [\\"'browser'\\", \\"wars\\"], - descriptionFiles: [\\"'a'\\", \\"b\\", \\"'c'\\"], - enforceExtension: false, - enforceModuleExtension: false, - extensions: [\\"hey\\", \\"ho\\"], - mainFields: [\\"main\\", \\"'story'\\"], - mainFiles: [\\"'noMainFileHere'\\", \\"iGuess\\"], - modules: [\\"one\\", \\"'two'\\"], - unsafeCache: false, - resolveLoader: { - modules: [\\"'node_modules'\\", \\"mode_nodules\\"], - extensions: [\\"jsVal\\", \\"'.json'\\"], - mainFields: [\\"loader\\", \\"'main'\\"], - moduleExtensions: [\\"'-loader'\\", \\"value\\"] - }, - plugins: [\\"somePlugin\\", \\"'stringVal'\\"], - symlinks: true - }, - module: { - noParse: function(content) { - return /jquery|lodash/.test(content); - }, - rules: [ - { - loader: \\"eslint-loader\\", - options: { - formatter: \\"someOption\\" - } - }, - { - loader: \\"vue-loader\\", - options: \\"vueObject\\" - }, - { - loader: \\"babel-loader\\", - include: \\"asdf\\" - } - ] - } -}; -" -`; - -exports[`remove transforms correctly using "fixture-3" data 5`] = ` -"module.exports = { - entry: { - a: \\"a.js\\", - b: \\"taddda\\", - }, - mode: \\"prod\\", - devServer: { - port: 9000, - }, - devtool: \\"eval\\", - plugins: [ - \\"plugin1\\", - \\"plugin2\\", - \\"plugin3\\", - ], - resolve: { - alias: { - inject: \\"{{#if_eq build 'standalone'}}\\", - hello: \\"'world'\\", - inject_1: \\"{{/if_eq}}\\", - world: \\"hello\\" - }, - aliasFields: [\\"'browser'\\", \\"wars\\"], - descriptionFiles: [\\"'a'\\", \\"b\\", \\"'c'\\"], - enforceExtension: false, - enforceModuleExtension: false, - extensions: [\\"hey\\", \\"ho\\"], - mainFields: [\\"main\\", \\"'story'\\"], - mainFiles: [\\"'noMainFileHere'\\", \\"iGuess\\"], - modules: [\\"one\\", \\"'two'\\"], - unsafeCache: false, - resolveLoader: { - modules: [\\"'node_modules'\\", \\"mode_nodules\\"], - extensions: [\\"jsVal\\", \\"'.json'\\"], - mainFields: [\\"loader\\", \\"'main'\\"], - moduleExtensions: [\\"'-loader'\\", \\"value\\"] - }, - plugins: [\\"somePlugin\\", \\"'stringVal'\\"], - symlinks: true - }, - module: { - noParse: function(content) { - return /jquery|lodash/.test(content); - }, - rules: [{ - loader: \\"vue-loader\\", - options: \\"vueObject\\" - }, { - loader: \\"babel-loader\\", - include: \\"asdf\\" - }] - } -}; -" -`; diff --git a/packages/utils/__tests__/__testfixtures__/fixture-0.input.js b/packages/utils/__tests__/__testfixtures__/fixture-0.input.js deleted file mode 100644 index 08023a9ca17..00000000000 --- a/packages/utils/__tests__/__testfixtures__/fixture-0.input.js +++ /dev/null @@ -1,134 +0,0 @@ -const webpack = require('webpack'); - -module.exports = { - entry: { - ed: 'index.js', - sheeran: "yea, good shit" - }, - output: { - filename: "'bundle'", - path: "'dist/assets'", - pathinfo: true, - publicPath: "'https://google.com'", - sourceMapFilename: "'[name].map'", - sourcePrefix: jscodeshift("'\t'"), - umdNamedDefine: true, - strictModuleExceptionHandling: true - }, - watchOptions: { - aggregateTimeout: 100, - poll: 90, - ignored: "/ok/" - }, - watch: 'me', - context: 'reassign me like one of your french girls', - devServer: { - contentBase: "edSheeran", - compress: true, - port: 9000, - empti: "ness" - }, - devtool: 'eval', - externals: { - highdash: { - commonjs: 'lodash', - amd: 'lodash' - } - }, - performance: { - hints: "'warning'", - maxEntrypointSize: 400000, - maxAssetSize: 100000, - assetFilter: - "function(assetFilename) {" + - "return assetFilename.endsWith('.js');" + - "}" - }, - mode: 'development', - bail: true, - cache: true, - profile: true, - merge: 'NotMuch', - parallelism: 69, - recordsInputPath: 'something', - recordsOutputPath: 'else', - recordsPath: 'Brooklyn', - amd: { - jQuery: true, - kQuery: false - }, - resolveLoader: { - moduleExtensions: [ '-loader' ] - }, - stats: { - assets: false, - assetsSort: "'gold'", - cached: true, - cachedAssets: true, - children: false, - chunks: true, - }, - target: 'something', - resolve: { - alias: { - inject: "{{#if_eq build 'standalone'}}", - hello: "'world'", - inject_1: "{{/if_eq}}", - world: "hello" - }, - aliasFields: ["'browser'", "wars"], - descriptionFiles: ["'a'", "b", "'c'"], - enforceExtension: false, - enforceModuleExtension: false, - extensions: ["hey", "ho"], - mainFields: ["main", "'story'"], - mainFiles: ["'noMainFileHere'", "iGuess"], - modules: ["one", "'two'"], - unsafeCache: false, - resolveLoader: { - modules: ["'node_modules'", "mode_nodules"], - extensions: ["jsVal", "'.json'"], - mainFields: ["loader", "'main'"], - moduleExtensions: ["'-loader'", "value"] - }, - plugins: ["somePlugin", "'stringVal'"], - symlinks: true - }, - plugins: ['something'], - module: { - rules: [ - { - loader: "'eslint-loader'", - enforce: "'pre'", - include: ["hey", "'Stringy'"], - options: { - formatter: "'someOption'" - } - }, - { - loader: "'vue-loader'", - options: "vueObject" - }, - { - loader: "'babel-loader'", - include: ["resolve('src')", "resolve('test')"] - }, - { - loader: "'url-loader'", - options: { - limit: 10000, - name: "utils.assetsPath('img/[name].[hash:7].[ext]')", - inject: "{{#if_eq build 'standalone'}}" - } - }, - { - loader: "'url-loader'", - inject: "{{#if_eq build 'standalone'}}", - options: { - limit: "10000", - name: "utils.assetsPath('fonts/[name].[hash:7].[ext]')" - } - } - ] - }, -} \ No newline at end of file diff --git a/packages/utils/__tests__/__testfixtures__/fixture-1.input.js b/packages/utils/__tests__/__testfixtures__/fixture-1.input.js deleted file mode 100644 index a0995453769..00000000000 --- a/packages/utils/__tests__/__testfixtures__/fixture-1.input.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {}; \ No newline at end of file diff --git a/packages/utils/__tests__/__testfixtures__/fixture-2.input.js b/packages/utils/__tests__/__testfixtures__/fixture-2.input.js deleted file mode 100644 index 95a9b98f57a..00000000000 --- a/packages/utils/__tests__/__testfixtures__/fixture-2.input.js +++ /dev/null @@ -1,25 +0,0 @@ -const webpack = require("webpack"); - -module.exports = { - entry: { - objects: "are", - super: [ - "yeah", - { - test: new RegExp(/\.(js|vue)$/), - loader: "'eslint-loader'", - enforce: "'pre'", - include: ["customObj", "'Stringy'"], - options: { - formatter: "'oki'", - updateMe: "sure" - } - } - ], - nice: "':)'", - foo: "Promise.resolve()", - man: "() => duper", - mode: "yaaa" - - } -} diff --git a/packages/utils/__tests__/__testfixtures__/fixture-3.input.js b/packages/utils/__tests__/__testfixtures__/fixture-3.input.js deleted file mode 100644 index 05830ad1166..00000000000 --- a/packages/utils/__tests__/__testfixtures__/fixture-3.input.js +++ /dev/null @@ -1,62 +0,0 @@ -module.exports = { - entry: { - a: "a.js", - b: "taddda", - }, - mode: "prod", - devServer: { - port: 9000, - }, - devtool: "eval", - plugins: [ - "plugin1", - "plugin2", - "plugin3", - ], - resolve: { - alias: { - inject: "{{#if_eq build 'standalone'}}", - hello: "'world'", - inject_1: "{{/if_eq}}", - world: "hello" - }, - aliasFields: ["'browser'", "wars"], - descriptionFiles: ["'a'", "b", "'c'"], - enforceExtension: false, - enforceModuleExtension: false, - extensions: ["hey", "ho"], - mainFields: ["main", "'story'"], - mainFiles: ["'noMainFileHere'", "iGuess"], - modules: ["one", "'two'"], - unsafeCache: false, - resolveLoader: { - modules: ["'node_modules'", "mode_nodules"], - extensions: ["jsVal", "'.json'"], - mainFields: ["loader", "'main'"], - moduleExtensions: ["'-loader'", "value"] - }, - plugins: ["somePlugin", "'stringVal'"], - symlinks: true - }, - module: { - noParse: function(content) { - return /jquery|lodash/.test(content); - }, - rules: [ - { - loader: "eslint-loader", - options: { - formatter: "someOption" - } - }, - { - loader: "vue-loader", - options: "vueObject" - }, - { - loader: "babel-loader", - include: "asdf" - } - ] - } -}; diff --git a/packages/utils/__tests__/ast-utils.test.ts b/packages/utils/__tests__/ast-utils.test.ts index 6883531049f..547e3b8cbb9 100644 --- a/packages/utils/__tests__/ast-utils.test.ts +++ b/packages/utils/__tests__/ast-utils.test.ts @@ -1,294 +1,308 @@ -"use strict"; - -import * as j from "jscodeshift/dist/core"; -import * as utils from "../ast-utils"; -import { Node } from "../types/NodePath"; - -describe("utils", () => { - describe("createProperty", () => { - it("should create properties for Boolean", () => { - const res = utils.createProperty(j, "foo", true); - expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); - }); - - it("should create properties for Number", () => { - const res = utils.createProperty(j, "foo", -1); - expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); - }); - - it("should create properties for String", () => { - const res = utils.createProperty(j, "foo", "bar"); - expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); - }); - - it("should create properties for complex keys", () => { - const res = utils.createProperty(j, "foo-bar", "bar"); - expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); - }); - - it("should create properties for non-literal keys", () => { - const res = utils.createProperty(j, 1, "bar"); - expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); - }); - }); - - describe("findPluginsByName", () => { - it("should find plugins in AST", () => { - const ast = j(` +'use strict'; + +import j from 'jscodeshift/dist/core'; +import { + addProperty, + createIdentifierOrLiteral, + createLiteral, + createOrUpdatePluginByName, + createProperty, + findObjWithOneOfKeys, + findPluginsArrayAndRemoveIfEmpty, + findPluginsByName, + findRootNodesByName, + findVariableToPlugin, + getRequire, + safeTraverse, + safeTraverseAndGetType, +} from '../src/ast-utils'; +import { Node } from '../src/types/NodePath'; + +describe('utils', () => { + describe('createProperty', () => { + it('should create properties for Boolean', () => { + const res = createProperty(j, 'foo', true); + expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); + }); + + it('should create properties for Number', () => { + const res = createProperty(j, 'foo', -1); + expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); + }); + + it('should create properties for String', () => { + const res = createProperty(j, 'foo', 'bar'); + expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); + }); + + it('should create properties for complex keys', () => { + const res = createProperty(j, 'foo-bar', 'bar'); + expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); + }); + + it('should create properties for non-literal keys', () => { + const res = createProperty(j, 1, 'bar'); + expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); + }); + }); + + describe('findPluginsByName', () => { + it('should find plugins in AST', () => { + const ast = j(` { foo: new webpack.optimize.UglifyJsPlugin() } `); - const res = utils.findPluginsByName(j, ast, ["webpack.optimize.UglifyJsPlugin"]); - expect(res.size()).toEqual(1); - }); + const res = findPluginsByName(j, ast, ['webpack.optimize.UglifyJsPlugin']); + expect(res.size()).toEqual(1); + }); - it("should find all plugins in AST", () => { - const ast = j(` + it('should find all plugins in AST', () => { + const ast = j(` [ new UglifyJsPlugin(), new TestPlugin() ] `); - const res = utils.findPluginsByName(j, ast, ["UglifyJsPlugin", "TestPlugin"]); - expect(res.size()).toEqual(2); - }); + const res = findPluginsByName(j, ast, ['UglifyJsPlugin', 'TestPlugin']); + expect(res.size()).toEqual(2); + }); - it("should not find false positives", () => { - const ast = j(` + it('should not find false positives', () => { + const ast = j(` { foo: new UglifyJsPlugin() } `); - const res = utils.findPluginsByName(j, ast, ["webpack.optimize.UglifyJsPlugin"]); - expect(res.size()).toEqual(0); - }); - }); - - describe("findPluginsArrayAndRemoveIfEmpty", () => { - it("should remove plugins property", () => { - const ast = j(` + const res = findPluginsByName(j, ast, ['webpack.optimize.UglifyJsPlugin']); + expect(res.size()).toEqual(0); + }); + }); + + describe('findPluginsArrayAndRemoveIfEmpty', () => { + it('should remove plugins property', () => { + const ast = j(` const a = { plugins: [] } `); - utils.findPluginsArrayAndRemoveIfEmpty(j, ast); - expect(ast.toSource()).toMatchSnapshot(); - }); + findPluginsArrayAndRemoveIfEmpty(j, ast); + expect(ast.toSource()).toMatchSnapshot(); + }); - it("It should not remove plugins array, given an array with length greater than zero", () => { - const ast = j(` + it('It should not remove plugins array, given an array with length greater than zero', () => { + const ast = j(` const a = { plugins: [ new MyCustomPlugin() ] } `); - utils.findPluginsArrayAndRemoveIfEmpty(j, ast); - expect(ast.toSource()).toMatchSnapshot(); - }); - }); - - describe("findRootNodesByName", () => { - it("should find plugins: [] nodes", () => { - const ast = j(` + findPluginsArrayAndRemoveIfEmpty(j, ast); + expect(ast.toSource()).toMatchSnapshot(); + }); + }); + + describe('findRootNodesByName', () => { + it('should find plugins: [] nodes', () => { + const ast = j(` const a = { plugins: [], foo: { plugins: [] } } `); - const res = utils.findRootNodesByName(j, ast, "plugins"); - expect(res.size()).toEqual(2); - }); + const res = findRootNodesByName(j, ast, 'plugins'); + expect(res.size()).toEqual(2); + }); - it("should not find plugins: [] nodes", () => { - const ast = j(` + it('should not find plugins: [] nodes', () => { + const ast = j(` const a = { plugs: [] } `); - const res = utils.findRootNodesByName(j, ast, "plugins"); - expect(res.size()).toEqual(0); - }); - }); - - describe("createOrUpdatePluginByName", () => { - it("should create a new plugin without arguments", () => { - const ast = j("{ plugins: [] }"); - ast.find(j.ArrayExpression).forEach((node: Node) => { - utils.createOrUpdatePluginByName(j, node, "Plugin"); - }); - expect(ast.toSource()).toMatchSnapshot(); - }); - - it("should create a new plugin with arguments", () => { - const ast = j("{ plugins: [] }"); - ast.find(j.ArrayExpression).forEach((node: Node) => { - utils.createOrUpdatePluginByName(j, node, "Plugin", { - foo: "bar" - }); - }); - expect(ast.toSource()).toMatchSnapshot(); - }); - - it("should add an object as an argument", () => { - const ast = j("[new Plugin()]"); - ast.find(j.ArrayExpression).forEach((node: Node) => { - utils.createOrUpdatePluginByName(j, node, "Plugin", { - foo: true - }); - }); - expect(ast.toSource()).toMatchSnapshot(); - }); - - it("should merge options objects", () => { - const ast = j("[new Plugin({ foo: true })]"); - ast.find(j.ArrayExpression).forEach((node: Node) => { - utils.createOrUpdatePluginByName(j, node, "Plugin", { - bar: "baz", - foo: false - }); - utils.createOrUpdatePluginByName(j, node, "Plugin", { - "baz-long": true - }); - }); - expect(ast.toSource()).toMatchSnapshot(); - }); - }); - - describe("findVariableToPlugin", () => { - it("should find the variable name of a plugin", () => { - const ast = j(` + const res = findRootNodesByName(j, ast, 'plugins'); + expect(res.size()).toEqual(0); + }); + }); + + describe('createOrUpdatePluginByName', () => { + it('should create a new plugin without arguments', () => { + const ast = j('{ plugins: [] }'); + ast.find(j.ArrayExpression).forEach((node: Node) => { + createOrUpdatePluginByName(j, node, 'Plugin'); + }); + expect(ast.toSource()).toMatchSnapshot(); + }); + + it('should create a new plugin with arguments', () => { + const ast = j('{ plugins: [] }'); + ast.find(j.ArrayExpression).forEach((node: Node) => { + createOrUpdatePluginByName(j, node, 'Plugin', { + foo: 'bar', + }); + }); + expect(ast.toSource()).toMatchSnapshot(); + }); + + it('should add an object as an argument', () => { + const ast = j('[new Plugin()]'); + ast.find(j.ArrayExpression).forEach((node: Node) => { + createOrUpdatePluginByName(j, node, 'Plugin', { + foo: true, + }); + }); + expect(ast.toSource()).toMatchSnapshot(); + }); + + it('should merge options objects', () => { + const ast = j('[new Plugin({ foo: true })]'); + ast.find(j.ArrayExpression).forEach((node: Node) => { + createOrUpdatePluginByName(j, node, 'Plugin', { + bar: 'baz', + foo: false, + }); + createOrUpdatePluginByName(j, node, 'Plugin', { + 'baz-long': true, + }); + }); + expect(ast.toSource()).toMatchSnapshot(); + }); + }); + + describe('findVariableToPlugin', () => { + it('should find the variable name of a plugin', () => { + const ast = j(` const packageName = require('package-name'); const someOtherconst = somethingElse; const otherPackage = require('other-package'); `); - const found = utils.findVariableToPlugin(j, ast, "other-package"); - expect(found).toEqual("otherPackage"); - }); - }); - - describe("createLiteral", () => { - it("should create basic literal", () => { - const literal = utils.createLiteral(j, "stringLiteral"); - expect(j(literal).toSource()).toMatchSnapshot(); - }); - it("should create boolean", () => { - const literal = utils.createLiteral(j, "true"); - expect(j(literal).toSource()).toMatchSnapshot(); - }); - }); - - describe("createIdentifierOrLiteral", () => { - it("should create basic literal", () => { - const literal = utils.createIdentifierOrLiteral(j, "'stringLiteral'"); - expect(j(literal).toSource()).toMatchSnapshot(); - }); - it("should create boolean", () => { - const literal = utils.createIdentifierOrLiteral(j, "true"); - expect(j(literal).toSource()).toMatchSnapshot(); - }); - }); - - describe("findObjWithOneOfKeys", () => { - it("should find keys", () => { - const ast = j(` + const found = findVariableToPlugin(j, ast, 'other-package'); + expect(found).toEqual('otherPackage'); + }); + }); + + describe('createLiteral', () => { + it('should create basic literal', () => { + const literal = createLiteral(j, 'stringLiteral'); + expect(j(literal).toSource()).toMatchSnapshot(); + }); + it('should create boolean', () => { + const literal = createLiteral(j, 'true'); + expect(j(literal).toSource()).toMatchSnapshot(); + }); + }); + + describe('createIdentifierOrLiteral', () => { + it('should create basic literal', () => { + const literal = createIdentifierOrLiteral(j, "'stringLiteral'"); + expect(j(literal).toSource()).toMatchSnapshot(); + }); + it('should create boolean', () => { + const literal = createIdentifierOrLiteral(j, 'true'); + expect(j(literal).toSource()).toMatchSnapshot(); + }); + }); + + describe('findObjWithOneOfKeys', () => { + it('should find keys', () => { + const ast = j(` const ab = { a: 1, b: 2 } `); - expect( - ast - .find(j.ObjectExpression) - .filter(p => utils.findObjWithOneOfKeys(p, ["a"])) - .size() - ).toEqual(1); - }); - }); - - describe("getRequire", () => { - it("should create a require statement", () => { - const require = utils.getRequire(j, "filesys", "fs"); - expect(j(require).toSource()).toMatchSnapshot(); - }); - }); - - describe("safeTraverse", () => { - it("should safe traverse", () => { - const testObject = { - type: "NodeType" - }; - const p = { - foo: { - bar: testObject - } - }; - const require = utils.safeTraverse(p, ["foo", "bar"]); - expect(require).toEqual(testObject); - }); - - it("should safe traverse thrice", () => { - const type = { - type: "NodeType" - }; - const p = { - parent: { - value: { - value: type - } - } - }; - const traversedValue = utils.safeTraverse(p, ["parent", "value", "value"]); - expect(traversedValue).toEqual(type); - }); - }); - - describe("safeTraverseAndGetType", () => { - it("should safe traverse and get type", () => { - const NODE_TYPE = "NodeType"; - const p = { - value: { - value: { - type: NODE_TYPE - } - } - }; - const typeValue = utils.safeTraverseAndGetType(p); - expect(typeValue).toEqual(NODE_TYPE); - }); - - it("should safe traverse and return false if not found", () => { - const NODE_TYPE = "NodeType"; - const p = { - foo: { - bar: { - type: NODE_TYPE - } - } - }; - const typeValue = utils.safeTraverseAndGetType(p); - expect(typeValue).toEqual(false); - }); - }); - - describe("addProperty", () => { - it("add entry property using init", () => { - const ast = j("module.exports = {}"); - const propertyValue = { - man: "() => duper", - nice: "':)'", - objects: "are", - super: [ - "yeah", - { - loader: "'eslint-loader'" - } - ] - }; - - const root = ast.find(j.ObjectExpression); - - root.forEach(p => { - utils.addProperty(j, p, "entry", propertyValue); - }); - - expect(ast.toSource()).toMatchSnapshot(); - }); - - it("add entry property using add", () => { - const ast = j(`module.exports = { + expect( + ast + .find(j.ObjectExpression) + .filter(p => findObjWithOneOfKeys(p, ['a'])) + .size(), + ).toEqual(1); + }); + }); + + describe('getRequire', () => { + it('should create a require statement', () => { + const require = getRequire(j, 'filesys', 'fs'); + expect(j(require).toSource()).toMatchSnapshot(); + }); + }); + + describe('safeTraverse', () => { + it('should safe traverse', () => { + const testObject = { + type: 'NodeType', + }; + const p = { + foo: { + bar: testObject, + }, + }; + const require = safeTraverse(p, ['foo', 'bar']); + expect(require).toEqual(testObject); + }); + + it('should safe traverse thrice', () => { + const type = { + type: 'NodeType', + }; + const p = { + parent: { + value: { + value: type, + }, + }, + }; + const traversedValue = safeTraverse(p, ['parent', 'value', 'value']); + expect(traversedValue).toEqual(type); + }); + }); + + describe('safeTraverseAndGetType', () => { + it('should safe traverse and get type', () => { + const NODE_TYPE = 'NodeType'; + const p = { + value: { + value: { + type: NODE_TYPE, + }, + }, + }; + const typeValue = safeTraverseAndGetType(p); + expect(typeValue).toEqual(NODE_TYPE); + }); + + it('should safe traverse and return false if not found', () => { + const NODE_TYPE = 'NodeType'; + const p = { + foo: { + bar: { + type: NODE_TYPE, + }, + }, + }; + const typeValue = safeTraverseAndGetType(p); + expect(typeValue).toEqual(false); + }); + }); + + describe('addProperty', () => { + it('add entry property using init', () => { + const ast = j('module.exports = {}'); + const propertyValue = { + man: '() => duper', + nice: "':)'", + objects: 'are', + super: [ + 'yeah', + { + loader: "'eslint-loader'", + }, + ], + }; + + const root = ast.find(j.ObjectExpression); + + root.forEach(p => { + addProperty(j, p, 'entry', propertyValue); + }); + + expect(ast.toSource()).toMatchSnapshot(); + }); + + it('add entry property using add', () => { + const ast = j(`module.exports = { entry: { objects: are, super: [yeah, { @@ -299,25 +313,25 @@ const a = { plugs: [] } man: () => duper } }`); - const propertyValue = { - man: "() => duper", - nice: "':)'", - objects: "are", - super: [ - "yeah", - { - loader: "'eslint-loader'" - } - ] - }; - - const root = ast.find(j.ObjectExpression); - - utils.findRootNodesByName(j, root, "entry").forEach((p: Node) => { - j(p).replaceWith(utils.addProperty(j, p, "entry", propertyValue, "add")); - }); - - expect(ast.toSource()).toMatchSnapshot(); - }); - }); + const propertyValue = { + man: '() => duper', + nice: "':)'", + objects: 'are', + super: [ + 'yeah', + { + loader: "'eslint-loader'", + }, + ], + }; + + const root = ast.find(j.ObjectExpression); + + findRootNodesByName(j, root, 'entry').forEach((p: Node) => { + j(p).replaceWith(addProperty(j, p, 'entry', propertyValue, 'add')); + }); + + expect(ast.toSource()).toMatchSnapshot(); + }); + }); }); diff --git a/packages/utils/defineTest.ts b/packages/utils/__tests__/defineTest.ts similarity index 55% rename from packages/utils/defineTest.ts rename to packages/utils/__tests__/defineTest.ts index 350e03a05ba..20a7806a164 100644 --- a/packages/utils/defineTest.ts +++ b/packages/utils/__tests__/defineTest.ts @@ -1,27 +1,21 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ -import * as fs from "fs"; -import * as path from "path"; +import fs from 'fs'; +import path from 'path'; -import { JSCodeshift, Node } from "./types/NodePath"; +import { JSCodeshift, Node } from '../src/types/NodePath'; interface Module { - ( - jscodeshift: JSCodeshift, - ast: Node, - initOptions: string | boolean | object, - action: string, - transformName?: string - ): Node; - default: transformType; - parser: string; + (jscodeshift: JSCodeshift, ast: Node, initOptions: string | boolean | object, action: string, transformName?: string): Node; + default: transformType; + parser: string; } type transformType = ( - jscodeshift: JSCodeshift, - ast: Node, - initOptions: string | boolean | object, - action: object | string, - transformName?: string + jscodeshift: JSCodeshift, + ast: Node, + initOptions: string | boolean | object, + action: object | string, + transformName?: string, ) => Node; /** @@ -49,45 +43,45 @@ type transformType = ( * @return {Function} Function that fires of the transforms */ function runSingleTransform( - dirName: string, - transformName: string, - testFilePrefix: string, - initOptions: object | boolean | string, - action: object | string + dirName: string, + transformName: string, + testFilePrefix: string, + initOptions: object | boolean | string, + action: object | string, ): string { - if (!testFilePrefix) { - testFilePrefix = transformName; - } - const fixtureDir = path.join(dirName, "__tests__", "__testfixtures__"); - const inputPath = path.join(fixtureDir, `${testFilePrefix}.input.js`); - const source = fs.readFileSync(inputPath, "utf8"); + if (!testFilePrefix) { + testFilePrefix = transformName; + } + const fixtureDir = path.join(dirName, '__testfixtures__'); + const inputPath = path.join(fixtureDir, `${testFilePrefix}.input.js`); + const source = fs.readFileSync(inputPath, 'utf8'); - let module: Module; - // Assumes transform and test are on the same level - if (action) { - module = require(path.join(dirName, "recursive-parser.ts")); - } else { - module = require(path.join(dirName, `${transformName}.ts`)); - } - // Handle ES6 modules using default export for the transform - const transform = module.default ? module.default : module; + let module: Module; + // Assumes transform and test are on the same level + if (action) { + module = require(path.join(dirName, '../../src', 'recursive-parser.ts')); + } else { + module = require(path.join(dirName, '../../src', transformName, `${transformName}.ts`)); + } + // Handle ES6 modules using default export for the transform + const transform = module.default ? module.default : module; - // Jest resets the module registry after each test, so we need to always get - // a fresh copy of jscodeshift on every test run. - // eslint-disable-next-line - let jscodeshift: JSCodeshift = require("jscodeshift/dist/core"); - if (module.parser) { - jscodeshift = jscodeshift.withParser(module.parser); - } - const ast: Node = jscodeshift(source); - if (initOptions || typeof initOptions === "boolean") { - return transform(jscodeshift, ast, initOptions, action, transformName).toSource({ - quote: "single" - }); - } - return transform(jscodeshift, ast, source, action).toSource({ - quote: "single" - }); + // Jest resets the module registry after each test, so we need to always get + // a fresh copy of jscodeshift on every test run. + // eslint-disable-next-line + let jscodeshift: JSCodeshift = require('jscodeshift/dist/core'); + if (module.parser) { + jscodeshift = jscodeshift.withParser(module.parser); + } + const ast: Node = jscodeshift(source); + if (initOptions || typeof initOptions === 'boolean') { + return transform(jscodeshift, ast, initOptions, action, transformName).toSource({ + quote: 'single', + }); + } + return transform(jscodeshift, ast, source, action).toSource({ + quote: 'single', + }); } /** @@ -108,19 +102,17 @@ function runSingleTransform( * @return {Void} Jest makes sure to execute the globally defined functions */ export default function defineTest( - dirName: string, - transformName: string, - testFilePrefix?: string, - transformObject?: object | string, - action?: object | string + dirName: string, + transformName: string, + testFilePrefix?: string, + transformObject?: object | string, + action?: object | string, ): void { - const testName: string = testFilePrefix - ? `transforms correctly using "${testFilePrefix}" data` - : "transforms correctly"; - describe(transformName, () => { - it(testName, () => { - const output = runSingleTransform(dirName, transformName, testFilePrefix, transformObject, action); - expect(output).toMatchSnapshot(); - }); - }); + const testName: string = testFilePrefix ? `transforms correctly using "${testFilePrefix}" data` : 'transforms correctly'; + describe(transformName, () => { + it(testName, () => { + const output = runSingleTransform(dirName, transformName, testFilePrefix, transformObject, action); + expect(output).toMatchSnapshot(); + }); + }); } diff --git a/packages/utils/__tests__/is-local-path.test.ts b/packages/utils/__tests__/is-local-path.test.ts index 654884b9e1a..4a8150f9467 100644 --- a/packages/utils/__tests__/is-local-path.test.ts +++ b/packages/utils/__tests__/is-local-path.test.ts @@ -1,24 +1,24 @@ -"use strict"; +'use strict'; -import * as path from "path"; -import { isLocalPath } from "../path-utils"; +import path from 'path'; +import { isLocalPath } from '../src/path-utils'; -describe("is-local-path", () => { - it("returns true for paths beginning in the current directory", () => { - const p = path.resolve(".", "test", "dir"); - expect(isLocalPath(p)).toBe(true); - }); +describe('is-local-path', () => { + it('returns true for paths beginning in the current directory', () => { + const p = path.resolve('.', 'test', 'dir'); + expect(isLocalPath(p)).toBe(true); + }); - it("returns true for absolute paths", () => { - const p = path.join("/", "test", "dir"); - expect(isLocalPath(p)).toBe(true); - }); + it('returns true for absolute paths', () => { + const p = path.join('/', 'test', 'dir'); + expect(isLocalPath(p)).toBe(true); + }); - it("returns false for npm packages names", () => { - expect(isLocalPath("webpack-scaffold-ylvis")).toBe(false); - }); + it('returns false for npm packages names', () => { + expect(isLocalPath('webpack-scaffold-ylvis')).toBe(false); + }); - it("returns false for scoped npm package names", () => { - expect(isLocalPath("@webpack/test")).toBe(false); - }); + it('returns false for scoped npm package names', () => { + expect(isLocalPath('@webpack/test')).toBe(false); + }); }); diff --git a/packages/utils/__tests__/npm-exists.test.ts b/packages/utils/__tests__/npm-exists.test.ts index a5a98f168f0..6d27c83faad 100644 --- a/packages/utils/__tests__/npm-exists.test.ts +++ b/packages/utils/__tests__/npm-exists.test.ts @@ -1,16 +1,16 @@ -"use strict"; -import exists from "../npm-exists"; +'use strict'; +import { npmExists } from '../src/npm-exists'; -describe("npm-exists", () => { - it("should successfully existence of a published module", () => { - exists("webpack-scaffold-demo").then(status => { - expect(status).toBe(true); - }); - }); +describe('npm-exists', () => { + it('should successfully existence of a published module', () => { + npmExists('webpack-scaffold-demo').then(status => { + expect(status).toBe(true); + }); + }); - it("should return false for the existence of a fake module", () => { - exists("webpack-scaffold-noop").then(status => { - expect(status).toBe(false); - }); - }); + it('should return false for the existence of a fake module', () => { + npmExists('webpack-scaffold-noop').then(status => { + expect(status).toBe(false); + }); + }); }); diff --git a/packages/utils/__tests__/npm-packages-exists.test.ts b/packages/utils/__tests__/npm-packages-exists.test.ts index 4c75f72699d..0e7762f9720 100644 --- a/packages/utils/__tests__/npm-packages-exists.test.ts +++ b/packages/utils/__tests__/npm-packages-exists.test.ts @@ -1,19 +1,19 @@ -import npmPackagesExists from "../npm-packages-exists"; -import { resolvePackages } from "../resolve-packages"; +import { npmPackagesExists } from '../src/npm-packages-exists'; +import { resolvePackages } from '../src/resolve-packages'; -jest.mock("../npm-exists"); -jest.mock("../resolve-packages"); +jest.mock('../src/npm-exists'); +jest.mock('../src/resolve-packages'); // TS is not aware that jest changes the type of resolvePackages const mockResolvePackages = resolvePackages as jest.Mock; -describe("npmPackagesExists", () => { - test("resolves packages when they are available on the local filesystem", () => { - npmPackagesExists(["./testpkg"]); - expect(mockResolvePackages.mock.calls[mockResolvePackages.mock.calls.length - 1][0]).toEqual(["./testpkg"]); - }); +describe('npmPackagesExists', () => { + test('resolves packages when they are available on the local filesystem', () => { + npmPackagesExists(['./testpkg']); + expect(mockResolvePackages.mock.calls[mockResolvePackages.mock.calls.length - 1][0]).toEqual(['./testpkg']); + }); - test("throws a TypeError when an npm package name doesn't include the prefix", () => { - expect(() => npmPackagesExists(["my-webpack-scaffold"])).toThrowError(TypeError); - }); + test("throws a TypeError when an npm package name doesn't include the prefix", () => { + expect(() => npmPackagesExists(['my-webpack-scaffold'])).toThrowError(TypeError); + }); }); diff --git a/packages/utils/__tests__/package-manager.test.ts b/packages/utils/__tests__/package-manager.test.ts deleted file mode 100644 index d46898c3df7..00000000000 --- a/packages/utils/__tests__/package-manager.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -"use strict"; - -import * as packageManager from "../package-manager"; - -import * as globalModules from "global-modules"; - -jest.mock("cross-spawn"); -jest.mock("fs"); - -describe("package-manager", () => { - // eslint-disable-next-line - const spawn = require("cross-spawn"); - // eslint-disable-next-line - const fs = require("fs"); - - const defaultSyncResult = { - error: null, - output: [null, null, null], - pid: 1234, - signal: null, - status: 1, - stderr: null, - stdout: null - }; - - function mockSpawnErrorOnce() { - spawn.sync.mockReturnValueOnce( - Object.assign({}, defaultSyncResult, { - error: new Error(), - status: null - }) - ); - } - - function mockSpawnErrorTwice() { - mockSpawnErrorOnce(); - mockSpawnErrorOnce(); - } - - function mockUpdateNPMOnce() { - fs.existsSync.mockReturnValueOnce(true); - fs.existsSync.mockReturnValueOnce(false); - fs.existsSync.mockReturnValueOnce(true); - fs.existsSync.mockReturnValueOnce(true); - fs.existsSync.mockReturnValueOnce(true); - } - - jest.spyOn(spawn, "sync").mockReturnValue(defaultSyncResult); - - it("should return 'npm' from getPackageManager", () => { - mockSpawnErrorOnce(); - expect(packageManager.getPackageManager()).toEqual("npm"); - }); - - it("should spawn npm from spawnChild", () => { - const packageName = "some-pkg"; - - packageManager.spawnChild(packageName); - expect(spawn.sync).toHaveBeenLastCalledWith("npm", ["install", "-g", packageName], { stdio: "inherit" }); - }); - - it("should spawn npm install from spawnChild", () => { - const packageName = "some-pkg"; - - mockSpawnErrorTwice(); - packageManager.spawnChild(packageName); - expect(spawn.sync).toHaveBeenLastCalledWith("npm", ["install", "-g", packageName], { stdio: "inherit" }); - }); - - it("should spawn npm update from spawnChild", () => { - const packageName = "some-pkg"; - - mockUpdateNPMOnce(); - - packageManager.spawnChild(packageName); - expect(spawn.sync).toHaveBeenLastCalledWith("npm", ["update", "-g", packageName], { stdio: "inherit" }); - }); - - it("should return the npm global dir from getPathToGlobalPackages if yarn is not installed", () => { - mockSpawnErrorOnce(); - const globalPath = packageManager.getPathToGlobalPackages(); - expect(globalPath).toBe(globalModules); - }); -}); diff --git a/packages/utils/__tests__/recursive-parser.test.ts b/packages/utils/__tests__/recursive-parser.test.ts deleted file mode 100644 index 20de356e54e..00000000000 --- a/packages/utils/__tests__/recursive-parser.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -"use strict"; - -import { join } from "path"; -import defineTest from "../defineTest"; - -defineTest(join(__dirname, ".."), "init", "fixture-1", "entry", { - foo: "Promise.resolve()", - man: "() => duper", - nice: "':)'", - objects: "are", - super: [ - "yeah", - { - enforce: "'pre'", - include: ["customObj", "'Stringy'"], - loader: "'eslint-loader'", - options: { - formatter: "'someOption'" - }, - test: new RegExp(/\.(js|vue)$/) - } - ] -}); - -defineTest(join(__dirname, ".."), "add", "fixture-2", "entry", { - foo: "Promise.resolve()", - man: "() => nice!!", - mode: "super-man", - nice: "'=)'", - objects: "are not", - super: [ - "op", - { - enforce: "'pre'", - include: ["asd", "'Stringy'"], - loader: "'pia-loader'", - options: { - formatter: "'nao'" - }, - test: new RegExp(/\.(wasm|c)$/) - } - ] -}); - -defineTest(join(__dirname, ".."), "remove", "fixture-3", "resolve", { - alias: null -}); - -defineTest(join(__dirname, ".."), "remove", "fixture-3", "plugins", ["plugin2"]); - -defineTest(join(__dirname, ".."), "remove", "fixture-3", "module", { - noParse: null -}); - -defineTest(join(__dirname, ".."), "remove", "fixture-3", "entry", { - a: null -}); - -defineTest(join(__dirname, ".."), "remove", "fixture-3", "module", { - rules: [ - { - loader: "eslint-loader" - } - ] -}); diff --git a/packages/utils/__tests__/recursive-parser/__snapshots__/recursive-parser.test.ts.snap b/packages/utils/__tests__/recursive-parser/__snapshots__/recursive-parser.test.ts.snap new file mode 100644 index 00000000000..3aa5786cc6e --- /dev/null +++ b/packages/utils/__tests__/recursive-parser/__snapshots__/recursive-parser.test.ts.snap @@ -0,0 +1,365 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`recursive parser add transforms correctly using "fixture-2" data 1`] = ` +"const webpack = require('webpack'); + +module.exports = { + entry: { + objects: 'are', + + super: [ + 'yeah', + { + test: new RegExp(/\\\\.(js|vue)$/), + loader: \\"'eslint-loader'\\", + enforce: \\"'pre'\\", + include: ['customObj', \\"'Stringy'\\"], + options: { + formatter: \\"'oki'\\", + updateMe: 'sure', + }, + }, + ], + + nice: \\"':)'\\", + foo: 'Promise.resolve()', + man: '() => duper', + mode: 'yaaa', + foo: Promise.resolve(), + man: () => nice!!, + mode: super-man, + nice: '=)', + objects: are not, + + super: [op, { + enforce: 'pre', + include: [asd, 'Stringy'], + loader: 'pia-loader', + + options: { + formatter: 'nao' + }, + + test: /\\\\.(wasm|c)$/ + }] + }, +}; +" +`; + +exports[`recursive parser init transforms correctly using "fixture-1" data 1`] = ` +"module.exports = { + entry: { + foo: Promise.resolve(), + man: () => duper, + nice: ':)', + objects: are, + + super: [yeah, { + enforce: 'pre', + include: [customObj, 'Stringy'], + loader: 'eslint-loader', + + options: { + formatter: 'someOption' + }, + + test: /\\\\.(js|vue)$/ + }] + } +}; +" +`; + +exports[`recursive parser remove transforms correctly using "fixture-3" data 1`] = ` +"module.exports = { + entry: { + a: 'a.js', + b: 'taddda', + }, + mode: 'prod', + devServer: { + port: 9000, + }, + devtool: 'eval', + plugins: ['plugin1', 'plugin2', 'plugin3'], + resolve: { + aliasFields: [\\"'browser'\\", 'wars'], + descriptionFiles: [\\"'a'\\", 'b', \\"'c'\\"], + enforceExtension: false, + enforceModuleExtension: false, + extensions: ['hey', 'ho'], + mainFields: ['main', \\"'story'\\"], + mainFiles: [\\"'noMainFileHere'\\", 'iGuess'], + modules: ['one', \\"'two'\\"], + unsafeCache: false, + + resolveLoader: { + modules: [\\"'node_modules'\\", 'mode_nodules'], + extensions: ['jsVal', \\"'.json'\\"], + mainFields: ['loader', \\"'main'\\"], + moduleExtensions: [\\"'-loader'\\", 'value'], + }, + + plugins: ['somePlugin', \\"'stringVal'\\"], + symlinks: true + }, + module: { + noParse: function(content) { + return /jquery|lodash/.test(content); + }, + rules: [ + { + loader: 'eslint-loader', + options: { + formatter: 'someOption', + }, + }, + { + loader: 'vue-loader', + options: 'vueObject', + }, + { + loader: 'babel-loader', + include: 'asdf', + }, + ], + }, +}; +" +`; + +exports[`recursive parser remove transforms correctly using "fixture-3" data 2`] = ` +"module.exports = { + entry: { + a: 'a.js', + b: 'taddda', + }, + mode: 'prod', + devServer: { + port: 9000, + }, + devtool: 'eval', + plugins: ['plugin1', 'plugin3'], + resolve: { + alias: { + inject: \\"{{#if_eq build 'standalone'}}\\", + hello: \\"'world'\\", + inject_1: '{{/if_eq}}', + world: 'hello', + }, + aliasFields: [\\"'browser'\\", 'wars'], + descriptionFiles: [\\"'a'\\", 'b', \\"'c'\\"], + enforceExtension: false, + enforceModuleExtension: false, + extensions: ['hey', 'ho'], + mainFields: ['main', \\"'story'\\"], + mainFiles: [\\"'noMainFileHere'\\", 'iGuess'], + modules: ['one', \\"'two'\\"], + unsafeCache: false, + resolveLoader: { + modules: [\\"'node_modules'\\", 'mode_nodules'], + extensions: ['jsVal', \\"'.json'\\"], + mainFields: ['loader', \\"'main'\\"], + moduleExtensions: [\\"'-loader'\\", 'value'], + }, + plugins: ['somePlugin', \\"'stringVal'\\"], + symlinks: true, + }, + module: { + noParse: function(content) { + return /jquery|lodash/.test(content); + }, + rules: [ + { + loader: 'eslint-loader', + options: { + formatter: 'someOption', + }, + }, + { + loader: 'vue-loader', + options: 'vueObject', + }, + { + loader: 'babel-loader', + include: 'asdf', + }, + ], + }, +}; +" +`; + +exports[`recursive parser remove transforms correctly using "fixture-3" data 3`] = ` +"module.exports = { + entry: { + a: 'a.js', + b: 'taddda', + }, + mode: 'prod', + devServer: { + port: 9000, + }, + devtool: 'eval', + plugins: ['plugin1', 'plugin2', 'plugin3'], + resolve: { + alias: { + inject: \\"{{#if_eq build 'standalone'}}\\", + hello: \\"'world'\\", + inject_1: '{{/if_eq}}', + world: 'hello', + }, + aliasFields: [\\"'browser'\\", 'wars'], + descriptionFiles: [\\"'a'\\", 'b', \\"'c'\\"], + enforceExtension: false, + enforceModuleExtension: false, + extensions: ['hey', 'ho'], + mainFields: ['main', \\"'story'\\"], + mainFiles: [\\"'noMainFileHere'\\", 'iGuess'], + modules: ['one', \\"'two'\\"], + unsafeCache: false, + resolveLoader: { + modules: [\\"'node_modules'\\", 'mode_nodules'], + extensions: ['jsVal', \\"'.json'\\"], + mainFields: ['loader', \\"'main'\\"], + moduleExtensions: [\\"'-loader'\\", 'value'], + }, + plugins: ['somePlugin', \\"'stringVal'\\"], + symlinks: true, + }, + module: { + rules: [ + { + loader: 'eslint-loader', + options: { + formatter: 'someOption', + }, + }, + { + loader: 'vue-loader', + options: 'vueObject', + }, + { + loader: 'babel-loader', + include: 'asdf', + }, + ] + }, +}; +" +`; + +exports[`recursive parser remove transforms correctly using "fixture-3" data 4`] = ` +"module.exports = { + entry: { + b: 'taddda' + }, + mode: 'prod', + devServer: { + port: 9000, + }, + devtool: 'eval', + plugins: ['plugin1', 'plugin2', 'plugin3'], + resolve: { + alias: { + inject: \\"{{#if_eq build 'standalone'}}\\", + hello: \\"'world'\\", + inject_1: '{{/if_eq}}', + world: 'hello', + }, + aliasFields: [\\"'browser'\\", 'wars'], + descriptionFiles: [\\"'a'\\", 'b', \\"'c'\\"], + enforceExtension: false, + enforceModuleExtension: false, + extensions: ['hey', 'ho'], + mainFields: ['main', \\"'story'\\"], + mainFiles: [\\"'noMainFileHere'\\", 'iGuess'], + modules: ['one', \\"'two'\\"], + unsafeCache: false, + resolveLoader: { + modules: [\\"'node_modules'\\", 'mode_nodules'], + extensions: ['jsVal', \\"'.json'\\"], + mainFields: ['loader', \\"'main'\\"], + moduleExtensions: [\\"'-loader'\\", 'value'], + }, + plugins: ['somePlugin', \\"'stringVal'\\"], + symlinks: true, + }, + module: { + noParse: function(content) { + return /jquery|lodash/.test(content); + }, + rules: [ + { + loader: 'eslint-loader', + options: { + formatter: 'someOption', + }, + }, + { + loader: 'vue-loader', + options: 'vueObject', + }, + { + loader: 'babel-loader', + include: 'asdf', + }, + ], + }, +}; +" +`; + +exports[`recursive parser remove transforms correctly using "fixture-3" data 5`] = ` +"module.exports = { + entry: { + a: 'a.js', + b: 'taddda', + }, + mode: 'prod', + devServer: { + port: 9000, + }, + devtool: 'eval', + plugins: ['plugin1', 'plugin2', 'plugin3'], + resolve: { + alias: { + inject: \\"{{#if_eq build 'standalone'}}\\", + hello: \\"'world'\\", + inject_1: '{{/if_eq}}', + world: 'hello', + }, + aliasFields: [\\"'browser'\\", 'wars'], + descriptionFiles: [\\"'a'\\", 'b', \\"'c'\\"], + enforceExtension: false, + enforceModuleExtension: false, + extensions: ['hey', 'ho'], + mainFields: ['main', \\"'story'\\"], + mainFiles: [\\"'noMainFileHere'\\", 'iGuess'], + modules: ['one', \\"'two'\\"], + unsafeCache: false, + resolveLoader: { + modules: [\\"'node_modules'\\", 'mode_nodules'], + extensions: ['jsVal', \\"'.json'\\"], + mainFields: ['loader', \\"'main'\\"], + moduleExtensions: [\\"'-loader'\\", 'value'], + }, + plugins: ['somePlugin', \\"'stringVal'\\"], + symlinks: true, + }, + module: { + noParse: function(content) { + return /jquery|lodash/.test(content); + }, + rules: [{ + loader: 'vue-loader', + options: 'vueObject', + }, { + loader: 'babel-loader', + include: 'asdf', + }], + }, +}; +" +`; diff --git a/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-0.input.js b/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-0.input.js new file mode 100644 index 00000000000..77da1aa352d --- /dev/null +++ b/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-0.input.js @@ -0,0 +1,131 @@ +const webpack = require('webpack'); + +module.exports = { + entry: { + ed: 'index.js', + sheeran: 'yea, good shit', + }, + output: { + filename: "'bundle'", + path: "'dist/assets'", + pathinfo: true, + publicPath: "'https://google.com'", + sourceMapFilename: "'[name].map'", + sourcePrefix: jscodeshift("'\t'"), + umdNamedDefine: true, + strictModuleExceptionHandling: true, + }, + watchOptions: { + aggregateTimeout: 100, + poll: 90, + ignored: '/ok/', + }, + watch: 'me', + context: 'reassign me like one of your french girls', + devServer: { + contentBase: 'edSheeran', + compress: true, + port: 9000, + empti: 'ness', + }, + devtool: 'eval', + externals: { + highdash: { + commonjs: 'lodash', + amd: 'lodash', + }, + }, + performance: { + hints: "'warning'", + maxEntrypointSize: 400000, + maxAssetSize: 100000, + assetFilter: 'function(assetFilename) {' + "return assetFilename.endsWith('.js');" + '}', + }, + mode: 'development', + bail: true, + cache: true, + profile: true, + merge: 'NotMuch', + parallelism: 69, + recordsInputPath: 'something', + recordsOutputPath: 'else', + recordsPath: 'Brooklyn', + amd: { + jQuery: true, + kQuery: false, + }, + resolveLoader: { + moduleExtensions: ['-loader'], + }, + stats: { + assets: false, + assetsSort: "'gold'", + cached: true, + cachedAssets: true, + children: false, + chunks: true, + }, + target: 'something', + resolve: { + alias: { + inject: "{{#if_eq build 'standalone'}}", + hello: "'world'", + inject_1: '{{/if_eq}}', + world: 'hello', + }, + aliasFields: ["'browser'", 'wars'], + descriptionFiles: ["'a'", 'b', "'c'"], + enforceExtension: false, + enforceModuleExtension: false, + extensions: ['hey', 'ho'], + mainFields: ['main', "'story'"], + mainFiles: ["'noMainFileHere'", 'iGuess'], + modules: ['one', "'two'"], + unsafeCache: false, + resolveLoader: { + modules: ["'node_modules'", 'mode_nodules'], + extensions: ['jsVal', "'.json'"], + mainFields: ['loader', "'main'"], + moduleExtensions: ["'-loader'", 'value'], + }, + plugins: ['somePlugin', "'stringVal'"], + symlinks: true, + }, + plugins: ['something'], + module: { + rules: [ + { + loader: "'eslint-loader'", + enforce: "'pre'", + include: ['hey', "'Stringy'"], + options: { + formatter: "'someOption'", + }, + }, + { + loader: "'vue-loader'", + options: 'vueObject', + }, + { + loader: "'babel-loader'", + include: ["resolve('src')", "resolve('test')"], + }, + { + loader: "'url-loader'", + options: { + limit: 10000, + name: "utils.assetsPath('img/[name].[hash:7].[ext]')", + inject: "{{#if_eq build 'standalone'}}", + }, + }, + { + loader: "'url-loader'", + inject: "{{#if_eq build 'standalone'}}", + options: { + limit: '10000', + name: "utils.assetsPath('fonts/[name].[hash:7].[ext]')", + }, + }, + ], + }, +}; diff --git a/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-1.input.js b/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-1.input.js new file mode 100644 index 00000000000..f053ebf7976 --- /dev/null +++ b/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-1.input.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-2.input.js b/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-2.input.js new file mode 100644 index 00000000000..2eb604b2062 --- /dev/null +++ b/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-2.input.js @@ -0,0 +1,24 @@ +const webpack = require('webpack'); + +module.exports = { + entry: { + objects: 'are', + super: [ + 'yeah', + { + test: new RegExp(/\.(js|vue)$/), + loader: "'eslint-loader'", + enforce: "'pre'", + include: ['customObj', "'Stringy'"], + options: { + formatter: "'oki'", + updateMe: 'sure', + }, + }, + ], + nice: "':)'", + foo: 'Promise.resolve()', + man: '() => duper', + mode: 'yaaa', + }, +}; diff --git a/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-3.input.js b/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-3.input.js new file mode 100644 index 00000000000..2f5a73e568b --- /dev/null +++ b/packages/utils/__tests__/recursive-parser/__testfixtures__/fixture-3.input.js @@ -0,0 +1,58 @@ +module.exports = { + entry: { + a: 'a.js', + b: 'taddda', + }, + mode: 'prod', + devServer: { + port: 9000, + }, + devtool: 'eval', + plugins: ['plugin1', 'plugin2', 'plugin3'], + resolve: { + alias: { + inject: "{{#if_eq build 'standalone'}}", + hello: "'world'", + inject_1: '{{/if_eq}}', + world: 'hello', + }, + aliasFields: ["'browser'", 'wars'], + descriptionFiles: ["'a'", 'b', "'c'"], + enforceExtension: false, + enforceModuleExtension: false, + extensions: ['hey', 'ho'], + mainFields: ['main', "'story'"], + mainFiles: ["'noMainFileHere'", 'iGuess'], + modules: ['one', "'two'"], + unsafeCache: false, + resolveLoader: { + modules: ["'node_modules'", 'mode_nodules'], + extensions: ['jsVal', "'.json'"], + mainFields: ['loader', "'main'"], + moduleExtensions: ["'-loader'", 'value'], + }, + plugins: ['somePlugin', "'stringVal'"], + symlinks: true, + }, + module: { + noParse: function(content) { + return /jquery|lodash/.test(content); + }, + rules: [ + { + loader: 'eslint-loader', + options: { + formatter: 'someOption', + }, + }, + { + loader: 'vue-loader', + options: 'vueObject', + }, + { + loader: 'babel-loader', + include: 'asdf', + }, + ], + }, +}; diff --git a/packages/utils/__tests__/recursive-parser/recursive-parser.test.ts b/packages/utils/__tests__/recursive-parser/recursive-parser.test.ts new file mode 100644 index 00000000000..ad1daaf8612 --- /dev/null +++ b/packages/utils/__tests__/recursive-parser/recursive-parser.test.ts @@ -0,0 +1,70 @@ +'use strict'; + +import { join } from 'path'; +import defineTest from '../defineTest'; + +describe('recursive parser' ,() => { + { + + defineTest(join(__dirname), 'init', 'fixture-1', 'entry', { + foo: 'Promise.resolve()', + man: '() => duper', + nice: "':)'", + objects: 'are', + super: [ + 'yeah', + { + enforce: "'pre'", + include: ['customObj', "'Stringy'"], + loader: "'eslint-loader'", + options: { + formatter: "'someOption'", + }, + test: new RegExp(/\.(js|vue)$/), + }, + ], + }); + + defineTest(join(__dirname), 'add', 'fixture-2', 'entry', { + foo: 'Promise.resolve()', + man: '() => nice!!', + mode: 'super-man', + nice: "'=)'", + objects: 'are not', + super: [ + 'op', + { + enforce: "'pre'", + include: ['asd', "'Stringy'"], + loader: "'pia-loader'", + options: { + formatter: "'nao'", + }, + test: new RegExp(/\.(wasm|c)$/), + }, + ], + }); + + defineTest(join(__dirname), 'remove', 'fixture-3', 'resolve', { + alias: null, + }); + + defineTest(join(__dirname), 'remove', 'fixture-3', 'plugins', ['plugin2']); + + defineTest(join(__dirname), 'remove', 'fixture-3', 'module', { + noParse: null, + }); + + defineTest(join(__dirname), 'remove', 'fixture-3', 'entry', { + a: null, + }); + + defineTest(join(__dirname), 'remove', 'fixture-3', 'module', { + rules: [ + { + loader: 'eslint-loader', + }, + ], + }); + } +}) diff --git a/packages/utils/__tests__/resolve-packages.test.ts b/packages/utils/__tests__/resolve-packages.test.ts index 765b907f1d2..ebe57c2477d 100644 --- a/packages/utils/__tests__/resolve-packages.test.ts +++ b/packages/utils/__tests__/resolve-packages.test.ts @@ -1,66 +1,64 @@ -"use strict"; +'use strict'; -import * as path from "path"; +import path from 'path'; function mockPromise(value) { - const isValueAPromise = (value || {}).then; - const mockedPromise = { - then(callback) { - return mockPromise(callback(value)); - } - }; + const isValueAPromise = (value || {}).then; + const mockedPromise = { + then(callback) { + return mockPromise(callback(value)); + }, + }; - return isValueAPromise ? value : mockedPromise; + return isValueAPromise ? value : mockedPromise; } function spawnChild(pkg) { - return pkg; + return pkg; } function getLoc(option) { - const packageModule = []; - option.filter(pkg => { - mockPromise(spawnChild(pkg)).then(() => { - try { - const loc = path.join("..", "..", "node_modules", pkg); - packageModule.push(loc); - } catch (err) { - throw new Error( - "Package wasn't validated correctly.." + "Submit an issue for " + pkg + " if this persists" - ); - } - }); - return packageModule; - }); - return packageModule; + const packageModule = []; + option.filter(pkg => { + mockPromise(spawnChild(pkg)).then(() => { + try { + const loc = path.join('..', '..', 'node_modules', pkg); + packageModule.push(loc); + } catch (err) { + throw new Error("Package wasn't validated correctly.." + 'Submit an issue for ' + pkg + ' if this persists'); + } + }); + return packageModule; + }); + return packageModule; } -describe("resolve-packages", () => { - let moduleLoc; +describe('resolve-packages', () => { + let moduleLoc; - afterEach(() => { - moduleLoc = null; - }); + afterEach(() => { + moduleLoc = null; + }); - it("should resolve a location of a published module", () => { - moduleLoc = getLoc(["webpack-scaffold-ylvis"]); - expect(moduleLoc).toEqual([path.normalize("../../node_modules/webpack-scaffold-ylvis")]); - }); + it('should resolve a location of a published module', () => { + moduleLoc = getLoc(['webpack-scaffold-ylvis']); + expect(moduleLoc).toEqual([path.normalize('../../node_modules/webpack-scaffold-ylvis')]); + }); - it("should be empty if argument is blank", () => { - // normally caught before getting resolved - moduleLoc = getLoc([" "]); - expect(moduleLoc).toEqual([path.normalize("../../node_modules/ ")]); - }); + it('should be empty if argument is blank', () => { + // normally caught before getting resolved + moduleLoc = getLoc([' ']); + expect(moduleLoc).toEqual([path.normalize('../../node_modules/ ')]); + }); - it("should resolve multiple locations of published modules", () => { - /* we're testing multiple paths here. At Github this up for discussion, because if - * we validate each package on each run, we can catch and build the questions in init gradually - * while we get one filepath at the time. If not, this is a workaround. - */ - moduleLoc = getLoc(["webpack-scaffold-ylvis", "webpack-scaffold-noop"]); - expect(moduleLoc).toEqual([ - path.normalize("../../node_modules/webpack-scaffold-ylvis"), - path.normalize("../../node_modules/webpack-scaffold-noop") - ]); - }); + it('should resolve multiple locations of published modules', () => { + /* we're testing multiple paths here. At Github this up for discussion, because if + * we validate each package on each run, we can catch and build the questions in init gradually + * while we get one filepath at the time. If not, this is a workaround. + */ + moduleLoc = getLoc(['webpack-scaffold-ylvis', 'webpack-scaffold-noop']); + expect(moduleLoc).toEqual([ + path.normalize('../../node_modules/webpack-scaffold-ylvis'), + path.normalize('../../node_modules/webpack-scaffold-noop'), + ]); + }); }); diff --git a/packages/utils/__tests__/validate-identifier.test.ts b/packages/utils/__tests__/validate-identifier.test.ts index 96d36c09408..4f5f4b6a718 100644 --- a/packages/utils/__tests__/validate-identifier.test.ts +++ b/packages/utils/__tests__/validate-identifier.test.ts @@ -1,40 +1,40 @@ -"use strict"; +'use strict'; -import * as validateIdentifier from "../validate-identifier"; +import { isKeyword, isIdentifierChar, isIdentifierStart } from '../src/validate-identifier'; -describe("validate-identifier", () => { - it("should return true for reserved keyword", () => { - const l = "while"; - expect(validateIdentifier.isKeyword(l)).toBe(true); - }); +describe('validate-identifier', () => { + it('should return true for reserved keyword', () => { + const l = 'while'; + expect(isKeyword(l)).toBe(true); + }); - it("should return false for unreserved keyword", () => { - const l = "foo"; - expect(validateIdentifier.isKeyword(l)).toBe(false); - }); + it('should return false for unreserved keyword', () => { + const l = 'foo'; + expect(isKeyword(l)).toBe(false); + }); - it("should retrun false if literal is not in U+200C zero width non-joiner,\ + it('should retrun false if literal is not in U+200C zero width non-joiner,\ U+200D zero width joiner, or any symbol with \ - the Unicode derived core property ID_Continue", () => { - const l = "\u00A9"; - expect(validateIdentifier.isIdentifierChar(l)).toBe(false); - }); + the Unicode derived core property ID_Continue', () => { + const l = '\u00A9'; + expect(isIdentifierChar(l)).toBe(false); + }); - it("should retrun true if literal is in U+200C zero width non-joiner, U+200D zero width joiner,\ - or any symbol with the Unicode derived core property ID_Continue", () => { - const l = "foo$bar"; - expect(validateIdentifier.isIdentifierChar(l)).toBe(true); - }); + it('should retrun true if literal is in U+200C zero width non-joiner, U+200D zero width joiner,\ + or any symbol with the Unicode derived core property ID_Continue', () => { + const l = 'foo$bar'; + expect(isIdentifierChar(l)).toBe(true); + }); - it("should return true if literal name starts with \ - $, _ or any symbol with the unicode derived core property ID_Start", () => { - const l = "$foo"; - expect(validateIdentifier.isIdentifierStart(l)).toBe(true); - }); + it('should return true if literal name starts with \ + $, _ or any symbol with the unicode derived core property ID_Start', () => { + const l = '$foo'; + expect(isIdentifierStart(l)).toBe(true); + }); - it("should return false if literal name does not starts with \ - $, _ or any symbol with the unicode derived core property ID_Start", () => { - const l = "^bar"; - expect(validateIdentifier.isIdentifierStart(l)).toBe(false); - }); + it('should return false if literal name does not starts with \ + $, _ or any symbol with the unicode derived core property ID_Start', () => { + const l = '^bar'; + expect(isIdentifierStart(l)).toBe(false); + }); }); diff --git a/packages/utils/ast-utils.ts b/packages/utils/ast-utils.ts deleted file mode 100644 index 9db06690482..00000000000 --- a/packages/utils/ast-utils.ts +++ /dev/null @@ -1,668 +0,0 @@ -import { JSCodeshift, Node, valueType } from "./types/NodePath"; -import * as validateIdentifier from "./validate-identifier"; - -function isImportPresent(j: JSCodeshift, ast: Node, path: string): boolean { - if (typeof path !== "string") { - throw new Error(`path parameter should be string, recieved ${typeof path}`); - } - let importExists = false; - ast.find(j.CallExpression).forEach((callExp: Node): void => { - if ((callExp.value as Node).callee.name === "require" && (callExp.value as Node).arguments[0].value === path) { - importExists = true; - } - }); - return importExists; -} - -/** - * - * Traverse safely over a path object for array for paths - * @param {Object} obj - Object on which we traverse - * @param {Array} paths - Array of strings containing the traversal path - * @returns {Node} Value at given traversal path - */ - -function safeTraverse(obj: Node, paths: string[]): Node | Node[] { - // TODO: to revisit the type of this function, it's not clear what should return. - // Sometimes its return type is used as string - let val: Node = obj; - let idx = 0; - - while (idx < paths.length) { - if (!val) { - return null; - } - val = val[paths[idx]]; - idx++; - } - return val; -} - -/** - * - * Traverse safely and return `type` for path object with value.value property - * @param {Node} path - AST node - * @returns {String|Boolean} type at given path. - */ - -function safeTraverseAndGetType(path: Node): string | boolean { - const pathValue = safeTraverse(path, ["value", "value"]) as Node; - return pathValue ? pathValue.type : false; -} - -/** - * Convert nested MemberExpressions to strings like webpack.optimize.DedupePlugin - * @param {Node} path - AST node - * @returns {String} member expression string. - */ - -function memberExpressionToPathString(path: Node): string { - if (path && path.object) { - return [memberExpressionToPathString(path.object), path.property.name].join("."); - } - return path.name; -} - -// Convert Array like ['webpack', 'optimize', 'DedupePlugin'] to nested MemberExpressions -function pathsToMemberExpression(j: JSCodeshift, paths: string[]): Node { - if (!paths.length) { - return null; - } else if (paths.length === 1) { - return j.identifier(paths[0]); - } else { - const first: string[] = paths.slice(0, 1); - const rest: string[] = paths.slice(1); - return j.memberExpression(pathsToMemberExpression(j, rest), pathsToMemberExpression(j, first)); - } -} - -/** - * - * Find paths that match `new name.space.PluginName()` for a - * given array of plugin names - * - * @param {any} j — jscodeshift API - * @param {Node} node - Node to start search from - * @param {String[]} pluginNamesArray - Array of plugin names like `webpack.LoaderOptionsPlugin` - * @returns {Node} Node that has the pluginName - */ - -function findPluginsByName(j: JSCodeshift, node: Node, pluginNamesArray: string[]): Node { - return node.find(j.NewExpression).filter((path: Node): boolean => { - return pluginNamesArray.some( - (plugin: string): boolean => memberExpressionToPathString(path.get("callee").value as Node) === plugin - ); - }); -} - -/** - * It lookouts for the plugins property and, if the array is empty, it removes it from the AST - * @param {any} j - jscodeshift API - * @param {Node} rootNode - node to start search from - * @returns {Node} rootNode modified AST. - */ - -function findPluginsArrayAndRemoveIfEmpty(j: JSCodeshift, rootNode: Node): Node { - return rootNode.find(j.Identifier, { name: "plugins" }).forEach((node: Node): void => { - const elements = safeTraverse(node, ["parent", "value", "value", "elements"]) as Node[]; - if (!elements.length) { - j(node.parent).remove(); - } - }); -} - -/** - * - * Finds the path to the `name: []` node - * - * @param {any} j — jscodeshift API - * @param {Node} node - Node to start search from - * @param {String} propName - property to search for - * @returns {Node} found node and - */ - -function findRootNodesByName(j: JSCodeshift, node: Node, propName: string): Node { - return node.find(j.Property, { key: { name: propName } }); -} - -/** - * - * Creates an appropriate identifier or literal property - * - * @param {any} j — jscodeshift API - * @param {String | Boolean | Number} val - * @returns {Node} - */ - -function createIdentifierOrLiteral(j: JSCodeshift, val: valueType): Node { - // IPath | IPath doesn't work, find another way - let literalVal = val; - // We'll need String to native type conversions - if (!Array.isArray(val)) { - if (typeof val === "string" || (typeof val === "object" && val.__paths)) { - // 'true' => true - if (val === "true") { - literalVal = true; - return j.literal(literalVal); - } - // 'false' => false - if (val === "false") { - literalVal = false; - return j.literal(literalVal); - } - // '1' => 1 - if (!isNaN(Number(val))) { - literalVal = Number(val); - return j.literal(literalVal); - } - if (typeof val === "object" && val.__paths) { - const regExpVal = ((val.__paths[0].value as JSCodeshift).program as Node).body[0].expression; - return j.literal(regExpVal.value); - } else if (typeof literalVal === "string") { - // Use identifier instead - if ( - !validateIdentifier.isKeyword(literalVal) || - !validateIdentifier.isIdentifierStart(literalVal) || - !validateIdentifier.isIdentifierChar(literalVal) - ) { - return j.identifier(literalVal); - } - } - } - } - return j.literal(literalVal); -} - -/** - * - * Creates an appropriate literal property - * - * @param {any} j — jscodeshift API - * @param {String | Boolean | Number} val - * @returns {Node} - */ - -function createLiteral(j: JSCodeshift, val: valueType): Node { - let literalVal: valueType = val; - // We'll need String to native type conversions - if (typeof val === "string") { - // 'true' => true - if (val === "true") { - literalVal = true; - } - // 'false' => false - else if (val === "false") { - literalVal = false; - } - // '1' => 1 - if (!isNaN(Number(val))) { - literalVal = Number(val); - } - } - return j.literal(literalVal); -} - -/** - * - * Creates an Object's property with a given key and value - * - * @param {any} j — jscodeshift API - * @param {String | Number} key - Property key - * @param {String | Number | Boolean} value - Property value - * @returns {Node} - */ - -function createProperty(j: JSCodeshift, key: string | number, value: valueType): Node { - return j.property("init", createIdentifierOrLiteral(j, key), createLiteral(j, value)); -} - -/** - * - * Adds or updates the value of a key within a root - * webpack configuration property that's of type Object. - * - * @param {any} j — jscodeshift API - * @param {Node} rootNode - node of root webpack configuration - * @param {String} configProperty - key of an Object webpack configuration property - * @param {String} key - key within the configuration object to update - * @param {Object} value - the value to set for the key - * @returns {Void} - */ - -function addOrUpdateConfigObject( - j: JSCodeshift, - rootNode: Node, - configProperty: string, - key: string, - value: valueType -): void { - const propertyExists = rootNode.properties.filter((node: Node): boolean => node.key.name === configProperty).length; - - if (propertyExists) { - rootNode.properties - .filter((path: Node): boolean => path.key.name === configProperty) - .forEach((path: Node): void => { - const newProperties = (path.value as Node).properties.filter((p: Node): boolean => p.key.name !== key); - newProperties.push(j.objectProperty(j.identifier(key), value)); - (path.value as Node).properties = newProperties; - }); - } else { - rootNode.properties.push( - j.objectProperty( - j.identifier(configProperty), - j.objectExpression([j.objectProperty(j.identifier(key), value)]) - ) - ); - } -} - -/** - * - * Finds and removes a node for a given plugin name. If the plugin - * is the last in the plugins array, the array is also removed. - * - * @param {any} j — jscodeshift API - * @param {Node} node - node to start search from - * @param {String} pluginName - name of the plugin to remove - * @returns {Node | Void} - path to the root webpack configuration object if plugin is found - */ - -function findAndRemovePluginByName(j: JSCodeshift, node: Node, pluginName: string): Node { - let rootPath: Node; - - findPluginsByName(j, node, [pluginName]) - .filter((path: Node): boolean => !!safeTraverse(path, ["parent", "value"])) - .forEach((path: Node): void => { - rootPath = safeTraverse(path, ["parent", "parent", "parent", "value"]) as Node; - const arrayPath = path.parent.value as Node; - if (arrayPath.elements && arrayPath.elements.length === 1) { - j(path.parent.parent).remove(); - } else { - j(path).remove(); - } - }); - - return rootPath; -} - -/** - * - * Finds or creates a node for a given plugin name string with options object - * If plugin declaration already exist, options are merged. - * - * @param {any} j — jscodeshift API - * @param {Node} rootNodePath - `plugins: []` NodePath where plugin should be added. - * See https://github.com/facebook/jscodeshift/wiki/jscodeshift-Documentation#nodepaths - * @param {String} pluginName - ex. `webpack.LoaderOptionsPlugin` - * @param {Object} options - plugin options - * @returns {Void} - */ - -function createOrUpdatePluginByName(j: JSCodeshift, rootNodePath: Node, pluginName: string, options?: object): void { - const pluginInstancePath: Node = findPluginsByName(j, j(rootNodePath), [pluginName]); - let optionsProps: Node[]; - if (options) { - optionsProps = Object.keys(options).map( - (key: string): Node => { - return createProperty(j, key, options[key]); - } - ); - } - - // If plugin declaration already exist - if (pluginInstancePath.size()) { - pluginInstancePath.forEach((path: Node): void => { - // There are options we want to pass as argument - if (optionsProps) { - const args: Node[] = (path.value as Node).arguments; - if (args.length) { - // Plugin is called with object as arguments - // we will merge those objects - const currentProps: Node = j(path) - .find(j.ObjectExpression) - .get("properties"); - - optionsProps.forEach((opt: Node): void => { - // Search for same keys in the existing object - const existingProps = j(currentProps) - .find(j.Identifier) - .filter((p: Node): boolean => opt.key.value === (p.value as Node).name); - - if (existingProps.size()) { - // Replacing values for the same key - existingProps.forEach((p: Node): void => { - j(p.parent).replaceWith(opt); - }); - } else { - // Adding new key:values - (currentProps.value as Node[]).push(opt); - } - }); - } else { - // Plugin is called without arguments - args.push(j.objectExpression(optionsProps)); - } - } - }); - } else { - let argumentsArray: Node[] = []; - if (optionsProps) { - argumentsArray = [j.objectExpression(optionsProps)]; - } - const loaderPluginInstance = j.newExpression( - pathsToMemberExpression(j, pluginName.split(".").reverse()), - argumentsArray - ); - (rootNodePath.value as Node).elements.push(loaderPluginInstance); - } -} - -/** - * - * Finds the variable to which a third party plugin is assigned to - * - * @param {any} j — jscodeshift API - * @param {Node} rootNode - `plugins: []` Root Node. - * See https://github.com/facebook/jscodeshift/wiki/jscodeshift-Documentation#nodepaths - * @param {String} pluginPackageName - ex. `extract-text-plugin` - * @returns {String} variable name - ex. 'const s = require(s) gives "s"` - */ - -function findVariableToPlugin(j: JSCodeshift, rootNode: Node, pluginPackageName: string): string { - const moduleVarNames: Node[] = rootNode - .find(j.VariableDeclarator) - .filter(j.filters.VariableDeclarator.requiresModule(pluginPackageName)) - .nodes(); - if (moduleVarNames.length === 0) { - return null; - } - return moduleVarNames.pop().id.name; -} - -/** - * - * Returns true if type is given type - * @param {Node} path - AST node - * @param {String} type - node type - * @returns {Boolean} - */ - -function isType(path: Node, type: string): boolean { - return path.type === type; -} - -function findObjWithOneOfKeys(p: Node, keyNames: string[]): boolean { - return (p.value as Node).properties.reduce((predicate: boolean, prop: Node): boolean => { - const name: string = prop.key.name; - return keyNames.includes(name) || predicate; - }, false); -} - -/** - * - * Returns constructed require symbol - * @param {any} j — jscodeshift API - * @param {String} constName - Name of require - * @param {String} packagePath - path of required package - * @returns {Node} - the created ast - */ - -function getRequire(j: JSCodeshift, constName: string, packagePath: string): Node { - return j.variableDeclaration("const", [ - j.variableDeclarator( - j.identifier(constName), - j.callExpression(j.identifier("require"), [j.literal(packagePath)]) - ) - ]); -} - -/** - * - * Recursively adds an object/property to a node - * @param {any} j — jscodeshift API - * @param {Node} p - AST node - * @param {String} key - key of a key/val object - * @param {Any} value - Any type of object - * @param {String} action - Action to be done on the given ast - * @returns {Node} - the created ast - */ - -function addProperty(j: JSCodeshift, p: Node, key: string, value: valueType, action?: string): Node { - if (!p) { - return; - } - let valForNode: valueType; - if (Array.isArray(value)) { - let arrExp: Node = j.arrayExpression([]); - if (safeTraverseAndGetType(p) === "ArrayExpression") { - arrExp = (p.value as Node).value as Node; - } - value.forEach((val: valueType): void => { - addProperty(j, arrExp, null, val); - }); - valForNode = arrExp; - } else if (typeof value === "object" && !(value.__paths || value instanceof RegExp)) { - let objectExp: Node = j.objectExpression([]); - if (safeTraverseAndGetType(p) === "ObjectExpression") { - objectExp = (p.value as Node).value as Node; - } - // object -> loop through it - Object.keys(value).forEach((prop: string): void => { - addProperty(j, objectExp, prop, value[prop]); - }); - valForNode = objectExp; - } else { - valForNode = createIdentifierOrLiteral(j, value); - } - let pushVal: valueType; - if (key) { - pushVal = j.property("init", j.identifier(key), valForNode); - } else { - pushVal = valForNode; - } - - // we only return the generated pushVal which will be replace the node path - if (action === "add") { - return pushVal; - } - - if (p.properties) { - p.properties.push(pushVal); - return p; - } - if (p.value && (p.value as Node).properties) { - (p.value as Node).properties.push(pushVal); - return p; - } - if (p.elements) { - p.elements.push(pushVal); - return p; - } - return; -} - -/** - * - * Removes an object/property from the config - * @param {any} j — jscodeshift API - * @param {Node} ast - AST node - * @param {String} key - key of a key/val object - * @param {Any} value - Any type of object - * @returns {Node} - the created ast - */ - -function removeProperty(j: JSCodeshift, ast: Node, key: string, value: valueType): Node { - if (typeof value === "object" && !Array.isArray(value)) { - // override for module.rules / loaders - if (key === "module" && value.rules) { - return ast - .find(j.Property, { - value: { - type: "Literal", - value: value.rules[0].loader - } - }) - .forEach((p: Node): void => { - j(p.parent).remove(); - }); - } - } - - // value => array - if (Array.isArray(value)) { - return ast - .find(j.Literal, { - value: value[0] - }) - .forEach((p: Node): void => { - const configKey = safeTraverse(p, ["parent", "parent", "node", "key", "name"]); - if (configKey === key) { - j(p).remove(); - } - }); - } - - // value => literal string / boolean / nested object - let objKeyToRemove: string | null = null; - if (value === null) { - objKeyToRemove = key; - } else if (typeof value === "object") { - for (const innerKey in value) { - if (value[innerKey] === null) { - objKeyToRemove = innerKey; - } - } - } - return ast - .find(j.Property, { - key: { - name: objKeyToRemove, - type: "Identifier" - } - }) - .forEach((p: Node): void => { - j(p).remove(); - }); -} - -/** - * - * Get an property named topScope from yeoman and inject it to the top scope of - * the config, outside module.exports - * - * @param j — jscodeshift API - * @param ast - jscodeshift API - * @param {any} value - transformation object to scaffold - * @param {String} action - action that indicates what to be done to the AST - * @returns ast - jscodeshift API - */ - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function parseTopScope(j: JSCodeshift, ast: Node, value: string[], action: string): boolean | Node { - function createTopScopeProperty(p: Node): boolean { - value.forEach((n: string): void => { - if ( - !(p.value as Node).body[0].declarations || - n.indexOf((p.value as Node).body[0].declarations[0].id.name) <= 0 - ) { - (p.value as Node).body.splice(-1, 0, n); - } - }); - return false; // TODO: debug later - } - if (value) { - return ast.find(j.Program).filter((p: Node): boolean => createTopScopeProperty(p)); - } else { - return ast; - } -} - -/** - * - * Transform for merge. Finds the merge property from yeoman and creates a way - * for users to allow webpack-merge in their scaffold - * - * @param j — jscodeshift API - * @param ast - jscodeshift API - * @param {any} value - transformation object to scaffold - * @param {String} action - action that indicates what to be done to the AST - * @returns ast - jscodeshift API - */ - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -function parseMerge(j: JSCodeshift, ast: Node, value: string[], action: string): boolean | Node { - function createMergeProperty(p: Node, configIdentifier: string): boolean { - // FIXME Use j.callExp() - const exportsDecl: Node[] = (p.value as Node).body.map( - (n: Node): Node => { - if (n.expression) { - return n.expression.right; - } - } - ); - const bodyLength = exportsDecl.length; - const newVal: Node = {}; - newVal.type = "ExpressionStatement"; - newVal.expression = { - left: { - computed: false, - object: j.identifier("module"), - property: j.identifier("exports"), - type: "MemberExpression" - }, - operator: "=", - right: j.callExpression(j.identifier("merge"), [j.identifier(configIdentifier), exportsDecl.pop()]), - type: "AssignmentExpression" - }; - - (p.value as Node).body[bodyLength - 1] = newVal; - return false; // TODO: debug later - } - - function addMergeImports(configIdentifier: string, configPath: string): void { - if (typeof configIdentifier !== "string" || typeof configPath !== "string") { - throw new Error( - `Both parameters should be strings. recieved ${typeof configIdentifier}, ${typeof configPath}` - ); - } - ast.find(j.Program).forEach((p: Node): void => { - if (!isImportPresent(j, ast, "webpack-merge")) { - (p.value as Node).body.splice(-1, 0, `const merge = require('webpack-merge')`); - } - - if (!isImportPresent(j, ast, configPath)) { - (p.value as Node).body.splice(-1, 0, `const ${configIdentifier} = require('${configPath}')`); - } - }); - } - - if (value) { - const [configIdentifier, configPath] = value; - addMergeImports(configIdentifier, configPath); - return ast.find(j.Program).filter((p: Node): boolean => createMergeProperty(p, configIdentifier)); - } else { - return ast; - } -} - -export { - safeTraverse, - safeTraverseAndGetType, - createProperty, - findPluginsByName, - findRootNodesByName, - addOrUpdateConfigObject, - findAndRemovePluginByName, - createOrUpdatePluginByName, - findVariableToPlugin, - findPluginsArrayAndRemoveIfEmpty, - isType, - createLiteral, - createIdentifierOrLiteral, - findObjWithOneOfKeys, - getRequire, - addProperty, - removeProperty, - parseTopScope, - parseMerge -}; diff --git a/packages/utils/index.ts b/packages/utils/index.ts deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/utils/npm-packages-exists.ts b/packages/utils/npm-packages-exists.ts deleted file mode 100644 index 6ef302b6140..00000000000 --- a/packages/utils/npm-packages-exists.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { resolve } from 'path'; -import { existsSync } from 'fs'; -import chalk from "chalk"; -import npmExists from "./npm-exists"; -import { isLocalPath } from "./path-utils"; -import { resolvePackages } from "./resolve-packages"; -import { getPathToGlobalPackages } from "./package-manager"; -const WEBPACK_SCAFFOLD_PREFIX = "webpack-scaffold"; - -/** - * - * Loops through an array and checks if a package is registered - * on npm and throws an error if it is not. - * - * @param {String[]} pkg - Array of packages to check existence of - * @returns {Array} resolvePackages - Returns a process to install the packages - */ - -export default function npmPackagesExists(pkg: string[]): void { - const acceptedPackages: string[] = []; - - function resolvePackagesIfReady(): void | Function { - if (acceptedPackages.length === pkg.length) { - return resolvePackages(acceptedPackages); - } - } - - pkg.forEach((scaffold: string): void => { - if (isLocalPath(scaffold)) { - // If the scaffold is a path to a local folder, no name validation is necessary. - acceptedPackages.push(scaffold); - resolvePackagesIfReady(); - return; - } - if (existsSync(resolve(getPathToGlobalPackages(), scaffold))) { - // If scaffold is already installed or is a linked package - acceptedPackages.push(scaffold); - resolvePackagesIfReady(); - return; - } - // The scaffold is on npm; validate name and existence - if ( - scaffold.length <= WEBPACK_SCAFFOLD_PREFIX.length || - scaffold.slice(0, WEBPACK_SCAFFOLD_PREFIX.length) !== WEBPACK_SCAFFOLD_PREFIX - ) { - throw new TypeError( - chalk.bold(`${scaffold} isn't a valid name.\n`) + - chalk.red(`\nIt should be prefixed with '${WEBPACK_SCAFFOLD_PREFIX}', but have different suffix.\n`) - ); - } - - npmExists(scaffold) - .then((moduleExists: boolean): void => { - if (moduleExists) { - acceptedPackages.push(scaffold); - } else { - Error.stackTraceLimit = 0; - throw new TypeError(`Cannot resolve location of package ${scaffold}.`); - } - }) - .catch((err: Error): void => { - console.error(err.stack || err); - process.exit(0); - }) - .then(resolvePackagesIfReady); - }); -} diff --git a/packages/utils/package-manager.ts b/packages/utils/package-manager.ts deleted file mode 100644 index 57a7e51e21d..00000000000 --- a/packages/utils/package-manager.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { SpawnSyncReturns } from "child_process"; - -import * as spawn from "cross-spawn"; -import * as fs from "fs"; -import * as path from "path"; - -/** - * - * Returns the name of package manager to use, - * preferring yarn over npm if available - * - * @returns {String} - The package manager name - */ - -export function getPackageManager(): string { - const hasLocalNPM = fs.existsSync(path.resolve(process.cwd(), "package-lock.json")); - const hasLocalYarn = fs.existsSync(path.resolve(process.cwd(), "yarn.lock")); - if (hasLocalNPM) { - return "npm"; - } else if (hasLocalYarn) { - return "yarn"; - } else if (spawn.sync("yarn", [" --version"], { stdio: "ignore" }).error) { - return "npm"; - } else { - return "npm"; - } -} - -/** - * - * Spawns a new process using the respective package manager - * - * @param {String} pkg - The dependency to be installed - * @param {Boolean} isNew - indicates if it needs to be updated or installed - * @returns {Function} spawn - Installs the package - */ - -function spawnWithArg(pkg: string, isNew: boolean): SpawnSyncReturns { - const packageManager: string = getPackageManager(); - let options: string[] = []; - - if (packageManager === "npm") { - options = [isNew ? "install" : "update", "-g", pkg]; - } else { - options = ["global", isNew ? "add" : "upgrade", pkg]; - } - - return spawn.sync(packageManager, options, { - stdio: "inherit" - }); -} - -/** - * - * Returns the path to globally installed - * npm packages, depending on the available - * package manager determined by `getPackageManager` - * - * @returns {String} path - Path to global node_modules folder - */ -export function getPathToGlobalPackages(): string { - const manager: string = getPackageManager(); - - if (manager === "yarn") { - try { - const yarnDir = spawn - .sync("yarn", ["global", "dir"]) - .stdout.toString() - .trim(); - return path.join(yarnDir, "node_modules"); - } catch (e) { - // Default to the global npm path below - } - } - - return require("global-modules"); -} -/** - * - * Spawns a new process that installs the scaffold/dependency - * - * @param {String} pkg - The dependency to be installed - * @returns {SpawnSyncReturns} spawn - Installs the package - */ -export function spawnChild(pkg: string): SpawnSyncReturns { - const rootPath: string = getPathToGlobalPackages(); - const pkgPath: string = path.resolve(rootPath, pkg); - const isNew = !fs.existsSync(pkgPath); - - return spawnWithArg(pkg, isNew); -} diff --git a/packages/utils/package.json b/packages/utils/package.json index 1671920115f..e2568d411f5 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -2,15 +2,15 @@ "name": "@webpack-cli/utils", "version": "1.0.1-alpha.0", "description": "webpack-cli utility files", - "main": "index.js", - "types": "index.d.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", "publishConfig": { "access": "public" }, "author": "", "license": "MIT", "dependencies": { - "chalk": "2.4.2", + "chalk": "3.0.0", "cross-spawn": "6.0.5", "findup-sync": "4.0.0", "global-modules": "2.0.0", @@ -20,10 +20,10 @@ "p-each-series": "2.1.0", "prettier": "1.18.2", "yeoman-environment": "2.7.0", - "yeoman-generator": "4.5.0" + "yeoman-generator": "4.5.0", + "@webpack-cli/package-utils": "^1.0.0" }, "devDependencies": { - "@types/chalk": "2.2.0", "@types/cross-spawn": "6.0.0", "@types/got": "9.6.7", "@types/jest": "24.0.17", @@ -39,5 +39,8 @@ "build": "tsc", "test": "jest --detectOpenHandles", "watch": "npm run build && tsc -w" - } + }, + "files": [ + "lib" + ] } diff --git a/packages/utils/recursive-parser.ts b/packages/utils/recursive-parser.ts deleted file mode 100644 index aff433f6449..00000000000 --- a/packages/utils/recursive-parser.ts +++ /dev/null @@ -1,51 +0,0 @@ -import * as utils from "./ast-utils"; -import { JSCodeshift, Node, valueType } from "./types/NodePath"; - -export default function recursiveTransform( - j: JSCodeshift, - ast: Node, - key: string, - value: valueType, - action: string -): boolean | Node { - if (key === "topScope") { - if (Array.isArray(value)) { - return utils.parseTopScope(j, ast, value, action); - } - console.error("Error in parsing top scope, Array required"); - return false; - } else if (key === "merge") { - if (Array.isArray(value)) { - return utils.parseMerge(j, ast, value, action); - } - } - const node: Node = utils.findRootNodesByName(j, ast, key); - - // get module.exports prop - const root = ast - .find(j.ObjectExpression) - .filter((p: Node): boolean => { - return ( - utils.safeTraverse(p, ["parentPath", "value", "left", "object", "name"]) === "module" && - utils.safeTraverse(p, ["parentPath", "value", "left", "property", "name"]) === "exports" - ); - }) - .filter((p: Node): boolean => !!(p.value as Node).properties); - - if (node.size() !== 0) { - if (action === "add") { - return utils.findRootNodesByName(j, root, key).forEach((p: Node): void => { - j(p).replaceWith(utils.addProperty(j, p, key, value, action)); - }); - } else if (action === "remove") { - return utils.removeProperty(j, root, key, value); - } - } else { - return root.forEach((p: Node): void => { - if (value) { - // init, add new property - utils.addProperty(j, p, key, value, null); - } - }); - } -} diff --git a/packages/utils/resolve-packages.ts b/packages/utils/resolve-packages.ts deleted file mode 100644 index 5cf8eff42c4..00000000000 --- a/packages/utils/resolve-packages.ts +++ /dev/null @@ -1,93 +0,0 @@ -import chalk from "chalk"; -import * as path from "path"; - -import modifyConfigHelper from "./modify-config-helper"; -import { getPathToGlobalPackages } from "./package-manager"; -import { spawnChild } from "./package-manager"; -import { isLocalPath } from "./path-utils"; - -interface ChildProcess { - status: number; -} - -/** - * - * Attaches a promise to the installation of the package - * - * @param {Function} child - The function to attach a promise to - * @returns {Promise} promise - Returns a promise to the installation - */ - -export function processPromise(child: ChildProcess): Promise { - return new Promise((resolve: () => void, reject: () => void): void => { - if (child.status !== 0) { - reject(); - } else { - resolve(); - } - }); -} - -/** - * - * Resolves and installs the packages, later sending them to @creator - * - * @param {String[]} pkg - The dependencies to be installed - * @returns {Function|Error} creator - Builds - * a webpack configuration through yeoman or throws an error - */ - -export function resolvePackages(pkg: string[]): Function | void { - Error.stackTraceLimit = 30; - - const packageLocations: string[] = []; - - function invokeGeneratorIfReady(): void { - if (packageLocations.length === pkg.length) { - modifyConfigHelper("init", null, null, packageLocations); - } - } - - pkg.forEach((scaffold: string): void => { - // Resolve paths to modules on local filesystem - if (isLocalPath(scaffold)) { - let absolutePath: string = scaffold; - - try { - absolutePath = path.resolve(process.cwd(), scaffold); - require.resolve(absolutePath); - packageLocations.push(absolutePath); - } catch (err) { - console.error(`Cannot find a generator at ${absolutePath}.`); - console.error("\nReason:\n"); - console.error(chalk.bold.red(err)); - process.exitCode = 1; - } - - invokeGeneratorIfReady(); - return; - } - - // Resolve modules on npm registry - processPromise(spawnChild(scaffold)) - .then((): void => { - try { - const globalPath: string = getPathToGlobalPackages(); - packageLocations.push(path.resolve(globalPath, scaffold)); - } catch (err) { - console.error("Package wasn't validated correctly.."); - console.error("Submit an issue for", pkg, "if this persists"); - console.error("\nReason: \n"); - console.error(chalk.bold.red(err)); - process.exitCode = 1; - } - }) - .catch((err: string): void => { - console.error("Package couldn't be installed, aborting.."); - console.error("\nReason: \n"); - console.error(chalk.bold.red(err)); - process.exitCode = 1; - }) - .then(invokeGeneratorIfReady); - }); -} diff --git a/packages/utils/scaffold.ts b/packages/utils/scaffold.ts deleted file mode 100644 index dbfc7e97a3c..00000000000 --- a/packages/utils/scaffold.ts +++ /dev/null @@ -1,104 +0,0 @@ -import chalk from "chalk"; -import * as j from "jscodeshift"; -import pEachSeries = require("p-each-series"); -import * as path from "path"; -import { getPackageManager } from "./package-manager"; - -import { findProjectRoot } from "./path-utils"; - -import { Error } from "./types"; -import { Config, TransformConfig } from "./types"; -import propTypes from "./prop-types"; -import astTransform from "./recursive-parser"; -import runPrettier from "./run-prettier"; -import { Node } from "./types/NodePath"; - -/** - * - * Maps back transforms that needs to be run using the configuration - * provided. - * - * @param {Object} config - Configuration to transform - * @returns {Array} - An array with keys on which transformations need to be run - */ - -function mapOptionsToTransform(config: Config): string[] { - return Object.keys(config.webpackOptions).filter((k: string): boolean => propTypes.has(k)); -} - -/** - * - * Runs the transformations from an object we get from yeoman - * - * @param {Object} transformConfig - Configuration to transform - * @param {String} action - Action to be done on the given ast - * @returns {Promise} - A promise that writes each transform, runs prettier - * and writes the file - */ - -export default function runTransform(transformConfig: TransformConfig, action: string): void { - // webpackOptions.name sent to nameTransform if match - const webpackConfig = Object.keys(transformConfig).filter((p: string): boolean => { - return p !== "configFile" && p !== "configPath" && p !== "usingDefaults"; - }); - const initActionNotDefined = action && action !== "init" ? true : false; - - webpackConfig.forEach( - (scaffoldPiece: string): Promise => { - const config: Config = transformConfig[scaffoldPiece]; - - const transformations = mapOptionsToTransform(config); - - if (config.topScope && !transformations.includes("topScope")) { - transformations.push("topScope"); - } - - if (config.merge && !transformations.includes("merge")) { - transformations.push("merge"); - } - - const ast: Node = j(initActionNotDefined ? transformConfig.configFile : "module.exports = {}"); - - const transformAction: string = action || null; - - return pEachSeries(transformations, (f: string): boolean | Node => { - if (f === "merge" || f === "topScope") { - // TODO: typing here is difficult to understand - // eslint-disable-next-line @typescript-eslint/no-explicit-any - return astTransform(j, ast, f, config[f] as any, transformAction); - } - return astTransform(j, ast, f, config.webpackOptions[f], transformAction); - }) - .then((): void | PromiseLike => { - let configurationName: string; - if (!config.configName) { - configurationName = "webpack.config.js"; - } else { - configurationName = "webpack." + config.configName + ".js"; - } - const projectRoot = findProjectRoot(); - const outputPath: string = initActionNotDefined - ? transformConfig.configPath - : path.join(projectRoot || process.cwd(), configurationName); - const source: string = ast.toSource({ - quote: "single" - }); - runPrettier(outputPath, source); - }) - .catch((err: Error): void => { - console.error(err.message ? err.message : err); - }); - } - ); - - const runCommand = getPackageManager() === "yarn" ? "yarn build" : "npm run build"; - - let successMessage: string = - chalk.green(`Congratulations! Your new webpack configuration file has been created!\n\n`) + - `You can now run ${chalk.green(runCommand)} to bundle your application!\n\n`; - - if (initActionNotDefined && transformConfig.config.item) { - successMessage = chalk.green(`Congratulations! ${transformConfig.config.item} has been ${action}ed!\n`); - } - process.stdout.write(`\n${successMessage}`); -} diff --git a/packages/utils/src/ast-utils.ts b/packages/utils/src/ast-utils.ts new file mode 100644 index 00000000000..0bc8bc86ed0 --- /dev/null +++ b/packages/utils/src/ast-utils.ts @@ -0,0 +1,644 @@ +import { JSCodeshift, Node, valueType } from './types/NodePath'; +import { isIdentifierStart, isIdentifierChar, isKeyword } from './validate-identifier'; + +function isImportPresent(j: JSCodeshift, ast: Node, path: string): boolean { + if (typeof path !== 'string') { + throw new Error(`path parameter should be string, recieved ${typeof path}`); + } + let importExists = false; + ast.find(j.CallExpression).forEach((callExp: Node): void => { + if ((callExp.value as Node).callee.name === 'require' && (callExp.value as Node).arguments[0].value === path) { + importExists = true; + } + }); + return importExists; +} + +/** + * + * Traverse safely over a path object for array for paths + * @param {Object} obj - Object on which we traverse + * @param {Array} paths - Array of strings containing the traversal path + * @returns {Node} Value at given traversal path + */ + +function safeTraverse(obj: Node, paths: string[]): Node | Node[] { + // TODO: to revisit the type of this function, it's not clear what should return. + // Sometimes its return type is used as string + let val: Node = obj; + let idx = 0; + + while (idx < paths.length) { + if (!val) { + return null; + } + val = val[paths[idx]]; + idx++; + } + return val; +} + +/** + * + * Traverse safely and return `type` for path object with value.value property + * @param {Node} path - AST node + * @returns {String|Boolean} type at given path. + */ + +function safeTraverseAndGetType(path: Node): string | boolean { + const pathValue = safeTraverse(path, ['value', 'value']) as Node; + return pathValue ? pathValue.type : false; +} + +/** + * Convert nested MemberExpressions to strings like webpack.optimize.DedupePlugin + * @param {Node} path - AST node + * @returns {String} member expression string. + */ + +function memberExpressionToPathString(path: Node): string { + if (path && path.object) { + return [memberExpressionToPathString(path.object), path.property.name].join('.'); + } + return path.name; +} + +// Convert Array like ['webpack', 'optimize', 'DedupePlugin'] to nested MemberExpressions +function pathsToMemberExpression(j: JSCodeshift, paths: string[]): Node { + if (!paths.length) { + return null; + } else if (paths.length === 1) { + return j.identifier(paths[0]); + } else { + const first: string[] = paths.slice(0, 1); + const rest: string[] = paths.slice(1); + return j.memberExpression(pathsToMemberExpression(j, rest), pathsToMemberExpression(j, first)); + } +} + +/** + * + * Find paths that match `new name.space.PluginName()` for a + * given array of plugin names + * + * @param {any} j — jscodeshift API + * @param {Node} node - Node to start search from + * @param {String[]} pluginNamesArray - Array of plugin names like `webpack.LoaderOptionsPlugin` + * @returns {Node} Node that has the pluginName + */ + +function findPluginsByName(j: JSCodeshift, node: Node, pluginNamesArray: string[]): Node { + return node.find(j.NewExpression).filter((path: Node): boolean => { + return pluginNamesArray.some( + (plugin: string): boolean => memberExpressionToPathString(path.get('callee').value as Node) === plugin, + ); + }); +} + +/** + * It lookouts for the plugins property and, if the array is empty, it removes it from the AST + * @param {any} j - jscodeshift API + * @param {Node} rootNode - node to start search from + * @returns {Node} rootNode modified AST. + */ + +function findPluginsArrayAndRemoveIfEmpty(j: JSCodeshift, rootNode: Node): Node { + return rootNode.find(j.Identifier, { name: 'plugins' }).forEach((node: Node): void => { + const elements = safeTraverse(node, ['parent', 'value', 'value', 'elements']) as Node[]; + if (!elements.length) { + j(node.parent).remove(); + } + }); +} + +/** + * + * Finds the path to the `name: []` node + * + * @param {any} j — jscodeshift API + * @param {Node} node - Node to start search from + * @param {String} propName - property to search for + * @returns {Node} found node and + */ + +function findRootNodesByName(j: JSCodeshift, node: Node, propName: string): Node { + return node.find(j.Property, { key: { name: propName } }); +} + +/** + * + * Creates an appropriate identifier or literal property + * + * @param {any} j — jscodeshift API + * @param {String | Boolean | Number} val + * @returns {Node} + */ + +function createIdentifierOrLiteral(j: JSCodeshift, val: valueType): Node { + // IPath | IPath doesn't work, find another way + let literalVal = val; + // We'll need String to native type conversions + if (!Array.isArray(val)) { + if (typeof val === 'string' || (typeof val === 'object' && val.__paths)) { + // 'true' => true + if (val === 'true') { + literalVal = true; + return j.literal(literalVal); + } + // 'false' => false + if (val === 'false') { + literalVal = false; + return j.literal(literalVal); + } + // '1' => 1 + if (!isNaN(Number(val))) { + literalVal = Number(val); + return j.literal(literalVal); + } + if (typeof val === 'object' && val.__paths) { + const regExpVal = ((val.__paths[0].value as JSCodeshift).program as Node).body[0].expression; + return j.literal(regExpVal.value); + } else if (typeof literalVal === 'string') { + // Use identifier instead + if (!isKeyword(literalVal) || !isIdentifierStart(literalVal) || !isIdentifierChar(literalVal)) { + return j.identifier(literalVal); + } + } + } + } + return j.literal(literalVal); +} + +/** + * + * Creates an appropriate literal property + * + * @param {any} j — jscodeshift API + * @param {String | Boolean | Number} val + * @returns {Node} + */ + +function createLiteral(j: JSCodeshift, val: valueType): Node { + let literalVal: valueType = val; + // We'll need String to native type conversions + if (typeof val === 'string') { + // 'true' => true + if (val === 'true') { + literalVal = true; + } + // 'false' => false + else if (val === 'false') { + literalVal = false; + } + // '1' => 1 + if (!isNaN(Number(val))) { + literalVal = Number(val); + } + } + return j.literal(literalVal); +} + +/** + * + * Creates an Object's property with a given key and value + * + * @param {any} j — jscodeshift API + * @param {String | Number} key - Property key + * @param {String | Number | Boolean} value - Property value + * @returns {Node} + */ + +function createProperty(j: JSCodeshift, key: string | number, value: valueType): Node { + return j.property('init', createIdentifierOrLiteral(j, key), createLiteral(j, value)); +} + +/** + * + * Adds or updates the value of a key within a root + * webpack configuration property that's of type Object. + * + * @param {any} j — jscodeshift API + * @param {Node} rootNode - node of root webpack configuration + * @param {String} configProperty - key of an Object webpack configuration property + * @param {String} key - key within the configuration object to update + * @param {Object} value - the value to set for the key + * @returns {Void} + */ + +function addOrUpdateConfigObject(j: JSCodeshift, rootNode: Node, configProperty: string, key: string, value: valueType): void { + const propertyExists = rootNode.properties.filter((node: Node): boolean => node.key.name === configProperty).length; + + if (propertyExists) { + rootNode.properties + .filter((path: Node): boolean => path.key.name === configProperty) + .forEach((path: Node): void => { + const newProperties = (path.value as Node).properties.filter((p: Node): boolean => p.key.name !== key); + newProperties.push(j.objectProperty(j.identifier(key), value)); + (path.value as Node).properties = newProperties; + }); + } else { + rootNode.properties.push( + j.objectProperty(j.identifier(configProperty), j.objectExpression([j.objectProperty(j.identifier(key), value)])), + ); + } +} + +/** + * + * Finds and removes a node for a given plugin name. If the plugin + * is the last in the plugins array, the array is also removed. + * + * @param {any} j — jscodeshift API + * @param {Node} node - node to start search from + * @param {String} pluginName - name of the plugin to remove + * @returns {Node | Void} - path to the root webpack configuration object if plugin is found + */ + +function findAndRemovePluginByName(j: JSCodeshift, node: Node, pluginName: string): Node { + let rootPath: Node; + + findPluginsByName(j, node, [pluginName]) + .filter((path: Node): boolean => !!safeTraverse(path, ['parent', 'value'])) + .forEach((path: Node): void => { + rootPath = safeTraverse(path, ['parent', 'parent', 'parent', 'value']) as Node; + const arrayPath = path.parent.value as Node; + if (arrayPath.elements && arrayPath.elements.length === 1) { + j(path.parent.parent).remove(); + } else { + j(path).remove(); + } + }); + + return rootPath; +} + +/** + * + * Finds or creates a node for a given plugin name string with options object + * If plugin declaration already exist, options are merged. + * + * @param {any} j — jscodeshift API + * @param {Node} rootNodePath - `plugins: []` NodePath where plugin should be added. + * See https://github.com/facebook/jscodeshift/wiki/jscodeshift-Documentation#nodepaths + * @param {String} pluginName - ex. `webpack.LoaderOptionsPlugin` + * @param {Object} options - plugin options + * @returns {Void} + */ + +function createOrUpdatePluginByName(j: JSCodeshift, rootNodePath: Node, pluginName: string, options?: object): void { + const pluginInstancePath: Node = findPluginsByName(j, j(rootNodePath), [pluginName]); + let optionsProps: Node[]; + if (options) { + optionsProps = Object.keys(options).map( + (key: string): Node => { + return createProperty(j, key, options[key]); + }, + ); + } + + // If plugin declaration already exist + if (pluginInstancePath.size()) { + pluginInstancePath.forEach((path: Node): void => { + // There are options we want to pass as argument + if (optionsProps) { + const args: Node[] = (path.value as Node).arguments; + if (args.length) { + // Plugin is called with object as arguments + // we will merge those objects + const currentProps: Node = j(path) + .find(j.ObjectExpression) + .get('properties'); + + optionsProps.forEach((opt: Node): void => { + // Search for same keys in the existing object + const existingProps = j(currentProps) + .find(j.Identifier) + .filter((p: Node): boolean => opt.key.value === (p.value as Node).name); + + if (existingProps.size()) { + // Replacing values for the same key + existingProps.forEach((p: Node): void => { + j(p.parent).replaceWith(opt); + }); + } else { + // Adding new key:values + (currentProps.value as Node[]).push(opt); + } + }); + } else { + // Plugin is called without arguments + args.push(j.objectExpression(optionsProps)); + } + } + }); + } else { + let argumentsArray: Node[] = []; + if (optionsProps) { + argumentsArray = [j.objectExpression(optionsProps)]; + } + const loaderPluginInstance = j.newExpression(pathsToMemberExpression(j, pluginName.split('.').reverse()), argumentsArray); + (rootNodePath.value as Node).elements.push(loaderPluginInstance); + } +} + +/** + * + * Finds the variable to which a third party plugin is assigned to + * + * @param {any} j — jscodeshift API + * @param {Node} rootNode - `plugins: []` Root Node. + * See https://github.com/facebook/jscodeshift/wiki/jscodeshift-Documentation#nodepaths + * @param {String} pluginPackageName - ex. `extract-text-plugin` + * @returns {String} variable name - ex. 'const s = require(s) gives "s"` + */ + +function findVariableToPlugin(j: JSCodeshift, rootNode: Node, pluginPackageName: string): string { + const moduleVarNames: Node[] = rootNode + .find(j.VariableDeclarator) + .filter(j.filters.VariableDeclarator.requiresModule(pluginPackageName)) + .nodes(); + if (moduleVarNames.length === 0) { + return null; + } + return moduleVarNames.pop().id.name; +} + +/** + * + * Returns true if type is given type + * @param {Node} path - AST node + * @param {String} type - node type + * @returns {Boolean} + */ + +function isType(path: Node, type: string): boolean { + return path.type === type; +} + +function findObjWithOneOfKeys(p: Node, keyNames: string[]): boolean { + return (p.value as Node).properties.reduce((predicate: boolean, prop: Node): boolean => { + const name: string = prop.key.name; + return keyNames.includes(name) || predicate; + }, false); +} + +/** + * + * Returns constructed require symbol + * @param {any} j — jscodeshift API + * @param {String} constName - Name of require + * @param {String} packagePath - path of required package + * @returns {Node} - the created ast + */ + +function getRequire(j: JSCodeshift, constName: string, packagePath: string): Node { + return j.variableDeclaration('const', [ + j.variableDeclarator(j.identifier(constName), j.callExpression(j.identifier('require'), [j.literal(packagePath)])), + ]); +} + +/** + * + * Recursively adds an object/property to a node + * @param {any} j — jscodeshift API + * @param {Node} p - AST node + * @param {String} key - key of a key/val object + * @param {Any} value - Any type of object + * @param {String} action - Action to be done on the given ast + * @returns {Node} - the created ast + */ + +function addProperty(j: JSCodeshift, p: Node, key: string, value: valueType, action?: string): Node { + if (!p) { + return; + } + let valForNode: valueType; + if (Array.isArray(value)) { + let arrExp: Node = j.arrayExpression([]); + if (safeTraverseAndGetType(p) === 'ArrayExpression') { + arrExp = (p.value as Node).value as Node; + } + value.forEach((val: valueType): void => { + addProperty(j, arrExp, null, val); + }); + valForNode = arrExp; + } else if (typeof value === 'object' && !(value.__paths || value instanceof RegExp)) { + let objectExp: Node = j.objectExpression([]); + if (safeTraverseAndGetType(p) === 'ObjectExpression') { + objectExp = (p.value as Node).value as Node; + } + // object -> loop through it + Object.keys(value).forEach((prop: string): void => { + addProperty(j, objectExp, prop, value[prop]); + }); + valForNode = objectExp; + } else { + valForNode = createIdentifierOrLiteral(j, value); + } + let pushVal: valueType; + if (key) { + pushVal = j.property('init', j.identifier(key), valForNode); + } else { + pushVal = valForNode; + } + + // we only return the generated pushVal which will be replace the node path + if (action === 'add') { + return pushVal; + } + + if (p.properties) { + p.properties.push(pushVal); + return p; + } + if (p.value && (p.value as Node).properties) { + (p.value as Node).properties.push(pushVal); + return p; + } + if (p.elements) { + p.elements.push(pushVal); + return p; + } + return; +} + +/** + * + * Removes an object/property from the config + * @param {any} j — jscodeshift API + * @param {Node} ast - AST node + * @param {String} key - key of a key/val object + * @param {Any} value - Any type of object + * @returns {Node} - the created ast + */ + +function removeProperty(j: JSCodeshift, ast: Node, key: string, value: valueType): Node { + if (typeof value === 'object' && !Array.isArray(value)) { + // override for module.rules / loaders + if (key === 'module' && value.rules) { + return ast + .find(j.Property, { + value: { + type: 'Literal', + value: value.rules[0].loader, + }, + }) + .forEach((p: Node): void => { + j(p.parent).remove(); + }); + } + } + + // value => array + if (Array.isArray(value)) { + return ast + .find(j.Literal, { + value: value[0], + }) + .forEach((p: Node): void => { + const configKey = safeTraverse(p, ['parent', 'parent', 'node', 'key', 'name']); + if (configKey === key) { + j(p).remove(); + } + }); + } + + // value => literal string / boolean / nested object + let objKeyToRemove: string | null = null; + if (value === null) { + objKeyToRemove = key; + } else if (typeof value === 'object') { + for (const innerKey in value) { + if (value[innerKey] === null) { + objKeyToRemove = innerKey; + } + } + } + return ast + .find(j.Property, { + key: { + name: objKeyToRemove, + type: 'Identifier', + }, + }) + .forEach((p: Node): void => { + j(p).remove(); + }); +} + +/** + * + * Get an property named topScope from yeoman and inject it to the top scope of + * the config, outside module.exports + * + * @param j — jscodeshift API + * @param ast - jscodeshift API + * @param {any} value - transformation object to scaffold + * @param {String} action - action that indicates what to be done to the AST + * @returns ast - jscodeshift API + */ + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function parseTopScope(j: JSCodeshift, ast: Node, value: string[], action: string): boolean | Node { + function createTopScopeProperty(p: Node): boolean { + value.forEach((n: string): void => { + if (!(p.value as Node).body[0].declarations || n.indexOf((p.value as Node).body[0].declarations[0].id.name) <= 0) { + (p.value as Node).body.splice(-1, 0, n); + } + }); + return false; // TODO: debug later + } + if (value) { + return ast.find(j.Program).filter((p: Node): boolean => createTopScopeProperty(p)); + } else { + return ast; + } +} + +/** + * + * Transform for merge. Finds the merge property from yeoman and creates a way + * for users to allow webpack-merge in their scaffold + * + * @param j — jscodeshift API + * @param ast - jscodeshift API + * @param {any} value - transformation object to scaffold + * @param {String} action - action that indicates what to be done to the AST + * @returns ast - jscodeshift API + */ + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function parseMerge(j: JSCodeshift, ast: Node, value: string[], action: string): boolean | Node { + function createMergeProperty(p: Node, configIdentifier: string): boolean { + // FIXME Use j.callExp() + const exportsDecl: Node[] = (p.value as Node).body.map( + (n: Node): Node => { + if (n.expression) { + return n.expression.right; + } + }, + ); + const bodyLength = exportsDecl.length; + const newVal: Node = {}; + newVal.type = 'ExpressionStatement'; + newVal.expression = { + left: { + computed: false, + object: j.identifier('module'), + property: j.identifier('exports'), + type: 'MemberExpression', + }, + operator: '=', + right: j.callExpression(j.identifier('merge'), [j.identifier(configIdentifier), exportsDecl.pop()]), + type: 'AssignmentExpression', + }; + + (p.value as Node).body[bodyLength - 1] = newVal; + return false; // TODO: debug later + } + + function addMergeImports(configIdentifier: string, configPath: string): void { + if (typeof configIdentifier !== 'string' || typeof configPath !== 'string') { + throw new Error(`Both parameters should be strings. recieved ${typeof configIdentifier}, ${typeof configPath}`); + } + ast.find(j.Program).forEach((p: Node): void => { + if (!isImportPresent(j, ast, 'webpack-merge')) { + (p.value as Node).body.splice(-1, 0, `const merge = require('webpack-merge')`); + } + + if (!isImportPresent(j, ast, configPath)) { + (p.value as Node).body.splice(-1, 0, `const ${configIdentifier} = require('${configPath}')`); + } + }); + } + + if (value) { + const [configIdentifier, configPath] = value; + addMergeImports(configIdentifier, configPath); + return ast.find(j.Program).filter((p: Node): boolean => createMergeProperty(p, configIdentifier)); + } else { + return ast; + } +} + +export { + safeTraverse, + safeTraverseAndGetType, + createProperty, + findPluginsByName, + findRootNodesByName, + addOrUpdateConfigObject, + findAndRemovePluginByName, + createOrUpdatePluginByName, + findVariableToPlugin, + findPluginsArrayAndRemoveIfEmpty, + isType, + createLiteral, + createIdentifierOrLiteral, + findObjWithOneOfKeys, + getRequire, + addProperty, + removeProperty, + parseTopScope, + parseMerge, +}; diff --git a/packages/utils/copy-utils.ts b/packages/utils/src/copy-utils.ts similarity index 98% rename from packages/utils/copy-utils.ts rename to packages/utils/src/copy-utils.ts index 1ea841788a4..6b017a36c25 100644 --- a/packages/utils/copy-utils.ts +++ b/packages/utils/src/copy-utils.ts @@ -1,4 +1,4 @@ -import * as path from "path"; +import path from "path"; /** * Takes in a file path in the `./templates` directory. Copies that diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts new file mode 100644 index 00000000000..fe8f6bfe4f0 --- /dev/null +++ b/packages/utils/src/index.ts @@ -0,0 +1,11 @@ +export * from './ast-utils'; +export * from './copy-utils'; +export * from './modify-config-helper'; +export * from "./npm-exists"; +export * from './npm-packages-exists'; +export * from './recursive-parser'; +export * from './resolve-packages'; +export * from './run-prettier'; +export * from './scaffold'; +export * from './validate-identifier' +export * from './prop-types' diff --git a/packages/utils/modify-config-helper.ts b/packages/utils/src/modify-config-helper.ts similarity index 94% rename from packages/utils/modify-config-helper.ts rename to packages/utils/src/modify-config-helper.ts index 47bd58cd18a..42468314f54 100644 --- a/packages/utils/modify-config-helper.ts +++ b/packages/utils/src/modify-config-helper.ts @@ -1,11 +1,10 @@ -import chalk from 'chalk'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as yeoman from 'yeoman-environment'; -import * as Generator from 'yeoman-generator'; - -import runTransform from './scaffold'; -import { getPackageManager } from './package-manager'; +import chalk = require('chalk'); +import fs from 'fs'; +import path from 'path'; +import yeoman from 'yeoman-environment'; +import Generator from 'yeoman-generator'; +import { runTransform } from './scaffold'; +import { getPackageManager } from '@webpack-cli/package-utils'; export interface Config extends Object { item?: { @@ -46,7 +45,7 @@ const DEFAULT_WEBPACK_CONFIG_FILENAME = 'webpack.config.js'; * @returns {Function} runTransform - Returns a transformation instance */ -export default function modifyHelperUtil( +export function modifyHelperUtil( action: string, generator: typeof Generator, configFile: string = DEFAULT_WEBPACK_CONFIG_FILENAME, diff --git a/packages/utils/npm-exists.ts b/packages/utils/src/npm-exists.ts similarity index 87% rename from packages/utils/npm-exists.ts rename to packages/utils/src/npm-exists.ts index 0db70f11883..579237f9992 100644 --- a/packages/utils/npm-exists.ts +++ b/packages/utils/src/npm-exists.ts @@ -1,4 +1,4 @@ -import * as got from "got"; +import got from "got"; // TODO: to understand the type // eslint-disable-next-line @@ -15,7 +15,7 @@ const constant = (value: boolean) => (res: got.Response): boolean | Prom // TODO: figure out the correct type here // eslint-disable-next-line -export default function npmExists(moduleName: string): Promise { +export function npmExists(moduleName: string): Promise { const hostname = "https://www.npmjs.org"; const pkgUrl = `${hostname}/package/${moduleName}`; return got(pkgUrl, { diff --git a/packages/utils/src/npm-packages-exists.ts b/packages/utils/src/npm-packages-exists.ts new file mode 100644 index 00000000000..883e6d8f1f9 --- /dev/null +++ b/packages/utils/src/npm-packages-exists.ts @@ -0,0 +1,67 @@ +import { resolve } from 'path'; +import { existsSync } from 'fs'; +import chalk = require('chalk'); +import { npmExists } from './npm-exists'; +import { isLocalPath } from './path-utils'; +import { resolvePackages } from './resolve-packages'; +import { getPathToGlobalPackages } from '@webpack-cli/package-utils'; +const WEBPACK_SCAFFOLD_PREFIX = 'webpack-scaffold'; + +/** + * + * Loops through an array and checks if a package is registered + * on npm and throws an error if it is not. + * + * @param {String[]} pkg - Array of packages to check existence of + * @returns {Array} resolvePackages - Returns a process to install the packages + */ + +export function npmPackagesExists(pkg: string[]): void { + const acceptedPackages: string[] = []; + + function resolvePackagesIfReady(): void | Function { + if (acceptedPackages.length === pkg.length) { + return resolvePackages(acceptedPackages); + } + } + + pkg.forEach((scaffold: string): void => { + if (isLocalPath(scaffold)) { + // If the scaffold is a path to a local folder, no name validation is necessary. + acceptedPackages.push(scaffold); + resolvePackagesIfReady(); + return; + } + if (existsSync(resolve(getPathToGlobalPackages(), scaffold))) { + // If scaffold is already installed or is a linked package + acceptedPackages.push(scaffold); + resolvePackagesIfReady(); + return; + } + // The scaffold is on npm; validate name and existence + if ( + scaffold.length <= WEBPACK_SCAFFOLD_PREFIX.length || + scaffold.slice(0, WEBPACK_SCAFFOLD_PREFIX.length) !== WEBPACK_SCAFFOLD_PREFIX + ) { + throw new TypeError( + chalk.bold(`${scaffold} isn't a valid name.\n`) + + chalk.red(`\nIt should be prefixed with '${WEBPACK_SCAFFOLD_PREFIX}', but have different suffix.\n`), + ); + } + + npmExists(scaffold) + .then((moduleExists: boolean): void => { + if (moduleExists) { + acceptedPackages.push(scaffold); + } else { + Error.stackTraceLimit = 0; + throw new TypeError(`Cannot resolve location of package ${scaffold}.`); + } + }) + .catch((err: Error): void => { + console.error(err.stack || err); + process.exit(0); + }) + .then(resolvePackagesIfReady); + }); +} diff --git a/packages/utils/path-utils.ts b/packages/utils/src/path-utils.ts similarity index 90% rename from packages/utils/path-utils.ts rename to packages/utils/src/path-utils.ts index 29def6d2257..6c4b65e1872 100644 --- a/packages/utils/path-utils.ts +++ b/packages/utils/src/path-utils.ts @@ -1,6 +1,6 @@ -import * as findup from "findup-sync"; -import * as fs from "fs"; -import * as path from "path"; +import findup from "findup-sync"; +import fs from "fs"; +import path from "path"; /** * Attempts to detect whether the string is a local path regardless of its diff --git a/packages/utils/prop-types.ts b/packages/utils/src/prop-types.ts similarity index 87% rename from packages/utils/prop-types.ts rename to packages/utils/src/prop-types.ts index cccf77a1079..46c70a9c6a0 100644 --- a/packages/utils/prop-types.ts +++ b/packages/utils/src/prop-types.ts @@ -5,7 +5,7 @@ * @returns {Set} A new set with accepted webpack properties */ -const PROP_TYPES: Set = new Set([ +export const PROP_TYPES: Set = new Set([ "amd", "bail", "cache", @@ -37,4 +37,3 @@ const PROP_TYPES: Set = new Set([ "watchOptions" ]); -export default PROP_TYPES; diff --git a/packages/utils/src/recursive-parser.ts b/packages/utils/src/recursive-parser.ts new file mode 100644 index 00000000000..624b0c18faa --- /dev/null +++ b/packages/utils/src/recursive-parser.ts @@ -0,0 +1,47 @@ +import { parseTopScope, findRootNodesByName, addProperty, removeProperty, parseMerge, safeTraverse } from './ast-utils'; +import { JSCodeshift, Node, valueType } from './types/NodePath'; + +export function recursiveTransform(j: JSCodeshift, ast: Node, key: string, value: valueType, action: string): boolean | Node { + if (key === 'topScope') { + if (Array.isArray(value)) { + return parseTopScope(j, ast, value, action); + } + console.error('Error in parsing top scope, Array required'); + return false; + } else if (key === 'merge') { + if (Array.isArray(value)) { + return parseMerge(j, ast, value, action); + } + } + const node: Node = findRootNodesByName(j, ast, key); + + // get module.exports prop + const root = ast + .find(j.ObjectExpression) + .filter((p: Node): boolean => { + return ( + safeTraverse(p, ['parentPath', 'value', 'left', 'object', 'name']) === 'module' && + safeTraverse(p, ['parentPath', 'value', 'left', 'property', 'name']) === 'exports' + ); + }) + .filter((p: Node): boolean => !!(p.value as Node).properties); + + if (node.size() !== 0) { + if (action === 'add') { + return findRootNodesByName(j, root, key).forEach((p: Node): void => { + j(p).replaceWith(addProperty(j, p, key, value, action)); + }); + } else if (action === 'remove') { + return removeProperty(j, root, key, value); + } + } else { + return root.forEach((p: Node): void => { + if (value) { + // init, add new property + addProperty(j, p, key, value, null); + } + }); + } +} + +export default recursiveTransform; diff --git a/packages/utils/src/resolve-packages.ts b/packages/utils/src/resolve-packages.ts new file mode 100644 index 00000000000..615dad39d0e --- /dev/null +++ b/packages/utils/src/resolve-packages.ts @@ -0,0 +1,92 @@ +import chalk = require('chalk'); +import path from 'path'; +import { modifyHelperUtil } from './modify-config-helper'; +import { getPathToGlobalPackages, spawnChild } from '@webpack-cli/package-utils'; +import { isLocalPath } from './path-utils'; +import { ExecaSyncReturnValue } from 'execa'; + +interface ChildProcess { + status: number; +} + +/** + * + * Attaches a promise to the installation of the package + * + * @param {Function} child - The function to attach a promise to + * @returns {Promise} promise - Returns a promise to the installation + */ + +export function processPromise(child: ExecaSyncReturnValue): Promise { + return new Promise((resolve: () => void, reject: () => void): void => { + if (child.exitCode !== 0) { + reject(); + } else { + resolve(); + } + }); +} + +/** + * + * Resolves and installs the packages, later sending them to @creator + * + * @param {String[]} pkg - The dependencies to be installed + * @returns {Function|Error} creator - Builds + * a webpack configuration through yeoman or throws an error + */ + +export function resolvePackages(pkg: string[]): Function | void { + Error.stackTraceLimit = 30; + + const packageLocations: string[] = []; + + function invokeGeneratorIfReady(): void { + if (packageLocations.length === pkg.length) { + modifyHelperUtil('init', null, null, packageLocations); + } + } + + pkg.forEach((scaffold: string): void => { + // Resolve paths to modules on local filesystem + if (isLocalPath(scaffold)) { + let absolutePath: string = scaffold; + + try { + absolutePath = path.resolve(process.cwd(), scaffold); + require.resolve(absolutePath); + packageLocations.push(absolutePath); + } catch (err) { + console.error(`Cannot find a generator at ${absolutePath}.`); + console.error('\nReason:\n'); + console.error(chalk.bold.red(err)); + process.exitCode = 1; + } + + invokeGeneratorIfReady(); + return; + } + + // Resolve modules on npm registry + processPromise(spawnChild(scaffold)) + .then((): void => { + try { + const globalPath: string = getPathToGlobalPackages(); + packageLocations.push(path.resolve(globalPath, scaffold)); + } catch (err) { + console.error("Package wasn't validated correctly.."); + console.error('Submit an issue for', pkg, 'if this persists'); + console.error('\nReason: \n'); + console.error(chalk.bold.red(err)); + process.exitCode = 1; + } + }) + .catch((err: string): void => { + console.error("Package couldn't be installed, aborting.."); + console.error('\nReason: \n'); + console.error(chalk.bold.red(err)); + process.exitCode = 1; + }) + .then(invokeGeneratorIfReady); + }); +} diff --git a/packages/utils/run-prettier.ts b/packages/utils/src/run-prettier.ts similarity index 86% rename from packages/utils/run-prettier.ts rename to packages/utils/src/run-prettier.ts index 5f0537f82ef..0b5d3e56784 100644 --- a/packages/utils/run-prettier.ts +++ b/packages/utils/src/run-prettier.ts @@ -1,6 +1,6 @@ import chalk from "chalk"; -import * as fs from "fs"; -import * as prettier from "prettier"; +import fs from "fs"; +import prettier from "prettier"; /** * @@ -12,7 +12,7 @@ import * as prettier from "prettier"; * @returns {Void} Writes a file at given location and prints messages accordingly */ -export default function runPrettier(outputPath: string, source: string, cb?: Function): void { +export function runPrettier(outputPath: string, source: string, cb?: Function): void { function validateConfig(): void | Function { let prettySource: string; let error: object; diff --git a/packages/utils/src/scaffold.ts b/packages/utils/src/scaffold.ts new file mode 100644 index 00000000000..9fff45f1fed --- /dev/null +++ b/packages/utils/src/scaffold.ts @@ -0,0 +1,102 @@ +import chalk = require('chalk'); +import j from 'jscodeshift'; +import pEachSeries = require('p-each-series'); +import path from 'path'; +import { getPackageManager } from '@webpack-cli/package-utils'; +import { findProjectRoot } from './path-utils'; +import { Error } from './types'; +import { Config, TransformConfig } from './types'; +import { PROP_TYPES } from './prop-types'; +import { recursiveTransform } from './recursive-parser'; +import { runPrettier } from './run-prettier'; +import { Node } from './types/NodePath'; + +/** + * + * Maps back transforms that needs to be run using the configuration + * provided. + * + * @param {Object} config - Configuration to transform + * @returns {Array} - An array with keys on which transformations need to be run + */ + +function mapOptionsToTransform(config: Config): string[] { + return Object.keys(config.webpackOptions).filter((k: string): boolean => PROP_TYPES.has(k)); +} + +/** + * + * Runs the transformations from an object we get from yeoman + * + * @param {Object} transformConfig - Configuration to transform + * @param {String} action - Action to be done on the given ast + * @returns {Promise} - A promise that writes each transform, runs prettier + * and writes the file + */ + +export function runTransform(transformConfig: TransformConfig, action: string): void { + // webpackOptions.name sent to nameTransform if match + const webpackConfig = Object.keys(transformConfig).filter((p: string): boolean => { + return p !== 'configFile' && p !== 'configPath' && p !== 'usingDefaults'; + }); + const initActionNotDefined = action && action !== 'init' ? true : false; + + webpackConfig.forEach( + (scaffoldPiece: string): Promise => { + const config: Config = transformConfig[scaffoldPiece]; + + const transformations = mapOptionsToTransform(config); + + if (config.topScope && !transformations.includes('topScope')) { + transformations.push('topScope'); + } + + if (config.merge && !transformations.includes('merge')) { + transformations.push('merge'); + } + + const ast: Node = j(initActionNotDefined ? transformConfig.configFile : 'module.exports = {}'); + + const transformAction: string = action || null; + + return pEachSeries(transformations, (f: string): boolean | Node => { + if (f === 'merge' || f === 'topScope') { + // TODO: typing here is difficult to understand + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return recursiveTransform(j, ast, f, config[f] as any, transformAction); + } + return recursiveTransform(j, ast, f, config.webpackOptions[f], transformAction); + }) + .then((): void | PromiseLike => { + let configurationName: string; + if (!config.configName) { + configurationName = 'webpack.config.js'; + } else { + configurationName = 'webpack.' + config.configName + '.js'; + } + const projectRoot = findProjectRoot(); + const outputPath: string = initActionNotDefined + ? transformConfig.configPath + : path.join(projectRoot || process.cwd(), configurationName); + const source: string = ast.toSource({ + quote: 'single', + }); + runPrettier(outputPath, source); + }) + .catch((err: Error): void => { + console.error(err.message ? err.message : err); + }); + }, + ); + + const runCommand = getPackageManager() === 'yarn' ? 'yarn build' : 'npm run build'; + + let successMessage: string = + chalk.green(`Congratulations! Your new webpack configuration file has been created!\n\n`) + + `You can now run ${chalk.green(runCommand)} to bundle your application!\n\n`; + + if (initActionNotDefined && transformConfig.config.item) { + successMessage = chalk.green(`Congratulations! ${transformConfig.config.item} has been ${action}ed!\n`); + } + process.stdout.write(`\n${successMessage}`); +} diff --git a/packages/utils/types/Config.ts b/packages/utils/src/types/Config.ts similarity index 100% rename from packages/utils/types/Config.ts rename to packages/utils/src/types/Config.ts diff --git a/packages/utils/types/Error.ts b/packages/utils/src/types/Error.ts similarity index 100% rename from packages/utils/types/Error.ts rename to packages/utils/src/types/Error.ts diff --git a/packages/utils/types/NodePath.ts b/packages/utils/src/types/NodePath.ts similarity index 100% rename from packages/utils/types/NodePath.ts rename to packages/utils/src/types/NodePath.ts diff --git a/packages/utils/types/index.ts b/packages/utils/src/types/index.ts similarity index 100% rename from packages/utils/types/index.ts rename to packages/utils/src/types/index.ts diff --git a/packages/utils/validate-identifier.ts b/packages/utils/src/validate-identifier.ts similarity index 98% rename from packages/utils/validate-identifier.ts rename to packages/utils/src/validate-identifier.ts index 272b01f364a..4f3044020af 100644 --- a/packages/utils/validate-identifier.ts +++ b/packages/utils/src/validate-identifier.ts @@ -74,8 +74,8 @@ let nonASCIIidentifierStartChars = let nonASCIIidentifierChars = "\u200c\u200d\xb7\u0300-\u036f\u0387\u0483-\u0487\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u0669\u0670\u06d6-\u06dc\u06df-\u06e4\u06e7\u06e8\u06ea-\u06ed\u06f0-\u06f9\u0711\u0730-\u074a\u07a6-\u07b0\u07c0-\u07c9\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0859-\u085b\u08e4-\u0903\u093a-\u093c\u093e-\u094f\u0951-\u0957\u0962\u0963\u0966-\u096f\u0981-\u0983\u09bc\u09be-\u09c4\u09c7\u09c8\u09cb-\u09cd\u09d7\u09e2\u09e3\u09e6-\u09ef\u0a01-\u0a03\u0a3c\u0a3e-\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a66-\u0a71\u0a75\u0a81-\u0a83\u0abc\u0abe-\u0ac5\u0ac7-\u0ac9\u0acb-\u0acd\u0ae2\u0ae3\u0ae6-\u0aef\u0b01-\u0b03\u0b3c\u0b3e-\u0b44\u0b47\u0b48\u0b4b-\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b66-\u0b6f\u0b82\u0bbe-\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcd\u0bd7\u0be6-\u0bef\u0c00-\u0c03\u0c3e-\u0c44\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0c66-\u0c6f\u0c81-\u0c83\u0cbc\u0cbe-\u0cc4\u0cc6-\u0cc8\u0cca-\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0ce6-\u0cef\u0d01-\u0d03\u0d3e-\u0d44\u0d46-\u0d48\u0d4a-\u0d4d\u0d57\u0d62\u0d63\u0d66-\u0d6f\u0d82\u0d83\u0dca\u0dcf-\u0dd4\u0dd6\u0dd8-\u0ddf\u0de6-\u0def\u0df2\u0df3\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0e50-\u0e59\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0ed0-\u0ed9\u0f18\u0f19\u0f20-\u0f29\u0f35\u0f37\u0f39\u0f3e\u0f3f\u0f71-\u0f84\u0f86\u0f87\u0f8d-\u0f97\u0f99-\u0fbc\u0fc6\u102b-\u103e\u1040-\u1049\u1056-\u1059\u105e-\u1060\u1062-\u1064\u1067-\u106d\u1071-\u1074\u1082-\u108d\u108f-\u109d\u135d-\u135f\u1369-\u1371\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b4-\u17d3\u17dd\u17e0-\u17e9\u180b-\u180d\u1810-\u1819\u18a9\u1920-\u192b\u1930-\u193b\u1946-\u194f\u19b0-\u19c0\u19c8\u19c9\u19d0-\u19da\u1a17-\u1a1b\u1a55-\u1a5e\u1a60-\u1a7c\u1a7f-\u1a89\u1a90-\u1a99\u1ab0-\u1abd\u1b00-\u1b04\u1b34-\u1b44\u1b50-\u1b59\u1b6b-\u1b73\u1b80-\u1b82\u1ba1-\u1bad\u1bb0-\u1bb9\u1be6-\u1bf3\u1c24-\u1c37\u1c40-\u1c49\u1c50-\u1c59\u1cd0-\u1cd2\u1cd4-\u1ce8\u1ced\u1cf2-\u1cf4\u1cf8\u1cf9\u1dc0-\u1df5\u1dfc-\u1dff\u203f\u2040\u2054\u20d0-\u20dc\u20e1\u20e5-\u20f0\u2cef-\u2cf1\u2d7f\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua620-\ua629\ua66f\ua674-\ua67d\ua69f\ua6f0\ua6f1\ua802\ua806\ua80b\ua823-\ua827\ua880\ua881\ua8b4-\ua8c4\ua8d0-\ua8d9\ua8e0-\ua8f1\ua900-\ua909\ua926-\ua92d\ua947-\ua953\ua980-\ua983\ua9b3-\ua9c0\ua9d0-\ua9d9\ua9e5\ua9f0-\ua9f9\uaa29-\uaa36\uaa43\uaa4c\uaa4d\uaa50-\uaa59\uaa7b-\uaa7d\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uaaeb-\uaaef\uaaf5\uaaf6\uabe3-\uabea\uabec\uabed\uabf0-\uabf9\ufb1e\ufe00-\ufe0f\ufe20-\ufe2d\ufe33\ufe34\ufe4d-\ufe4f\uff10-\uff19\uff3f"; -const nonASCIIidentifierStart: RegExp = new RegExp("[" + nonASCIIidentifierStartChars + "]"); -const nonASCIIidentifier: RegExp = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); +const nonASCIIidentifierStart = new RegExp("[" + nonASCIIidentifierStartChars + "]"); +const nonASCIIidentifier = new RegExp("[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]"); nonASCIIidentifierStartChars = nonASCIIidentifierChars = null; diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json index 8b1269a36b6..38744ce287c 100644 --- a/packages/utils/tsconfig.json +++ b/packages/utils/tsconfig.json @@ -1,3 +1,12 @@ -{ - "extends": "../../tsconfig.packages.json" -} +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"], + "references": [ + {"path": "../package-utils"} + ] +} diff --git a/packages/webpack-cli/__tests__/command/external.test.js b/packages/webpack-cli/__tests__/command/external.test.js deleted file mode 100644 index f6a393ffa5c..00000000000 --- a/packages/webpack-cli/__tests__/command/external.test.js +++ /dev/null @@ -1,9 +0,0 @@ -const ExternalCommand = require('../../lib/commands/external'); - -describe('external command', () => { - it('should check existence of package', () => { - const exists = ExternalCommand.checkIfPackageExists('info'); - - expect(exists).toBeTruthy(); - }); -}); diff --git a/packages/webpack-cli/bin/cli.js b/packages/webpack-cli/bin/cli.js index c7a51b210b5..8978f0081d8 100755 --- a/packages/webpack-cli/bin/cli.js +++ b/packages/webpack-cli/bin/cli.js @@ -4,7 +4,6 @@ require('v8-compile-cache'); const execa = require('execa'); const importLocal = require('import-local'); -const logger = require('../lib/utils/logger'); const parseArgs = require('../lib/utils/parse-args'); // Prefer the local installation of webpack-cli diff --git a/packages/webpack-cli/lib/commands/ExternalCommand.js b/packages/webpack-cli/lib/commands/ExternalCommand.js new file mode 100644 index 00000000000..6eeb617279c --- /dev/null +++ b/packages/webpack-cli/lib/commands/ExternalCommand.js @@ -0,0 +1,38 @@ +const { prompt } = require('enquirer'); +const chalk = require('chalk'); +const logger = require('../utils/logger'); +const execa = require('execa'); +const { packageExists, promptInstallation } = require('@webpack-cli/package-utils'); + +const packagePrefix = '@webpack-cli'; + +class ExternalCommand { + static async runCommand(command, args = []) { + const executedCommand = await execa(command, args, { + stdio: 'inherit', + shell: true, + }); + return new Promise((resolve, reject) => { + executedCommand.on('error', error => { + reject(error); + }); + + executedCommand.on('exit', () => { + resolve(); + }); + }); + } + + static async run(name, ...args) { + const scopeName = packagePrefix + '/' + name; + let pkgLoc = packageExists(scopeName); + if (!pkgLoc) { + pkgLoc = await promptInstallation(`${scopeName}`, () => { + logger.error(`The command moved into a separate package: ${chalk.keyword('orange')(scopeName)}\n`); + }); + } + return pkgLoc ? require(scopeName).default(...args) : null; + } +} + +module.exports = ExternalCommand; diff --git a/packages/webpack-cli/lib/commands/external.js b/packages/webpack-cli/lib/commands/external.js deleted file mode 100644 index f2333f5345e..00000000000 --- a/packages/webpack-cli/lib/commands/external.js +++ /dev/null @@ -1,74 +0,0 @@ -const { prompt } = require('enquirer'); -const chalk = require('chalk'); -const logger = require('../utils/logger'); -const execa = require('execa'); - -const packagePrefix = '@webpack-cli'; - -class ExternalCommand { - static async runCommand(command, args = []) { - const executedCommand = await execa(command, args, { - stdio: 'inherit', - shell: true, - }); - return new Promise((resolve, reject) => { - executedCommand.on('error', error => { - reject(error); - }); - - executedCommand.on('exit', () => { - resolve(); - }); - }); - } - - /** - * - * @param extName - * @returns {boolean} - */ - static checkIfPackageExists(extName) { - try { - require(`${packagePrefix}/${extName}`); - return true; - } catch (err) { - return false; - } - } - static async promptInstallation(packageName, name) { - const path = require('path'); - const fs = require('fs'); - const isYarn = fs.existsSync(path.resolve(process.cwd(), 'yarn.lock')); - const packageManager = isYarn ? 'yarn' : 'npm'; - const options = [isYarn ? 'add' : 'install', '-D', packageName]; - - const commandToBeRun = `${packageManager} ${options.join(' ')}`; - logger.error(`The command moved into a separate package: ${chalk.keyword('orange')(packageName)}\n`); - const question = `Would you like to install ${name}? (That will run ${chalk.green(commandToBeRun)})`; - const { installConfirm } = await prompt([ - { - type: 'confirm', - name: 'installConfirm', - message: question, - initial: 'Y' - }, - ]); - if (installConfirm) { - await ExternalCommand.runCommand(commandToBeRun); - return ExternalCommand.checkIfPackageExists(name); - } - // eslint-disable-next-line require-atomic-updates - process.exitCode = -1; - } - - static async run(name, ...args) { - let pkgLoc = ExternalCommand.checkIfPackageExists(name); - const scopeName = packagePrefix + '/' + name; - if (!pkgLoc) { - pkgLoc = await ExternalCommand.promptInstallation(scopeName, name); - } - return pkgLoc ? require(scopeName).default(...args) : null; - } -} - -module.exports = ExternalCommand; diff --git a/packages/webpack-cli/lib/groups/ConfigGroup.js b/packages/webpack-cli/lib/groups/ConfigGroup.js index 7a762e912b3..ea4c6a40ae6 100644 --- a/packages/webpack-cli/lib/groups/ConfigGroup.js +++ b/packages/webpack-cli/lib/groups/ConfigGroup.js @@ -1,8 +1,11 @@ const { existsSync } = require('fs'); const { resolve, sep, dirname, parse } = require('path'); const { extensions } = require('interpret'); - +const { logger } = require('@webpack-cli/logger'); +const { packageExists, promptInstallation } = require('@webpack-cli/package-utils'); const GroupHelper = require('../utils/GroupHelper'); +const chalk = require('chalk'); +const rechoir = require('rechoir'); const DEFAULT_CONFIG_LOC = [ '.webpack/webpack.config', @@ -12,6 +15,12 @@ const DEFAULT_CONFIG_LOC = [ 'webpack.config', ]; +const fileTypes = { + '.babel.js': ['@babel/register', 'babel-register', 'babel-core/register', 'babel/register'], + '.babel.ts': ['@babel/register'], + '.ts': ['ts-node/register', 'tsconfig-paths/register'], +}; + const getDefaultConfigFiles = () => { return DEFAULT_CONFIG_LOC.map(filename => { return Object.keys(extensions).map(ext => { @@ -44,35 +53,30 @@ class ConfigGroup extends GroupHelper { super(options); } - requireModule(path, cb) { - const result = cb(path); - if (result && result.__esModule && result.default) { - return { - content: result.default, - path: path, - }; + requireLoader(extension, path) { + try { + rechoir.prepare(extensions, path, process.cwd()); + } catch (e) { + throw e; } - return { - path: path, - content: result, - }; } requireConfig(configModule) { - if (!configModule.module) { - return this.requireModule(configModule.path, require); - } else if (Array.isArray(configModule.module)) { - configModule.module.forEach(mod => { - const moduleRequire = require(mod.module); - return this.requireModule(configModule.path, moduleRequire); - }); - } else if (typeof configModule.module === 'string') { - const moduleRequire = require(configModule.module); - return this.requireModule(configModule.path, moduleRequire); - } else { - const moduleRequire = require(configModule.module.module)(module); - return this.requireModule(configModule.path, moduleRequire); + const extension = Object.keys(fileTypes).find(t => configModule.ext.endsWith(t)); + + if (extension) { + this.requireLoader(extension, configModule.path); + } + + let config = require(configModule.path); + if (config.default) { + config = config.default; } + + return { + content: config, + path: configModule.path, + }; } finalize(moduleObj) { diff --git a/packages/webpack-cli/lib/utils/logger.js b/packages/webpack-cli/lib/utils/logger.js index 292e403a3a7..afddba961c2 100644 --- a/packages/webpack-cli/lib/utils/logger.js +++ b/packages/webpack-cli/lib/utils/logger.js @@ -1,5 +1,3 @@ -const logger = require('webpack-log')({ - name: 'webpack', -}); +const { logger } = require('@webpack-cli/logger'); module.exports = logger; diff --git a/packages/webpack-cli/lib/webpack-cli.js b/packages/webpack-cli/lib/webpack-cli.js index 1b0ac49c2d3..8e382df1df6 100644 --- a/packages/webpack-cli/lib/webpack-cli.js +++ b/packages/webpack-cli/lib/webpack-cli.js @@ -283,7 +283,7 @@ class WebpackCLI extends GroupHelper { async runCommand(command, ...args) { // TODO: rename and depreciate init - return await require('./commands/external').run(defaultCommands[command.name], ...args); + return await require('./commands/ExternalCommand').run(defaultCommands[command.name], ...args); } runHelp(args) { diff --git a/packages/webpack-cli/package.json b/packages/webpack-cli/package.json index 85c756d0b21..639b5c68e12 100644 --- a/packages/webpack-cli/package.json +++ b/packages/webpack-cli/package.json @@ -38,7 +38,10 @@ "interpret": "^2.0.0", "v8-compile-cache": "^2.1.0", "webpack-log": "^3.0.1", - "webpack-merge": "^4.2.2" + "webpack-merge": "^4.2.2", + "@webpack-cli/package-utils": "1.0.0", + "@webpack-cli/logger": "1.0.0", + "rechoir": "^0.7.0" }, "peerDependencies": { "webpack": "^5.0.0-beta.12" diff --git a/packages/webpack-scaffold/.gitignore b/packages/webpack-scaffold/.gitignore index 72f5245cbdd..fe608509c3d 100644 --- a/packages/webpack-scaffold/.gitignore +++ b/packages/webpack-scaffold/.gitignore @@ -1,3 +1,4 @@ *.js !*.test.js !/**/*.test.js +lib/ diff --git a/packages/webpack-scaffold/__tests__/index.test.ts b/packages/webpack-scaffold/__tests__/index.test.ts index 525cba64003..e79ecc26d19 100755 --- a/packages/webpack-scaffold/__tests__/index.test.ts +++ b/packages/webpack-scaffold/__tests__/index.test.ts @@ -1,110 +1,119 @@ -"use strict"; -import * as utils from "../index"; +import { + createArrowFunction, + createAssetFilterFunction, + createDynamicPromise, + createRegularFunction, + parseValue, + CheckList, + Confirm, + createExternalFunction, + createRequire, + List, + RawList, InputValidate, Input, +} from '../src'; -describe("utils", () => { - beforeEach(() => { - this.mockSelf = { - prompt: arg => { - return arg[0]; - } - }; - }); - describe("createArrowFunction", () => { - it("should stringify an arrow function", () => { - expect(utils.createArrowFunction("app.js")).toMatchSnapshot(); - }); - }); - describe("createRegularFunction", () => { - it("should stringify a regular function", () => { - expect(utils.createRegularFunction("app.js")).toMatchSnapshot(); - }); - }); - describe("createDynamicPromise", () => { - it("should stringify an single value", () => { - expect(utils.createDynamicPromise("app.js")).toMatchSnapshot(); - }); - it("should stringify an array", () => { - expect(utils.createDynamicPromise(["app.js", "index.js"])).toMatchSnapshot(); - }); - }); - describe("createAssetFilterFunction", () => { - it("should stringify an assetFilterFunction", () => { - expect(utils.createAssetFilterFunction("js")).toMatchSnapshot(); - }); - }); - describe("parseValue", () => { - it("should parse value", () => { - expect(utils.parseValue("\t")).toMatchSnapshot(); - }); - it("should parse value with raw value", () => { - expect(utils.parseValue("hell\u{6F}")).toMatchSnapshot(); - }); - }); - describe("createExternalFunction", () => { - it("should stringify an ExternalFunction", () => { - expect(utils.createExternalFunction("js")).toMatchSnapshot(); - }); - }); - describe("createRequire", () => { - it("should stringify a require statement", () => { - expect(utils.createRequire("webpack")).toMatchSnapshot(); - }); - }); - describe("Inquirer", () => { - it("should make default value for a List", () => { - expect(utils.List(this.mockSelf, "entry", "does it work?", ["Yes", "Maybe"], "Yes", true)).toEqual({ - entry: "Yes" - }); - }); - it("should make a RawList object", () => { - expect(utils.RawList("output", "does it work?", ["Yes", "Maybe"])).toEqual({ - choices: ["Yes", "Maybe"], - message: "does it work?", - name: "output", - type: "rawlist" - }); - }); - it("should make a CheckList object", () => { - expect(utils.CheckList("context", "does it work?", ["Yes", "Maybe"])).toEqual({ - choices: ["Yes", "Maybe"], - message: "does it work?", - name: "context", - type: "checkbox" - }); - }); - it("should emulate a prompt for list input", () => { - expect(utils.Input(this.mockSelf, "plugins", "what is your plugin?", "openJSF", false)).toEqual({ - type: "input", - name: "plugins", - message: "what is your plugin?", - default: "openJSF" - }); - }); - it("should return a default Input object value", () => { - expect(utils.Input(this.mockSelf, "plugins", "what is your plugin?", "my-plugin", true)).toEqual({ - plugins: "my-plugin" - }); - }); - it("should emulate a prompt for confirm", () => { - expect(utils.Confirm(this.mockSelf, "context", "what is your context?", true, false)).toEqual({ - name: "context", - default: true, - message: "what is your context?", - type: "confirm" - }); - }); - it("should make a Confirm object with yes as default", () => { - expect(utils.Confirm(this.mockSelf, "context", "what is your context?", true, true)).toEqual({ - context: true - }); - }); - it("should make an Input object with validation", () => { - expect(utils.InputValidate(this.mockSelf, "plugins", "what is your plugin?", () => true)).toMatchSnapshot(); - }); - it("should make an Input object with validation and default value", () => { - expect( - utils.InputValidate(this.mockSelf, "plugins", "what is your plugin?", () => true, "my-plugin") - ).toMatchSnapshot(); - }); - }); +describe('utils', () => { + beforeEach(() => { + this.mockSelf = { + prompt: arg => { + return arg[0]; + }, + }; + }); + describe('createArrowFunction', () => { + it('should stringify an arrow function', () => { + expect(createArrowFunction('app.js')).toMatchSnapshot(); + }); + }); + describe('createRegularFunction', () => { + it('should stringify a regular function', () => { + expect(createRegularFunction('app.js')).toMatchSnapshot(); + }); + }); + describe('createDynamicPromise', () => { + it('should stringify an single value', () => { + expect(createDynamicPromise('app.js')).toMatchSnapshot(); + }); + it('should stringify an array', () => { + expect(createDynamicPromise(['app.js', 'index.js'])).toMatchSnapshot(); + }); + }); + describe('createAssetFilterFunction', () => { + it('should stringify an assetFilterFunction', () => { + expect(createAssetFilterFunction('js')).toMatchSnapshot(); + }); + }); + describe('parseValue', () => { + it('should parse value', () => { + expect(parseValue('\t')).toMatchSnapshot(); + }); + it('should parse value with raw value', () => { + expect(parseValue('hell\u{6F}')).toMatchSnapshot(); + }); + }); + describe('createExternalFunction', () => { + it('should stringify an ExternalFunction', () => { + expect(createExternalFunction('js')).toMatchSnapshot(); + }); + }); + describe('createRequire', () => { + it('should stringify a require statement', () => { + expect(createRequire('webpack')).toMatchSnapshot(); + }); + }); + describe('Inquirer', () => { + it('should make default value for a List', () => { + expect(List(this.mockSelf, 'entry', 'does it work?', ['Yes', 'Maybe'], 'Yes', true)).toEqual({ + entry: 'Yes', + }); + }); + it('should make a RawList object', () => { + expect(RawList('output', 'does it work?', ['Yes', 'Maybe'])).toEqual({ + choices: ['Yes', 'Maybe'], + message: 'does it work?', + name: 'output', + type: 'rawlist', + }); + }); + it('should make a CheckList object', () => { + expect(CheckList('context', 'does it work?', ['Yes', 'Maybe'])).toEqual({ + choices: ['Yes', 'Maybe'], + message: 'does it work?', + name: 'context', + type: 'checkbox', + }); + }); + it('should emulate a prompt for list input', () => { + expect(Input(this.mockSelf, 'plugins', 'what is your plugin?', 'openJSF', false)).toEqual({ + type: 'input', + name: 'plugins', + message: 'what is your plugin?', + default: 'openJSF', + }); + }); + it('should return a default Input object value', () => { + expect(Input(this.mockSelf, 'plugins', 'what is your plugin?', 'my-plugin', true)).toEqual({ + plugins: 'my-plugin', + }); + }); + it('should emulate a prompt for confirm', () => { + expect(Confirm(this.mockSelf, 'context', 'what is your context?', true, false)).toEqual({ + name: 'context', + default: true, + message: 'what is your context?', + type: 'confirm', + }); + }); + it('should make a Confirm object with yes as default', () => { + expect(Confirm(this.mockSelf, 'context', 'what is your context?', true, true)).toEqual({ + context: true, + }); + }); + it('should make an Input object with validation', () => { + expect(InputValidate(this.mockSelf, 'plugins', 'what is your plugin?', () => true)).toMatchSnapshot(); + }); + it('should make an Input object with validation and default value', () => { + expect(InputValidate(this.mockSelf, 'plugins', 'what is your plugin?', () => true, 'my-plugin')).toMatchSnapshot(); + }); + }); }); diff --git a/packages/webpack-scaffold/package.json b/packages/webpack-scaffold/package.json index e5a9142058a..874fe157765 100644 --- a/packages/webpack-scaffold/package.json +++ b/packages/webpack-scaffold/package.json @@ -2,8 +2,8 @@ "name": "@webpack-cli/webpack-scaffold", "version": "1.0.1-alpha.0", "description": "Utility files for webpack-scaffold", - "main": "index.js", - "types": "index.d.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", "publishConfig": { "access": "public" }, @@ -20,5 +20,8 @@ "test": "jest --detectOpenHandles", "build": "tsc", "watch": "npm run build && tsc -w" - } + }, + "files": [ + "lib" + ] } diff --git a/packages/webpack-scaffold/index.ts b/packages/webpack-scaffold/src/index.ts similarity index 97% rename from packages/webpack-scaffold/index.ts rename to packages/webpack-scaffold/src/index.ts index a63e16a40aa..015aa256eed 100755 --- a/packages/webpack-scaffold/index.ts +++ b/packages/webpack-scaffold/src/index.ts @@ -1,5 +1,5 @@ -import * as jscodeshift from "jscodeshift"; -import * as Generator from "yeoman-generator"; +import jscodeshift from "jscodeshift"; +import Generator from "yeoman-generator"; /* eslint-disable @typescript-eslint/no-explicit-any */ diff --git a/packages/webpack-scaffold/tsconfig.json b/packages/webpack-scaffold/tsconfig.json index 8b1269a36b6..fd0ff87aea4 100644 --- a/packages/webpack-scaffold/tsconfig.json +++ b/packages/webpack-scaffold/tsconfig.json @@ -1,3 +1,9 @@ -{ - "extends": "../../tsconfig.packages.json" -} +{ + "extends": "../../tsconfig.packages.json", + "compilerOptions": { + "outDir": "./lib", + "rootDir": "./src", + "composite": true + }, + "include": ["./src"] +} diff --git a/scripts/buildPackages.js b/scripts/buildPackages.js new file mode 100644 index 00000000000..197edd7dc11 --- /dev/null +++ b/scripts/buildPackages.js @@ -0,0 +1,32 @@ +'use strict'; + +const fs = require('fs'); +const path = require('path'); +// eslint-disable-next-line node/no-unpublished-require +const execa = require('execa'); +// eslint-disable-next-line node/no-unpublished-require +const chalk = require('chalk'); + +const PACKAGES_DIR = path.resolve(__dirname, '../packages'); + +function getPackages() { + return fs + .readdirSync(PACKAGES_DIR) + .map(file => path.resolve(PACKAGES_DIR, file)) + .filter(f => fs.lstatSync(path.resolve(f)).isDirectory()); +} + +const packages = getPackages(); + +const packagesWithTs = packages.filter(p => fs.existsSync(path.resolve(p, 'tsconfig.json'))); + +const args = ['tsc', '-b', ...packagesWithTs, ...process.argv.slice(2)]; + +try { + execa.sync('yarn', args, { stdio: 'inherit' }); + console.log(chalk.inverse.green(' Successfully built TypeScript definition files ')); +} catch (e) { + console.error(chalk.inverse.red(' Unable to build TypeScript definition files ')); + console.error(e.stack); + process.exitCode = 1; +} diff --git a/smoketests/watch/watch.array.smoketest.js b/smoketests/watch/watch.array.smoketest.js index 200c7549331..4da5a1ab643 100644 --- a/smoketests/watch/watch.array.smoketest.js +++ b/smoketests/watch/watch.array.smoketest.js @@ -3,6 +3,7 @@ const assert = require('assert'); const { unlinkSync, renameSync } = require('fs'); const { resolve } = require('path'); +// eslint-disable-next-line node/no-unpublished-require const { appendDataIfFileExists, runAndGetWatchProc, copyFileAsync } = require('../../test/utils/test-utils'); console.log('\n============================ ARRAY/CHILD COMPILATION ============================\n'); diff --git a/smoketests/watch/watch.single.smoketest.js b/smoketests/watch/watch.single.smoketest.js index 998c627ad2d..4536e4fba8b 100644 --- a/smoketests/watch/watch.single.smoketest.js +++ b/smoketests/watch/watch.single.smoketest.js @@ -3,6 +3,7 @@ const assert = require('assert'); const { unlinkSync, renameSync } = require('fs'); const { resolve } = require('path'); +// eslint-disable-next-line node/no-unpublished-require const { appendDataIfFileExists, runAndGetWatchProc, copyFileAsync } = require('../../test/utils/test-utils'); console.log('\n============================ SINGLE COMPILATION ============================\n'); diff --git a/test/typescript/.gitignore b/test/typescript/.gitignore new file mode 100644 index 00000000000..8f4fcdeff50 --- /dev/null +++ b/test/typescript/.gitignore @@ -0,0 +1,5 @@ +yarn.lock +package-lock.json +node_modules/ +*.js +*.js.map diff --git a/test/typescript/main.ts b/test/typescript/main.ts new file mode 100644 index 00000000000..5dbd072a4f6 --- /dev/null +++ b/test/typescript/main.ts @@ -0,0 +1 @@ +console.log('Main typescript file'); diff --git a/test/typescript/package.json b/test/typescript/package.json new file mode 100644 index 00000000000..43237a25bed --- /dev/null +++ b/test/typescript/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "typescript": "^3.8.2", + "ts-node": "^8.6.2", + "tsconfig-paths": "^3.9.0" + } +} diff --git a/test/typescript/typescript.test.js b/test/typescript/typescript.test.js new file mode 100644 index 00000000000..0d328a3e418 --- /dev/null +++ b/test/typescript/typescript.test.js @@ -0,0 +1,17 @@ +// eslint-disable-next-line node/no-unpublished-require +const { run, runInstall } = require('../utils/test-utils'); +const { stat } = require('fs'); +const { resolve } = require('path'); + +describe('webpack cli', () => { + it('should support typescript file', async () => { + await runInstall(__dirname); + const { stderr, stdout } = run(__dirname, ['-c', './webpack.config.ts']); + expect(stderr).toBeFalsy(); + expect(stdout).toBeTruthy(); + stat(resolve(__dirname, 'bin/foo.bundle.js'), (err, stats) => { + expect(err).toBe(null); + expect(stats.isFile()).toBe(true); + }); + }); +}); diff --git a/test/typescript/webpack.config.ts b/test/typescript/webpack.config.ts new file mode 100644 index 00000000000..3fcf302d52d --- /dev/null +++ b/test/typescript/webpack.config.ts @@ -0,0 +1,13 @@ +/** eslint-disable **/ +import * as path from 'path'; + +const config = { + mode: 'production', + entry: './main.ts', + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'foo.bundle.js', + }, +}; + +export default config; diff --git a/test/utils/test-utils.js b/test/utils/test-utils.js index e22ec0cc97a..61735cb9f1b 100644 --- a/test/utils/test-utils.js +++ b/test/utils/test-utils.js @@ -177,6 +177,12 @@ function copyFile(testCase, file) { } } +async function runInstall(cwd) { + await execa('yarn', { + cwd, + }); +} + module.exports = { run, runWatch, @@ -186,4 +192,5 @@ module.exports = { copyFile, copyFileAsync, appendDataToMultipleIfFilesExists, + runInstall, }; diff --git a/tsconfig.base.json b/tsconfig.base.json index 20786e2daef..82a3a6962f8 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,19 +1,22 @@ -{ - "compilerOptions": { - "allowSyntheticDefaultImports": true, - "module": "commonjs", - "moduleResolution": "node", - "skipLibCheck": true, - "target": "es6", - "lib": ["es6", "es2017"], - "resolveJsonModule": true, - "sourceMap": true - }, - "include": ["packages/**/*.ts"], - "exclude": [ - "node_modules/**", - "packages/*/node_modules/**", - "packages/**/__tests__/*.test.ts", - "packages/**/__testfixtures__/*.ts" - ] -} +{ + "compilerOptions": { + "allowSyntheticDefaultImports": true, + "module": "commonjs", + "moduleResolution": "node", + "skipLibCheck": true, + "target": "es2017", + "lib": ["es6", "es2017"], + "resolveJsonModule": true, + "sourceMap": true, + "composite": true, + "esModuleInterop": true + }, + + "exclude": [ + "node_modules/**", + "packages/*/node_modules/**", + "packages/**/__tests__/*.test.ts", + "packages/**/__testfixtures__/*.ts", + "test" + ] +} diff --git a/yarn.lock b/yarn.lock index b32747d42aa..26933e66c3c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2249,13 +2249,6 @@ "@types/connect" "*" "@types/node" "*" -"@types/chalk@2.2.0": - version "2.2.0" - resolved "https://registry.yarnpkg.com/@types/chalk/-/chalk-2.2.0.tgz#b7f6e446f4511029ee8e3f43075fb5b73fbaa0ba" - integrity sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw== - dependencies: - chalk "*" - "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -3802,14 +3795,6 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@*, chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.4.1, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -3819,6 +3804,14 @@ chalk@2.4.2, chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.1, chalk@^2.4. escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@3.0.0, chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^1.0.0, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -5385,6 +5378,21 @@ execa@^3.2.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +execa@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.0.tgz#7f37d6ec17f09e6b8fc53288611695b6d12b9daf" + integrity sha512-JbDUxwV3BoT5ZVXQrSVbAiaXhXUkIwvbhPIwZ0N13kX+5yCzOhUNdocxB/UQRuYOHRYYwAxKYwJYc0T4D12pDA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -10549,6 +10557,13 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" +rechoir@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca" + integrity sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q== + dependencies: + resolve "^1.9.0" + redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -10811,7 +10826,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@1.x, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.3.2: +resolve@1.x, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.3.2, resolve@^1.9.0: version "1.15.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.1.tgz#27bdcdeffeaf2d6244b95bb0f9f4b4653451f3e8" integrity sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w== @@ -12208,6 +12223,11 @@ typescript@3.7.x, typescript@^3.7.2: resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae" integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw== +typescript@^3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.2.tgz#91d6868aaead7da74f493c553aeff76c0c0b1d5a" + integrity sha512-EgOVgL/4xfVrCMbhYKUQTdF37SQn4Iw73H5BgCrF1Abdun7Kwy/QZsE/ssAy0y4LxBbvua3PIbFsbRczWWnDdQ== + typical@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"