123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- "use strict";
- const fs = require("fs");
- const path = require("path");
- const chalk = require("chalk");
- const diff = require("diff");
- const inquirer = require("inquirer");
- const PLazy = require("p-lazy");
- const Listr = require("listr");
- const { validate } = require("webpack");
- const { WebpackOptionsValidationError } = require("webpack");
- const runPrettier = require("../utils/run-prettier");
- /**
- *
- * Runs migration on a given configuration using AST's and promises
- * to sequentially transform a configuration file.
- *
- * @param {Array} args - Migrate arguments such as input and
- * output path
- * @returns {Function} Runs the migration using the 'runMigrate'
- * function.
- */
- module.exports = function migrate(...args) {
- const filePaths = args.slice(3);
- if (!filePaths.length) {
- const errMsg = "\n ✖ Please specify a path to your webpack config \n ";
- console.error(chalk.red(errMsg));
- return;
- }
- const currentConfigPath = path.resolve(process.cwd(), filePaths[0]);
- let outputConfigPath;
- if (!filePaths[1]) {
- return inquirer
- .prompt([
- {
- type: "confirm",
- name: "confirmPath",
- message:
- "Migration output path not specified. " +
- "Do you want to use your existing webpack " +
- "configuration?",
- default: "Y"
- }
- ])
- .then(ans => {
- if (!ans["confirmPath"]) {
- console.error(chalk.red("✖ ︎Migration aborted due no output path"));
- return;
- }
- outputConfigPath = path.resolve(process.cwd(), filePaths[0]);
- return runMigration(currentConfigPath, outputConfigPath);
- })
- .catch(err => {
- console.error(err);
- });
- }
- outputConfigPath = path.resolve(process.cwd(), filePaths[1]);
- return runMigration(currentConfigPath, outputConfigPath);
- };
- /**
- *
- * Runs migration on a given configuration using AST's and promises
- * to sequentially transform a configuration file.
- *
- * @param {String} currentConfigPath - input path for config
- * @param {String} outputConfigPath - output path for config
- * @returns {Promise} Runs the migration using a promise that
- * will throw any errors during each transform or output if the
- * user decides to abort the migration
- */
- function runMigration(currentConfigPath, outputConfigPath) {
- const recastOptions = {
- quote: "single"
- };
- const tasks = new Listr([
- {
- title: "Reading webpack config",
- task: ctx =>
- new PLazy((resolve, reject) => {
- fs.readFile(currentConfigPath, "utf8", (err, content) => {
- if (err) {
- reject(err);
- }
- try {
- const jscodeshift = require("jscodeshift");
- ctx.source = content;
- ctx.ast = jscodeshift(content);
- resolve();
- } catch (err) {
- reject("Error generating AST", err);
- }
- });
- })
- },
- {
- title: "Migrating config to newest version",
- task: ctx => {
- const transformations = require("../migrate").transformations;
- return new Listr(
- Object.keys(transformations).map(key => {
- const transform = transformations[key];
- return {
- title: key,
- task: _ => transform(ctx.ast, ctx.source)
- };
- })
- );
- }
- }
- ]);
- tasks
- .run()
- .then(ctx => {
- const result = ctx.ast.toSource(recastOptions);
- const diffOutput = diff.diffLines(ctx.source, result);
- diffOutput.forEach(diffLine => {
- if (diffLine.added) {
- process.stdout.write(chalk.green(`+ ${diffLine.value}`));
- } else if (diffLine.removed) {
- process.stdout.write(chalk.red(`- ${diffLine.value}`));
- }
- });
- return inquirer
- .prompt([
- {
- type: "confirm",
- name: "confirmMigration",
- message: "Are you sure these changes are fine?",
- default: "Y"
- }
- ])
- .then(answers => {
- if (answers["confirmMigration"]) {
- return inquirer.prompt([
- {
- type: "confirm",
- name: "confirmValidation",
- message:
- "Do you want to validate your configuration? " +
- "(If you're using webpack merge, validation isn't useful)",
- default: "Y"
- }
- ]);
- } else {
- console.log(chalk.red("✖ Migration aborted"));
- }
- })
- .then(answer => {
- if (!answer) return;
- runPrettier(outputConfigPath, result, err => {
- if (err) {
- throw err;
- }
- });
- if (answer["confirmValidation"]) {
- const webpackOptionsValidationErrors = validate(
- require(outputConfigPath)
- );
- if (webpackOptionsValidationErrors.length) {
- console.log(
- chalk.red(
- "\n✖ Your configuration validation wasn't successful \n"
- )
- );
- console.error(
- new WebpackOptionsValidationError(
- webpackOptionsValidationErrors
- ).message
- );
- }
- }
- console.log(
- chalk.green(
- `\n✔︎ New webpack config file is at ${outputConfigPath}.`
- )
- );
- console.log(
- chalk.green(
- "✔︎ Heads up! Updating to the latest version could contain breaking changes."
- )
- );
- console.log(
- chalk.green(
- "✔︎ Plugin and loader dependencies may need to be updated."
- )
- );
- });
- })
- .catch(err => {
- const errMsg = "\n ✖ ︎Migration aborted due to some errors: \n";
- console.error(chalk.red(errMsg));
- console.error(err);
- process.exitCode = 1;
- });
- }
|