From 04f0f6691a95dbafd141ea2181667df857753dce Mon Sep 17 00:00:00 2001 From: Even Stensberg Date: Thu, 21 Dec 2017 16:43:31 +0100 Subject: [PATCH] adds module ast --- .../module/__snapshots__/module.test.js.snap | 126 ++++++++++++++++++ .../module/__testfixtures__/module-2.input.js | 42 ++++++ lib/init/transformations/module/module.js | 62 +++++++-- .../transformations/module/module.test.js | 122 +++++++++++++++++ lib/utils/ast-utils.js | 5 +- 5 files changed, 345 insertions(+), 12 deletions(-) create mode 100644 lib/init/transformations/module/__testfixtures__/module-2.input.js diff --git a/lib/init/transformations/module/__snapshots__/module.test.js.snap b/lib/init/transformations/module/__snapshots__/module.test.js.snap index 537735ba1a7..9a7c0dcce10 100644 --- a/lib/init/transformations/module/__snapshots__/module.test.js.snap +++ b/lib/init/transformations/module/__snapshots__/module.test.js.snap @@ -99,6 +99,55 @@ exports[`module transforms correctly using "module-0" data 2`] = ` " `; +exports[`module transforms correctly using "module-0" data 3`] = ` +"module.exports = { + entry: 'index.js', + + output: { + filename: 'bundle.js' + }, + + module: { + rules: [{ + test: /\\\\.(js|vue)$/, + loader: 'eslint-loader', + enforce: 'pre', + include: [customObj, 'Stringy'], + + options: { + formatter: 'someOption' + } + }, { + test: /\\\\.vue$/, + loader: 'vue-loader', + options: vueObject + }, { + test: /\\\\.js$/, + loader: 'babel-loader', + include: [resolve('src'), resolve('test')] + }, { + test: /\\\\.(png|jpe?g|gif|svg)(\\\\?.*)?$/, + loader: 'url-loader', + + options: { + limit: 10000, + name: utils.assetsPath('img/[name].[hash:7].[ext]') + } + }, { + test: /\\\\.(woff2?|eot|ttf|otf)(\\\\?.*)?$/, + loader: 'url-loader', + + options: { + limit: 10000, + name: utils.assetsPath('fonts/[name].[hash:7].[ext]'), + someArr: [Hey] + } + }] + } +} +" +`; + exports[`module transforms correctly using "module-1" data 1`] = ` "module.exports = { entry: 'index.js', @@ -129,3 +178,80 @@ exports[`module transforms correctly using "module-1" data 1`] = ` } " `; + +exports[`module transforms correctly using "module-1" data 2`] = ` +"module.exports = { + entry: 'index.js', + + output: { + filename: 'bundle.js' + }, + + module: { + noParse: /jquery|lodash/, + + rules: [{ + test: /\\\\.js$/, + + parser: { + amd: false + }, + + use: ['htmllint-loader', { + loader: 'html-loader', + + options: { + hello: 'world' + } + }] + }] + } +} +" +`; + +exports[`module transforms correctly using "module-2" data 1`] = ` +"module.exports = { + entry: 'index.js', + output: { + filename: 'bundle.js' + }, + 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/lib/init/transformations/module/__testfixtures__/module-2.input.js b/lib/init/transformations/module/__testfixtures__/module-2.input.js new file mode 100644 index 00000000000..c8bebc01efd --- /dev/null +++ b/lib/init/transformations/module/__testfixtures__/module-2.input.js @@ -0,0 +1,42 @@ +module.exports = { + entry: 'index.js', + output: { + filename: 'bundle.js' + }, + 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/lib/init/transformations/module/module.js b/lib/init/transformations/module/module.js index 0c7abb32749..0b838e119fb 100644 --- a/lib/init/transformations/module/module.js +++ b/lib/init/transformations/module/module.js @@ -14,19 +14,59 @@ const utils = require("../../../utils/ast-utils"); * @returns ast - jscodeshift API */ -module.exports = function(j, ast, webpackProperties, action) { - function createModuleProperties(p) { - utils.pushCreateProperty(j, p, "module", j.objectExpression([])); - return utils.safeTraverse(p, ["key", "name"] === "module"); +module.exports = function moduleTransform(j, ast, webpackProperties, action) { + function createModuleProperty(p) { + if (typeof webpackProperties === "string") { + return utils.pushCreateProperty(j, p, "module", webpackProperties); + } + if (Array.isArray(webpackProperties)) { + const externalArray = utils.createArrayWithChildren( + j, + "module", + webpackProperties, + true + ); + return p.value.properties.push(externalArray); + } else { + utils.pushCreateProperty(j, p, "module", j.objectExpression([])); + return utils.pushObjectKeys(j, p, webpackProperties, "module"); + } } - function createRules(p) { - return utils.pushObjectKeys(j, p, webpackProperties, "module"); + function editModuleProperty(p) { + return utils.pushObjectKeys(j, p, webpackProperties, "module", true); } - if (webpackProperties && action === "init") { - return ast - .find(j.ObjectExpression) - .filter(p => utils.isAssignment(null, p, createModuleProperties)) - .forEach(p => createRules(p)); + if (webpackProperties) { + if (action === "init") { + return ast + .find(j.ObjectExpression) + .filter(p => utils.isAssignment(null, p, createModuleProperty)); + } else if (action === "add") { + const moduleNode = utils.findRootNodesByName(j, ast, "module"); + if (moduleNode.size() !== 0 && typeof webpackProperties === "object") { + return ast + .find(j.ObjectExpression) + .filter(p => utils.isAssignment(null, p, editModuleProperty)); + } else if (moduleNode.size() !== 0 && webpackProperties.length) { + return ast + .find(j.ObjectExpression) + .filter( + p => + utils.safeTraverse(p, ["parentPath", "value", "key", "name"]) === + "module" + ) + .forEach(p => { + j(p).replaceWith( + utils.createIdentifierOrLiteral(j, webpackProperties) + ); + }); + } else { + return moduleTransform(j, ast, webpackProperties, "init"); + } + } else if (action === "remove") { + // TODO + } else if (action === "update") { + // TODO + } } else { return ast; } diff --git a/lib/init/transformations/module/module.test.js b/lib/init/transformations/module/module.test.js index 8ce97e3e102..ed6356b3bd0 100644 --- a/lib/init/transformations/module/module.test.js +++ b/lib/init/transformations/module/module.test.js @@ -124,3 +124,125 @@ defineTest( }, "init" ); + +defineTest( + __dirname, + "module", + "module-0", + { + rules: [ + { + test: new RegExp(/\.(js|vue)$/), + loader: "'eslint-loader'", + enforce: "'pre'", + include: ["customObj", "'Stringy'"], + options: { + formatter: "'someOption'" + } + }, + { + test: new RegExp(/\.vue$/), + loader: "'vue-loader'", + options: "vueObject" + }, + { + test: new RegExp(/\.js$/), + loader: "'babel-loader'", + include: ["resolve('src')", "resolve('test')"] + }, + { + test: new RegExp(/\.(png|jpe?g|gif|svg)(\?.*)?$/), + loader: "'url-loader'", + options: { + limit: 10000, + name: "utils.assetsPath('img/[name].[hash:7].[ext]')" + } + }, + { + test: new RegExp(/\.(woff2?|eot|ttf|otf)(\?.*)?$/), + loader: "'url-loader'", + options: { + limit: "10000", + name: "utils.assetsPath('fonts/[name].[hash:7].[ext]')", + someArr: ["Hey"] + } + } + ] + }, + "init" +); + +defineTest( + __dirname, + "module", + "module-1", + { + noParse: /jquery|lodash/, + rules: [ + { + test: new RegExp(/\.js$/), + parser: { + amd: false + }, + use: [ + "'htmllint-loader'", + { + loader: "'html-loader'", + options: { + hello: "'world'" + } + } + ] + } + ] + }, + "add" +); + +defineTest( + __dirname, + "module", + "module-2", + { + rules: [ + { + test: new RegExp(/\.(js|vue)$/), + loader: "'eslint-loader'", + enforce: "'pre'", + include: ["customObj", "'Stringy'"], + options: { + formatter: "'someOption'" + } + }, + { + test: new RegExp(/\.vue$/), + loader: "'vue-loader'", + options: "vueObject" + }, + { + test: new RegExp(/\.js$/), + loader: "'babel-loader'", + include: ["resolve('src')", "resolve('test')"] + }, + { + test: new RegExp(/\.(png|jpe?g|gif|svg)(\?.*)?$/), + loader: "'url-loader'", + options: { + limit: 10000, + name: "utils.assetsPath('img/[name].[hash:7].[ext]')", + inject: "{{#if_eq build 'standalone'}}" + } + }, + { + test: new RegExp(/\.(woff2?|eot|ttf|otf)(\?.*)?$/), + loader: "'url-loader'", + inject: "{{#if_eq build 'standalone'}}", + options: { + limit: "10000", + name: "utils.assetsPath('fonts/[name].[hash:7].[ext]')" + } + } + ] + }, + "add" +); diff --git a/lib/utils/ast-utils.js b/lib/utils/ast-utils.js index 95b5637231a..2a4dbd67e28 100644 --- a/lib/utils/ast-utils.js +++ b/lib/utils/ast-utils.js @@ -564,7 +564,6 @@ function pushObjectKeys( } } else if (Array.isArray(webpackProperties[webpackProp])) { if (reassign) { - // todo: improve the hash algo return j(p) .find(j.Property, { key: { name: webpackProp } }) .filter(props => props.value.key.name === webpackProp) @@ -577,6 +576,10 @@ function pushObjectKeys( } }); webpackProperties[webpackProp].forEach(underlyingprop => { + if (typeof underlyingprop === "object") { + //TODO loaders + return; + } if (!markedProps.includes(underlyingprop)) { propsToMerge.push(underlyingprop); }