diff --git a/packages/plugin-minify/README.md b/packages/plugin-minify/README.md index 2c250484c..629a9aaca 100644 --- a/packages/plugin-minify/README.md +++ b/packages/plugin-minify/README.md @@ -28,6 +28,7 @@ npm i @putout/plugin-putout -D "mangleClassNames": true }], "minify/merge-variables": "on", + "minify/merge-loops": "on", "minify/remove-var-undefined": "on", "minify/remove-return-undefined": "on", "minify/simplify-floor": "on", @@ -329,6 +330,27 @@ var a; var b; ``` +## merge-loops + +Check out in 🐊[**Putout Editor**](https://putout.cloudcmd.io/#/gist/c9b77f37202389d30924135c2db3db9e/345edfc73c65b6cdf53c9b5e68bf689e4128291f). + +### ❌ Example of incorrect code + +```js +for (const aa of a) + d.push(aa); + +for (const bb of b) + d.push(bb); +``` + +### ✅ Example of correct code + +```js +for (const aa of [...a, ...b]) + d.push(aa); +``` + ## simplify-floor Not only shorter, but faster: diff --git a/packages/plugin-minify/lib/merge-loops/fixture/merge-loops-fix.js b/packages/plugin-minify/lib/merge-loops/fixture/merge-loops-fix.js new file mode 100644 index 000000000..e78eca529 --- /dev/null +++ b/packages/plugin-minify/lib/merge-loops/fixture/merge-loops-fix.js @@ -0,0 +1,7 @@ +for (const aa of [...a, ...b]) + d.push(aa); + +b.forEach((bb) => d.push(bb)); + +for (const aa of [...a, ...b]) + d.push(aa); diff --git a/packages/plugin-minify/lib/merge-loops/fixture/merge-loops.js b/packages/plugin-minify/lib/merge-loops/fixture/merge-loops.js new file mode 100644 index 000000000..935b30cbf --- /dev/null +++ b/packages/plugin-minify/lib/merge-loops/fixture/merge-loops.js @@ -0,0 +1,11 @@ +a.forEach(aa=>d.push(aa)), +b.forEach(bb=>d.push(bb)); + +b.forEach(bb=>d.push(bb)); + + +for (const aa of a) + d.push(aa); + +for (const bb of b) + d.push(bb); \ No newline at end of file diff --git a/packages/plugin-minify/lib/merge-loops/index.js b/packages/plugin-minify/lib/merge-loops/index.js new file mode 100644 index 000000000..ed22df00d --- /dev/null +++ b/packages/plugin-minify/lib/merge-loops/index.js @@ -0,0 +1,40 @@ +import { + operator, + template, +} from 'putout'; + +const { + remove, + getTemplateValues, + compare, +} = operator; + +const FOR = 'for (const __a of __b)__c(__e)'; + +const createLoop = template(`for (const __a of [...__b, ...__z])__c(__e)`, { + placeholderPattern: /^__[a-z]$/, +}); + +export const report = () => `Merge loops`; + +export const replace = () => ({ + '__a.forEach((__b) => __e(__b)),__c.forEach((__d) => __e(__d))': 'for (const __b of [...__a, ...__c])__e(__b)', + [FOR]: ({__a, __b, __c, __e}, path) => { + const next = path.getNextSibling(); + + if (compare(next, FOR)) { + const {__b: __z} = getTemplateValues(next, FOR); + remove(next); + + return createLoop({ + __a, + __b, + __c, + __e, + __z, + }); + } + + return path; + }, +}); diff --git a/packages/plugin-minify/lib/merge-loops/index.spec.js b/packages/plugin-minify/lib/merge-loops/index.spec.js new file mode 100644 index 000000000..221f3164e --- /dev/null +++ b/packages/plugin-minify/lib/merge-loops/index.spec.js @@ -0,0 +1,19 @@ +import {createTest} from '@putout/test'; +import * as plugin from './index.js'; + +const test = createTest(import.meta.url, { + printer: 'putout', + plugins: [ + ['merge-loops', plugin], + ], +}); + +test('packages: merge-loops: report', (t) => { + t.report('merge-loops', `Merge loops`); + t.end(); +}); + +test('packages: merge-loops: transform', (t) => { + t.transform('merge-loops'); + t.end(); +}); diff --git a/packages/plugin-minify/test/fixture/merge-loops-fix.js b/packages/plugin-minify/test/fixture/merge-loops-fix.js new file mode 100644 index 000000000..da34e276f --- /dev/null +++ b/packages/plugin-minify/test/fixture/merge-loops-fix.js @@ -0,0 +1,9 @@ +(a.forEach((A) => d.push(A)), b.forEach((_) => d.push(_))); + +b.forEach((B) => d.push(B)); + +for (const c of a) + d.push(c); + +for (const C of b) + d.push(C); diff --git a/packages/plugin-minify/test/fixture/merge-loops.js b/packages/plugin-minify/test/fixture/merge-loops.js new file mode 100644 index 000000000..935b30cbf --- /dev/null +++ b/packages/plugin-minify/test/fixture/merge-loops.js @@ -0,0 +1,11 @@ +a.forEach(aa=>d.push(aa)), +b.forEach(bb=>d.push(bb)); + +b.forEach(bb=>d.push(bb)); + + +for (const aa of a) + d.push(aa); + +for (const bb of b) + d.push(bb); \ No newline at end of file diff --git a/packages/plugin-minify/test/minify.js b/packages/plugin-minify/test/minify.js index dc394695a..2b1a3fdbd 100644 --- a/packages/plugin-minify/test/minify.js +++ b/packages/plugin-minify/test/minify.js @@ -97,3 +97,8 @@ test('plugin-minify: transform: if', (t) => { t.transform('if'); t.end(); }); + +test('plugin-minify: transform: merge-loops', (t) => { + t.transform('merge-loops'); + t.end(); +});