From d8b57af68e9e4a4209323f07011df0a3df9d58d2 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Thu, 26 Jan 2017 12:41:11 +0100 Subject: [PATCH 01/43] fix: Support for more complex query strings in loaders syntax --- .../loaders/__testfixtures__/loaders.input.js | 4 +- .../__testfixtures__/loaders.output.js | 6 ++- lib/transformations/loaders/loaders.js | 38 ++++++++++++------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/lib/transformations/loaders/__testfixtures__/loaders.input.js b/lib/transformations/loaders/__testfixtures__/loaders.input.js index ea18dc9b021..2d48781598d 100644 --- a/lib/transformations/loaders/__testfixtures__/loaders.input.js +++ b/lib/transformations/loaders/__testfixtures__/loaders.input.js @@ -9,7 +9,7 @@ export default [{ module: { loaders: [{ test: /\.css$/, - loader: 'style!css?modules=true' + loader: 'style!css?modules&importLoaders=1&string=test123' }] } }, { @@ -62,4 +62,4 @@ export default [{ loader: 'my-post-loader' }] } -}]; \ No newline at end of file +}]; diff --git a/lib/transformations/loaders/__testfixtures__/loaders.output.js b/lib/transformations/loaders/__testfixtures__/loaders.output.js index 1d79bfd6418..2229d05139e 100644 --- a/lib/transformations/loaders/__testfixtures__/loaders.output.js +++ b/lib/transformations/loaders/__testfixtures__/loaders.output.js @@ -14,7 +14,9 @@ export default [{ }, { loader: 'css-loader', options: { - modules: true + modules: true, + importLoaders: 1, + string: 'test123' } }] }] @@ -71,4 +73,4 @@ export default [{ enforce: 'post' }] } -}]; \ No newline at end of file +}]; diff --git a/lib/transformations/loaders/loaders.js b/lib/transformations/loaders/loaders.js index 2559c3ec3da..874be2759cf 100644 --- a/lib/transformations/loaders/loaders.js +++ b/lib/transformations/loaders/loaders.js @@ -3,8 +3,8 @@ const safeTraverse = require('../safeTraverse'); module.exports = function(j, ast) { const createArrayExpression = function(p) { - var objs = p.parent.node.value.value.split('!').map(val => j.objectExpression([j.property('init', - j.identifier('loader'), + var objs = p.parent.node.value.value.split('!').map(val => j.objectExpression([j.property('init', + j.identifier('loader'), j.literal(val) )])); var loaderArray = j.arrayExpression(objs); @@ -13,9 +13,16 @@ module.exports = function(j, ast) { }; const createLiteral = val => { - var literalVal = val; - if(val === 'true') literalVal = true; - if(val === 'false') literalVal = false; + let literalVal = val; + // We'll need String to native type conversions + if (typeof val === 'string') { + // 'true' => true + if (val === 'true') literalVal = true; + // 'false' => false + if (val === 'false') literalVal = false; + // '1' => 1 + if (!isNaN(Number(val))) literalVal = Number(val); + } return j.literal(literalVal); }; @@ -24,9 +31,12 @@ module.exports = function(j, ast) { var loaderValue = properties.reduce((val, prop) => prop.key.name === 'loader' ? prop.value.value : val, ''); var loader = loaderValue.split('?')[0]; var query = loaderValue.split('?')[1]; - var options = query.split('&').map(option => - j.objectProperty(j.identifier(option.split('=')[0]),createLiteral(option.split('=')[1])) - ); + var options = query.split('&').map(option => { + const param = option.split('='); + const key = param[0]; + const val = param[1] || true; // No value in query string means it is truthy value + return j.objectProperty(j.identifier(key), createLiteral(val)); + }); var loaderProp = j.property('init', j.identifier('loader'), j.literal(loader)); var queryProp = j.property('init', j.identifier('options'), j.objectExpression(options)); return j.objectExpression([loaderProp, queryProp]); @@ -42,7 +52,7 @@ module.exports = function(j, ast) { const findLoaderWithQueryString = p => { return p.value.properties.reduce((predicate, prop) => safeTraverse(prop, ['value', 'value', 'indexOf']) && prop.value.value.indexOf('?') > -1 || predicate, false); }; - + const checkForLoader = p => p.value.name === 'loaders' && safeTraverse(p, ['parent', 'parent', 'parent', 'node', 'key', 'name']) === 'module'; const fitIntoLoaders = p => { @@ -50,14 +60,14 @@ module.exports = function(j, ast) { p.value.properties.map(prop => { const keyName = prop.key.name; if(keyName === 'loaders') { - loaders = prop.value; + loaders = prop.value; } }); p.value.properties.map(prop => { const keyName = prop.key.name; if(keyName !== 'loaders'){ const enforceVal = keyName === 'preLoaders' ? 'pre' : 'post'; - + prop.value.elements.map(elem => { elem.properties.push( j.property( 'init', j.identifier('enforce'), j.literal(enforceVal) ) ); if(loaders && loaders.type === 'ArrayExpression') { @@ -73,7 +83,7 @@ module.exports = function(j, ast) { } return p; }; - + const prepostLoaders = () => ast .find(j.ObjectExpression) .filter(findObjWithPrePostLoaders) @@ -102,7 +112,7 @@ module.exports = function(j, ast) { .replaceWith(createLoaderWithQuery); const loaderWithQueryProp = () => ast.find(j.Identifier) - .filter(p => p.value.name === 'query') + .filter(p => p.value.name === 'query') .replaceWith(j.identifier('options')); const addLoaderSuffix = () => ast.find(j.ObjectExpression) @@ -113,4 +123,4 @@ module.exports = function(j, ast) { transforms.forEach(t => t()); return ast.toSource({quote:'single'}); -}; \ No newline at end of file +}; From 465b9154d50a0d70d13f12e690822dfe66dac072 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Thu, 26 Jan 2017 13:01:43 +0100 Subject: [PATCH 02/43] style: Re-format source code for loaders transformation --- lib/transformations/loaders/loaders.js | 145 ++++++++++++++++--------- 1 file changed, 96 insertions(+), 49 deletions(-) diff --git a/lib/transformations/loaders/loaders.js b/lib/transformations/loaders/loaders.js index 874be2759cf..356a148bfbb 100644 --- a/lib/transformations/loaders/loaders.js +++ b/lib/transformations/loaders/loaders.js @@ -3,11 +3,14 @@ const safeTraverse = require('../safeTraverse'); module.exports = function(j, ast) { const createArrayExpression = function(p) { - var objs = p.parent.node.value.value.split('!').map(val => j.objectExpression([j.property('init', - j.identifier('loader'), - j.literal(val) - )])); - var loaderArray = j.arrayExpression(objs); + let objs = p.parent.node.value.value.split('!') + .map(val => j.objectExpression([ + j.property('init', + j.identifier('loader'), + j.literal(val) + ) + ])); + let loaderArray = j.arrayExpression(objs); p.parent.node.value = loaderArray; return p; }; @@ -27,50 +30,69 @@ module.exports = function(j, ast) { }; const createLoaderWithQuery = p => { - var properties = p.value.properties; - var loaderValue = properties.reduce((val, prop) => prop.key.name === 'loader' ? prop.value.value : val, ''); - var loader = loaderValue.split('?')[0]; - var query = loaderValue.split('?')[1]; - var options = query.split('&').map(option => { + let properties = p.value.properties; + let loaderValue = properties + .reduce((val, prop) => prop.key.name === 'loader' ? prop.value.value : val, ''); + let loader = loaderValue.split('?')[0]; + let query = loaderValue.split('?')[1]; + let options = query.split('&').map(option => { const param = option.split('='); const key = param[0]; const val = param[1] || true; // No value in query string means it is truthy value return j.objectProperty(j.identifier(key), createLiteral(val)); }); - var loaderProp = j.property('init', j.identifier('loader'), j.literal(loader)); - var queryProp = j.property('init', j.identifier('options'), j.objectExpression(options)); + let loaderProp = j.property('init', j.identifier('loader'), j.literal(loader)); + let queryProp = j.property('init', j.identifier('options'), j.objectExpression(options)); return j.objectExpression([loaderProp, queryProp]); }; const findObjWithPrePostLoaders = p => { - return p.value.properties.reduce((predicate, prop) => prop.key.name === 'preLoaders' || prop.key.name === 'postLoaders' || predicate , false); + return p.value.properties + .reduce((predicate, prop) => { + const name = prop.key.name; + return name === 'preLoaders' + || name === 'postLoaders' + || predicate; + }, false); }; const findObjWithLoaderProp = p => { - return p.value.properties.reduce((predicate, prop) => prop.key.name === 'loader' || predicate , false); + return p.value.properties + .reduce((predicate, prop) => { + return prop.key.name === 'loader' + || predicate; + }, false); }; const findLoaderWithQueryString = p => { - return p.value.properties.reduce((predicate, prop) => safeTraverse(prop, ['value', 'value', 'indexOf']) && prop.value.value.indexOf('?') > -1 || predicate, false); + return p.value.properties + .reduce((predicate, prop) => { + return safeTraverse(prop, ['value', 'value', 'indexOf']) + && prop.value.value.indexOf('?') > -1 + || predicate; + }, false); }; - const checkForLoader = p => p.value.name === 'loaders' && safeTraverse(p, ['parent', 'parent', 'parent', 'node', 'key', 'name']) === 'module'; + const checkForLoader = p => p.value.name === 'loaders' && safeTraverse(p, + ['parent', 'parent', 'parent', 'node', 'key', 'name']) === 'module'; const fitIntoLoaders = p => { let loaders; p.value.properties.map(prop => { const keyName = prop.key.name; - if(keyName === 'loaders') { + if (keyName === 'loaders') { loaders = prop.value; } }); p.value.properties.map(prop => { const keyName = prop.key.name; - if(keyName !== 'loaders'){ + if (keyName !== 'loaders') { const enforceVal = keyName === 'preLoaders' ? 'pre' : 'post'; prop.value.elements.map(elem => { - elem.properties.push( j.property( 'init', j.identifier('enforce'), j.literal(enforceVal) ) ); - if(loaders && loaders.type === 'ArrayExpression') { + elem.properties.push(j.property('init', + j.identifier('enforce'), + j.literal(enforceVal))); + if (loaders && loaders.type === 'ArrayExpression') { loaders.elements.push(elem); } else { prop.key.name = 'loaders'; @@ -78,49 +100,74 @@ module.exports = function(j, ast) { }); } }); - if(loaders){ + if (loaders) { p.value.properties = p.value.properties.filter(prop => prop.key.name === 'loaders'); } return p; }; const prepostLoaders = () => ast - .find(j.ObjectExpression) - .filter(findObjWithPrePostLoaders) - .forEach(p => p = fitIntoLoaders(p)); + .find(j.ObjectExpression) + .filter(findObjWithPrePostLoaders) + .forEach(p => p = fitIntoLoaders(p)); const loadersToRules = () => ast - .find(j.Identifier) - .filter(checkForLoader) - .forEach(p => p.value.name = 'rules'); + .find(j.Identifier) + .filter(checkForLoader) + .forEach(p => p.value.name = 'rules'); const loaderToUse = () => ast - .find(j.Identifier) - .filter(p => (p.value.name === 'loaders' || p.value.name === 'loader') && safeTraverse(p, ['parent', 'parent', 'parent', 'parent', 'node', 'key', 'name']) === 'rules') - .forEach(p => p.value.name = 'use'); - + .find(j.Identifier) + .filter(p => { + return (p.value.name === 'loaders' || p.value.name === 'loader') + && safeTraverse(p, + ['parent', 'parent', 'parent', 'parent', 'node', 'key', 'name']) === 'rules'; + }) + .forEach(p => p.value.name = 'use'); const loadersInArray = () => ast - .find(j.Identifier) - .filter(p => p.value.name === 'use' && p.parent.node.value.type === 'Literal' && p.parent.node.value.value.indexOf('!') > 0) - .forEach(createArrayExpression); + .find(j.Identifier) + .filter(p => { + return p.value.name === 'use' + && p.parent.node.value.type === 'Literal' + && p.parent.node.value.value.indexOf('!') > 0; + }) + .forEach(createArrayExpression); const loaderWithQueryParam = () => ast - .find(j.ObjectExpression) - .filter(findObjWithLoaderProp) - .filter(findLoaderWithQueryString) - .replaceWith(createLoaderWithQuery); - - const loaderWithQueryProp = () => ast.find(j.Identifier) - .filter(p => p.value.name === 'query') - .replaceWith(j.identifier('options')); - - const addLoaderSuffix = () => ast.find(j.ObjectExpression) - .forEach(path => path.value.properties.map(prop => {if((prop.key.name === 'loader' || prop.key.name ==='use') && safeTraverse(prop, ['value', 'value']) && prop.value.value.indexOf('-loader') === -1) prop.value = j.literal(prop.value.value + '-loader');})) - .toSource(); - - const transforms = [ prepostLoaders, loadersToRules, loaderToUse, loadersInArray, loaderWithQueryParam, loaderWithQueryProp, addLoaderSuffix]; + .find(j.ObjectExpression) + .filter(findObjWithLoaderProp) + .filter(findLoaderWithQueryString) + .replaceWith(createLoaderWithQuery); + + const loaderWithQueryProp = () => ast + .find(j.Identifier) + .filter(p => p.value.name === 'query') + .replaceWith(j.identifier('options')); + + const addLoaderSuffix = () => ast + .find(j.ObjectExpression) + .forEach(path => { + path.value.properties.forEach(prop => { + if ((prop.key.name === 'loader' || prop.key.name === 'use') + && safeTraverse(prop, ['value', 'value']) + && prop.value.value.indexOf('-loader') === -1) { + prop.value = j.literal(prop.value.value + '-loader'); + } + }); + }) + .toSource(); + + const transforms = [ + prepostLoaders, + loadersToRules, + loaderToUse, + loadersInArray, + loaderWithQueryParam, + loaderWithQueryProp, + addLoaderSuffix + ]; transforms.forEach(t => t()); - return ast.toSource({quote:'single'}); + return ast.toSource({ quote: 'single' }); }; From 7da4804b1a1d60e709063bf03a3bb46eb568ffab Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Thu, 26 Jan 2017 13:28:11 +0100 Subject: [PATCH 03/43] style: Don't run eslint on fixtures code --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index f48045523db..a7cecca09b8 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1 @@ -__testfixtures__ +**/__testfixtures__/* From 0278297e2a7da2e4e014990d6ba21275fb7d2afc Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Thu, 26 Jan 2017 13:29:29 +0100 Subject: [PATCH 04/43] WIP: Added tests for removeJsonLoader --- .../removeJsonLoader.input.js | 22 +++++++++++++++++++ .../removeJsonLoader.output.js | 19 ++++++++++++++++ .../__tests__/removeJsonLoader.test.js | 3 +++ .../removeJsonLoader/removeJsonLoader.js | 5 +++++ 4 files changed, 49 insertions(+) create mode 100644 lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js create mode 100644 lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js create mode 100644 lib/transformations/removeJsonLoader/__tests__/removeJsonLoader.test.js create mode 100644 lib/transformations/removeJsonLoader/removeJsonLoader.js diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js new file mode 100644 index 00000000000..f8afdce4e69 --- /dev/null +++ b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js @@ -0,0 +1,22 @@ +export default [{ + module: { + rules: [{ + test: /\.yml/, + use: ['json-loader', 'another-loader', 'yml-loader'] + }] + } +}, { + module: { + rules: [{ + test: /\.yml/, + use: ['json-loader', 'yml-loader'] + }] + } +}, { + module: { + rules: [{ + test: /\.json/, + use: 'json-loader' + }] + } +}]; diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js new file mode 100644 index 00000000000..ba60ffff58f --- /dev/null +++ b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js @@ -0,0 +1,19 @@ +export default [{ + module: { + rules: [{ + test: /\.yml/, + use: ['another-loader', 'yml-loader'] + }] + } +}, { + module: { + rules: [{ + test: /\.yml/, + use: 'yml-loader' + }] + } +}, { + module: { + rules: [] + } +}]; diff --git a/lib/transformations/removeJsonLoader/__tests__/removeJsonLoader.test.js b/lib/transformations/removeJsonLoader/__tests__/removeJsonLoader.test.js new file mode 100644 index 00000000000..c52b5ae7c81 --- /dev/null +++ b/lib/transformations/removeJsonLoader/__tests__/removeJsonLoader.test.js @@ -0,0 +1,3 @@ +import {defineTest} from '../../defineTest'; + +defineTest(__dirname, 'removeJsonLoader'); diff --git a/lib/transformations/removeJsonLoader/removeJsonLoader.js b/lib/transformations/removeJsonLoader/removeJsonLoader.js new file mode 100644 index 00000000000..3d1278bb7eb --- /dev/null +++ b/lib/transformations/removeJsonLoader/removeJsonLoader.js @@ -0,0 +1,5 @@ +const safeTraverse = require('../safeTraverse'); + +module.exports = function(j, ast) { + return ast.toSource(); +}; From cdd2cada06d4a3c7ca424d8bedbd0969bf886caa Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Fri, 27 Jan 2017 09:10:45 +0100 Subject: [PATCH 05/43] Do not pre-process test fixtures with eslint --fix since it makes our code less reliable. Pre-processing fixtures with eslint makes our transform way less reliable since we basically doing 2 transforms each time. In user-land it won't probably the case and we need to test only our code. Even if we want to provide re-formatting of the code with eslint for users, this should probably be a sepaeate task. --- lib/transformations/defineTest.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/transformations/defineTest.js b/lib/transformations/defineTest.js index d7ab908c482..2a010eeaeb7 100644 --- a/lib/transformations/defineTest.js +++ b/lib/transformations/defineTest.js @@ -65,8 +65,7 @@ function runTest(dirName, transformName, options, testFilePrefix) { jscodeshift, ast ); - const newOutput = cli.executeOnText(output).results[0].output; - expect((newOutput || '').trim()).toEqual(expectedOutput.trim()); + expect((output || '').trim()).toEqual(expectedOutput.trim()); } module.exports.runTest = runTest; From 97866e12b87cf756dbd8d9a1956d05088e08ba3c Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Fri, 27 Jan 2017 09:13:41 +0100 Subject: [PATCH 06/43] Use spaces instead of tabs for indentation in fixtures to get reliable results. It looks like tabs are treated differently even by differrent tools. This was leading to some false test fails. Replacing tabs with spaces makes it reliable for tests to run. --- .../loaders/__testfixtures__/loaders.input.js | 114 +++++++-------- .../__testfixtures__/loaders.output.js | 136 +++++++++--------- .../removeJsonLoader.input.js | 52 ++++--- .../removeJsonLoader.output.js | 40 ++++-- .../resolve/__testfixtures__/resolve.input.js | 28 ++-- .../__testfixtures__/resolve.output.js | 26 ++-- 6 files changed, 211 insertions(+), 185 deletions(-) diff --git a/lib/transformations/loaders/__testfixtures__/loaders.input.js b/lib/transformations/loaders/__testfixtures__/loaders.input.js index 2d48781598d..e0d498f6506 100644 --- a/lib/transformations/loaders/__testfixtures__/loaders.input.js +++ b/lib/transformations/loaders/__testfixtures__/loaders.input.js @@ -1,65 +1,65 @@ export default [{ - module: { - loaders: [{ - test: /\.js$/, - loader: 'babel' - }] - } + module: { + loaders: [{ + test: /\.js$/, + loader: 'babel' + }] + } }, { - module: { - loaders: [{ - test: /\.css$/, - loader: 'style!css?modules&importLoaders=1&string=test123' - }] - } + module: { + loaders: [{ + test: /\.css$/, + loader: 'style!css?modules&importLoaders=1&string=test123' + }] + } }, { - module: { - loaders: [{ - test: /\.css$/, - loaders: [{ - loader: 'style' - }, { - loader: 'css', - query: { - modules: true - } - }] - }] - } + module: { + loaders: [{ + test: /\.css$/, + loaders: [{ + loader: 'style' + }, { + loader: 'css', + query: { + modules: true + } + }] + }] + } }, { - module: { - preLoaders:[{ - test: /\.js$/, - loader: 'eslint' - }] - } + module: { + preLoaders:[{ + test: /\.js$/, + loader: 'eslint' + }] + } }, { - module: { - postLoaders:[{ - test: /\.js$/, - loader: 'my-post' - }] - } + module: { + postLoaders:[{ + test: /\.js$/, + loader: 'my-post' + }] + } }, { - module: { - preLoaders:[{ - test: /\.js$/, - loader: 'eslint-loader' - }], - loaders: [{ - test: /\.js$/, - loader: 'babel-loader' - }] - } + module: { + preLoaders:[{ + test: /\.js$/, + loader: 'eslint-loader' + }], + loaders: [{ + test: /\.js$/, + loader: 'babel-loader' + }] + } }, { - module: { - loaders: [{ - test: /\.js$/, - loader: 'babel-loader' - }], - postLoaders:[{ - test: /\.js$/, - loader: 'my-post-loader' - }] - } + module: { + loaders: [{ + test: /\.js$/, + loader: 'babel-loader' + }], + postLoaders:[{ + test: /\.js$/, + loader: 'my-post-loader' + }] + } }]; diff --git a/lib/transformations/loaders/__testfixtures__/loaders.output.js b/lib/transformations/loaders/__testfixtures__/loaders.output.js index 2229d05139e..a6a55b75c85 100644 --- a/lib/transformations/loaders/__testfixtures__/loaders.output.js +++ b/lib/transformations/loaders/__testfixtures__/loaders.output.js @@ -1,76 +1,76 @@ export default [{ - module: { - rules: [{ - test: /\.js$/, - use: 'babel-loader' - }] - } + module: { + rules: [{ + test: /\.js$/, + use: 'babel-loader' + }] + } }, { - module: { - rules: [{ - test: /\.css$/, - use: [{ - loader: 'style-loader' - }, { - loader: 'css-loader', - options: { - modules: true, - importLoaders: 1, - string: 'test123' - } - }] - }] - } + module: { + rules: [{ + test: /\.css$/, + use: [{ + loader: 'style-loader' + }, { + loader: 'css-loader', + options: { + modules: true, + importLoaders: 1, + string: 'test123' + } + }] + }] + } }, { - module: { - rules: [{ - test: /\.css$/, - use: [{ - loader: 'style-loader' - }, { - loader: 'css-loader', - options: { - modules: true - } - }] - }] - } + module: { + rules: [{ + test: /\.css$/, + use: [{ + loader: 'style-loader' + }, { + loader: 'css-loader', + options: { + modules: true + } + }] + }] + } }, { - module: { - rules:[{ - test: /\.js$/, - use: 'eslint-loader', - enforce: 'pre' - }] - } + module: { + rules:[{ + test: /\.js$/, + use: 'eslint-loader', + enforce: 'pre' + }] + } }, { - module: { - rules:[{ - test: /\.js$/, - use: 'my-post-loader', - enforce: 'post' - }] - } + module: { + rules:[{ + test: /\.js$/, + use: 'my-post-loader', + enforce: 'post' + }] + } }, { - module: { - rules: [{ - test: /\.js$/, - use: 'babel-loader' - }, { - test: /\.js$/, - use: 'eslint-loader', - enforce: 'pre' - }] - } + module: { + rules: [{ + test: /\.js$/, + use: 'babel-loader' + }, { + test: /\.js$/, + use: 'eslint-loader', + enforce: 'pre' + }] + } }, { - module: { - rules: [{ - test: /\.js$/, - use: 'babel-loader' - }, { - test: /\.js$/, - use: 'my-post-loader', - enforce: 'post' - }] - } + module: { + rules: [{ + test: /\.js$/, + use: 'babel-loader' + }, { + test: /\.js$/, + use: 'my-post-loader', + enforce: 'post' + }] + } }]; diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js index f8afdce4e69..c2918a5fb3c 100644 --- a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js +++ b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js @@ -1,22 +1,38 @@ export default [{ - module: { - rules: [{ - test: /\.yml/, - use: ['json-loader', 'another-loader', 'yml-loader'] - }] - } + module: { + rules: [{ + test: /\.yml/, + use: ['json-loader', 'another-loader', 'yml-loader'] + }] + } }, { - module: { - rules: [{ - test: /\.yml/, - use: ['json-loader', 'yml-loader'] - }] - } + module: { + rules: [{ + test: /\.yml/, + use: ['json-loader', 'yml-loader'] + }] + } }, { - module: { - rules: [{ - test: /\.json/, - use: 'json-loader' - }] - } + module: { + rules: [ + { + test: /\.json/, + use: 'json-loader' + } + ] + } +}, { + module: { + rules: [{ + test: /\.yml/, + use: ['json-loader', 'another-loader', 'yml-loader'] + }, { + test: /\.yml/, + use: ['json-loader', 'yml-loader'] + }, { + test: /\.json/, + use: 'json-loader' + }] + } }]; + diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js index ba60ffff58f..8089cd91cfa 100644 --- a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js +++ b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js @@ -1,19 +1,29 @@ export default [{ - module: { - rules: [{ - test: /\.yml/, - use: ['another-loader', 'yml-loader'] - }] - } + module: { + rules: [{ + test: /\.yml/, + use: ['another-loader', 'yml-loader'] + }] + } }, { - module: { - rules: [{ - test: /\.yml/, - use: 'yml-loader' - }] - } + module: { + rules: [{ + test: /\.yml/, + use: 'yml-loader' + }] + } }, { - module: { - rules: [] - } + module: { + rules: [] + } +}, { + module: { + rules: [{ + test: /\.yml/, + use: ['another-loader', 'yml-loader'] + }, { + test: /\.yml/, + use: 'yml-loader' + }] + } }]; diff --git a/lib/transformations/resolve/__testfixtures__/resolve.input.js b/lib/transformations/resolve/__testfixtures__/resolve.input.js index e0e0527a935..2b83fcf26ce 100644 --- a/lib/transformations/resolve/__testfixtures__/resolve.input.js +++ b/lib/transformations/resolve/__testfixtures__/resolve.input.js @@ -1,20 +1,20 @@ import path from 'path'; export default [{ - resolve: { - root: path.resolve('/src') - } + resolve: { + root: path.resolve('/src') + } }, { - resolve: { - root: [path.resolve('/src')] - } + resolve: { + root: [path.resolve('/src')] + } }, { - resolve: { - root: [path.resolve('/src'), 'node_modules'] - } + resolve: { + root: [path.resolve('/src'), 'node_modules'] + } }, { - resolve: { - root: path.resolve('/src'), - modules: ['node_modules'] - } -}]; \ No newline at end of file + resolve: { + root: path.resolve('/src'), + modules: ['node_modules'] + } +}]; diff --git a/lib/transformations/resolve/__testfixtures__/resolve.output.js b/lib/transformations/resolve/__testfixtures__/resolve.output.js index a20165e694d..8335bdcdcb6 100644 --- a/lib/transformations/resolve/__testfixtures__/resolve.output.js +++ b/lib/transformations/resolve/__testfixtures__/resolve.output.js @@ -1,19 +1,19 @@ import path from 'path'; export default [{ - resolve: { - modules: [path.resolve('/src')] - } + resolve: { + modules: [path.resolve('/src')] + } }, { - resolve: { - modules: [path.resolve('/src')] - } + resolve: { + modules: [path.resolve('/src')] + } }, { - resolve: { - modules: [path.resolve('/src'), 'node_modules'] - } + resolve: { + modules: [path.resolve('/src'), 'node_modules'] + } }, { - resolve: { - modules: ['node_modules', path.resolve('/src')] - } -}]; \ No newline at end of file + resolve: { + modules: ['node_modules', path.resolve('/src')] + } +}]; From dcdcd915c3c6407c766dd71f1412eb360fd91e02 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Fri, 27 Jan 2017 09:15:16 +0100 Subject: [PATCH 07/43] Introduce removeJsonLoaderTransform that remove json-loader from loaders sections. --- lib/transformations/index.js | 6 ++- .../removeJsonLoader/removeJsonLoader.js | 49 +++++++++++++++++-- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/lib/transformations/index.js b/lib/transformations/index.js index 5cebd4f274e..f7a03271700 100644 --- a/lib/transformations/index.js +++ b/lib/transformations/index.js @@ -1,7 +1,9 @@ const loaderTransform = require('./loaders/loaders'); const resolveTransform = require('./resolve/resolve'); +const removeJsonLoaderTransform = require('./removeJsonLoader/removeJsonLoader'); module.exports = { loaderTransform: loaderTransform, - resolveTransform: resolveTransform -}; \ No newline at end of file + resolveTransform: resolveTransform, + removeJsonLoaderTransform: removeJsonLoaderTransform +}; diff --git a/lib/transformations/removeJsonLoader/removeJsonLoader.js b/lib/transformations/removeJsonLoader/removeJsonLoader.js index 3d1278bb7eb..4b63fd0518b 100644 --- a/lib/transformations/removeJsonLoader/removeJsonLoader.js +++ b/lib/transformations/removeJsonLoader/removeJsonLoader.js @@ -1,5 +1,48 @@ -const safeTraverse = require('../safeTraverse'); - module.exports = function(j, ast) { - return ast.toSource(); + function getLoadersPropertyPaths(ast) { + return ast.find(j.Property, { key: { name: 'use' } }); + } + + function removeLoaderByName(path, name) { + const loadersNode = path.value.value; + switch (loadersNode.type) { + case j.ArrayExpression.name: { + let loaders = loadersNode.elements.map(p => p.value); + const loaderIndex = 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 is only one element left, convert to string + if (loaders.length === 1) { + j(path.get('value')).replaceWith(j.literal(loaders[0])); + } + 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(ast) { + getLoadersPropertyPaths(ast) + .forEach(path => removeLoaderByName(path, 'json-loader')); + } + + const transforms = [ + removeLoaders + ]; + + transforms.forEach(t => t(ast)); + + return ast.toSource({ quote: 'single' }); }; From 02c1425924c6878dcd238933dfca0026a4e51f55 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Fri, 27 Jan 2017 12:46:48 +0100 Subject: [PATCH 08/43] style: Re-format code of resolve transformation --- lib/transformations/resolve/resolve.js | 32 ++++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/lib/transformations/resolve/resolve.js b/lib/transformations/resolve/resolve.js index 77329ded59e..e7b5ba36581 100644 --- a/lib/transformations/resolve/resolve.js +++ b/lib/transformations/resolve/resolve.js @@ -1,29 +1,32 @@ module.exports = function transformer(j, ast) { const getRootVal = p => { - return p.node.value.properties.filter(prop => prop.key.name ==='root')[0]; + return p.node.value.properties.filter(prop => prop.key.name === 'root')[0]; }; - + const getRootIndex = p => { - return p.node.value.properties.reduce((rootIndex, prop, index) => prop.key.name === 'root' ? index: rootIndex, -1); + return p.node.value.properties + .reduce((rootIndex, prop, index) => { + return prop.key.name === 'root' ? index : rootIndex; + }, -1); }; - + const isModulePresent = p => { - const modules = p.node.value.properties.filter(prop => prop.key.name ==='modules'); + const modules = p.node.value.properties.filter(prop => prop.key.name === 'modules'); return modules.length > 0 && modules[0]; }; - + const createModuleArray = p => { const rootVal = getRootVal(p); let modulesVal = null; - if(rootVal.value.type === 'ArrayExpression') { + if (rootVal.value.type === 'ArrayExpression') { modulesVal = rootVal.value.elements; } else { modulesVal = [rootVal.value]; } let module = isModulePresent(p); - if(!module) { + if (!module) { module = j.property('init', j.identifier('modules'), j.arrayExpression(modulesVal)); p.node.value.properties = p.node.value.properties.concat([module]); } else { @@ -35,8 +38,13 @@ module.exports = function transformer(j, ast) { }; return ast - .find(j.Property) - .filter(p => p.node.key.name === 'resolve' && p.node.value.properties.filter(prop => prop.key.name ==='root').length === 1) - .forEach(createModuleArray) - .toSource(); + .find(j.Property) + .filter(p => { + return p.node.key.name === 'resolve' + && p.node.value.properties + .filter(prop => prop.key.name === 'root') + .length === 1; + }) + .forEach(createModuleArray) + .toSource(); }; From eaab59a30865d248b69917b42cb0197018bfe08c Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Fri, 27 Jan 2017 17:25:11 +0100 Subject: [PATCH 09/43] Introduce uglifyJsPluginTransform --- lib/transformations/index.js | 4 ++- .../__testfixtures__/.editorconfig | 3 +++ .../__testfixtures__/uglifyJsPlugin.input.js | 21 +++++++++++++++ .../__testfixtures__/uglifyJsPlugin.output.js | 26 +++++++++++++++++++ .../__tests__/uglifyJsPlugin.test.js | 3 +++ .../uglifyJsPlugin/uglifyJsPlugin.js | 26 +++++++++++++++++++ 6 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 lib/transformations/uglifyJsPlugin/__testfixtures__/.editorconfig create mode 100644 lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.input.js create mode 100644 lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.output.js create mode 100644 lib/transformations/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.js create mode 100644 lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js diff --git a/lib/transformations/index.js b/lib/transformations/index.js index f7a03271700..258fb223978 100644 --- a/lib/transformations/index.js +++ b/lib/transformations/index.js @@ -1,9 +1,11 @@ const loaderTransform = require('./loaders/loaders'); const resolveTransform = require('./resolve/resolve'); const removeJsonLoaderTransform = require('./removeJsonLoader/removeJsonLoader'); +const uglifyJsPluginTransform = require('./uglifyJsPluginTransform/uglifyJsPluginTransform'); module.exports = { loaderTransform: loaderTransform, resolveTransform: resolveTransform, - removeJsonLoaderTransform: removeJsonLoaderTransform + removeJsonLoaderTransform: removeJsonLoaderTransform, + uglifyJsPluginTransform: uglifyJsPluginTransform }; diff --git a/lib/transformations/uglifyJsPlugin/__testfixtures__/.editorconfig b/lib/transformations/uglifyJsPlugin/__testfixtures__/.editorconfig new file mode 100644 index 00000000000..adbdb1ba476 --- /dev/null +++ b/lib/transformations/uglifyJsPlugin/__testfixtures__/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4 diff --git a/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.input.js b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.input.js new file mode 100644 index 00000000000..da8cf793523 --- /dev/null +++ b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.input.js @@ -0,0 +1,21 @@ +module.exports = { + plugins: [ + new webpack.optimize.UglifyJsPlugin() + ] +} + +module.exports = { + devtool: "source-map", + plugins: [ + new webpack.optimize.UglifyJsPlugin({}) + ] +} + +module.exports = { + devtool: "cheap-source-map", + plugins: [ + new webpack.optimize.UglifyJsPlugin({ + compress: {} + }) + ] +} diff --git a/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.output.js b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.output.js new file mode 100644 index 00000000000..8ebe6323e52 --- /dev/null +++ b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.output.js @@ -0,0 +1,26 @@ +module.exports = { + plugins: [ + new webpack.optimize.UglifyJsPlugin({ + sourceMap: true + }) + ] +} + +module.exports = { + devtool: "source-map", + plugins: [ + new webpack.optimize.UglifyJsPlugin({ + sourceMap: true + }) + ] +} + +module.exports = { + devtool: "cheap-source-map", + plugins: [ + new webpack.optimize.UglifyJsPlugin({ + compress: {}, + sourceMap: true + }) + ] +} diff --git a/lib/transformations/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.js b/lib/transformations/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.js new file mode 100644 index 00000000000..df9704e291f --- /dev/null +++ b/lib/transformations/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.js @@ -0,0 +1,3 @@ +import {defineTest} from '../../defineTest'; + +defineTest(__dirname, 'uglifyJsPlugin'); diff --git a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js new file mode 100644 index 00000000000..3a4f0ba0134 --- /dev/null +++ b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js @@ -0,0 +1,26 @@ +module.exports = function(j, ast) { + + function createSourceMapsProperty() { + return j.property('init', j.identifier('sourceMap'), j.identifier('true')); + } + + return ast + .find(j.NewExpression) + .filter(path => path.get('callee').value.property.name === 'UglifyJsPlugin') + .forEach(path => { + const args = path.value.arguments; + + if (args.length) { + // Plugin is called with object as arguments + j(path) + .find(j.ObjectExpression) + .get('properties') + .value + .push(createSourceMapsProperty()); + } else { + // Plugin is called without arguments + args.push(j.objectExpression([createSourceMapsProperty()])); + } + }) + .toSource({ quote: 'single' }); +}; From c15acac4bd4b7b6e9c8036209810ab3498c2f065 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Fri, 27 Jan 2017 17:25:46 +0100 Subject: [PATCH 10/43] Add .editorconfig to fixtures directories --- lib/transformations/loaders/__testfixtures__/.editorconfig | 3 +++ .../removeJsonLoader/__testfixtures__/.editorconfig | 3 +++ lib/transformations/resolve/__testfixtures__/.editorconfig | 3 +++ 3 files changed, 9 insertions(+) create mode 100644 lib/transformations/loaders/__testfixtures__/.editorconfig create mode 100644 lib/transformations/removeJsonLoader/__testfixtures__/.editorconfig create mode 100644 lib/transformations/resolve/__testfixtures__/.editorconfig diff --git a/lib/transformations/loaders/__testfixtures__/.editorconfig b/lib/transformations/loaders/__testfixtures__/.editorconfig new file mode 100644 index 00000000000..adbdb1ba476 --- /dev/null +++ b/lib/transformations/loaders/__testfixtures__/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4 diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/.editorconfig b/lib/transformations/removeJsonLoader/__testfixtures__/.editorconfig new file mode 100644 index 00000000000..adbdb1ba476 --- /dev/null +++ b/lib/transformations/removeJsonLoader/__testfixtures__/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4 diff --git a/lib/transformations/resolve/__testfixtures__/.editorconfig b/lib/transformations/resolve/__testfixtures__/.editorconfig new file mode 100644 index 00000000000..adbdb1ba476 --- /dev/null +++ b/lib/transformations/resolve/__testfixtures__/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4 From 4fa696d2bfdb7097834b06d507b9901bef2d0c8e Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Fri, 27 Jan 2017 17:40:27 +0100 Subject: [PATCH 11/43] Add OccurrenceOrderPlugin transformation --- .../__testfixtures__/.editorconfig | 3 +++ .../__testfixtures__/occurenceOrderPlugin.input.js | 12 ++++++++++++ .../__testfixtures__/occurenceOrderPlugin.output.js | 7 +++++++ .../__tests__/occurenceOrderPlugin.js | 3 +++ .../occurenceOrderPlugin/occurenceOrderPlugin.js | 9 +++++++++ 5 files changed, 34 insertions(+) create mode 100644 lib/transformations/occurenceOrderPlugin/__testfixtures__/.editorconfig create mode 100644 lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.input.js create mode 100644 lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.output.js create mode 100644 lib/transformations/occurenceOrderPlugin/__tests__/occurenceOrderPlugin.js create mode 100644 lib/transformations/occurenceOrderPlugin/occurenceOrderPlugin.js diff --git a/lib/transformations/occurenceOrderPlugin/__testfixtures__/.editorconfig b/lib/transformations/occurenceOrderPlugin/__testfixtures__/.editorconfig new file mode 100644 index 00000000000..adbdb1ba476 --- /dev/null +++ b/lib/transformations/occurenceOrderPlugin/__testfixtures__/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4 diff --git a/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.input.js b/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.input.js new file mode 100644 index 00000000000..81cc3dfbda0 --- /dev/null +++ b/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.input.js @@ -0,0 +1,12 @@ +module.exports = { + plugins: [ + new webpack.optimize.OccurrenceOrderPlugin(), + ] +} + +module.exports = { + plugins: [ + new webpack.optimize.OccurrenceOrderPlugin(), + new webpack.optimize.UglifyJsPlugin() + ] +} diff --git a/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.output.js b/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.output.js new file mode 100644 index 00000000000..05f06a188a0 --- /dev/null +++ b/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.output.js @@ -0,0 +1,7 @@ +module.exports = { + plugins: [] +} + +module.exports = { + plugins: [new webpack.optimize.UglifyJsPlugin()] +} diff --git a/lib/transformations/occurenceOrderPlugin/__tests__/occurenceOrderPlugin.js b/lib/transformations/occurenceOrderPlugin/__tests__/occurenceOrderPlugin.js new file mode 100644 index 00000000000..2305c3254fe --- /dev/null +++ b/lib/transformations/occurenceOrderPlugin/__tests__/occurenceOrderPlugin.js @@ -0,0 +1,3 @@ +import {defineTest} from '../../defineTest'; + +defineTest(__dirname, 'occurenceOrderPlugin'); diff --git a/lib/transformations/occurenceOrderPlugin/occurenceOrderPlugin.js b/lib/transformations/occurenceOrderPlugin/occurenceOrderPlugin.js new file mode 100644 index 00000000000..0248088a701 --- /dev/null +++ b/lib/transformations/occurenceOrderPlugin/occurenceOrderPlugin.js @@ -0,0 +1,9 @@ +module.exports = function(j, ast) { + return ast + .find(j.NewExpression) + .filter(path => path.get('callee').value.property.name === 'OccurrenceOrderPlugin') + .forEach(path => { + j(path).remove(); + }) + .toSource({ quote: 'single' }); +}; From 1cbd96a9a0858a7f324b51b9d4da93d048d5bfa0 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 1 Feb 2017 14:32:04 +0100 Subject: [PATCH 12/43] fixup! Introduce uglifyJsPluginTransform --- lib/transformations/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/transformations/index.js b/lib/transformations/index.js index 258fb223978..5f26ee7477c 100644 --- a/lib/transformations/index.js +++ b/lib/transformations/index.js @@ -1,7 +1,7 @@ const loaderTransform = require('./loaders/loaders'); const resolveTransform = require('./resolve/resolve'); const removeJsonLoaderTransform = require('./removeJsonLoader/removeJsonLoader'); -const uglifyJsPluginTransform = require('./uglifyJsPluginTransform/uglifyJsPluginTransform'); +const uglifyJsPluginTransform = require('./uglifyJsPlugin/uglifyJsPlugin'); module.exports = { loaderTransform: loaderTransform, From 97e547ac945118cec335d0c274d39e16beecade4 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 1 Feb 2017 15:42:18 +0100 Subject: [PATCH 13/43] Made OccurrenceOrderPlugin in to a more generic removeDeprecatedPlugins transform --- lib/transformations/index.js | 4 ++- .../occurenceOrderPlugin.input.js | 12 ------- .../occurenceOrderPlugin.output.js | 7 ---- .../__tests__/occurenceOrderPlugin.js | 3 -- .../occurenceOrderPlugin.js | 9 ----- .../__testfixtures__/.editorconfig | 0 .../removeDeprecatedPlugins.input.js | 22 ++++++++++++ .../removeDeprecatedPlugins.output.js | 10 ++++++ .../__tests__/removeDeprecatedPlugins.js | 3 ++ .../removeDeprecatedPlugins.js | 34 +++++++++++++++++++ 10 files changed, 72 insertions(+), 32 deletions(-) delete mode 100644 lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.input.js delete mode 100644 lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.output.js delete mode 100644 lib/transformations/occurenceOrderPlugin/__tests__/occurenceOrderPlugin.js delete mode 100644 lib/transformations/occurenceOrderPlugin/occurenceOrderPlugin.js rename lib/transformations/{occurenceOrderPlugin => removeDeprecatedPlugins}/__testfixtures__/.editorconfig (100%) create mode 100644 lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.input.js create mode 100644 lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.output.js create mode 100644 lib/transformations/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.js create mode 100644 lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js diff --git a/lib/transformations/index.js b/lib/transformations/index.js index 5f26ee7477c..976eeea14b0 100644 --- a/lib/transformations/index.js +++ b/lib/transformations/index.js @@ -2,10 +2,12 @@ const loaderTransform = require('./loaders/loaders'); const resolveTransform = require('./resolve/resolve'); const removeJsonLoaderTransform = require('./removeJsonLoader/removeJsonLoader'); const uglifyJsPluginTransform = require('./uglifyJsPlugin/uglifyJsPlugin'); +const removeDeprecatedPluginsTransform = require('./removeDeprecatedPlugins/removeDeprecatedPlugins'); module.exports = { loaderTransform: loaderTransform, resolveTransform: resolveTransform, removeJsonLoaderTransform: removeJsonLoaderTransform, - uglifyJsPluginTransform: uglifyJsPluginTransform + uglifyJsPluginTransform: uglifyJsPluginTransform, + removeDeprecatedPluginsTransform: removeDeprecatedPluginsTransform }; diff --git a/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.input.js b/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.input.js deleted file mode 100644 index 81cc3dfbda0..00000000000 --- a/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.input.js +++ /dev/null @@ -1,12 +0,0 @@ -module.exports = { - plugins: [ - new webpack.optimize.OccurrenceOrderPlugin(), - ] -} - -module.exports = { - plugins: [ - new webpack.optimize.OccurrenceOrderPlugin(), - new webpack.optimize.UglifyJsPlugin() - ] -} diff --git a/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.output.js b/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.output.js deleted file mode 100644 index 05f06a188a0..00000000000 --- a/lib/transformations/occurenceOrderPlugin/__testfixtures__/occurenceOrderPlugin.output.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - plugins: [] -} - -module.exports = { - plugins: [new webpack.optimize.UglifyJsPlugin()] -} diff --git a/lib/transformations/occurenceOrderPlugin/__tests__/occurenceOrderPlugin.js b/lib/transformations/occurenceOrderPlugin/__tests__/occurenceOrderPlugin.js deleted file mode 100644 index 2305c3254fe..00000000000 --- a/lib/transformations/occurenceOrderPlugin/__tests__/occurenceOrderPlugin.js +++ /dev/null @@ -1,3 +0,0 @@ -import {defineTest} from '../../defineTest'; - -defineTest(__dirname, 'occurenceOrderPlugin'); diff --git a/lib/transformations/occurenceOrderPlugin/occurenceOrderPlugin.js b/lib/transformations/occurenceOrderPlugin/occurenceOrderPlugin.js deleted file mode 100644 index 0248088a701..00000000000 --- a/lib/transformations/occurenceOrderPlugin/occurenceOrderPlugin.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = function(j, ast) { - return ast - .find(j.NewExpression) - .filter(path => path.get('callee').value.property.name === 'OccurrenceOrderPlugin') - .forEach(path => { - j(path).remove(); - }) - .toSource({ quote: 'single' }); -}; diff --git a/lib/transformations/occurenceOrderPlugin/__testfixtures__/.editorconfig b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/.editorconfig similarity index 100% rename from lib/transformations/occurenceOrderPlugin/__testfixtures__/.editorconfig rename to lib/transformations/removeDeprecatedPlugins/__testfixtures__/.editorconfig diff --git a/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.input.js b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.input.js new file mode 100644 index 00000000000..e130c0b800e --- /dev/null +++ b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.input.js @@ -0,0 +1,22 @@ +// Works for OccurrenceOrderPlugin +module.exports = { + plugins: [ + new webpack.optimize.OccurrenceOrderPlugin(), + ] +} + +// Works for DedupePlugin +module.exports = { + plugins: [ + new webpack.optimize.DedupePlugin(), + ] +} + +// Doesn't remove unmatched plugins +module.exports = { + plugins: [ + new webpack.optimize.OccurrenceOrderPlugin(), + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.DedupePlugin() + ] +} diff --git a/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.output.js b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.output.js new file mode 100644 index 00000000000..93610a91119 --- /dev/null +++ b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.output.js @@ -0,0 +1,10 @@ +// Works for OccurrenceOrderPlugin +module.exports = {} + +// Works for DedupePlugin +module.exports = {} + +// Doesn't remove unmatched plugins +module.exports = { + plugins: [new webpack.optimize.UglifyJsPlugin()] +} diff --git a/lib/transformations/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.js b/lib/transformations/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.js new file mode 100644 index 00000000000..45f69ac3bb4 --- /dev/null +++ b/lib/transformations/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.js @@ -0,0 +1,3 @@ +import {defineTest} from '../../defineTest'; + +defineTest(__dirname, 'removeDeprecatedPlugins'); diff --git a/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js new file mode 100644 index 00000000000..7701e2beb6f --- /dev/null +++ b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js @@ -0,0 +1,34 @@ +module.exports = function(j, ast) { + // List of deprecated plugins to remove + // each item refers to webpack.optimize.[NAME] construct + const deprecatedPlugingsList = [ + 'webpack.optimize.OccurrenceOrderPlugin', + 'webpack.optimize.DedupePlugin' + ]; + + // Convert nested MemberExpressions to strings like webpack.optimize.DedupePlugin + function memberToString(path) { + if (path && path.object) { + return [memberToString(path.object), path.property.name].join('.'); + } + return path.name; + } + + return ast + .find(j.NewExpression) + .filter(path => { + return deprecatedPlugingsList.some( + plugin => memberToString(path.get('callee').value) === plugin + ); + }) + .forEach(path => { + // Check how many plugins are defined and + // if there is only last plugin left remove `plugins: []` completely + if (path.parent.value.elements.length === 1) { + j(path.parent.parent).remove(); + } else { + j(path).remove(); + } + }) + .toSource({ quote: 'single' }); +}; From 6242628e72cc3ad21a77dedbb28c483716368c83 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 1 Feb 2017 15:55:08 +0100 Subject: [PATCH 14/43] Renamed safeTraverse to utils to allow multiple jscodeshift-helpers to be defined in it --- lib/transformations/loaders/loaders.js | 2 +- lib/transformations/{safeTraverse.js => utils.js} | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) rename lib/transformations/{safeTraverse.js => utils.js} (66%) diff --git a/lib/transformations/loaders/loaders.js b/lib/transformations/loaders/loaders.js index 356a148bfbb..43aaa750445 100644 --- a/lib/transformations/loaders/loaders.js +++ b/lib/transformations/loaders/loaders.js @@ -1,4 +1,4 @@ -const safeTraverse = require('../safeTraverse'); +const safeTraverse = require('../utils').safeTraverse; module.exports = function(j, ast) { diff --git a/lib/transformations/safeTraverse.js b/lib/transformations/utils.js similarity index 66% rename from lib/transformations/safeTraverse.js rename to lib/transformations/utils.js index 63dae968a27..72dde50269f 100644 --- a/lib/transformations/safeTraverse.js +++ b/lib/transformations/utils.js @@ -1,4 +1,4 @@ -module.exports = function safeTraverse (obj, paths) { +function safeTraverse(obj, paths) { let val = obj; let idx = 0; @@ -10,4 +10,8 @@ module.exports = function safeTraverse (obj, paths) { idx++; } return val; +} + +module.exports = { + safeTraverse, }; From 0f24d8d838b008172e60608847d81027239c34fa Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 1 Feb 2017 16:03:59 +0100 Subject: [PATCH 15/43] Share memberExpressionToPathString when working with plugins --- .../removeDeprecatedPlugins.js | 12 +++--------- lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js | 4 +++- lib/transformations/utils.js | 9 +++++++++ 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js index 7701e2beb6f..8f902e9504d 100644 --- a/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js +++ b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js @@ -1,3 +1,5 @@ +const memberExpressionToPathString = require('../utils').memberExpressionToPathString; + module.exports = function(j, ast) { // List of deprecated plugins to remove // each item refers to webpack.optimize.[NAME] construct @@ -6,19 +8,11 @@ module.exports = function(j, ast) { 'webpack.optimize.DedupePlugin' ]; - // Convert nested MemberExpressions to strings like webpack.optimize.DedupePlugin - function memberToString(path) { - if (path && path.object) { - return [memberToString(path.object), path.property.name].join('.'); - } - return path.name; - } - return ast .find(j.NewExpression) .filter(path => { return deprecatedPlugingsList.some( - plugin => memberToString(path.get('callee').value) === plugin + plugin => memberExpressionToPathString(path.get('callee').value) === plugin ); }) .forEach(path => { diff --git a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js index 3a4f0ba0134..5a8def17b6f 100644 --- a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js +++ b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js @@ -1,3 +1,5 @@ +const pluginPath = require('../utils').memberExpressionToPathString; + module.exports = function(j, ast) { function createSourceMapsProperty() { @@ -6,7 +8,7 @@ module.exports = function(j, ast) { return ast .find(j.NewExpression) - .filter(path => path.get('callee').value.property.name === 'UglifyJsPlugin') + .filter(path => pluginPath(path.get('callee').value) === 'webpack.optimize.UglifyJsPlugin') .forEach(path => { const args = path.value.arguments; diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index 72dde50269f..b742f953279 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -12,6 +12,15 @@ function safeTraverse(obj, paths) { return val; } +// Convert nested MemberExpressions to strings like webpack.optimize.DedupePlugin +function memberExpressionToPathString(path) { + if (path && path.object) { + return [memberExpressionToPathString(path.object), path.property.name].join('.'); + } + return path.name; +} + module.exports = { safeTraverse, + memberExpressionToPathString }; From c731d18ee3a0b8d5b8f5ef58e5d6ca5c1c322503 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 1 Feb 2017 16:14:07 +0100 Subject: [PATCH 16/43] Introduce findPluginsByName function --- .../removeDeprecatedPlugins.js | 10 ++-------- .../uglifyJsPlugin/uglifyJsPlugin.js | 6 ++---- lib/transformations/utils.js | 15 ++++++++++++++- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js index 8f902e9504d..6c6fa5eccad 100644 --- a/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js +++ b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js @@ -1,4 +1,4 @@ -const memberExpressionToPathString = require('../utils').memberExpressionToPathString; +const findPluginsByName = require('../utils').findPluginsByName; module.exports = function(j, ast) { // List of deprecated plugins to remove @@ -8,13 +8,7 @@ module.exports = function(j, ast) { 'webpack.optimize.DedupePlugin' ]; - return ast - .find(j.NewExpression) - .filter(path => { - return deprecatedPlugingsList.some( - plugin => memberExpressionToPathString(path.get('callee').value) === plugin - ); - }) + return findPluginsByName(j, ast, deprecatedPlugingsList) .forEach(path => { // Check how many plugins are defined and // if there is only last plugin left remove `plugins: []` completely diff --git a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js index 5a8def17b6f..a7f9eff64fc 100644 --- a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js +++ b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js @@ -1,4 +1,4 @@ -const pluginPath = require('../utils').memberExpressionToPathString; +const findPluginsByName = require('../utils').findPluginsByName; module.exports = function(j, ast) { @@ -6,9 +6,7 @@ module.exports = function(j, ast) { return j.property('init', j.identifier('sourceMap'), j.identifier('true')); } - return ast - .find(j.NewExpression) - .filter(path => pluginPath(path.get('callee').value) === 'webpack.optimize.UglifyJsPlugin') + return findPluginsByName(j, ast, ['webpack.optimize.UglifyJsPlugin']) .forEach(path => { const args = path.value.arguments; diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index b742f953279..29cb055e85d 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -20,7 +20,20 @@ function memberExpressionToPathString(path) { return path.name; } +// Return paths that match `new name.space.PluginName()` +// for a given array of plugin names +function findPluginsByName(j, node, pluginNamesArray) { + return node + .find(j.NewExpression) + .filter(path => { + return pluginNamesArray.some( + plugin => memberExpressionToPathString(path.get('callee').value) === plugin + ); + }); +} + module.exports = { safeTraverse, - memberExpressionToPathString + memberExpressionToPathString, + findPluginsByName }; From a8d8c313288240ee8d6567c3b3a06b9ab49a0826 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 1 Feb 2017 16:52:35 +0100 Subject: [PATCH 17/43] WIP on LoaderOptionsPlugin --- .../__testfixtures__/.editorconfig | 3 ++ .../loaderOptionsPlugin.input.js | 21 ++++++++ .../loaderOptionsPlugin.output.js | 27 ++++++++++ .../__tests__/loaderOptionsPlugin.test.js | 3 ++ .../loaderOptionsPlugin.js | 53 +++++++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 lib/transformations/loaderOptionsPlugin/__testfixtures__/.editorconfig create mode 100644 lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js create mode 100644 lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js create mode 100644 lib/transformations/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.js create mode 100644 lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js diff --git a/lib/transformations/loaderOptionsPlugin/__testfixtures__/.editorconfig b/lib/transformations/loaderOptionsPlugin/__testfixtures__/.editorconfig new file mode 100644 index 00000000000..adbdb1ba476 --- /dev/null +++ b/lib/transformations/loaderOptionsPlugin/__testfixtures__/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4 diff --git a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js new file mode 100644 index 00000000000..c9361d7518a --- /dev/null +++ b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js @@ -0,0 +1,21 @@ +module.exports = { + plugins: [ + new webpack.optimize.UglifyJsPlugin() + ] +} + +module.exports = { + plugins: [ + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.LoaderOptionsPlugin() + ] +} + +module.exports = { + plugins: [ + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.LoaderOptionsPlugin({ + foo: 'bar' + }) + ] +} diff --git a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js new file mode 100644 index 00000000000..187565ac6e1 --- /dev/null +++ b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js @@ -0,0 +1,27 @@ +module.exports = { + plugins: [ + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.LoaderOptionsPlugin({ + minimize: true + }) + ] +} + +module.exports = { + plugins: [ + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.LoaderOptionsPlugin({ + minimize: true + }) + ] +} + +module.exports = { + plugins: [ + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.LoaderOptionsPlugin({ + foo: 'bar', + minimize: true + }) + ] +} diff --git a/lib/transformations/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.js b/lib/transformations/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.js new file mode 100644 index 00000000000..58c37df95d3 --- /dev/null +++ b/lib/transformations/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.js @@ -0,0 +1,3 @@ +import {defineTest} from '../../defineTest'; + +defineTest(__dirname, 'loaderOptionsPlugin'); diff --git a/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js new file mode 100644 index 00000000000..5133ac82119 --- /dev/null +++ b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js @@ -0,0 +1,53 @@ +const findPluginsByName = require('../utils').findPluginsByName; + +module.exports = function(j, ast) { + + function createProperty(key, value) { + return j.property( + 'init', + j.identifier(key), + typeof value === 'string' ? j.identifier(value) : j.literal(value) + ); + } + + return findPluginsByName(j, ast, ['webpack.optimize.UglifyJsPlugin']) + .forEach(path => { + const pluginsPath = path.parent; + const loaderPluginPaths = findPluginsByName(j, + j(pluginsPath), + ['webpack.optimize.LoaderOptionsPlugin']); + + // If LoaderOptionsPlugin declaration exist + if (loaderPluginPaths.size()) { + loaderPluginPaths.forEach(path => { + const args = path.value.arguments; + if (args.length) { + // Plugin is called with object as arguments + j(path) + .find(j.ObjectExpression) + .get('properties') + .value + .push(createProperty('minimize', true)); + } else { + // Plugin is called without arguments + args.push( + j.objectExpression([createProperty('minimize', true)]) + ); + } + }); + } else { + const loaderPluginInstance = j.newExpression( + j.memberExpression( + j.memberExpression( + j.identifier('webpack'), + j.identifier('optimize') + ), j.identifier('LoaderOptionsPlugin') + ), [ + j.objectExpression([createProperty('minimize', true)]) + ] + ); + pluginsPath.value.elements.push(loaderPluginInstance); + } + }) + .toSource({ quote: 'single' }); +}; From d6a7364df43a99160d05720f8e40292c8a13a951 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Fri, 3 Feb 2017 19:30:16 +0100 Subject: [PATCH 18/43] WIP on LoaderOptionsPlugin --- .../loaderOptionsPlugin.input.js | 4 + .../loaderOptionsPlugin.output.js | 9 ++ .../loaderOptionsPlugin.js | 61 ++++---------- lib/transformations/utils.js | 84 ++++++++++++++++++- 4 files changed, 113 insertions(+), 45 deletions(-) diff --git a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js index c9361d7518a..c93bbbd0de8 100644 --- a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js +++ b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js @@ -11,6 +11,10 @@ module.exports = { ] } +module.exports = { + debug: true +} + module.exports = { plugins: [ new webpack.optimize.UglifyJsPlugin(), diff --git a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js index 187565ac6e1..2812350669a 100644 --- a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js +++ b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js @@ -16,6 +16,15 @@ module.exports = { ] } +module.exports = { + debug: true, + plugins: [ + new webpack.optimize.LoaderOptionsPlugin({ + debug: true + }) + ] +} + module.exports = { plugins: [ new webpack.optimize.UglifyJsPlugin(), diff --git a/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js index 5133ac82119..e92561b1b66 100644 --- a/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js +++ b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js @@ -1,53 +1,28 @@ const findPluginsByName = require('../utils').findPluginsByName; +const createOrUpdatePluginByName = require('../utils').createOrUpdatePluginByName; module.exports = function(j, ast) { + const loaderOptions = {}; - function createProperty(key, value) { - return j.property( - 'init', - j.identifier(key), - typeof value === 'string' ? j.identifier(value) : j.literal(value) - ); + // If there is debug: true, set debug: true in the plugin + // TODO: remove global debug setting + // TODO: I can't figure out how to find the topmost `debug: true`. help! + if (ast.find(j.Identifier, { name: 'debug' }).size()) { + loaderOptions.debug = true; } - return findPluginsByName(j, ast, ['webpack.optimize.UglifyJsPlugin']) - .forEach(path => { - const pluginsPath = path.parent; - const loaderPluginPaths = findPluginsByName(j, - j(pluginsPath), - ['webpack.optimize.LoaderOptionsPlugin']); + // If there is UglifyJsPlugin, set minimize: true + if (findPluginsByName(j, ast, ['webpack.optimize.UglifyJsPlugin']).size()) { + loaderOptions.minimize = true; + } - // If LoaderOptionsPlugin declaration exist - if (loaderPluginPaths.size()) { - loaderPluginPaths.forEach(path => { - const args = path.value.arguments; - if (args.length) { - // Plugin is called with object as arguments - j(path) - .find(j.ObjectExpression) - .get('properties') - .value - .push(createProperty('minimize', true)); - } else { - // Plugin is called without arguments - args.push( - j.objectExpression([createProperty('minimize', true)]) - ); - } - }); - } else { - const loaderPluginInstance = j.newExpression( - j.memberExpression( - j.memberExpression( - j.identifier('webpack'), - j.identifier('optimize') - ), j.identifier('LoaderOptionsPlugin') - ), [ - j.objectExpression([createProperty('minimize', true)]) - ] - ); - pluginsPath.value.elements.push(loaderPluginInstance); - } + return ast + .find(j.ArrayExpression) + .filter(path => { + return path.parent.value.key.name === 'plugins'; + }) + .forEach(path => { + createOrUpdatePluginByName(j, path, 'webpack.optimize.LoaderOptionsPlugin', loaderOptions); }) .toSource({ quote: 'single' }); }; diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index 29cb055e85d..482f0bd793b 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -20,6 +20,22 @@ function memberExpressionToPathString(path) { return path.name; } +// Convert Array like ['webpack', 'optimize', 'DedupePlugin'] to nested MemberExpressions +function pathsToMemberExpression(j, paths) { + if (!paths.length) { + return null; + } else if (paths.length === 1) { + return j.identifier(paths[0]); + } else { + const first = paths.slice(0, 1); + const rest = paths.slice(1); + return j.memberExpression( + pathsToMemberExpression(j, rest), + pathsToMemberExpression(j, first) + ); + } +} + // Return paths that match `new name.space.PluginName()` // for a given array of plugin names function findPluginsByName(j, node, pluginNamesArray) { @@ -32,8 +48,72 @@ function findPluginsByName(j, node, pluginNamesArray) { }); } +/* + * @function createProperty + * + * Creates an Object's property with a given value + * + * @param j — jscodeshift API + * @param { string } key - Property key + * @param { string | number | boolean } value - Property value + * @returns Node + * */ +function createProperty(j, key, value) { + return j.property( + 'init', + j.identifier(key), + typeof value === 'string' ? j.identifier(value) : j.literal(value) + ); +} + +/* +* @function createOrUpdatePluginByName +* +* Findes or creates a node for a given plugin name string with options object +* If plugin decalaration already exist, options are merged. +* +* @param j — jscodeshift API +* @param { NodePath } rooNodePath - `plugins: []` NodePath where plugin should be added. See https://github.com/facebook/jscodeshift/wiki/jscodeshift-Documentation#nodepaths +* @param { string } pluginName - ex. `webpack.optimize.LoaderOptionsPlugin` +* @param { Object } options - plugin options +* @returns void +* */ +function createOrUpdatePluginByName(j, rootNodePath, pluginName, options) { + const pluginInstancePath = findPluginsByName(j, j(rootNodePath), [pluginName]); + const optionsProps = Object.keys(options).map(key => { + return createProperty(j, key, options[key]); + }); + + // If plugin declaration already exist + if (pluginInstancePath.size()) { + pluginInstancePath.forEach(path => { + const args = path.value.arguments; + if (args.length) { + // Plugin is called with object as arguments + j(path) + .find(j.ObjectExpression) + .get('properties') + .value + .concat(optionsProps); + } else { + // Plugin is called without arguments + args.push( + j.objectExpression(optionsProps) + ); + } + }); + } else { + const loaderPluginInstance = j.newExpression( + pathsToMemberExpression(j, pluginName.split('.').reverse()), [ + j.objectExpression(optionsProps) + ] + ); + rootNodePath.value.elements.push(loaderPluginInstance); + } +} + module.exports = { safeTraverse, - memberExpressionToPathString, - findPluginsByName + findPluginsByName, + createOrUpdatePluginByName }; From e198fa1ccd22bc3943aede3832b4f13f3bddfdf1 Mon Sep 17 00:00:00 2001 From: Pavithra K Date: Tue, 7 Feb 2017 21:27:24 +0530 Subject: [PATCH 19/43] WIP Extract Plugin --- .../extractTextPlugin.input.js | 17 +++++++++ .../extractTextPlugin.output.js | 20 +++++++++++ .../__tests__/extractTextPlugin.test.js | 3 ++ .../extractTextPlugin/extractTextPlugin.js | 35 +++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js create mode 100644 lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js create mode 100644 lib/transformations/extractTextPlugin/__tests__/extractTextPlugin.test.js create mode 100644 lib/transformations/extractTextPlugin/extractTextPlugin.js diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js new file mode 100644 index 00000000000..590e60bdba9 --- /dev/null +++ b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js @@ -0,0 +1,17 @@ +let ExtractTextPlugin = require('extract-text-webpack-plugin'); + +let extractCSS = new ExtractTextPlugin('stylesheets/[name].css'); +let extractLESS = new ExtractTextPlugin('stylesheets/[name].less'); + +module.export = { + module: { + rules: [{ + test: /\.css$/, + use: ExtractTextPlugin.extract('style-loader', 'css-loader') + } + ] + }, + plugins: [ + new ExtractTextPlugin("styles.css"), + ] +} \ No newline at end of file diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js new file mode 100644 index 00000000000..7316fd38d48 --- /dev/null +++ b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js @@ -0,0 +1,20 @@ +let ExtractTextPlugin = require('extract-text-webpack-plugin'); + +let extractCSS = new ExtractTextPlugin('stylesheets/[name].css'); +let extractLESS = new ExtractTextPlugin('stylesheets/[name].less'); + +module.export = { + module: { + rules: [{ + test: /\.css$/, + use: ExtractTextPlugin.extract({ + fallback: "style-loader", + use: "css-loader" + }) + } + ] + }, + plugins: [ + new ExtractTextPlugin("styles.css"), + ] +} \ No newline at end of file diff --git a/lib/transformations/extractTextPlugin/__tests__/extractTextPlugin.test.js b/lib/transformations/extractTextPlugin/__tests__/extractTextPlugin.test.js new file mode 100644 index 00000000000..ed30265e91e --- /dev/null +++ b/lib/transformations/extractTextPlugin/__tests__/extractTextPlugin.test.js @@ -0,0 +1,3 @@ +import {defineTest} from '../../defineTest'; + +defineTest(__dirname, 'extractTextPlugin'); diff --git a/lib/transformations/extractTextPlugin/extractTextPlugin.js b/lib/transformations/extractTextPlugin/extractTextPlugin.js new file mode 100644 index 00000000000..5186e3b3954 --- /dev/null +++ b/lib/transformations/extractTextPlugin/extractTextPlugin.js @@ -0,0 +1,35 @@ +const safeTraverse = require('../utils').safeTraverse; +const findPluginsByName = require('../utils').findPluginsByName; + +module.exports = function(j, ast) { + const changeArguments = function(p) { + // const args = p.value.arguments; + // if(args.length === 1) { + // return p; + // } else if(args.length === 2) { + // if (args.filter(p => p.type === 'Literal').length == 2){ + // const newArgs = j.objectExpression(args.map((p, index) => [ + // j.property('init', + // j.identifier(index === 0 ? 'fallback': 'use'), + // j.literal(p.value) + // ) + // ])); + // console.log(newArgs); + // } + // } + return p; + }; + const name = getName(j, ast, 'extract-text-webpack-plugin'); + ast.find(j.CallExpression) + .filter(p => p.value.callee.object) + .filter(p => p.value.callee.object.name === name) + .forEach(changeArguments); + + return ast.toSource({ quote: 'single' }); +}; + +const getName = function(j, ast, pkgName){ + return 'ExtractTextPlugin'; +}; + + From 7ffb1e8be06776e43a3b923b2832bb0254455cab Mon Sep 17 00:00:00 2001 From: Pavithra K Date: Sat, 11 Feb 2017 18:50:54 +0530 Subject: [PATCH 20/43] Gets basic case of extract text plugin working --- .../extractTextPlugin.input.js | 11 +++---- .../extractTextPlugin.output.js | 23 +++++++------ .../extractTextPlugin/extractTextPlugin.js | 33 ++++++++++--------- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js index 590e60bdba9..7b8c0bb2845 100644 --- a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js +++ b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js @@ -5,13 +5,12 @@ let extractLESS = new ExtractTextPlugin('stylesheets/[name].less'); module.export = { module: { - rules: [{ - test: /\.css$/, - use: ExtractTextPlugin.extract('style-loader', 'css-loader') - } - ] + rules: [{ + test: /\.css$/, + use: ExtractTextPlugin.extract('style-loader', 'css-loader') + }] }, plugins: [ - new ExtractTextPlugin("styles.css"), + new ExtractTextPlugin("styles.css"), ] } \ No newline at end of file diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js index 7316fd38d48..a61231c8cf8 100644 --- a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js +++ b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js @@ -4,17 +4,16 @@ let extractCSS = new ExtractTextPlugin('stylesheets/[name].css'); let extractLESS = new ExtractTextPlugin('stylesheets/[name].less'); module.export = { - module: { - rules: [{ - test: /\.css$/, - use: ExtractTextPlugin.extract({ - fallback: "style-loader", - use: "css-loader" - }) - } + module: { + rules: [{ + test: /\.css$/, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: 'css-loader' + }) + }] + }, + plugins: [ + new ExtractTextPlugin("styles.css"), ] - }, - plugins: [ - new ExtractTextPlugin("styles.css"), - ] } \ No newline at end of file diff --git a/lib/transformations/extractTextPlugin/extractTextPlugin.js b/lib/transformations/extractTextPlugin/extractTextPlugin.js index 5186e3b3954..5567ed8817d 100644 --- a/lib/transformations/extractTextPlugin/extractTextPlugin.js +++ b/lib/transformations/extractTextPlugin/extractTextPlugin.js @@ -3,29 +3,32 @@ const findPluginsByName = require('../utils').findPluginsByName; module.exports = function(j, ast) { const changeArguments = function(p) { - // const args = p.value.arguments; + const args = p.value.arguments; // if(args.length === 1) { // return p; - // } else if(args.length === 2) { - // if (args.filter(p => p.type === 'Literal').length == 2){ - // const newArgs = j.objectExpression(args.map((p, index) => [ - // j.property('init', - // j.identifier(index === 0 ? 'fallback': 'use'), - // j.literal(p.value) - // ) - // ])); - // console.log(newArgs); - // } - // } + // } else + const literalArgs = args.filter(p => p.type === 'Literal'); + if (literalArgs && literalArgs.length > 1) { + const newArgs = j.objectExpression(literalArgs.map((p, index) => + j.property('init', + j.identifier(index === 0 ? 'fallback': 'use'), + j.literal(p.value) + ) + )); + p.value.arguments = [newArgs]; + } + console.log(p.value.arguments); return p; }; const name = getName(j, ast, 'extract-text-webpack-plugin'); - ast.find(j.CallExpression) + return ast.find(j.CallExpression) .filter(p => p.value.callee.object) .filter(p => p.value.callee.object.name === name) - .forEach(changeArguments); + .forEach(changeArguments) + .toSource({ quote: 'single' }) + //.forEach(p => console.log(p.toSource())); - return ast.toSource({ quote: 'single' }); + //return ast.toSource({ quote: 'single' }); }; const getName = function(j, ast, pkgName){ From 8c2c9ad571096c43cdaa1408a8d8dd98a9531ff1 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Mon, 13 Feb 2017 09:57:54 +0100 Subject: [PATCH 21/43] Fixed ExtractTextPlugin tests by properly formatting both input and output. Added .editorconfig --- .../__testfixtures__/.editorconfig | 3 ++ .../extractTextPlugin.input.js | 12 ++++---- .../extractTextPlugin.output.js | 28 ++++++++++--------- 3 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 lib/transformations/extractTextPlugin/__testfixtures__/.editorconfig diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/.editorconfig b/lib/transformations/extractTextPlugin/__testfixtures__/.editorconfig new file mode 100644 index 00000000000..adbdb1ba476 --- /dev/null +++ b/lib/transformations/extractTextPlugin/__testfixtures__/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4 diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js index 7b8c0bb2845..8e468e89a57 100644 --- a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js +++ b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js @@ -5,12 +5,14 @@ let extractLESS = new ExtractTextPlugin('stylesheets/[name].less'); module.export = { module: { - rules: [{ - test: /\.css$/, - use: ExtractTextPlugin.extract('style-loader', 'css-loader') - }] + rules: [ + { + test: /\.css$/, + use: ExtractTextPlugin.extract('style-loader', 'css-loader') + } + ] }, plugins: [ new ExtractTextPlugin("styles.css"), ] -} \ No newline at end of file +} diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js index a61231c8cf8..61f52a3ed59 100644 --- a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js +++ b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js @@ -4,16 +4,18 @@ let extractCSS = new ExtractTextPlugin('stylesheets/[name].css'); let extractLESS = new ExtractTextPlugin('stylesheets/[name].less'); module.export = { - module: { - rules: [{ - test: /\.css$/, - use: ExtractTextPlugin.extract({ - fallback: 'style-loader', - use: 'css-loader' - }) - }] - }, - plugins: [ - new ExtractTextPlugin("styles.css"), - ] -} \ No newline at end of file + module: { + rules: [ + { + test: /\.css$/, + use: ExtractTextPlugin.extract({ + fallback: 'style-loader', + use: 'css-loader' + }) + } + ] + }, + plugins: [ + new ExtractTextPlugin("styles.css"), + ] +} From 0dabfc3b93010e188cf10ec960ff3197335bd66b Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Tue, 14 Feb 2017 15:12:58 +0100 Subject: [PATCH 22/43] Added tests for utils --- .../__snapshots__/utils.test.js.snap | 20 ++++ lib/transformations/utils.js | 101 ++++++++++++------ lib/transformations/utils.test.js | 96 +++++++++++++++++ 3 files changed, 187 insertions(+), 30 deletions(-) create mode 100644 lib/transformations/__snapshots__/utils.test.js.snap create mode 100644 lib/transformations/utils.test.js diff --git a/lib/transformations/__snapshots__/utils.test.js.snap b/lib/transformations/__snapshots__/utils.test.js.snap new file mode 100644 index 00000000000..87d1b012cee --- /dev/null +++ b/lib/transformations/__snapshots__/utils.test.js.snap @@ -0,0 +1,20 @@ +exports[`utils createOrUpdatePluginByName should add an object as an argument 1`] = ` +"[new Plugin({ + foo: true +})]" +`; + +exports[`utils createOrUpdatePluginByName should create a new plugin with arguments 1`] = ` +"{ plugins: [new Plugin({ + foo: bar +})] }" +`; + +exports[`utils createOrUpdatePluginByName should create a new plugin without arguments 1`] = `"{ plugins: [new Plugin()] }"`; + +exports[`utils createOrUpdatePluginByName should merge options objects 1`] = ` +"[new Plugin({ + foo: false, + bar: baz +})]" +`; diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index 482f0bd793b..a3ceb112ca6 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -48,6 +48,21 @@ function findPluginsByName(j, node, pluginNamesArray) { }); } +/* + * @function findPluginsRootNodes + * + * Finds the path to the `plugins: []` node + * + * @param j — jscodeshift API + * @param { Node } node - Node to start search from + * @returns Path + * */ +function findPluginsRootNodes(j, node) { + return node + .find(j.Property, { key: { name: 'plugins' } }) + .map(path => path); +} + /* * @function createProperty * @@ -67,46 +82,71 @@ function createProperty(j, key, value) { } /* -* @function createOrUpdatePluginByName -* -* Findes or creates a node for a given plugin name string with options object -* If plugin decalaration already exist, options are merged. -* -* @param j — jscodeshift API -* @param { NodePath } rooNodePath - `plugins: []` NodePath where plugin should be added. See https://github.com/facebook/jscodeshift/wiki/jscodeshift-Documentation#nodepaths -* @param { string } pluginName - ex. `webpack.optimize.LoaderOptionsPlugin` -* @param { Object } options - plugin options -* @returns void -* */ + * @function createOrUpdatePluginByName + * + * Findes or creates a node for a given plugin name string with options object + * If plugin decalaration already exist, options are merged. + * + * @param j — jscodeshift API + * @param { NodePath } rooNodePath - `plugins: []` NodePath where plugin should be added. See https://github.com/facebook/jscodeshift/wiki/jscodeshift-Documentation#nodepaths + * @param { string } pluginName - ex. `webpack.optimize.LoaderOptionsPlugin` + * @param { Object } options - plugin options + * @returns void + * */ function createOrUpdatePluginByName(j, rootNodePath, pluginName, options) { const pluginInstancePath = findPluginsByName(j, j(rootNodePath), [pluginName]); - const optionsProps = Object.keys(options).map(key => { - return createProperty(j, key, options[key]); - }); + let optionsProps; + if (options) { + optionsProps = Object.keys(options).map(key => { + return createProperty(j, key, options[key]); + }); + } // If plugin declaration already exist if (pluginInstancePath.size()) { pluginInstancePath.forEach(path => { - const args = path.value.arguments; - if (args.length) { - // Plugin is called with object as arguments - j(path) - .find(j.ObjectExpression) - .get('properties') - .value - .concat(optionsProps); - } else { - // Plugin is called without arguments - args.push( - j.objectExpression(optionsProps) - ); + // There are options we want to pass as argument + if (optionsProps) { + const args = path.value.arguments; + if (args.length) { + // Plugin is called with object as arguments + // we will merge those objects + let currentProps = j(path) + .find(j.ObjectExpression) + .get('properties'); + + optionsProps.forEach(opt => { + // Search for same keys in the existing object + const currentOptName = opt.key.name; + j(currentProps) + .find(j.Identifier) + .forEach(path => { + if (path.value.name === currentOptName) { + // Merging values for same key + j(path.parent).replaceWith(opt); + } else { + // Adding new key:values + currentProps.value.push(opt); + } + }); + }); + + } else { + // Plugin is called without arguments + args.push( + j.objectExpression(optionsProps) + ); + } } }); } else { + let argumentsArray = []; + if (optionsProps) { + argumentsArray = [j.objectExpression(optionsProps)]; + } const loaderPluginInstance = j.newExpression( - pathsToMemberExpression(j, pluginName.split('.').reverse()), [ - j.objectExpression(optionsProps) - ] + pathsToMemberExpression(j, pluginName.split('.').reverse()), + argumentsArray ); rootNodePath.value.elements.push(loaderPluginInstance); } @@ -115,5 +155,6 @@ function createOrUpdatePluginByName(j, rootNodePath, pluginName, options) { module.exports = { safeTraverse, findPluginsByName, + findPluginsRootNodes, createOrUpdatePluginByName }; diff --git a/lib/transformations/utils.test.js b/lib/transformations/utils.test.js new file mode 100644 index 00000000000..9cf31921dc2 --- /dev/null +++ b/lib/transformations/utils.test.js @@ -0,0 +1,96 @@ +const j = require('jscodeshift/dist/core'); +const utils = require('./utils'); + +describe('utils', () => { + 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); + }); + + 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); + }); + + 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('findPluginsRootNodes', () => { + it('should find plugins: [] nodes', () => { + const ast = j(` +var a = { plugins: [], foo: { plugins: [] } } +`); + const res = utils.findPluginsRootNodes(j, ast); + expect(res.size()).toEqual(2); + }); + + it('should not find plugins: [] nodes', () => { + const ast = j(` +var a = { plugs: [] } +`); + const res = utils.findPluginsRootNodes(j, ast); + 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 => { + 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 => { + 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 => { + 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 => { + utils.createOrUpdatePluginByName(j, node, 'Plugin', { foo: false, bar: 'baz' }); + }); + expect(ast.toSource()).toMatchSnapshot(); + }); + }); +}); From 2bbfc4ca1976223308ff34d0042bbb31e374b9e2 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 11:08:45 +0100 Subject: [PATCH 23/43] Fixed createOrUpdatePluginByName implementation --- .../__snapshots__/utils.test.js.snap | 3 ++- lib/transformations/utils.js | 21 ++++++++++--------- lib/transformations/utils.test.js | 3 ++- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/transformations/__snapshots__/utils.test.js.snap b/lib/transformations/__snapshots__/utils.test.js.snap index 87d1b012cee..260405d37b3 100644 --- a/lib/transformations/__snapshots__/utils.test.js.snap +++ b/lib/transformations/__snapshots__/utils.test.js.snap @@ -15,6 +15,7 @@ exports[`utils createOrUpdatePluginByName should create a new plugin without arg exports[`utils createOrUpdatePluginByName should merge options objects 1`] = ` "[new Plugin({ foo: false, - bar: baz + bar: baz, + baz-long: true })]" `; diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index a3ceb112ca6..072d02585ed 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -117,18 +117,19 @@ function createOrUpdatePluginByName(j, rootNodePath, pluginName, options) { optionsProps.forEach(opt => { // Search for same keys in the existing object - const currentOptName = opt.key.name; - j(currentProps) + const existingProps = j(currentProps) .find(j.Identifier) - .forEach(path => { - if (path.value.name === currentOptName) { - // Merging values for same key - j(path.parent).replaceWith(opt); - } else { - // Adding new key:values - currentProps.value.push(opt); - } + .filter(path => opt.key.name === path.value.name); + + if (existingProps.size()) { + // Replacing values for the same key + existingProps.forEach(path => { + j(path.parent).replaceWith(opt); }); + } else { + // Adding new key:values + currentProps.value.push(opt); + } }); } else { diff --git a/lib/transformations/utils.test.js b/lib/transformations/utils.test.js index 9cf31921dc2..90b6b28e0c2 100644 --- a/lib/transformations/utils.test.js +++ b/lib/transformations/utils.test.js @@ -88,7 +88,8 @@ var a = { plugs: [] } ast .find(j.ArrayExpression) .forEach(node => { - utils.createOrUpdatePluginByName(j, node, 'Plugin', { foo: false, bar: 'baz' }); + utils.createOrUpdatePluginByName(j, node, 'Plugin', { bar: 'baz', foo: false }); + utils.createOrUpdatePluginByName(j, node, 'Plugin', { 'baz-long': true }); }); expect(ast.toSource()).toMatchSnapshot(); }); From 333ff9177e80b95a091b009bd2a05171c5315a51 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 12:06:25 +0100 Subject: [PATCH 24/43] Always use Literals for keys for now --- .../__snapshots__/utils.test.js.snap | 40 ++++++++++++++++--- lib/transformations/utils.js | 12 +++--- lib/transformations/utils.test.js | 27 +++++++++++++ 3 files changed, 69 insertions(+), 10 deletions(-) diff --git a/lib/transformations/__snapshots__/utils.test.js.snap b/lib/transformations/__snapshots__/utils.test.js.snap index 260405d37b3..d7e2da8c4b2 100644 --- a/lib/transformations/__snapshots__/utils.test.js.snap +++ b/lib/transformations/__snapshots__/utils.test.js.snap @@ -1,12 +1,12 @@ exports[`utils createOrUpdatePluginByName should add an object as an argument 1`] = ` "[new Plugin({ - foo: true + \"foo\": true })]" `; exports[`utils createOrUpdatePluginByName should create a new plugin with arguments 1`] = ` "{ plugins: [new Plugin({ - foo: bar + \"foo\": \"bar\" })] }" `; @@ -14,8 +14,38 @@ exports[`utils createOrUpdatePluginByName should create a new plugin without arg exports[`utils createOrUpdatePluginByName should merge options objects 1`] = ` "[new Plugin({ - foo: false, - bar: baz, - baz-long: true + \"foo\": false, + \"bar\": \"baz\", + \"baz-long\": true })]" `; + +exports[`utils createProperty should create properties for Boolean 1`] = ` +"{ + \"foo\": true +}" +`; + +exports[`utils createProperty should create properties for Number 1`] = ` +"{ + \"foo\": -1 +}" +`; + +exports[`utils createProperty should create properties for String 1`] = ` +"{ + \"foo\": \"bar\" +}" +`; + +exports[`utils createProperty should create properties for complex keys 1`] = ` +"{ + \"foo-bar\": \"bar\" +}" +`; + +exports[`utils createProperty should create properties for non-literal keys 1`] = ` +"{ + 1: \"bar\" +}" +`; diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index 072d02585ed..edb4c76ee4a 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -66,18 +66,19 @@ function findPluginsRootNodes(j, node) { /* * @function createProperty * - * Creates an Object's property with a given value + * Creates an Object's property with a given key and value + * Note: For now it always create a literal (String) for keys. * * @param j — jscodeshift API - * @param { string } key - Property key + * @param { string | number } key - Property key * @param { string | number | boolean } value - Property value * @returns Node * */ function createProperty(j, key, value) { return j.property( 'init', - j.identifier(key), - typeof value === 'string' ? j.identifier(value) : j.literal(value) + j.literal(key), + j.literal(value) ); } @@ -119,7 +120,7 @@ function createOrUpdatePluginByName(j, rootNodePath, pluginName, options) { // Search for same keys in the existing object const existingProps = j(currentProps) .find(j.Identifier) - .filter(path => opt.key.name === path.value.name); + .filter(path => opt.key.value === path.value.name); if (existingProps.size()) { // Replacing values for the same key @@ -155,6 +156,7 @@ function createOrUpdatePluginByName(j, rootNodePath, pluginName, options) { module.exports = { safeTraverse, + createProperty, findPluginsByName, findPluginsRootNodes, createOrUpdatePluginByName diff --git a/lib/transformations/utils.test.js b/lib/transformations/utils.test.js index 90b6b28e0c2..9bbe82c1988 100644 --- a/lib/transformations/utils.test.js +++ b/lib/transformations/utils.test.js @@ -2,6 +2,33 @@ const j = require('jscodeshift/dist/core'); const utils = require('./utils'); 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(` From 734b3be3d421b72716cd5b010c65e195da4d33ed Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 12:06:43 +0100 Subject: [PATCH 25/43] Fixed LoaderOptionsPlugin --- .../loaderOptionsPlugin.input.js | 18 +----------- .../loaderOptionsPlugin.output.js | 29 ++----------------- .../loaderOptionsPlugin.js | 4 +-- 3 files changed, 4 insertions(+), 47 deletions(-) diff --git a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js index c93bbbd0de8..60493cf28ab 100644 --- a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js +++ b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.input.js @@ -1,21 +1,5 @@ module.exports = { - plugins: [ - new webpack.optimize.UglifyJsPlugin() - ] -} - -module.exports = { - plugins: [ - new webpack.optimize.UglifyJsPlugin(), - new webpack.optimize.LoaderOptionsPlugin() - ] -} - -module.exports = { - debug: true -} - -module.exports = { + debug: true, plugins: [ new webpack.optimize.UglifyJsPlugin(), new webpack.optimize.LoaderOptionsPlugin({ diff --git a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js index 2812350669a..0ee29f2ad8b 100644 --- a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js +++ b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js @@ -1,36 +1,11 @@ -module.exports = { - plugins: [ - new webpack.optimize.UglifyJsPlugin(), - new webpack.optimize.LoaderOptionsPlugin({ - minimize: true - }) - ] -} - -module.exports = { - plugins: [ - new webpack.optimize.UglifyJsPlugin(), - new webpack.optimize.LoaderOptionsPlugin({ - minimize: true - }) - ] -} - module.exports = { debug: true, - plugins: [ - new webpack.optimize.LoaderOptionsPlugin({ - debug: true - }) - ] -} - -module.exports = { plugins: [ new webpack.optimize.UglifyJsPlugin(), new webpack.optimize.LoaderOptionsPlugin({ foo: 'bar', - minimize: true + 'debug': true, + 'minimize': true }) ] } diff --git a/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js index e92561b1b66..5449fa78d14 100644 --- a/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js +++ b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js @@ -18,9 +18,7 @@ module.exports = function(j, ast) { return ast .find(j.ArrayExpression) - .filter(path => { - return path.parent.value.key.name === 'plugins'; - }) + .filter(path => path.parent.value.key.name === 'plugins') .forEach(path => { createOrUpdatePluginByName(j, path, 'webpack.optimize.LoaderOptionsPlugin', loaderOptions); }) From 73ef8ce5fcd02a0b4c1c45c9bd902c1f7157105d Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 14:36:34 +0100 Subject: [PATCH 26/43] Return the full AST for compatibility --- lib/transformations/utils.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index edb4c76ee4a..d4564eed86a 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -58,9 +58,7 @@ function findPluginsByName(j, node, pluginNamesArray) { * @returns Path * */ function findPluginsRootNodes(j, node) { - return node - .find(j.Property, { key: { name: 'plugins' } }) - .map(path => path); + return node.find(j.Property, { key: { name: 'plugins' } }); } /* From 6d21726d00026904e7b090c88ae512534e566e26 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 14:38:29 +0100 Subject: [PATCH 27/43] Implemented BannerPlugin transformation. See https://webpack.js.org/guides/migrating/#bannerplugin-breaking-change --- .../BannerPlugin/BannerPlugin.js | 24 +++++++++++++++++++ .../__testfixtures__/.editorconfig | 3 +++ .../__testfixtures__/BannerPlugin.input.js | 5 ++++ .../__testfixtures__/BannerPlugin.output.js | 9 +++++++ .../__tests__/BannerPlugin.test.js | 3 +++ 5 files changed, 44 insertions(+) create mode 100644 lib/transformations/BannerPlugin/BannerPlugin.js create mode 100644 lib/transformations/BannerPlugin/__testfixtures__/.editorconfig create mode 100644 lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.input.js create mode 100644 lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.output.js create mode 100644 lib/transformations/BannerPlugin/__tests__/BannerPlugin.test.js diff --git a/lib/transformations/BannerPlugin/BannerPlugin.js b/lib/transformations/BannerPlugin/BannerPlugin.js new file mode 100644 index 00000000000..42930092e6f --- /dev/null +++ b/lib/transformations/BannerPlugin/BannerPlugin.js @@ -0,0 +1,24 @@ +const utils = require('../utils'); + +module.exports = function(j, ast) { + const loaderOptions = {}; + + utils.findPluginsByName(j, ast, ['webpack.BannerPlugin']) + .forEach(path => { + const args = path.value.arguments; + // 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) { + loaderOptions.banner = args[0].value; + // and remove the first argument + path.value.arguments = [path.value.arguments[1]]; + } + }); + + return utils.findPluginsRootNodes(j, ast) + .forEach(path => { + utils.createOrUpdatePluginByName(j, path, 'webpack.BannerPlugin', loaderOptions); + }) + .toSource({ quote: 'single' }); +}; diff --git a/lib/transformations/BannerPlugin/__testfixtures__/.editorconfig b/lib/transformations/BannerPlugin/__testfixtures__/.editorconfig new file mode 100644 index 00000000000..adbdb1ba476 --- /dev/null +++ b/lib/transformations/BannerPlugin/__testfixtures__/.editorconfig @@ -0,0 +1,3 @@ +[*] +indent_style = space +indent_size = 4 diff --git a/lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.input.js b/lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.input.js new file mode 100644 index 00000000000..56c89e72d84 --- /dev/null +++ b/lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.input.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + new webpack.BannerPlugin('Banner', { raw: true, entryOnly: true }) + ] +} diff --git a/lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.output.js b/lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.output.js new file mode 100644 index 00000000000..5e1fa1dece6 --- /dev/null +++ b/lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.output.js @@ -0,0 +1,9 @@ +module.exports = { + plugins: [ + new webpack.BannerPlugin({ + raw: true, + entryOnly: true, + 'banner': 'Banner' + }) + ] +} diff --git a/lib/transformations/BannerPlugin/__tests__/BannerPlugin.test.js b/lib/transformations/BannerPlugin/__tests__/BannerPlugin.test.js new file mode 100644 index 00000000000..daf6ba88be7 --- /dev/null +++ b/lib/transformations/BannerPlugin/__tests__/BannerPlugin.test.js @@ -0,0 +1,3 @@ +import {defineTest} from '../../defineTest'; + +defineTest(__dirname, 'BannerPlugin'); From e8deaed955d3c0358bcff74b0c37315156fe4985 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 15:33:57 +0100 Subject: [PATCH 28/43] Use shorthand object syntax --- lib/transformations/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/transformations/index.js b/lib/transformations/index.js index 976eeea14b0..0f50295408d 100644 --- a/lib/transformations/index.js +++ b/lib/transformations/index.js @@ -5,9 +5,9 @@ const uglifyJsPluginTransform = require('./uglifyJsPlugin/uglifyJsPlugin'); const removeDeprecatedPluginsTransform = require('./removeDeprecatedPlugins/removeDeprecatedPlugins'); module.exports = { - loaderTransform: loaderTransform, - resolveTransform: resolveTransform, - removeJsonLoaderTransform: removeJsonLoaderTransform, - uglifyJsPluginTransform: uglifyJsPluginTransform, - removeDeprecatedPluginsTransform: removeDeprecatedPluginsTransform + loaderTransform, + resolveTransform, + removeJsonLoaderTransform, + uglifyJsPluginTransform, + removeDeprecatedPluginsTransform }; From 8f5a9d7d3b5c312feea9701827cf4ba6f050cac3 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 15:34:12 +0100 Subject: [PATCH 29/43] Added JSDoc for findPluginsByName util function --- lib/transformations/utils.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index d4564eed86a..12135ee3d4a 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -36,8 +36,16 @@ function pathsToMemberExpression(j, paths) { } } -// Return paths that match `new name.space.PluginName()` -// for a given array of plugin names +/* +* @function findPluginsByName +* +* Find paths that match `new name.space.PluginName()` for a given array of plugin names +* +* @param j — jscodeshift API +* @param { Node } node - Node to start search from +* @param { Array } pluginNamesArray - Array of plugin names like `webpack.optimize.LoaderOptionsPlugin` +* @returns Path + * */ function findPluginsByName(j, node, pluginNamesArray) { return node .find(j.NewExpression) From 5bcc5ecbd655abe813dde4312ea45f555a67acb4 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 15:37:01 +0100 Subject: [PATCH 30/43] Export all available transforms --- lib/transformations/index.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/transformations/index.js b/lib/transformations/index.js index 0f50295408d..7135d992add 100644 --- a/lib/transformations/index.js +++ b/lib/transformations/index.js @@ -2,6 +2,9 @@ const loaderTransform = require('./loaders/loaders'); const resolveTransform = require('./resolve/resolve'); const removeJsonLoaderTransform = require('./removeJsonLoader/removeJsonLoader'); const uglifyJsPluginTransform = require('./uglifyJsPlugin/uglifyJsPlugin'); +const loaderOptionsPluginTransform = require('./loaderOptionsPlugin/loaderOptionsPlugin'); +const bannerPluginTransform = require('./bannerPlugin/bannerPlugin'); +const extractTextPluginTransform = require('./extractTextPlugin/extractTextPlugin'); const removeDeprecatedPluginsTransform = require('./removeDeprecatedPlugins/removeDeprecatedPlugins'); module.exports = { @@ -9,5 +12,8 @@ module.exports = { resolveTransform, removeJsonLoaderTransform, uglifyJsPluginTransform, + loaderOptionsPluginTransform, + bannerPluginTransform, + extractTextPluginTransform, removeDeprecatedPluginsTransform }; From 4601054609c2ad9cce84fac1617f8f2411de6ea7 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 15:41:08 +0100 Subject: [PATCH 31/43] fixup! Implemented BannerPlugin transformation. --- .../__testfixtures__/.editorconfig | 0 .../__testfixtures__/bannerPlugin.input.js} | 0 .../__testfixtures__/bannerPlugin.output.js} | 0 .../__tests__/bannerPlugin.test.js} | 2 +- .../BannerPlugin.js => bannerPlugin/bannerPlugin.js} | 0 5 files changed, 1 insertion(+), 1 deletion(-) rename lib/transformations/{BannerPlugin => bannerPlugin}/__testfixtures__/.editorconfig (100%) rename lib/transformations/{BannerPlugin/__testfixtures__/BannerPlugin.input.js => bannerPlugin/__testfixtures__/bannerPlugin.input.js} (100%) rename lib/transformations/{BannerPlugin/__testfixtures__/BannerPlugin.output.js => bannerPlugin/__testfixtures__/bannerPlugin.output.js} (100%) rename lib/transformations/{BannerPlugin/__tests__/BannerPlugin.test.js => bannerPlugin/__tests__/bannerPlugin.test.js} (54%) rename lib/transformations/{BannerPlugin/BannerPlugin.js => bannerPlugin/bannerPlugin.js} (100%) diff --git a/lib/transformations/BannerPlugin/__testfixtures__/.editorconfig b/lib/transformations/bannerPlugin/__testfixtures__/.editorconfig similarity index 100% rename from lib/transformations/BannerPlugin/__testfixtures__/.editorconfig rename to lib/transformations/bannerPlugin/__testfixtures__/.editorconfig diff --git a/lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.input.js b/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin.input.js similarity index 100% rename from lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.input.js rename to lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin.input.js diff --git a/lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.output.js b/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin.output.js similarity index 100% rename from lib/transformations/BannerPlugin/__testfixtures__/BannerPlugin.output.js rename to lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin.output.js diff --git a/lib/transformations/BannerPlugin/__tests__/BannerPlugin.test.js b/lib/transformations/bannerPlugin/__tests__/bannerPlugin.test.js similarity index 54% rename from lib/transformations/BannerPlugin/__tests__/BannerPlugin.test.js rename to lib/transformations/bannerPlugin/__tests__/bannerPlugin.test.js index daf6ba88be7..69bcd2e34f0 100644 --- a/lib/transformations/BannerPlugin/__tests__/BannerPlugin.test.js +++ b/lib/transformations/bannerPlugin/__tests__/bannerPlugin.test.js @@ -1,3 +1,3 @@ import {defineTest} from '../../defineTest'; -defineTest(__dirname, 'BannerPlugin'); +defineTest(__dirname, 'bannerPlugin'); diff --git a/lib/transformations/BannerPlugin/BannerPlugin.js b/lib/transformations/bannerPlugin/bannerPlugin.js similarity index 100% rename from lib/transformations/BannerPlugin/BannerPlugin.js rename to lib/transformations/bannerPlugin/bannerPlugin.js From 83c65dbc735fd9fd2f9f0bad76f97b7cb59b2557 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 15:53:18 +0100 Subject: [PATCH 32/43] Simplified directory structure and colocate tests with source files. --- .../__tests__/bannerPlugin.test.js | 3 -- .../bannerPlugin/bannerPlugin.test.js | 3 ++ lib/transformations/defineTest.js | 29 +++++++++---------- .../{__tests__ => }/extractTextPlugin.test.js | 2 +- .../loaderOptionsPlugin.test.js | 2 +- .../loaders/__tests__/loaders.test.js | 3 -- lib/transformations/loaders/loaders.test.js | 3 ++ ...ins.js => removeDeprecatedPlugins.test.js} | 2 +- .../__tests__/removeJsonLoader.test.js | 3 -- .../removeJsonLoader/removeJsonLoader.test.js | 3 ++ .../resolve/__tests__/resolve.test.js | 3 -- lib/transformations/resolve/resolve.test.js | 3 ++ .../__tests__/uglifyJsPlugin.test.js | 3 -- .../uglifyJsPlugin/uglifyJsPlugin.test.js | 3 ++ 14 files changed, 32 insertions(+), 33 deletions(-) delete mode 100644 lib/transformations/bannerPlugin/__tests__/bannerPlugin.test.js create mode 100644 lib/transformations/bannerPlugin/bannerPlugin.test.js rename lib/transformations/extractTextPlugin/{__tests__ => }/extractTextPlugin.test.js (50%) rename lib/transformations/loaderOptionsPlugin/{__tests__ => }/loaderOptionsPlugin.test.js (51%) delete mode 100644 lib/transformations/loaders/__tests__/loaders.test.js create mode 100644 lib/transformations/loaders/loaders.test.js rename lib/transformations/removeDeprecatedPlugins/{__tests__/removeDeprecatedPlugins.js => removeDeprecatedPlugins.test.js} (53%) delete mode 100644 lib/transformations/removeJsonLoader/__tests__/removeJsonLoader.test.js create mode 100644 lib/transformations/removeJsonLoader/removeJsonLoader.test.js delete mode 100644 lib/transformations/resolve/__tests__/resolve.test.js create mode 100644 lib/transformations/resolve/resolve.test.js delete mode 100644 lib/transformations/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.js create mode 100644 lib/transformations/uglifyJsPlugin/uglifyJsPlugin.test.js diff --git a/lib/transformations/bannerPlugin/__tests__/bannerPlugin.test.js b/lib/transformations/bannerPlugin/__tests__/bannerPlugin.test.js deleted file mode 100644 index 69bcd2e34f0..00000000000 --- a/lib/transformations/bannerPlugin/__tests__/bannerPlugin.test.js +++ /dev/null @@ -1,3 +0,0 @@ -import {defineTest} from '../../defineTest'; - -defineTest(__dirname, 'bannerPlugin'); diff --git a/lib/transformations/bannerPlugin/bannerPlugin.test.js b/lib/transformations/bannerPlugin/bannerPlugin.test.js new file mode 100644 index 00000000000..b04cd99f5cb --- /dev/null +++ b/lib/transformations/bannerPlugin/bannerPlugin.test.js @@ -0,0 +1,3 @@ +const defineTest = require('../defineTest'); + +defineTest(__dirname, 'bannerPlugin'); diff --git a/lib/transformations/defineTest.js b/lib/transformations/defineTest.js index 2a010eeaeb7..fb109b5cc64 100644 --- a/lib/transformations/defineTest.js +++ b/lib/transformations/defineTest.js @@ -42,32 +42,31 @@ function runTest(dirName, transformName, options, testFilePrefix) { testFilePrefix = transformName; } - const fixtureDir = path.join(dirName, '..', '__testfixtures__'); + const fixtureDir = path.join(dirName, '__testfixtures__'); const inputPath = path.join(fixtureDir, testFilePrefix + '.input.js'); const source = fs.readFileSync(inputPath, 'utf8'); const expectedOutput = fs.readFileSync( - path.join(fixtureDir, testFilePrefix + '.output.js'), - 'utf8' - ); - // Assumes transform is one level up from __tests__ directory - const module = require(path.join(dirName, '..', transformName + '.js')); - // Handle ES6 modules using default export for the transform + path.join(fixtureDir, testFilePrefix + '.output.js'), + 'utf8' + ); + // Assumes transform and test are on the same level + const module = require(path.join(dirName, transformName + '.js')); + // 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. + // Jest resets the module registry after each test, so we need to always get + // a fresh copy of jscodeshift on every test run. let jscodeshift = require('jscodeshift/dist/core'); if (module.parser) { jscodeshift = jscodeshift.withParser(module.parser); } const ast = jscodeshift(source); const output = transform( - jscodeshift, + jscodeshift, ast - ); + ); expect((output || '').trim()).toEqual(expectedOutput.trim()); } -module.exports.runTest = runTest; /** * Handles some boilerplate around defining a simple jest/Jasmine test for a @@ -75,12 +74,12 @@ module.exports.runTest = runTest; */ function defineTest(dirName, transformName, options, testFilePrefix) { const testName = testFilePrefix - ? `transforms correctly using "${testFilePrefix}" data` - : 'transforms correctly'; + ? `transforms correctly using "${testFilePrefix}" data` + : 'transforms correctly'; describe(transformName, () => { it(testName, () => { runTest(dirName, transformName, options, testFilePrefix); }); }); } -module.exports.defineTest = defineTest; +module.exports = defineTest; diff --git a/lib/transformations/extractTextPlugin/__tests__/extractTextPlugin.test.js b/lib/transformations/extractTextPlugin/extractTextPlugin.test.js similarity index 50% rename from lib/transformations/extractTextPlugin/__tests__/extractTextPlugin.test.js rename to lib/transformations/extractTextPlugin/extractTextPlugin.test.js index ed30265e91e..66d74802356 100644 --- a/lib/transformations/extractTextPlugin/__tests__/extractTextPlugin.test.js +++ b/lib/transformations/extractTextPlugin/extractTextPlugin.test.js @@ -1,3 +1,3 @@ -import {defineTest} from '../../defineTest'; +const defineTest = require('../defineTest'); defineTest(__dirname, 'extractTextPlugin'); diff --git a/lib/transformations/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.js b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.test.js similarity index 51% rename from lib/transformations/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.js rename to lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.test.js index 58c37df95d3..d0ef4fbd923 100644 --- a/lib/transformations/loaderOptionsPlugin/__tests__/loaderOptionsPlugin.test.js +++ b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.test.js @@ -1,3 +1,3 @@ -import {defineTest} from '../../defineTest'; +const defineTest = require('../defineTest'); defineTest(__dirname, 'loaderOptionsPlugin'); diff --git a/lib/transformations/loaders/__tests__/loaders.test.js b/lib/transformations/loaders/__tests__/loaders.test.js deleted file mode 100644 index 2ac7f34f3d9..00000000000 --- a/lib/transformations/loaders/__tests__/loaders.test.js +++ /dev/null @@ -1,3 +0,0 @@ -const defineTest = require('../../defineTest').defineTest; - -defineTest(__dirname, 'loaders'); diff --git a/lib/transformations/loaders/loaders.test.js b/lib/transformations/loaders/loaders.test.js new file mode 100644 index 00000000000..c554f493583 --- /dev/null +++ b/lib/transformations/loaders/loaders.test.js @@ -0,0 +1,3 @@ +const defineTest = require('../defineTest'); + +defineTest(__dirname, 'loaders'); diff --git a/lib/transformations/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.js b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.test.js similarity index 53% rename from lib/transformations/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.js rename to lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.test.js index 45f69ac3bb4..2d310117db8 100644 --- a/lib/transformations/removeDeprecatedPlugins/__tests__/removeDeprecatedPlugins.js +++ b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.test.js @@ -1,3 +1,3 @@ -import {defineTest} from '../../defineTest'; +const defineTest = require('../defineTest'); defineTest(__dirname, 'removeDeprecatedPlugins'); diff --git a/lib/transformations/removeJsonLoader/__tests__/removeJsonLoader.test.js b/lib/transformations/removeJsonLoader/__tests__/removeJsonLoader.test.js deleted file mode 100644 index c52b5ae7c81..00000000000 --- a/lib/transformations/removeJsonLoader/__tests__/removeJsonLoader.test.js +++ /dev/null @@ -1,3 +0,0 @@ -import {defineTest} from '../../defineTest'; - -defineTest(__dirname, 'removeJsonLoader'); diff --git a/lib/transformations/removeJsonLoader/removeJsonLoader.test.js b/lib/transformations/removeJsonLoader/removeJsonLoader.test.js new file mode 100644 index 00000000000..3ca0f2fec5a --- /dev/null +++ b/lib/transformations/removeJsonLoader/removeJsonLoader.test.js @@ -0,0 +1,3 @@ +const defineTest = require('../defineTest'); + +defineTest(__dirname, 'removeJsonLoader'); diff --git a/lib/transformations/resolve/__tests__/resolve.test.js b/lib/transformations/resolve/__tests__/resolve.test.js deleted file mode 100644 index 9096049f910..00000000000 --- a/lib/transformations/resolve/__tests__/resolve.test.js +++ /dev/null @@ -1,3 +0,0 @@ -const defineTest = require('../../defineTest').defineTest; - -defineTest(__dirname, 'resolve'); diff --git a/lib/transformations/resolve/resolve.test.js b/lib/transformations/resolve/resolve.test.js new file mode 100644 index 00000000000..30a26b5348b --- /dev/null +++ b/lib/transformations/resolve/resolve.test.js @@ -0,0 +1,3 @@ +const defineTest = require('../defineTest'); + +defineTest(__dirname, 'resolve'); diff --git a/lib/transformations/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.js b/lib/transformations/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.js deleted file mode 100644 index df9704e291f..00000000000 --- a/lib/transformations/uglifyJsPlugin/__tests__/uglifyJsPlugin.test.js +++ /dev/null @@ -1,3 +0,0 @@ -import {defineTest} from '../../defineTest'; - -defineTest(__dirname, 'uglifyJsPlugin'); diff --git a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.test.js b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.test.js new file mode 100644 index 00000000000..a1e96e08b47 --- /dev/null +++ b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.test.js @@ -0,0 +1,3 @@ +const defineTest = require('../defineTest'); + +defineTest(__dirname, 'uglifyJsPlugin'); From c12df128c66947524cf59017a7b2bbc5b0e23f28 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 15:59:30 +0100 Subject: [PATCH 33/43] Switch to snapshot testing and removed output fixtures --- .../bannerPlugin.test.js.snap} | 7 +- lib/transformations/defineTest.js | 11 +-- .../extractTextPlugin.test.js.snap | 24 ++++++ .../extractTextPlugin.output.js | 21 ----- .../loaderOptionsPlugin.test.js.snap | 14 ++++ .../loaderOptionsPlugin.output.js | 11 --- .../__snapshots__/loaders.test.js.snap | 80 +++++++++++++++++++ .../__testfixtures__/loaders.output.js | 76 ------------------ .../removeDeprecatedPlugins.test.js.snap} | 7 +- .../removeJsonLoader.test.js.snap | 33 ++++++++ .../removeJsonLoader.output.js | 29 ------- .../__snapshots__/resolve.test.js.snap | 22 +++++ .../__testfixtures__/resolve.output.js | 19 ----- .../uglifyJsPlugin.test.js.snap} | 9 ++- 14 files changed, 191 insertions(+), 172 deletions(-) rename lib/transformations/bannerPlugin/{__testfixtures__/bannerPlugin.output.js => __snapshots__/bannerPlugin.test.js.snap} (52%) create mode 100644 lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap delete mode 100644 lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js create mode 100644 lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap delete mode 100644 lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js create mode 100644 lib/transformations/loaders/__snapshots__/loaders.test.js.snap delete mode 100644 lib/transformations/loaders/__testfixtures__/loaders.output.js rename lib/transformations/removeDeprecatedPlugins/{__testfixtures__/removeDeprecatedPlugins.output.js => __snapshots__/removeDeprecatedPlugins.test.js.snap} (50%) create mode 100644 lib/transformations/removeJsonLoader/__snapshots__/removeJsonLoader.test.js.snap delete mode 100644 lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js create mode 100644 lib/transformations/resolve/__snapshots__/resolve.test.js.snap delete mode 100644 lib/transformations/resolve/__testfixtures__/resolve.output.js rename lib/transformations/uglifyJsPlugin/{__testfixtures__/uglifyJsPlugin.output.js => __snapshots__/uglifyJsPlugin.test.js.snap} (73%) diff --git a/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin.output.js b/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap similarity index 52% rename from lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin.output.js rename to lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap index 5e1fa1dece6..4d2e8d18219 100644 --- a/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin.output.js +++ b/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap @@ -1,9 +1,12 @@ -module.exports = { +exports[`bannerPlugin transforms correctly 1`] = ` +"module.exports = { plugins: [ new webpack.BannerPlugin({ raw: true, entryOnly: true, - 'banner': 'Banner' + \'banner\': \'Banner\' }) ] } +" +`; diff --git a/lib/transformations/defineTest.js b/lib/transformations/defineTest.js index fb109b5cc64..bdd0442cc5e 100644 --- a/lib/transformations/defineTest.js +++ b/lib/transformations/defineTest.js @@ -45,10 +45,6 @@ function runTest(dirName, transformName, options, testFilePrefix) { const fixtureDir = path.join(dirName, '__testfixtures__'); const inputPath = path.join(fixtureDir, testFilePrefix + '.input.js'); const source = fs.readFileSync(inputPath, 'utf8'); - const expectedOutput = fs.readFileSync( - path.join(fixtureDir, testFilePrefix + '.output.js'), - 'utf8' - ); // Assumes transform and test are on the same level const module = require(path.join(dirName, transformName + '.js')); // Handle ES6 modules using default export for the transform @@ -61,11 +57,8 @@ function runTest(dirName, transformName, options, testFilePrefix) { jscodeshift = jscodeshift.withParser(module.parser); } const ast = jscodeshift(source); - const output = transform( - jscodeshift, - ast - ); - expect((output || '').trim()).toEqual(expectedOutput.trim()); + const output = transform(jscodeshift, ast); + expect(output).toMatchSnapshot(); } /** diff --git a/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap b/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap new file mode 100644 index 00000000000..28784339e3d --- /dev/null +++ b/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap @@ -0,0 +1,24 @@ +exports[`extractTextPlugin transforms correctly 1`] = ` +"let ExtractTextPlugin = require(\'extract-text-webpack-plugin\'); + +let extractCSS = new ExtractTextPlugin(\'stylesheets/[name].css\'); +let extractLESS = new ExtractTextPlugin(\'stylesheets/[name].less\'); + +module.export = { + module: { + rules: [ + { + test: /\\.css$/, + use: ExtractTextPlugin.extract({ + fallback: \'style-loader\', + use: \'css-loader\' + }) + } + ] + }, + plugins: [ + new ExtractTextPlugin(\"styles.css\"), + ] +} +" +`; diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js deleted file mode 100644 index 61f52a3ed59..00000000000 --- a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.output.js +++ /dev/null @@ -1,21 +0,0 @@ -let ExtractTextPlugin = require('extract-text-webpack-plugin'); - -let extractCSS = new ExtractTextPlugin('stylesheets/[name].css'); -let extractLESS = new ExtractTextPlugin('stylesheets/[name].less'); - -module.export = { - module: { - rules: [ - { - test: /\.css$/, - use: ExtractTextPlugin.extract({ - fallback: 'style-loader', - use: 'css-loader' - }) - } - ] - }, - plugins: [ - new ExtractTextPlugin("styles.css"), - ] -} diff --git a/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap b/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap new file mode 100644 index 00000000000..db38d48df07 --- /dev/null +++ b/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap @@ -0,0 +1,14 @@ +exports[`loaderOptionsPlugin transforms correctly 1`] = ` +"module.exports = { + debug: true, + plugins: [ + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.LoaderOptionsPlugin({ + foo: \'bar\', + \'debug\': true, + \'minimize\': true + }) + ] +} +" +`; diff --git a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js b/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js deleted file mode 100644 index 0ee29f2ad8b..00000000000 --- a/lib/transformations/loaderOptionsPlugin/__testfixtures__/loaderOptionsPlugin.output.js +++ /dev/null @@ -1,11 +0,0 @@ -module.exports = { - debug: true, - plugins: [ - new webpack.optimize.UglifyJsPlugin(), - new webpack.optimize.LoaderOptionsPlugin({ - foo: 'bar', - 'debug': true, - 'minimize': true - }) - ] -} diff --git a/lib/transformations/loaders/__snapshots__/loaders.test.js.snap b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap new file mode 100644 index 00000000000..23d95720046 --- /dev/null +++ b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap @@ -0,0 +1,80 @@ +exports[`loaders transforms correctly 1`] = ` +"export default [{ + module: { + rules: [{ + test: /\\.js$/, + use: \'babel-loader\' + }] + } +}, { + module: { + rules: [{ + test: /\\.css$/, + use: [{ + loader: \'style-loader\' + }, { + loader: \'css-loader\', + + options: { + modules: true, + importLoaders: 1, + string: \'test123\' + } + }] + }] + } +}, { + module: { + rules: [{ + test: /\\.css$/, + use: [{ + loader: \'style-loader\' + }, { + loader: \'css-loader\', + options: { + modules: true + } + }] + }] + } +}, { + module: { + rules:[{ + test: /\\.js$/, + use: \'eslint-loader\', + enforce: \'pre\' + }] + } +}, { + module: { + rules:[{ + test: /\\.js$/, + use: \'my-post-loader\', + enforce: \'post\' + }] + } +}, { + module: { + rules: [{ + test: /\\.js$/, + use: \'babel-loader\' + }, { + test: /\\.js$/, + use: \'eslint-loader\', + enforce: \'pre\' + }] + } +}, { + module: { + rules: [{ + test: /\\.js$/, + use: \'babel-loader\' + }, { + test: /\\.js$/, + use: \'my-post-loader\', + enforce: \'post\' + }] + } +}]; +" +`; diff --git a/lib/transformations/loaders/__testfixtures__/loaders.output.js b/lib/transformations/loaders/__testfixtures__/loaders.output.js deleted file mode 100644 index a6a55b75c85..00000000000 --- a/lib/transformations/loaders/__testfixtures__/loaders.output.js +++ /dev/null @@ -1,76 +0,0 @@ -export default [{ - module: { - rules: [{ - test: /\.js$/, - use: 'babel-loader' - }] - } -}, { - module: { - rules: [{ - test: /\.css$/, - use: [{ - loader: 'style-loader' - }, { - loader: 'css-loader', - options: { - modules: true, - importLoaders: 1, - string: 'test123' - } - }] - }] - } -}, { - module: { - rules: [{ - test: /\.css$/, - use: [{ - loader: 'style-loader' - }, { - loader: 'css-loader', - options: { - modules: true - } - }] - }] - } -}, { - module: { - rules:[{ - test: /\.js$/, - use: 'eslint-loader', - enforce: 'pre' - }] - } -}, { - module: { - rules:[{ - test: /\.js$/, - use: 'my-post-loader', - enforce: 'post' - }] - } -}, { - module: { - rules: [{ - test: /\.js$/, - use: 'babel-loader' - }, { - test: /\.js$/, - use: 'eslint-loader', - enforce: 'pre' - }] - } -}, { - module: { - rules: [{ - test: /\.js$/, - use: 'babel-loader' - }, { - test: /\.js$/, - use: 'my-post-loader', - enforce: 'post' - }] - } -}]; diff --git a/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.output.js b/lib/transformations/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.js.snap similarity index 50% rename from lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.output.js rename to lib/transformations/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.js.snap index 93610a91119..05c68a9e487 100644 --- a/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.output.js +++ b/lib/transformations/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.js.snap @@ -1,10 +1,13 @@ -// Works for OccurrenceOrderPlugin +exports[`removeDeprecatedPlugins transforms correctly 1`] = ` +"// Works for OccurrenceOrderPlugin module.exports = {} // Works for DedupePlugin module.exports = {} -// Doesn't remove unmatched plugins +// Doesn\'t remove unmatched plugins module.exports = { plugins: [new webpack.optimize.UglifyJsPlugin()] } +" +`; diff --git a/lib/transformations/removeJsonLoader/__snapshots__/removeJsonLoader.test.js.snap b/lib/transformations/removeJsonLoader/__snapshots__/removeJsonLoader.test.js.snap new file mode 100644 index 00000000000..09f7beb2c79 --- /dev/null +++ b/lib/transformations/removeJsonLoader/__snapshots__/removeJsonLoader.test.js.snap @@ -0,0 +1,33 @@ +exports[`removeJsonLoader transforms correctly 1`] = ` +"export default [{ + module: { + rules: [{ + test: /\\.yml/, + use: [\'another-loader\', \'yml-loader\'] + }] + } +}, { + module: { + rules: [{ + test: /\\.yml/, + use: \'yml-loader\' + }] + } +}, { + module: { + rules: [] + } +}, { + module: { + rules: [{ + test: /\\.yml/, + use: [\'another-loader\', \'yml-loader\'] + }, { + test: /\\.yml/, + use: \'yml-loader\' + }] + } +}]; + +" +`; diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js deleted file mode 100644 index 8089cd91cfa..00000000000 --- a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.output.js +++ /dev/null @@ -1,29 +0,0 @@ -export default [{ - module: { - rules: [{ - test: /\.yml/, - use: ['another-loader', 'yml-loader'] - }] - } -}, { - module: { - rules: [{ - test: /\.yml/, - use: 'yml-loader' - }] - } -}, { - module: { - rules: [] - } -}, { - module: { - rules: [{ - test: /\.yml/, - use: ['another-loader', 'yml-loader'] - }, { - test: /\.yml/, - use: 'yml-loader' - }] - } -}]; diff --git a/lib/transformations/resolve/__snapshots__/resolve.test.js.snap b/lib/transformations/resolve/__snapshots__/resolve.test.js.snap new file mode 100644 index 00000000000..ca978abfbcb --- /dev/null +++ b/lib/transformations/resolve/__snapshots__/resolve.test.js.snap @@ -0,0 +1,22 @@ +exports[`resolve transforms correctly 1`] = ` +"import path from \'path\'; + +export default [{ + resolve: { + modules: [path.resolve(\'/src\')] + } +}, { + resolve: { + modules: [path.resolve(\'/src\')] + } +}, { + resolve: { + modules: [path.resolve(\'/src\'), \'node_modules\'] + } +}, { + resolve: { + modules: [\'node_modules\', path.resolve(\'/src\')] + } +}]; +" +`; diff --git a/lib/transformations/resolve/__testfixtures__/resolve.output.js b/lib/transformations/resolve/__testfixtures__/resolve.output.js deleted file mode 100644 index 8335bdcdcb6..00000000000 --- a/lib/transformations/resolve/__testfixtures__/resolve.output.js +++ /dev/null @@ -1,19 +0,0 @@ -import path from 'path'; - -export default [{ - resolve: { - modules: [path.resolve('/src')] - } -}, { - resolve: { - modules: [path.resolve('/src')] - } -}, { - resolve: { - modules: [path.resolve('/src'), 'node_modules'] - } -}, { - resolve: { - modules: ['node_modules', path.resolve('/src')] - } -}]; diff --git a/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.output.js b/lib/transformations/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.js.snap similarity index 73% rename from lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.output.js rename to lib/transformations/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.js.snap index 8ebe6323e52..cbff7c2cad5 100644 --- a/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.output.js +++ b/lib/transformations/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.js.snap @@ -1,4 +1,5 @@ -module.exports = { +exports[`uglifyJsPlugin transforms correctly 1`] = ` +"module.exports = { plugins: [ new webpack.optimize.UglifyJsPlugin({ sourceMap: true @@ -7,7 +8,7 @@ module.exports = { } module.exports = { - devtool: "source-map", + devtool: \"source-map\", plugins: [ new webpack.optimize.UglifyJsPlugin({ sourceMap: true @@ -16,7 +17,7 @@ module.exports = { } module.exports = { - devtool: "cheap-source-map", + devtool: \"cheap-source-map\", plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: {}, @@ -24,3 +25,5 @@ module.exports = { }) ] } +" +`; From 45ccf979390380ea15318f877e3618f6e1185795 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 16:03:29 +0100 Subject: [PATCH 34/43] All transformations return AST to allow chaining --- lib/transformations/bannerPlugin/bannerPlugin.js | 3 +-- lib/transformations/defineTest.js | 2 +- .../extractTextPlugin/extractTextPlugin.js | 13 ++++++------- .../loaderOptionsPlugin/loaderOptionsPlugin.js | 3 +-- lib/transformations/loaders/loaders.js | 2 +- .../removeDeprecatedPlugins.js | 3 +-- .../removeJsonLoader/removeJsonLoader.js | 2 +- lib/transformations/resolve/resolve.js | 3 +-- .../uglifyJsPlugin/uglifyJsPlugin.js | 3 +-- 9 files changed, 14 insertions(+), 20 deletions(-) diff --git a/lib/transformations/bannerPlugin/bannerPlugin.js b/lib/transformations/bannerPlugin/bannerPlugin.js index 42930092e6f..5f900067847 100644 --- a/lib/transformations/bannerPlugin/bannerPlugin.js +++ b/lib/transformations/bannerPlugin/bannerPlugin.js @@ -19,6 +19,5 @@ module.exports = function(j, ast) { return utils.findPluginsRootNodes(j, ast) .forEach(path => { utils.createOrUpdatePluginByName(j, path, 'webpack.BannerPlugin', loaderOptions); - }) - .toSource({ quote: 'single' }); + }); }; diff --git a/lib/transformations/defineTest.js b/lib/transformations/defineTest.js index bdd0442cc5e..341fad0133f 100644 --- a/lib/transformations/defineTest.js +++ b/lib/transformations/defineTest.js @@ -57,7 +57,7 @@ function runTest(dirName, transformName, options, testFilePrefix) { jscodeshift = jscodeshift.withParser(module.parser); } const ast = jscodeshift(source); - const output = transform(jscodeshift, ast); + const output = transform(jscodeshift, ast).toSource({ quote: 'single' }); expect(output).toMatchSnapshot(); } diff --git a/lib/transformations/extractTextPlugin/extractTextPlugin.js b/lib/transformations/extractTextPlugin/extractTextPlugin.js index 5567ed8817d..3fd4ede49ff 100644 --- a/lib/transformations/extractTextPlugin/extractTextPlugin.js +++ b/lib/transformations/extractTextPlugin/extractTextPlugin.js @@ -2,14 +2,14 @@ const safeTraverse = require('../utils').safeTraverse; const findPluginsByName = require('../utils').findPluginsByName; module.exports = function(j, ast) { - const changeArguments = function(p) { + const changeArguments = function(p) { const args = p.value.arguments; // if(args.length === 1) { // return p; - // } else + // } else const literalArgs = args.filter(p => p.type === 'Literal'); if (literalArgs && literalArgs.length > 1) { - const newArgs = j.objectExpression(literalArgs.map((p, index) => + const newArgs = j.objectExpression(literalArgs.map((p, index) => j.property('init', j.identifier(index === 0 ? 'fallback': 'use'), j.literal(p.value) @@ -18,16 +18,15 @@ module.exports = function(j, ast) { p.value.arguments = [newArgs]; } console.log(p.value.arguments); - return p; + return p; }; const name = getName(j, ast, 'extract-text-webpack-plugin'); return ast.find(j.CallExpression) .filter(p => p.value.callee.object) .filter(p => p.value.callee.object.name === name) - .forEach(changeArguments) - .toSource({ quote: 'single' }) + .forEach(changeArguments); //.forEach(p => console.log(p.toSource())); - + //return ast.toSource({ quote: 'single' }); }; diff --git a/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js index 5449fa78d14..910f19f3bb4 100644 --- a/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js +++ b/lib/transformations/loaderOptionsPlugin/loaderOptionsPlugin.js @@ -21,6 +21,5 @@ module.exports = function(j, ast) { .filter(path => path.parent.value.key.name === 'plugins') .forEach(path => { createOrUpdatePluginByName(j, path, 'webpack.optimize.LoaderOptionsPlugin', loaderOptions); - }) - .toSource({ quote: 'single' }); + }); }; diff --git a/lib/transformations/loaders/loaders.js b/lib/transformations/loaders/loaders.js index 43aaa750445..4c2f089bb65 100644 --- a/lib/transformations/loaders/loaders.js +++ b/lib/transformations/loaders/loaders.js @@ -169,5 +169,5 @@ module.exports = function(j, ast) { ]; transforms.forEach(t => t()); - return ast.toSource({ quote: 'single' }); + return ast; }; diff --git a/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js index 6c6fa5eccad..c4b5a6c93be 100644 --- a/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js +++ b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.js @@ -17,6 +17,5 @@ module.exports = function(j, ast) { } else { j(path).remove(); } - }) - .toSource({ quote: 'single' }); + }); }; diff --git a/lib/transformations/removeJsonLoader/removeJsonLoader.js b/lib/transformations/removeJsonLoader/removeJsonLoader.js index 4b63fd0518b..0b7bcbac56f 100644 --- a/lib/transformations/removeJsonLoader/removeJsonLoader.js +++ b/lib/transformations/removeJsonLoader/removeJsonLoader.js @@ -44,5 +44,5 @@ module.exports = function(j, ast) { transforms.forEach(t => t(ast)); - return ast.toSource({ quote: 'single' }); + return ast; }; diff --git a/lib/transformations/resolve/resolve.js b/lib/transformations/resolve/resolve.js index e7b5ba36581..3912703e9e0 100644 --- a/lib/transformations/resolve/resolve.js +++ b/lib/transformations/resolve/resolve.js @@ -45,6 +45,5 @@ module.exports = function transformer(j, ast) { .filter(prop => prop.key.name === 'root') .length === 1; }) - .forEach(createModuleArray) - .toSource(); + .forEach(createModuleArray); }; diff --git a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js index a7f9eff64fc..f5c4a12af3b 100644 --- a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js +++ b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.js @@ -21,6 +21,5 @@ module.exports = function(j, ast) { // Plugin is called without arguments args.push(j.objectExpression([createSourceMapsProperty()])); } - }) - .toSource({ quote: 'single' }); + }); }; From 99624b59a58ba4432f1aff88adeb8f3d62c607f6 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 16:42:22 +0100 Subject: [PATCH 35/43] Split separate test cases into separate files --- lib/transformations/defineTest.js | 6 +- .../__snapshots__/loaders.test.js.snap | 101 +++++++++++++++++- .../{loaders.input.js => loaders-0.input.js} | 0 .../__testfixtures__/loaders-1.input.js | 8 ++ .../__testfixtures__/loaders-2.input.js | 15 +++ .../__testfixtures__/loaders-3.input.js | 8 ++ .../__testfixtures__/loaders-4.input.js | 8 ++ .../__testfixtures__/loaders-5.input.js | 12 +++ .../__testfixtures__/loaders-6.input.js | 12 +++ lib/transformations/loaders/loaders.test.js | 8 +- .../removeDeprecatedPlugins.test.js.snap | 12 ++- .../removeDeprecatedPlugins-0.input.js | 6 ++ .../removeDeprecatedPlugins-1.input.js | 6 ++ .../removeDeprecatedPlugins-2.input.js | 8 ++ .../removeDeprecatedPlugins.input.js | 22 ---- .../removeDeprecatedPlugins.test.js | 4 +- .../removeJsonLoader.test.js.snap | 28 +++-- .../removeJsonLoader-0.input.js | 9 ++ .../removeJsonLoader-1.input.js | 8 ++ .../removeJsonLoader-2.input.js | 10 ++ .../removeJsonLoader-3.input.js | 15 +++ .../removeJsonLoader.input.js | 38 ------- .../removeJsonLoader/removeJsonLoader.test.js | 5 +- .../__snapshots__/uglifyJsPlugin.test.js.snap | 12 ++- .../uglifyJsPlugin-0.input.js | 5 + .../uglifyJsPlugin-1.input.js | 6 ++ .../uglifyJsPlugin-2.input.js | 8 ++ .../__testfixtures__/uglifyJsPlugin.input.js | 21 ---- .../uglifyJsPlugin/uglifyJsPlugin.test.js | 4 +- 29 files changed, 304 insertions(+), 101 deletions(-) rename lib/transformations/loaders/__testfixtures__/{loaders.input.js => loaders-0.input.js} (100%) create mode 100644 lib/transformations/loaders/__testfixtures__/loaders-1.input.js create mode 100644 lib/transformations/loaders/__testfixtures__/loaders-2.input.js create mode 100644 lib/transformations/loaders/__testfixtures__/loaders-3.input.js create mode 100644 lib/transformations/loaders/__testfixtures__/loaders-4.input.js create mode 100644 lib/transformations/loaders/__testfixtures__/loaders-5.input.js create mode 100644 lib/transformations/loaders/__testfixtures__/loaders-6.input.js create mode 100644 lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-0.input.js create mode 100644 lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-1.input.js create mode 100644 lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-2.input.js delete mode 100644 lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.input.js create mode 100644 lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-0.input.js create mode 100644 lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-1.input.js create mode 100644 lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-2.input.js create mode 100644 lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-3.input.js delete mode 100644 lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js create mode 100644 lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-0.input.js create mode 100644 lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-1.input.js create mode 100644 lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-2.input.js delete mode 100644 lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.input.js diff --git a/lib/transformations/defineTest.js b/lib/transformations/defineTest.js index 341fad0133f..7c58f195a1d 100644 --- a/lib/transformations/defineTest.js +++ b/lib/transformations/defineTest.js @@ -37,7 +37,7 @@ const cli = new cli_engine(eslintrules); * - Test data should be located in a directory called __testfixtures__ * alongside the transform and __tests__ directory. */ -function runTest(dirName, transformName, options, testFilePrefix) { +function runTest(dirName, transformName, testFilePrefix) { if (!testFilePrefix) { testFilePrefix = transformName; } @@ -65,13 +65,13 @@ function runTest(dirName, transformName, options, testFilePrefix) { * Handles some boilerplate around defining a simple jest/Jasmine test for a * jscodeshift transform. */ -function defineTest(dirName, transformName, options, testFilePrefix) { +function defineTest(dirName, transformName, testFilePrefix) { const testName = testFilePrefix ? `transforms correctly using "${testFilePrefix}" data` : 'transforms correctly'; describe(transformName, () => { it(testName, () => { - runTest(dirName, transformName, options, testFilePrefix); + runTest(dirName, transformName, testFilePrefix); }); }); } diff --git a/lib/transformations/loaders/__snapshots__/loaders.test.js.snap b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap index 23d95720046..25abb68c9ed 100644 --- a/lib/transformations/loaders/__snapshots__/loaders.test.js.snap +++ b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap @@ -1,4 +1,4 @@ -exports[`loaders transforms correctly 1`] = ` +exports[`loaders transforms correctly using "loaders-0" data 1`] = ` "export default [{ module: { rules: [{ @@ -78,3 +78,102 @@ exports[`loaders transforms correctly 1`] = ` }]; " `; + +exports[`loaders transforms correctly using "loaders-1" data 1`] = ` +"export default { + module: { + rules: [{ + test: /\\.css$/, + use: [{ + loader: \'style-loader\' + }, { + loader: \'css-loader\', + + options: { + modules: true, + importLoaders: 1, + string: \'test123\' + } + }] + }] + } +} +" +`; + +exports[`loaders transforms correctly using "loaders-2" data 1`] = ` +"export default { + module: { + rules: [{ + test: /\\.css$/, + use: [{ + loader: \'style-loader\' + }, { + loader: \'css-loader\', + options: { + modules: true + } + }] + }] + } +} +" +`; + +exports[`loaders transforms correctly using "loaders-3" data 1`] = ` +"export default { + module: { + rules:[{ + test: /\\.js$/, + use: \'eslint-loader\', + enforce: \'pre\' + }] + } +} +" +`; + +exports[`loaders transforms correctly using "loaders-4" data 1`] = ` +"export default { + module: { + rules:[{ + test: /\\.js$/, + use: \'my-post-loader\', + enforce: \'post\' + }] + } +} +" +`; + +exports[`loaders transforms correctly using "loaders-5" data 1`] = ` +"export default { + module: { + rules: [{ + test: /\\.js$/, + use: \'babel-loader\' + }, { + test: /\\.js$/, + use: \'eslint-loader\', + enforce: \'pre\' + }] + } +} +" +`; + +exports[`loaders transforms correctly using "loaders-6" data 1`] = ` +"export default { + module: { + rules: [{ + test: /\\.js$/, + use: \'babel-loader\' + }, { + test: /\\.js$/, + use: \'my-post-loader\', + enforce: \'post\' + }] + } +} +" +`; diff --git a/lib/transformations/loaders/__testfixtures__/loaders.input.js b/lib/transformations/loaders/__testfixtures__/loaders-0.input.js similarity index 100% rename from lib/transformations/loaders/__testfixtures__/loaders.input.js rename to lib/transformations/loaders/__testfixtures__/loaders-0.input.js diff --git a/lib/transformations/loaders/__testfixtures__/loaders-1.input.js b/lib/transformations/loaders/__testfixtures__/loaders-1.input.js new file mode 100644 index 00000000000..eae75024e61 --- /dev/null +++ b/lib/transformations/loaders/__testfixtures__/loaders-1.input.js @@ -0,0 +1,8 @@ +export default { + module: { + loaders: [{ + test: /\.css$/, + loader: 'style!css?modules&importLoaders=1&string=test123' + }] + } +} diff --git a/lib/transformations/loaders/__testfixtures__/loaders-2.input.js b/lib/transformations/loaders/__testfixtures__/loaders-2.input.js new file mode 100644 index 00000000000..771404a300c --- /dev/null +++ b/lib/transformations/loaders/__testfixtures__/loaders-2.input.js @@ -0,0 +1,15 @@ +export default { + module: { + loaders: [{ + test: /\.css$/, + loaders: [{ + loader: 'style' + }, { + loader: 'css', + query: { + modules: true + } + }] + }] + } +} diff --git a/lib/transformations/loaders/__testfixtures__/loaders-3.input.js b/lib/transformations/loaders/__testfixtures__/loaders-3.input.js new file mode 100644 index 00000000000..4d49e89a89b --- /dev/null +++ b/lib/transformations/loaders/__testfixtures__/loaders-3.input.js @@ -0,0 +1,8 @@ +export default { + module: { + preLoaders:[{ + test: /\.js$/, + loader: 'eslint' + }] + } +} diff --git a/lib/transformations/loaders/__testfixtures__/loaders-4.input.js b/lib/transformations/loaders/__testfixtures__/loaders-4.input.js new file mode 100644 index 00000000000..cc3e076bed9 --- /dev/null +++ b/lib/transformations/loaders/__testfixtures__/loaders-4.input.js @@ -0,0 +1,8 @@ +export default { + module: { + postLoaders:[{ + test: /\.js$/, + loader: 'my-post' + }] + } +} diff --git a/lib/transformations/loaders/__testfixtures__/loaders-5.input.js b/lib/transformations/loaders/__testfixtures__/loaders-5.input.js new file mode 100644 index 00000000000..6fd315e4d08 --- /dev/null +++ b/lib/transformations/loaders/__testfixtures__/loaders-5.input.js @@ -0,0 +1,12 @@ +export default { + module: { + preLoaders:[{ + test: /\.js$/, + loader: 'eslint-loader' + }], + loaders: [{ + test: /\.js$/, + loader: 'babel-loader' + }] + } +} diff --git a/lib/transformations/loaders/__testfixtures__/loaders-6.input.js b/lib/transformations/loaders/__testfixtures__/loaders-6.input.js new file mode 100644 index 00000000000..184e4e1ad08 --- /dev/null +++ b/lib/transformations/loaders/__testfixtures__/loaders-6.input.js @@ -0,0 +1,12 @@ +export default { + module: { + loaders: [{ + test: /\.js$/, + loader: 'babel-loader' + }], + postLoaders:[{ + test: /\.js$/, + loader: 'my-post-loader' + }] + } +} diff --git a/lib/transformations/loaders/loaders.test.js b/lib/transformations/loaders/loaders.test.js index c554f493583..3e77665cbe2 100644 --- a/lib/transformations/loaders/loaders.test.js +++ b/lib/transformations/loaders/loaders.test.js @@ -1,3 +1,9 @@ const defineTest = require('../defineTest'); -defineTest(__dirname, 'loaders'); +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'); diff --git a/lib/transformations/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.js.snap b/lib/transformations/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.js.snap index 05c68a9e487..da083b8d972 100644 --- a/lib/transformations/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.js.snap +++ b/lib/transformations/removeDeprecatedPlugins/__snapshots__/removeDeprecatedPlugins.test.js.snap @@ -1,11 +1,17 @@ -exports[`removeDeprecatedPlugins transforms correctly 1`] = ` +exports[`removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-0" data 1`] = ` "// Works for OccurrenceOrderPlugin module.exports = {} +" +`; -// Works for DedupePlugin +exports[`removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-1" data 1`] = ` +"// Works for DedupePlugin module.exports = {} +" +`; -// Doesn\'t remove unmatched plugins +exports[`removeDeprecatedPlugins transforms correctly using "removeDeprecatedPlugins-2" data 1`] = ` +"// Doesn\'t remove unmatched plugins module.exports = { plugins: [new webpack.optimize.UglifyJsPlugin()] } diff --git a/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-0.input.js b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-0.input.js new file mode 100644 index 00000000000..133c4984bfd --- /dev/null +++ b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-0.input.js @@ -0,0 +1,6 @@ +// Works for OccurrenceOrderPlugin +module.exports = { + plugins: [ + new webpack.optimize.OccurrenceOrderPlugin(), + ] +} diff --git a/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-1.input.js b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-1.input.js new file mode 100644 index 00000000000..a64dab79b37 --- /dev/null +++ b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-1.input.js @@ -0,0 +1,6 @@ +// Works for DedupePlugin +module.exports = { + plugins: [ + new webpack.optimize.DedupePlugin(), + ] +} diff --git a/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-2.input.js b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-2.input.js new file mode 100644 index 00000000000..26150117db4 --- /dev/null +++ b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins-2.input.js @@ -0,0 +1,8 @@ +// Doesn't remove unmatched plugins +module.exports = { + plugins: [ + new webpack.optimize.OccurrenceOrderPlugin(), + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.DedupePlugin() + ] +} diff --git a/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.input.js b/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.input.js deleted file mode 100644 index e130c0b800e..00000000000 --- a/lib/transformations/removeDeprecatedPlugins/__testfixtures__/removeDeprecatedPlugins.input.js +++ /dev/null @@ -1,22 +0,0 @@ -// Works for OccurrenceOrderPlugin -module.exports = { - plugins: [ - new webpack.optimize.OccurrenceOrderPlugin(), - ] -} - -// Works for DedupePlugin -module.exports = { - plugins: [ - new webpack.optimize.DedupePlugin(), - ] -} - -// Doesn't remove unmatched plugins -module.exports = { - plugins: [ - new webpack.optimize.OccurrenceOrderPlugin(), - new webpack.optimize.UglifyJsPlugin(), - new webpack.optimize.DedupePlugin() - ] -} diff --git a/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.test.js b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.test.js index 2d310117db8..64b89af0af3 100644 --- a/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.test.js +++ b/lib/transformations/removeDeprecatedPlugins/removeDeprecatedPlugins.test.js @@ -1,3 +1,5 @@ const defineTest = require('../defineTest'); -defineTest(__dirname, 'removeDeprecatedPlugins'); +defineTest(__dirname, 'removeDeprecatedPlugins', 'removeDeprecatedPlugins-0'); +defineTest(__dirname, 'removeDeprecatedPlugins', 'removeDeprecatedPlugins-1'); +defineTest(__dirname, 'removeDeprecatedPlugins', 'removeDeprecatedPlugins-2'); diff --git a/lib/transformations/removeJsonLoader/__snapshots__/removeJsonLoader.test.js.snap b/lib/transformations/removeJsonLoader/__snapshots__/removeJsonLoader.test.js.snap index 09f7beb2c79..0897d9afd2e 100644 --- a/lib/transformations/removeJsonLoader/__snapshots__/removeJsonLoader.test.js.snap +++ b/lib/transformations/removeJsonLoader/__snapshots__/removeJsonLoader.test.js.snap @@ -1,23 +1,39 @@ -exports[`removeJsonLoader transforms correctly 1`] = ` -"export default [{ +exports[`removeJsonLoader transforms correctly using "removeJsonLoader-0" data 1`] = ` +"export default { module: { rules: [{ test: /\\.yml/, use: [\'another-loader\', \'yml-loader\'] }] } -}, { +} + +" +`; + +exports[`removeJsonLoader transforms correctly using "removeJsonLoader-1" data 1`] = ` +"export default { module: { rules: [{ test: /\\.yml/, use: \'yml-loader\' }] } -}, { +} +" +`; + +exports[`removeJsonLoader transforms correctly using "removeJsonLoader-2" data 1`] = ` +"export default { module: { rules: [] } -}, { +} +" +`; + +exports[`removeJsonLoader transforms correctly using "removeJsonLoader-3" data 1`] = ` +"export default { module: { rules: [{ test: /\\.yml/, @@ -27,7 +43,7 @@ exports[`removeJsonLoader transforms correctly 1`] = ` use: \'yml-loader\' }] } -}]; +} " `; diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-0.input.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-0.input.js new file mode 100644 index 00000000000..f6c9a9da3ab --- /dev/null +++ b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-0.input.js @@ -0,0 +1,9 @@ +export default { + module: { + rules: [{ + test: /\.yml/, + use: ['json-loader', 'another-loader', 'yml-loader'] + }] + } +} + diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-1.input.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-1.input.js new file mode 100644 index 00000000000..05d06f79820 --- /dev/null +++ b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-1.input.js @@ -0,0 +1,8 @@ +export default { + module: { + rules: [{ + test: /\.yml/, + use: ['json-loader', 'yml-loader'] + }] + } +} diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-2.input.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-2.input.js new file mode 100644 index 00000000000..cc35396659d --- /dev/null +++ b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-2.input.js @@ -0,0 +1,10 @@ +export default { + module: { + rules: [ + { + test: /\.json/, + use: 'json-loader' + } + ] + } +} diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-3.input.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-3.input.js new file mode 100644 index 00000000000..247cb56f567 --- /dev/null +++ b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader-3.input.js @@ -0,0 +1,15 @@ +export default { + module: { + rules: [{ + test: /\.yml/, + use: ['json-loader', 'another-loader', 'yml-loader'] + }, { + test: /\.yml/, + use: ['json-loader', 'yml-loader'] + }, { + test: /\.json/, + use: 'json-loader' + }] + } +} + diff --git a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js b/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js deleted file mode 100644 index c2918a5fb3c..00000000000 --- a/lib/transformations/removeJsonLoader/__testfixtures__/removeJsonLoader.input.js +++ /dev/null @@ -1,38 +0,0 @@ -export default [{ - module: { - rules: [{ - test: /\.yml/, - use: ['json-loader', 'another-loader', 'yml-loader'] - }] - } -}, { - module: { - rules: [{ - test: /\.yml/, - use: ['json-loader', 'yml-loader'] - }] - } -}, { - module: { - rules: [ - { - test: /\.json/, - use: 'json-loader' - } - ] - } -}, { - module: { - rules: [{ - test: /\.yml/, - use: ['json-loader', 'another-loader', 'yml-loader'] - }, { - test: /\.yml/, - use: ['json-loader', 'yml-loader'] - }, { - test: /\.json/, - use: 'json-loader' - }] - } -}]; - diff --git a/lib/transformations/removeJsonLoader/removeJsonLoader.test.js b/lib/transformations/removeJsonLoader/removeJsonLoader.test.js index 3ca0f2fec5a..164f0045ee1 100644 --- a/lib/transformations/removeJsonLoader/removeJsonLoader.test.js +++ b/lib/transformations/removeJsonLoader/removeJsonLoader.test.js @@ -1,3 +1,6 @@ const defineTest = require('../defineTest'); -defineTest(__dirname, 'removeJsonLoader'); +defineTest(__dirname, 'removeJsonLoader', 'removeJsonLoader-0'); +defineTest(__dirname, 'removeJsonLoader', 'removeJsonLoader-1'); +defineTest(__dirname, 'removeJsonLoader', 'removeJsonLoader-2'); +defineTest(__dirname, 'removeJsonLoader', 'removeJsonLoader-3'); diff --git a/lib/transformations/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.js.snap b/lib/transformations/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.js.snap index cbff7c2cad5..92ef1d87a12 100644 --- a/lib/transformations/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.js.snap +++ b/lib/transformations/uglifyJsPlugin/__snapshots__/uglifyJsPlugin.test.js.snap @@ -1,4 +1,4 @@ -exports[`uglifyJsPlugin transforms correctly 1`] = ` +exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-0" data 1`] = ` "module.exports = { plugins: [ new webpack.optimize.UglifyJsPlugin({ @@ -6,8 +6,11 @@ exports[`uglifyJsPlugin transforms correctly 1`] = ` }) ] } +" +`; -module.exports = { +exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-1" data 1`] = ` +"module.exports = { devtool: \"source-map\", plugins: [ new webpack.optimize.UglifyJsPlugin({ @@ -15,8 +18,11 @@ module.exports = { }) ] } +" +`; -module.exports = { +exports[`uglifyJsPlugin transforms correctly using "uglifyJsPlugin-2" data 1`] = ` +"module.exports = { devtool: \"cheap-source-map\", plugins: [ new webpack.optimize.UglifyJsPlugin({ diff --git a/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-0.input.js b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-0.input.js new file mode 100644 index 00000000000..900f7042075 --- /dev/null +++ b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-0.input.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + new webpack.optimize.UglifyJsPlugin() + ] +} diff --git a/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-1.input.js b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-1.input.js new file mode 100644 index 00000000000..57d7eb1c192 --- /dev/null +++ b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-1.input.js @@ -0,0 +1,6 @@ +module.exports = { + devtool: "source-map", + plugins: [ + new webpack.optimize.UglifyJsPlugin({}) + ] +} diff --git a/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-2.input.js b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-2.input.js new file mode 100644 index 00000000000..3c13f02b203 --- /dev/null +++ b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin-2.input.js @@ -0,0 +1,8 @@ +module.exports = { + devtool: "cheap-source-map", + plugins: [ + new webpack.optimize.UglifyJsPlugin({ + compress: {} + }) + ] +} diff --git a/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.input.js b/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.input.js deleted file mode 100644 index da8cf793523..00000000000 --- a/lib/transformations/uglifyJsPlugin/__testfixtures__/uglifyJsPlugin.input.js +++ /dev/null @@ -1,21 +0,0 @@ -module.exports = { - plugins: [ - new webpack.optimize.UglifyJsPlugin() - ] -} - -module.exports = { - devtool: "source-map", - plugins: [ - new webpack.optimize.UglifyJsPlugin({}) - ] -} - -module.exports = { - devtool: "cheap-source-map", - plugins: [ - new webpack.optimize.UglifyJsPlugin({ - compress: {} - }) - ] -} diff --git a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.test.js b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.test.js index a1e96e08b47..a0c309ccb1e 100644 --- a/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.test.js +++ b/lib/transformations/uglifyJsPlugin/uglifyJsPlugin.test.js @@ -1,3 +1,5 @@ const defineTest = require('../defineTest'); -defineTest(__dirname, 'uglifyJsPlugin'); +defineTest(__dirname, 'uglifyJsPlugin', 'uglifyJsPlugin-0'); +defineTest(__dirname, 'uglifyJsPlugin', 'uglifyJsPlugin-1'); +defineTest(__dirname, 'uglifyJsPlugin', 'uglifyJsPlugin-2'); From 6f04f3d97de0e94047544991c56cb2d9786dc588 Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 18:05:51 +0100 Subject: [PATCH 36/43] Added tests and fixed some edge cases in BannerPlugin --- .../__snapshots__/bannerPlugin.test.js.snap | 20 ++++++++++++++++++- ...lugin.input.js => bannerPlugin-0.input.js} | 0 .../__testfixtures__/bannerPlugin-1.input.js | 4 ++++ .../__testfixtures__/bannerPlugin-2.input.js | 6 ++++++ .../bannerPlugin/bannerPlugin.js | 16 ++++++--------- .../bannerPlugin/bannerPlugin.test.js | 4 +++- 6 files changed, 38 insertions(+), 12 deletions(-) rename lib/transformations/bannerPlugin/__testfixtures__/{bannerPlugin.input.js => bannerPlugin-0.input.js} (100%) create mode 100644 lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-1.input.js create mode 100644 lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-2.input.js diff --git a/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap b/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap index 4d2e8d18219..8eb8caf991e 100644 --- a/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap +++ b/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap @@ -1,4 +1,4 @@ -exports[`bannerPlugin transforms correctly 1`] = ` +exports[`bannerPlugin transforms correctly using "bannerPlugin-0" data 1`] = ` "module.exports = { plugins: [ new webpack.BannerPlugin({ @@ -10,3 +10,21 @@ exports[`bannerPlugin transforms correctly 1`] = ` } " `; + +exports[`bannerPlugin transforms correctly using "bannerPlugin-1" data 1`] = ` +"// Should do nothing if there is no banner plugin +module.exports = { + plugins: [] +} +" +`; + +exports[`bannerPlugin transforms correctly using "bannerPlugin-2" data 1`] = ` +"// Only transform if it uses the old format +module.exports = { + plugins: [ + new webpack.BannerPlugin({}) + ] +} +" +`; diff --git a/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin.input.js b/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-0.input.js similarity index 100% rename from lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin.input.js rename to lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-0.input.js diff --git a/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-1.input.js b/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-1.input.js new file mode 100644 index 00000000000..0d66b9de1ac --- /dev/null +++ b/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-1.input.js @@ -0,0 +1,4 @@ +// Should do nothing if there is no banner plugin +module.exports = { + plugins: [] +} diff --git a/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-2.input.js b/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-2.input.js new file mode 100644 index 00000000000..90ecde8f0de --- /dev/null +++ b/lib/transformations/bannerPlugin/__testfixtures__/bannerPlugin-2.input.js @@ -0,0 +1,6 @@ +// Only transform if it uses the old format +module.exports = { + plugins: [ + new webpack.BannerPlugin({}) + ] +} diff --git a/lib/transformations/bannerPlugin/bannerPlugin.js b/lib/transformations/bannerPlugin/bannerPlugin.js index 5f900067847..9f40d172f7d 100644 --- a/lib/transformations/bannerPlugin/bannerPlugin.js +++ b/lib/transformations/bannerPlugin/bannerPlugin.js @@ -1,23 +1,19 @@ const utils = require('../utils'); module.exports = function(j, ast) { - const loaderOptions = {}; - - utils.findPluginsByName(j, ast, ['webpack.BannerPlugin']) + return utils.findPluginsByName(j, ast, ['webpack.BannerPlugin']) .forEach(path => { const args = path.value.arguments; - // If the first argument is a literal - // replace it with object notation + // 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) { - loaderOptions.banner = args[0].value; // and remove the first argument path.value.arguments = [path.value.arguments[1]]; + utils.createOrUpdatePluginByName(j, path.parent, 'webpack.BannerPlugin', { + banner: args[0].value + }); } }); - return utils.findPluginsRootNodes(j, ast) - .forEach(path => { - utils.createOrUpdatePluginByName(j, path, 'webpack.BannerPlugin', loaderOptions); - }); + }; diff --git a/lib/transformations/bannerPlugin/bannerPlugin.test.js b/lib/transformations/bannerPlugin/bannerPlugin.test.js index b04cd99f5cb..fee919e427e 100644 --- a/lib/transformations/bannerPlugin/bannerPlugin.test.js +++ b/lib/transformations/bannerPlugin/bannerPlugin.test.js @@ -1,3 +1,5 @@ const defineTest = require('../defineTest'); -defineTest(__dirname, 'bannerPlugin'); +defineTest(__dirname, 'bannerPlugin', 'bannerPlugin-0'); +defineTest(__dirname, 'bannerPlugin', 'bannerPlugin-1'); +defineTest(__dirname, 'bannerPlugin', 'bannerPlugin-2'); From 4223c3af2bd79d08732b575a7594599390fc960f Mon Sep 17 00:00:00 2001 From: Andrey Okonetchnikov Date: Wed, 15 Feb 2017 18:11:33 +0100 Subject: [PATCH 37/43] Introduce and export `transform` function It takes source and array of transformations and returns the new source code. Added "integration" tests. --- lib/migrate.js | 34 +++--- .../__snapshots__/index.test.js.snap | 100 ++++++++++++++++++ lib/transformations/index.js | 34 +++++- lib/transformations/index.test.js | 56 ++++++++++ 4 files changed, 205 insertions(+), 19 deletions(-) create mode 100644 lib/transformations/__snapshots__/index.test.js.snap create mode 100644 lib/transformations/index.test.js diff --git a/lib/migrate.js b/lib/migrate.js index 0ced71a064d..b9612a358ec 100644 --- a/lib/migrate.js +++ b/lib/migrate.js @@ -2,34 +2,36 @@ const fs = require('fs'); const jscodeshift = require('jscodeshift'); const diff = require('diff'); const chalk = require('chalk'); -const transformations = require('./transformations'); +const transform = require('./transformations').transform; const inquirer = require('inquirer'); module.exports = (currentConfigLoc, outputConfigLoc) => { let currentConfig = fs.readFileSync(currentConfigLoc, 'utf8'); - let ast = jscodeshift(currentConfig); - let transformNames = Object.keys(transformations); - transformNames.forEach(key => transformations[key](jscodeshift, ast)); - const outputConfig = ast.toSource(); + const outputConfig = transform(currentConfig); const diffOutput = diff.diffLines(currentConfig, outputConfig); diffOutput.map(diffLine => { - if(diffLine.added) { + if (diffLine.added) { process.stdout.write(chalk.green(`+ ${diffLine.value}`)); - } else if(diffLine.removed){ + } else if (diffLine.removed) { process.stdout.write(chalk.red(`- ${diffLine.value}`)); } }); - inquirer.prompt([{ - type: 'confirm', - name: 'confirmMigration', - message: 'Are you sure these changes are fine?', - default: 'Y'}]).then(answers => { - if(answers['confirmMigration']){ - // TODO validate the config + inquirer + .prompt([ + { + type: 'confirm', + name: 'confirmMigration', + message: 'Are you sure these changes are fine?', + default: 'Y' + } + ]) + .then(answers => { + if (answers['confirmMigration']) { + // TODO validate the config fs.writeFileSync(outputConfigLoc, outputConfig, 'utf8'); process.stdout.write(chalk.green(`Congratulations! Your new webpack v2 config file is at ${outputConfigLoc}`)); } else { - process.stdout.write(chalk.yellow('You aborted the migration')); + process.stdout.write(chalk.yellow('Migration aborted')); } }); -}; \ No newline at end of file +}; diff --git a/lib/transformations/__snapshots__/index.test.js.snap b/lib/transformations/__snapshots__/index.test.js.snap new file mode 100644 index 00000000000..ec9de1ff3f7 --- /dev/null +++ b/lib/transformations/__snapshots__/index.test.js.snap @@ -0,0 +1,100 @@ +exports[`transform should respect recast options 1`] = ` +" +module.exports = { + devtool: \'eval\', + entry: [ + \'./src/index\' + ], + output: { + path: path.join(__dirname, \'dist\'), + filename: \'index.js\' + }, + module: { + rules: [{ + test: /.js$/, + use: \"babel\", + include: path.join(__dirname, \'src\') + }] + }, + resolve: { + modules: [\'node_modules\', path.resolve(\'/src\')], + }, + plugins: [ + new webpack.optimize.UglifyJsPlugin({ + sourceMap: true, + }), + new webpack.optimize.LoaderOptionsPlugin({ + \"debug\": true, + \"minimize\": true, + }) + ], + debug: true +}; +" +`; + +exports[`transform should transform only using specified transformations 1`] = ` +" +module.exports = { + devtool: \'eval\', + entry: [ + \'./src/index\' + ], + output: { + path: path.join(__dirname, \'dist\'), + filename: \'index.js\' + }, + module: { + rules: [{ + test: /.js$/, + use: [\'babel\'], + include: path.join(__dirname, \'src\') + }] + }, + resolve: { + root: path.resolve(\'/src\'), + modules: [\'node_modules\'] + }, + plugins: [ + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.OccurrenceOrderPlugin() + ], + debug: true +}; +" +`; + +exports[`transform should transform using all transformations 1`] = ` +" +module.exports = { + devtool: \'eval\', + entry: [ + \'./src/index\' + ], + output: { + path: path.join(__dirname, \'dist\'), + filename: \'index.js\' + }, + module: { + rules: [{ + test: /.js$/, + use: \'babel\', + include: path.join(__dirname, \'src\') + }] + }, + resolve: { + modules: [\'node_modules\', path.resolve(\'/src\')] + }, + plugins: [ + new webpack.optimize.UglifyJsPlugin({ + sourceMap: true + }), + new webpack.optimize.LoaderOptionsPlugin({ + \'debug\': true, + \'minimize\': true + }) + ], + debug: true +}; +" +`; diff --git a/lib/transformations/index.js b/lib/transformations/index.js index 7135d992add..38d42103b11 100644 --- a/lib/transformations/index.js +++ b/lib/transformations/index.js @@ -1,4 +1,6 @@ -const loaderTransform = require('./loaders/loaders'); +const jscodeshift = require('jscodeshift'); + +const loadersTransform = require('./loaders/loaders'); const resolveTransform = require('./resolve/resolve'); const removeJsonLoaderTransform = require('./removeJsonLoader/removeJsonLoader'); const uglifyJsPluginTransform = require('./uglifyJsPlugin/uglifyJsPlugin'); @@ -7,8 +9,8 @@ const bannerPluginTransform = require('./bannerPlugin/bannerPlugin'); const extractTextPluginTransform = require('./extractTextPlugin/extractTextPlugin'); const removeDeprecatedPluginsTransform = require('./removeDeprecatedPlugins/removeDeprecatedPlugins'); -module.exports = { - loaderTransform, +const transformations = { + loadersTransform, resolveTransform, removeJsonLoaderTransform, uglifyJsPluginTransform, @@ -17,3 +19,29 @@ module.exports = { extractTextPluginTransform, removeDeprecatedPluginsTransform }; + +/* +* @function transform +* +* Tranforms a given source code by applying selected transformations to the AST +* +* @param { String } source - Source file contents +* @param { Array } transformations - List of trnasformation functions in defined the +* order to apply. By default all defined transfomations. +* @param { Object } options - Reacst formatting options +* @returns { String } Transformed source code +* */ +function transform(source, transforms, options) { + const ast = jscodeshift(source); + const recastOptions = Object.assign({ + quote: 'single' + }, options); + transforms = transforms || Object.keys(transformations).map(k => transformations[k]); + transforms.forEach(f => f(jscodeshift, ast)); + return ast.toSource(recastOptions); +} + +module.exports = { + transform, + transformations +}; diff --git a/lib/transformations/index.test.js b/lib/transformations/index.test.js new file mode 100644 index 00000000000..6058db357b7 --- /dev/null +++ b/lib/transformations/index.test.js @@ -0,0 +1,56 @@ +const transform = require('./index').transform; +const transformations = require('./index').transformations; + +const input = ` +module.exports = { + devtool: 'eval', + entry: [ + './src/index' + ], + output: { + path: path.join(__dirname, 'dist'), + filename: 'index.js' + }, + module: { + loaders: [{ + test: /\.js$/, + loaders: ['babel'], + include: path.join(__dirname, 'src') + }] + }, + resolve: { + root: path.resolve('/src'), + modules: ['node_modules'] + }, + plugins: [ + new webpack.optimize.UglifyJsPlugin(), + new webpack.optimize.OccurrenceOrderPlugin() + ], + debug: true +}; +`; + +describe('transform', () => { + it('should not transform if no transformations defined', () => { + const output = transform(input, []); + expect(output).toEqual(input); + }); + + it('should transform using all transformations', () => { + const output = transform(input); + expect(output).toMatchSnapshot(); + }); + + it('should transform only using specified transformations', () => { + const output = transform(input, [transformations.loadersTransform]); + expect(output).toMatchSnapshot(); + }); + + it('should respect recast options', () => { + const output = transform(input, undefined, { + quote: 'double', + trailingComma: true + }); + expect(output).toMatchSnapshot(); + }); +}); From 067f71ad5c0a9f4966ee45f80500aa88f87087f9 Mon Sep 17 00:00:00 2001 From: Pavithra K Date: Sun, 19 Feb 2017 20:38:56 +0530 Subject: [PATCH 38/43] Adds new utils and tests --- .../__snapshots__/index.test.js.snap | 8 ++-- .../__snapshots__/utils.test.js.snap | 21 +++++----- .../__snapshots__/bannerPlugin.test.js.snap | 2 +- .../extractTextPlugin/extractTextPlugin.js | 31 +++++++-------- .../loaderOptionsPlugin.test.js.snap | 4 +- .../__snapshots__/loaders.test.js.snap | 2 - lib/transformations/utils.js | 38 ++++++++++++++++++- lib/transformations/utils.test.js | 16 +++++++- 8 files changed, 81 insertions(+), 41 deletions(-) diff --git a/lib/transformations/__snapshots__/index.test.js.snap b/lib/transformations/__snapshots__/index.test.js.snap index ec9de1ff3f7..a64a0ff4044 100644 --- a/lib/transformations/__snapshots__/index.test.js.snap +++ b/lib/transformations/__snapshots__/index.test.js.snap @@ -24,8 +24,8 @@ module.exports = { sourceMap: true, }), new webpack.optimize.LoaderOptionsPlugin({ - \"debug\": true, - \"minimize\": true, + debug: true, + minimize: true, }) ], debug: true @@ -90,8 +90,8 @@ module.exports = { sourceMap: true }), new webpack.optimize.LoaderOptionsPlugin({ - \'debug\': true, - \'minimize\': true + debug: true, + minimize: true }) ], debug: true diff --git a/lib/transformations/__snapshots__/utils.test.js.snap b/lib/transformations/__snapshots__/utils.test.js.snap index d7e2da8c4b2..32bd1edc795 100644 --- a/lib/transformations/__snapshots__/utils.test.js.snap +++ b/lib/transformations/__snapshots__/utils.test.js.snap @@ -1,12 +1,12 @@ exports[`utils createOrUpdatePluginByName should add an object as an argument 1`] = ` "[new Plugin({ - \"foo\": true + foo: true })]" `; exports[`utils createOrUpdatePluginByName should create a new plugin with arguments 1`] = ` "{ plugins: [new Plugin({ - \"foo\": \"bar\" + foo: \"bar\" })] }" `; @@ -14,38 +14,39 @@ exports[`utils createOrUpdatePluginByName should create a new plugin without arg exports[`utils createOrUpdatePluginByName should merge options objects 1`] = ` "[new Plugin({ - \"foo\": false, - \"bar\": \"baz\", - \"baz-long\": true + foo: true, + bar: \"baz\", + foo: false, + baz-long: true })]" `; exports[`utils createProperty should create properties for Boolean 1`] = ` "{ - \"foo\": true + foo: true }" `; exports[`utils createProperty should create properties for Number 1`] = ` "{ - \"foo\": -1 + foo: -1 }" `; exports[`utils createProperty should create properties for String 1`] = ` "{ - \"foo\": \"bar\" + foo: \"bar\" }" `; exports[`utils createProperty should create properties for complex keys 1`] = ` "{ - \"foo-bar\": \"bar\" + foo-bar: \"bar\" }" `; exports[`utils createProperty should create properties for non-literal keys 1`] = ` "{ - 1: \"bar\" + 1: "bar" }" `; diff --git a/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap b/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap index 8eb8caf991e..d1317edc715 100644 --- a/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap +++ b/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap @@ -4,7 +4,7 @@ exports[`bannerPlugin transforms correctly using "bannerPlugin-0" data 1`] = ` new webpack.BannerPlugin({ raw: true, entryOnly: true, - \'banner\': \'Banner\' + banner: \'Banner\' }) ] } diff --git a/lib/transformations/extractTextPlugin/extractTextPlugin.js b/lib/transformations/extractTextPlugin/extractTextPlugin.js index 3fd4ede49ff..fd7ff350af0 100644 --- a/lib/transformations/extractTextPlugin/extractTextPlugin.js +++ b/lib/transformations/extractTextPlugin/extractTextPlugin.js @@ -1,5 +1,10 @@ -const safeTraverse = require('../utils').safeTraverse; -const findPluginsByName = require('../utils').findPluginsByName; +const utils = require('../utils'); + +function findInvocation(j, node, pluginName) { + return j(node) + .find(j.MemberExpression) + .filter(p => p.get('object').value.name === pluginName).size() > 0; +} module.exports = function(j, ast) { const changeArguments = function(p) { @@ -7,31 +12,21 @@ module.exports = function(j, ast) { // if(args.length === 1) { // return p; // } else - const literalArgs = args.filter(p => p.type === 'Literal'); + const literalArgs = args.filter(p => utils.isType('Literal')); if (literalArgs && literalArgs.length > 1) { const newArgs = j.objectExpression(literalArgs.map((p, index) => - j.property('init', - j.identifier(index === 0 ? 'fallback': 'use'), - j.literal(p.value) - ) + utils.createProperty(j, index === 0 ? 'fallback': 'use', p.value) )); p.value.arguments = [newArgs]; } - console.log(p.value.arguments); return p; }; - const name = getName(j, ast, 'extract-text-webpack-plugin'); + const name = utils.findVariableToPlugin(j, ast, 'extract-text-webpack-plugin'); + if(!name) return ast; + return ast.find(j.CallExpression) - .filter(p => p.value.callee.object) - .filter(p => p.value.callee.object.name === name) + .filter(p => findInvocation(j, p, name)) .forEach(changeArguments); - //.forEach(p => console.log(p.toSource())); - - //return ast.toSource({ quote: 'single' }); -}; - -const getName = function(j, ast, pkgName){ - return 'ExtractTextPlugin'; }; diff --git a/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap b/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap index db38d48df07..0d3e03ea0af 100644 --- a/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap +++ b/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap @@ -5,8 +5,8 @@ exports[`loaderOptionsPlugin transforms correctly 1`] = ` new webpack.optimize.UglifyJsPlugin(), new webpack.optimize.LoaderOptionsPlugin({ foo: \'bar\', - \'debug\': true, - \'minimize\': true + debug: true, + minimize: true }) ] } diff --git a/lib/transformations/loaders/__snapshots__/loaders.test.js.snap b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap index 25abb68c9ed..28739e546f7 100644 --- a/lib/transformations/loaders/__snapshots__/loaders.test.js.snap +++ b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap @@ -14,7 +14,6 @@ exports[`loaders transforms correctly using "loaders-0" data 1`] = ` loader: \'style-loader\' }, { loader: \'css-loader\', - options: { modules: true, importLoaders: 1, @@ -88,7 +87,6 @@ exports[`loaders transforms correctly using "loaders-1" data 1`] = ` loader: \'style-loader\' }, { loader: \'css-loader\', - options: { modules: true, importLoaders: 1, diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index 12135ee3d4a..4ed7dc8783d 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -83,7 +83,7 @@ function findPluginsRootNodes(j, node) { function createProperty(j, key, value) { return j.property( 'init', - j.literal(key), + j.identifier(key), j.literal(value) ); } @@ -160,10 +160,44 @@ function createOrUpdatePluginByName(j, rootNodePath, pluginName, options) { } } +/* + * @function findVariableToPlugin + * + * Finds the variable to which a third party plugin is assigned to + * + * @param 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. 'var s = require(s) gives "s"` + * */ + +function findVariableToPlugin(j, rootNode, pluginPackageName){ + const moduleVarNames = rootNode.find(j.VariableDeclarator) + .filter(j.filters.VariableDeclarator.requiresModule(pluginPackageName)) + .nodes(); + if (moduleVarNames.length === 0) return null; + return moduleVarNames.pop().id.name; +} + +/* +* @function isType +* +* Returns true if type is given type +* @param { Node} path - pathNode +* @param { string } type - node type +* @returns {boolean} +*/ + +function isType(path, type) { + return path.type === type; +} + module.exports = { safeTraverse, createProperty, findPluginsByName, findPluginsRootNodes, - createOrUpdatePluginByName + createOrUpdatePluginByName, + findVariableToPlugin, + isType }; diff --git a/lib/transformations/utils.test.js b/lib/transformations/utils.test.js index 9bbe82c1988..6cbb6b1d8ca 100644 --- a/lib/transformations/utils.test.js +++ b/lib/transformations/utils.test.js @@ -23,7 +23,7 @@ describe('utils', () => { expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); }); - it('should create properties for non-literal keys', () => { + xit('should create properties for non-literal keys', () => { const res = utils.createProperty(j, 1, 'bar'); expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); }); @@ -42,7 +42,7 @@ describe('utils', () => { it('should find all plugins in AST', () => { const ast = j(` [ - new UglifyJsPlugin(), + new UglifyJsPlugin(), new TestPlugin() ] `); @@ -121,4 +121,16 @@ var a = { plugs: [] } expect(ast.toSource()).toMatchSnapshot(); }); }); + + describe('findVariableToPlugin', () => { + it('should find the variable name of a plugin', () => { + const ast = j(` + var packageName = require('package-name'); + var someOtherVar = somethingElse; + var otherPackage = require('other-package'); + `); + const foundVar = utils.findVariableToPlugin(j, ast, 'other-package'); + expect(foundVar).toEqual('otherPackage'); + }); + }); }); From 99e99cdf3b86c4bae0ee1dd9dbe27018a4c27446 Mon Sep 17 00:00:00 2001 From: Pavithra K Date: Sun, 19 Feb 2017 20:57:39 +0530 Subject: [PATCH 39/43] Refactors loaders transforms --- .../__snapshots__/index.test.js.snap | 8 ++-- .../__snapshots__/utils.test.js.snap | 39 ++++++++++++++----- .../__snapshots__/bannerPlugin.test.js.snap | 2 +- .../extractTextPlugin.test.js.snap | 4 +- .../loaderOptionsPlugin.test.js.snap | 4 +- .../__snapshots__/loaders.test.js.snap | 18 ++------- lib/transformations/loaders/loaders.js | 33 ++++------------ lib/transformations/utils.js | 32 +++++++++++++-- lib/transformations/utils.test.js | 13 ++++++- 9 files changed, 90 insertions(+), 63 deletions(-) diff --git a/lib/transformations/__snapshots__/index.test.js.snap b/lib/transformations/__snapshots__/index.test.js.snap index a64a0ff4044..ec9de1ff3f7 100644 --- a/lib/transformations/__snapshots__/index.test.js.snap +++ b/lib/transformations/__snapshots__/index.test.js.snap @@ -24,8 +24,8 @@ module.exports = { sourceMap: true, }), new webpack.optimize.LoaderOptionsPlugin({ - debug: true, - minimize: true, + \"debug\": true, + \"minimize\": true, }) ], debug: true @@ -90,8 +90,8 @@ module.exports = { sourceMap: true }), new webpack.optimize.LoaderOptionsPlugin({ - debug: true, - minimize: true + \'debug\': true, + \'minimize\': true }) ], debug: true diff --git a/lib/transformations/__snapshots__/utils.test.js.snap b/lib/transformations/__snapshots__/utils.test.js.snap index 32bd1edc795..f70e77f3217 100644 --- a/lib/transformations/__snapshots__/utils.test.js.snap +++ b/lib/transformations/__snapshots__/utils.test.js.snap @@ -1,12 +1,32 @@ +exports[`utils createLiteral should create basic literal 1`] = ` +Object { + "comments": null, + "loc": null, + "regex": null, + "type": "Literal", + "value": "strintLiteral", +} +`; + +exports[`utils createLiteral should create boolean 1`] = ` +Object { + "comments": null, + "loc": null, + "regex": null, + "type": "Literal", + "value": true, +} +`; + exports[`utils createOrUpdatePluginByName should add an object as an argument 1`] = ` "[new Plugin({ - foo: true + \"foo\": true })]" `; exports[`utils createOrUpdatePluginByName should create a new plugin with arguments 1`] = ` "{ plugins: [new Plugin({ - foo: \"bar\" + \"foo\": \"bar\" })] }" `; @@ -14,34 +34,33 @@ exports[`utils createOrUpdatePluginByName should create a new plugin without arg exports[`utils createOrUpdatePluginByName should merge options objects 1`] = ` "[new Plugin({ - foo: true, - bar: \"baz\", - foo: false, - baz-long: true + \"foo\": false, + \"bar\": \"baz\", + \"baz-long\": true })]" `; exports[`utils createProperty should create properties for Boolean 1`] = ` "{ - foo: true + \"foo\": true }" `; exports[`utils createProperty should create properties for Number 1`] = ` "{ - foo: -1 + \"foo\": -1 }" `; exports[`utils createProperty should create properties for String 1`] = ` "{ - foo: \"bar\" + \"foo\": \"bar\" }" `; exports[`utils createProperty should create properties for complex keys 1`] = ` "{ - foo-bar: \"bar\" + \"foo-bar\": \"bar\" }" `; diff --git a/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap b/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap index d1317edc715..8eb8caf991e 100644 --- a/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap +++ b/lib/transformations/bannerPlugin/__snapshots__/bannerPlugin.test.js.snap @@ -4,7 +4,7 @@ exports[`bannerPlugin transforms correctly using "bannerPlugin-0" data 1`] = ` new webpack.BannerPlugin({ raw: true, entryOnly: true, - banner: \'Banner\' + \'banner\': \'Banner\' }) ] } diff --git a/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap b/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap index 28784339e3d..1f46321cc33 100644 --- a/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap +++ b/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap @@ -10,8 +10,8 @@ module.export = { { test: /\\.css$/, use: ExtractTextPlugin.extract({ - fallback: \'style-loader\', - use: \'css-loader\' + \'fallback\': \'style-loader\', + \'use\': \'css-loader\' }) } ] diff --git a/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap b/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap index 0d3e03ea0af..db38d48df07 100644 --- a/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap +++ b/lib/transformations/loaderOptionsPlugin/__snapshots__/loaderOptionsPlugin.test.js.snap @@ -5,8 +5,8 @@ exports[`loaderOptionsPlugin transforms correctly 1`] = ` new webpack.optimize.UglifyJsPlugin(), new webpack.optimize.LoaderOptionsPlugin({ foo: \'bar\', - debug: true, - minimize: true + \'debug\': true, + \'minimize\': true }) ] } diff --git a/lib/transformations/loaders/__snapshots__/loaders.test.js.snap b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap index 28739e546f7..08f90d49c2a 100644 --- a/lib/transformations/loaders/__snapshots__/loaders.test.js.snap +++ b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap @@ -11,14 +11,9 @@ exports[`loaders transforms correctly using "loaders-0" data 1`] = ` rules: [{ test: /\\.css$/, use: [{ - loader: \'style-loader\' + \'loader\': \'style\' }, { - loader: \'css-loader\', - options: { - modules: true, - importLoaders: 1, - string: \'test123\' - } + \'loader\': \'css?modules&importLoaders=1&string=test123\' }] }] } @@ -84,14 +79,9 @@ exports[`loaders transforms correctly using "loaders-1" data 1`] = ` rules: [{ test: /\\.css$/, use: [{ - loader: \'style-loader\' + \'loader\': \'style\' }, { - loader: \'css-loader\', - options: { - modules: true, - importLoaders: 1, - string: \'test123\' - } + \'loader\': \'css?modules&importLoaders=1&string=test123\' }] }] } diff --git a/lib/transformations/loaders/loaders.js b/lib/transformations/loaders/loaders.js index 4c2f089bb65..1490ee17a56 100644 --- a/lib/transformations/loaders/loaders.js +++ b/lib/transformations/loaders/loaders.js @@ -1,34 +1,17 @@ -const safeTraverse = require('../utils').safeTraverse; +const utils = require('../utils'); module.exports = function(j, ast) { const createArrayExpression = function(p) { let objs = p.parent.node.value.value.split('!') .map(val => j.objectExpression([ - j.property('init', - j.identifier('loader'), - j.literal(val) - ) + utils.createProperty(j, 'loader', val) ])); let loaderArray = j.arrayExpression(objs); p.parent.node.value = loaderArray; return p; }; - const createLiteral = val => { - let literalVal = val; - // We'll need String to native type conversions - if (typeof val === 'string') { - // 'true' => true - if (val === 'true') literalVal = true; - // 'false' => false - if (val === 'false') literalVal = false; - // '1' => 1 - if (!isNaN(Number(val))) literalVal = Number(val); - } - return j.literal(literalVal); - }; - const createLoaderWithQuery = p => { let properties = p.value.properties; let loaderValue = properties @@ -39,9 +22,9 @@ module.exports = function(j, ast) { const param = option.split('='); const key = param[0]; const val = param[1] || true; // No value in query string means it is truthy value - return j.objectProperty(j.identifier(key), createLiteral(val)); + return j.objectProperty(j.identifier(key), utils.createLiteral(val)); }); - let loaderProp = j.property('init', j.identifier('loader'), j.literal(loader)); + let loaderProp = utils.createProperty(j, 'loader', loader); let queryProp = j.property('init', j.identifier('options'), j.objectExpression(options)); return j.objectExpression([loaderProp, queryProp]); }; @@ -66,13 +49,13 @@ module.exports = function(j, ast) { const findLoaderWithQueryString = p => { return p.value.properties .reduce((predicate, prop) => { - return safeTraverse(prop, ['value', 'value', 'indexOf']) + return utils.safeTraverse(prop, ['value', 'value', 'indexOf']) && prop.value.value.indexOf('?') > -1 || predicate; }, false); }; - const checkForLoader = p => p.value.name === 'loaders' && safeTraverse(p, + const checkForLoader = p => p.value.name === 'loaders' && utils.safeTraverse(p, ['parent', 'parent', 'parent', 'node', 'key', 'name']) === 'module'; const fitIntoLoaders = p => { @@ -120,7 +103,7 @@ module.exports = function(j, ast) { .find(j.Identifier) .filter(p => { return (p.value.name === 'loaders' || p.value.name === 'loader') - && safeTraverse(p, + && utils.safeTraverse(p, ['parent', 'parent', 'parent', 'parent', 'node', 'key', 'name']) === 'rules'; }) .forEach(p => p.value.name = 'use'); @@ -150,7 +133,7 @@ module.exports = function(j, ast) { .forEach(path => { path.value.properties.forEach(prop => { if ((prop.key.name === 'loader' || prop.key.name === 'use') - && safeTraverse(prop, ['value', 'value']) + && utils.safeTraverse(prop, ['value', 'value']) && prop.value.value.indexOf('-loader') === -1) { prop.value = j.literal(prop.value.value + '-loader'); } diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index 4ed7dc8783d..9dcc24b8adf 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -73,7 +73,6 @@ function findPluginsRootNodes(j, node) { * @function createProperty * * Creates an Object's property with a given key and value - * Note: For now it always create a literal (String) for keys. * * @param j — jscodeshift API * @param { string | number } key - Property key @@ -83,11 +82,35 @@ function findPluginsRootNodes(j, node) { function createProperty(j, key, value) { return j.property( 'init', - j.identifier(key), - j.literal(value) + createLiteral(j, key), + createLiteral(j, value) ); } +/* + * @function createLiteral + * + * Creates an appropriate literal property + * + * @param j — jscodeshift API + * @param { string | boolean | number } val + * @returns { Node } + * */ + +function createLiteral(j, val) { + let literalVal = val; + // We'll need String to native type conversions + if (typeof val === 'string') { + // 'true' => true + if (val === 'true') literalVal = true; + // 'false' => false + if (val === 'false') literalVal = false; + // '1' => 1 + if (!isNaN(Number(val))) literalVal = Number(val); + } + return j.literal(literalVal); +} + /* * @function createOrUpdatePluginByName * @@ -199,5 +222,6 @@ module.exports = { findPluginsRootNodes, createOrUpdatePluginByName, findVariableToPlugin, - isType + isType, + createLiteral }; diff --git a/lib/transformations/utils.test.js b/lib/transformations/utils.test.js index 6cbb6b1d8ca..122c2e7878c 100644 --- a/lib/transformations/utils.test.js +++ b/lib/transformations/utils.test.js @@ -23,7 +23,7 @@ describe('utils', () => { expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); }); - xit('should create properties for non-literal keys', () => { + it('should create properties for non-literal keys', () => { const res = utils.createProperty(j, 1, 'bar'); expect(j(j.objectExpression([res])).toSource()).toMatchSnapshot(); }); @@ -133,4 +133,15 @@ var a = { plugs: [] } expect(foundVar).toEqual('otherPackage'); }); }); + + describe('createLiteral', () => { + it('should create basic literal', () => { + const literal = utils.createLiteral(j, 'strintLiteral'); + expect(literal).toMatchSnapshot(); + }); + it('should create boolean', () => { + const literal = utils.createLiteral(j, 'true'); + expect(literal).toMatchSnapshot(); + }); + }); }); From 3e064b42c0a11f1ad7396e268c991f3c8bf0c96e Mon Sep 17 00:00:00 2001 From: Pavithra K Date: Sun, 19 Feb 2017 21:20:08 +0530 Subject: [PATCH 40/43] Adds more refactoring --- .../__snapshots__/utils.test.js.snap | 2 +- .../__snapshots__/loaders.test.js.snap | 16 ++++++------ lib/transformations/loaders/loaders.js | 25 +++---------------- lib/transformations/utils.js | 12 ++++++++- lib/transformations/utils.test.js | 13 ++++++++++ 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/lib/transformations/__snapshots__/utils.test.js.snap b/lib/transformations/__snapshots__/utils.test.js.snap index f70e77f3217..f245f10773c 100644 --- a/lib/transformations/__snapshots__/utils.test.js.snap +++ b/lib/transformations/__snapshots__/utils.test.js.snap @@ -66,6 +66,6 @@ exports[`utils createProperty should create properties for complex keys 1`] = ` exports[`utils createProperty should create properties for non-literal keys 1`] = ` "{ - 1: "bar" + 1: \"bar\" }" `; diff --git a/lib/transformations/loaders/__snapshots__/loaders.test.js.snap b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap index 08f90d49c2a..4df1f857b19 100644 --- a/lib/transformations/loaders/__snapshots__/loaders.test.js.snap +++ b/lib/transformations/loaders/__snapshots__/loaders.test.js.snap @@ -36,7 +36,7 @@ exports[`loaders transforms correctly using "loaders-0" data 1`] = ` rules:[{ test: /\\.js$/, use: \'eslint-loader\', - enforce: \'pre\' + \'enforce\': \'pre\' }] } }, { @@ -44,7 +44,7 @@ exports[`loaders transforms correctly using "loaders-0" data 1`] = ` rules:[{ test: /\\.js$/, use: \'my-post-loader\', - enforce: \'post\' + \'enforce\': \'post\' }] } }, { @@ -55,7 +55,7 @@ exports[`loaders transforms correctly using "loaders-0" data 1`] = ` }, { test: /\\.js$/, use: \'eslint-loader\', - enforce: \'pre\' + \'enforce\': \'pre\' }] } }, { @@ -66,7 +66,7 @@ exports[`loaders transforms correctly using "loaders-0" data 1`] = ` }, { test: /\\.js$/, use: \'my-post-loader\', - enforce: \'post\' + \'enforce\': \'post\' }] } }]; @@ -114,7 +114,7 @@ exports[`loaders transforms correctly using "loaders-3" data 1`] = ` rules:[{ test: /\\.js$/, use: \'eslint-loader\', - enforce: \'pre\' + \'enforce\': \'pre\' }] } } @@ -127,7 +127,7 @@ exports[`loaders transforms correctly using "loaders-4" data 1`] = ` rules:[{ test: /\\.js$/, use: \'my-post-loader\', - enforce: \'post\' + \'enforce\': \'post\' }] } } @@ -143,7 +143,7 @@ exports[`loaders transforms correctly using "loaders-5" data 1`] = ` }, { test: /\\.js$/, use: \'eslint-loader\', - enforce: \'pre\' + \'enforce\': \'pre\' }] } } @@ -159,7 +159,7 @@ exports[`loaders transforms correctly using "loaders-6" data 1`] = ` }, { test: /\\.js$/, use: \'my-post-loader\', - enforce: \'post\' + \'enforce\': \'post\' }] } } diff --git a/lib/transformations/loaders/loaders.js b/lib/transformations/loaders/loaders.js index 1490ee17a56..2bb15f17a24 100644 --- a/lib/transformations/loaders/loaders.js +++ b/lib/transformations/loaders/loaders.js @@ -29,23 +29,6 @@ module.exports = function(j, ast) { return j.objectExpression([loaderProp, queryProp]); }; - const findObjWithPrePostLoaders = p => { - return p.value.properties - .reduce((predicate, prop) => { - const name = prop.key.name; - return name === 'preLoaders' - || name === 'postLoaders' - || predicate; - }, false); - }; - const findObjWithLoaderProp = p => { - return p.value.properties - .reduce((predicate, prop) => { - return prop.key.name === 'loader' - || predicate; - }, false); - }; - const findLoaderWithQueryString = p => { return p.value.properties .reduce((predicate, prop) => { @@ -72,9 +55,7 @@ module.exports = function(j, ast) { const enforceVal = keyName === 'preLoaders' ? 'pre' : 'post'; prop.value.elements.map(elem => { - elem.properties.push(j.property('init', - j.identifier('enforce'), - j.literal(enforceVal))); + elem.properties.push(utils.createProperty(j, 'enforce', enforceVal)); if (loaders && loaders.type === 'ArrayExpression') { loaders.elements.push(elem); } else { @@ -91,7 +72,7 @@ module.exports = function(j, ast) { const prepostLoaders = () => ast .find(j.ObjectExpression) - .filter(findObjWithPrePostLoaders) + .filter(p => utils.findObjWithOneOfKeys(p, ['preLoaders', 'postLoaders'])) .forEach(p => p = fitIntoLoaders(p)); const loadersToRules = () => ast @@ -119,7 +100,7 @@ module.exports = function(j, ast) { const loaderWithQueryParam = () => ast .find(j.ObjectExpression) - .filter(findObjWithLoaderProp) + .filter(p => utils.findObjWithOneOfKeys(p, 'loader')) .filter(findLoaderWithQueryString) .replaceWith(createLoaderWithQuery); diff --git a/lib/transformations/utils.js b/lib/transformations/utils.js index 9dcc24b8adf..5bf580d1de8 100644 --- a/lib/transformations/utils.js +++ b/lib/transformations/utils.js @@ -215,6 +215,15 @@ function isType(path, type) { return path.type === type; } +function findObjWithOneOfKeys (p, keyNames) { + return p.value.properties + .reduce((predicate, prop) => { + const name = prop.key.name; + return keyNames.indexOf(name) > -1 + || predicate; + }, false); +} + module.exports = { safeTraverse, createProperty, @@ -223,5 +232,6 @@ module.exports = { createOrUpdatePluginByName, findVariableToPlugin, isType, - createLiteral + createLiteral, + findObjWithOneOfKeys }; diff --git a/lib/transformations/utils.test.js b/lib/transformations/utils.test.js index 122c2e7878c..24160eeaf1d 100644 --- a/lib/transformations/utils.test.js +++ b/lib/transformations/utils.test.js @@ -144,4 +144,17 @@ var a = { plugs: [] } expect(literal).toMatchSnapshot(); }); }); + + describe('findObjWithOneOfKeys', () => { + it('should find keys', () => { + const ast = j(` + var ab = { + a: 1, + b: 2 + } + `); + expect(ast.find(j.ObjectExpression) + .filter(p => utils.findObjWithOneOfKeys(p, ['a'])).size()).toEqual(1); + }); + }); }); From d758330cebda3f7b9bcfa2ad0526f223ac2c7898 Mon Sep 17 00:00:00 2001 From: Pavithra K Date: Mon, 20 Feb 2017 01:12:00 +0530 Subject: [PATCH 41/43] Trims the input test --- .../__snapshots__/extractTextPlugin.test.js.snap | 3 --- .../__testfixtures__/extractTextPlugin.input.js | 3 --- 2 files changed, 6 deletions(-) diff --git a/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap b/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap index 1f46321cc33..43343ec274e 100644 --- a/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap +++ b/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap @@ -1,9 +1,6 @@ exports[`extractTextPlugin transforms correctly 1`] = ` "let ExtractTextPlugin = require(\'extract-text-webpack-plugin\'); -let extractCSS = new ExtractTextPlugin(\'stylesheets/[name].css\'); -let extractLESS = new ExtractTextPlugin(\'stylesheets/[name].less\'); - module.export = { module: { rules: [ diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js index 8e468e89a57..b3d65c2af13 100644 --- a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js +++ b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js @@ -1,8 +1,5 @@ let ExtractTextPlugin = require('extract-text-webpack-plugin'); -let extractCSS = new ExtractTextPlugin('stylesheets/[name].css'); -let extractLESS = new ExtractTextPlugin('stylesheets/[name].less'); - module.export = { module: { rules: [ From d66f4e154ace1c5fd05de486de91b3c1cf0807fa Mon Sep 17 00:00:00 2001 From: Pavithra K Date: Mon, 20 Feb 2017 01:24:37 +0530 Subject: [PATCH 42/43] Fixes eslint and parse bug --- lib/migrate.js | 1 - lib/transformations/defineTest.js | 4 ---- .../__snapshots__/extractTextPlugin.test.js.snap | 1 + .../__testfixtures__/extractTextPlugin.input.js | 1 + lib/transformations/extractTextPlugin/extractTextPlugin.js | 2 +- 5 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/migrate.js b/lib/migrate.js index b9612a358ec..953ece40967 100644 --- a/lib/migrate.js +++ b/lib/migrate.js @@ -1,5 +1,4 @@ const fs = require('fs'); -const jscodeshift = require('jscodeshift'); const diff = require('diff'); const chalk = require('chalk'); const transform = require('./transformations').transform; diff --git a/lib/transformations/defineTest.js b/lib/transformations/defineTest.js index 7c58f195a1d..64a2a77301d 100644 --- a/lib/transformations/defineTest.js +++ b/lib/transformations/defineTest.js @@ -13,10 +13,6 @@ const fs = require('fs'); const path = require('path'); -const cli_engine = require('eslint').CLIEngine; //eslint-disable-line -const eslintrules = require(process.cwd() + '/.eslintrc.json'); -eslintrules.fix = true; -const cli = new cli_engine(eslintrules); /** * Utility function to run a jscodeshift script within a unit test. This makes diff --git a/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap b/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap index 43343ec274e..17c8af0764e 100644 --- a/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap +++ b/lib/transformations/extractTextPlugin/__snapshots__/extractTextPlugin.test.js.snap @@ -1,5 +1,6 @@ exports[`extractTextPlugin transforms correctly 1`] = ` "let ExtractTextPlugin = require(\'extract-text-webpack-plugin\'); +let HTMLWebpackPlugin = require(\'html-webpack-plugin\'); module.export = { module: { diff --git a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js index b3d65c2af13..f578bb4342d 100644 --- a/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js +++ b/lib/transformations/extractTextPlugin/__testfixtures__/extractTextPlugin.input.js @@ -1,4 +1,5 @@ let ExtractTextPlugin = require('extract-text-webpack-plugin'); +let HTMLWebpackPlugin = require('html-webpack-plugin'); module.export = { module: { diff --git a/lib/transformations/extractTextPlugin/extractTextPlugin.js b/lib/transformations/extractTextPlugin/extractTextPlugin.js index fd7ff350af0..3d60fedffdb 100644 --- a/lib/transformations/extractTextPlugin/extractTextPlugin.js +++ b/lib/transformations/extractTextPlugin/extractTextPlugin.js @@ -12,7 +12,7 @@ module.exports = function(j, ast) { // if(args.length === 1) { // return p; // } else - const literalArgs = args.filter(p => utils.isType('Literal')); + const literalArgs = args.filter(p => utils.isType(p, 'Literal')); if (literalArgs && literalArgs.length > 1) { const newArgs = j.objectExpression(literalArgs.map((p, index) => utils.createProperty(j, index === 0 ? 'fallback': 'use', p.value) From e0539a1ddf1cd2f7f19d4313f66661c0b797c29a Mon Sep 17 00:00:00 2001 From: Pavithra K Date: Mon, 20 Feb 2017 01:57:20 +0530 Subject: [PATCH 43/43] Adds to the contributor docs about transforms --- CONTRIBUTING.md | 63 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a44a5803912..844a5065c7b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -128,6 +128,69 @@ to read on GitHub as well as in several git tools. For more information about what each part of the template mean, head up to the documentation in the [angular repo](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit-message-format) +## --migrate with the CLI + +This is a new feature in development for the CLI. + +``` +webpack --migrate +``` + +The expected result of the above command is to take the mentioned `webpack` configuration and create a new configuration file which is compatible with webpack 2. +It should be a valid new config and should keep intact all the features from the original config. +The new config will be as readable as possible (may be add some comments). + +With [#40](https://github.com/webpack/webpack-cli/pull/40), we have been able to add basic scaffolding and do many of the conversions recommended in the [docs](https://webpack.js.org/guides/migrating/). + +### How it's being done + +We use [`jscodeshift`](https://github.com/facebook/jscodeshift) transforms called `codemods` to accomplish this. +We have written a bunch of transformations under [/lib/transformations](https://github.com/webpack/webpack-cli/tree/master/lib/transformations),divided logically. +We convert the existing webpack config to [AST](https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/Parser_API). We then parse this tree for the specific features and modify it to conform to webpack v2... + +#### Structure of a transform + +The directory structure of a transform looks as follows - + +```sh +| +|--__snapshots__ +|--__testfixtures__ +| | +| |--transform-name.input.js +| +|--transform-name.js +|--transform-name.test.js +``` + +`transform-name.js` + +This file contains the actual transformation codemod. It applies specific transformation and parsing logic to accomplish its job +There are utilities available under `/lib/utils.js` which can help you with this. + +`transform-name.test.js` + +This is where you declare a new test case for your transformation. +Each test will refer to an input webpack config snippet. +Conventionally we write them in `\_\_testfixtures\_\_`. + +``` +const defineTest = require('../defineTest'); + +defineTest(__dirname, 'transform-name.input1.js'); +defineTest(__dirname, 'transform-name.input2.js'); +``` + +`defineTest` is a helper test method which helps us to run tests on all the transforms uniformly. +It takes the input file given as parameter and uses jest to create a snapshot of the output. This effectively tests the correctness of our transformation. + +### TODO + +This is still in a very raw form. We'd like to take this as close to a truly useful tool as possible. +We will still need to + - Support all kinds of webpack configuration(made using merge tools) + - Test these transforms against real world configurations. + ## Contributor License Agreement When submitting your contribution, a CLA (Contributor License Agreement) bot will come by to verify that you signed the CLA. If you are submitting a PR for the first time, it will link you to the right place to sign it. If you have committed your contributions using an email that is not the same as your email used on GitHub, the CLA bot can't accept your contribution.