From 4b9dfc3065b6d463359292a5f86b91f0a7a0186c Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Sun, 28 Jan 2018 15:34:39 +0100 Subject: [PATCH 01/27] Make BlockStatements take care of removing their children --- src/ast/nodes/BlockStatement.ts | 20 +++++++++++-- .../samples/for-in-scopes/_expected/amd.js | 1 - .../samples/for-in-scopes/_expected/cjs.js | 1 - .../samples/for-in-scopes/_expected/es.js | 1 - .../samples/for-in-scopes/_expected/iife.js | 1 - .../samples/for-in-scopes/_expected/umd.js | 1 - .../render-removed-statements/_config.js | 3 ++ .../_expected/amd.js | 24 ++++++++++++++++ .../_expected/cjs.js | 22 +++++++++++++++ .../render-removed-statements/_expected/es.js | 20 +++++++++++++ .../_expected/iife.js | 25 +++++++++++++++++ .../_expected/umd.js | 28 +++++++++++++++++++ .../samples/render-removed-statements/main.js | 28 +++++++++++++++++++ .../_expected/amd.js | 2 +- .../_expected/cjs.js | 2 +- .../_expected/es.js | 2 +- .../_expected/iife.js | 2 +- .../_expected/umd.js | 2 +- 18 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 test/form/samples/render-removed-statements/_config.js create mode 100644 test/form/samples/render-removed-statements/_expected/amd.js create mode 100644 test/form/samples/render-removed-statements/_expected/cjs.js create mode 100644 test/form/samples/render-removed-statements/_expected/es.js create mode 100644 test/form/samples/render-removed-statements/_expected/iife.js create mode 100644 test/form/samples/render-removed-statements/_expected/umd.js create mode 100644 test/form/samples/render-removed-statements/main.js diff --git a/src/ast/nodes/BlockStatement.ts b/src/ast/nodes/BlockStatement.ts index 9318e6397b7..6140d091230 100644 --- a/src/ast/nodes/BlockStatement.ts +++ b/src/ast/nodes/BlockStatement.ts @@ -63,8 +63,24 @@ export default class BlockStatement extends StatementBase { render (code: MagicString, options: RenderOptions) { if (this.body.length) { - for (const node of this.body) { - node.render(code, options); + let nextLineBreakPos = code.slice(this.start + 1, this.body[0].start).indexOf('\n'); + let nodeStart = Math.max(0, nextLineBreakPos + 1) + this.start + 1; + let nodeEnd; + for (let nodeIdx = 0; nodeIdx < this.body.length; nodeIdx++) { + const node = this.body[nodeIdx]; + if (nodeIdx === this.body.length - 1) { + nodeEnd = this.end - 1; + } else { + const nextNode = this.body[nodeIdx + 1]; + nextLineBreakPos = code.slice(node.end, nextNode.start).indexOf('\n'); + nodeEnd = Math.max(0, nextLineBreakPos + 1) + node.end; + } + if (!node.included) { + code.remove(nodeStart, nodeEnd); + } else { + node.render(code, options); + } + nodeStart = nodeEnd; } } else { super.render(code, options); diff --git a/test/form/samples/for-in-scopes/_expected/amd.js b/test/form/samples/for-in-scopes/_expected/amd.js index 5f11de3ea96..d3dc86884a2 100644 --- a/test/form/samples/for-in-scopes/_expected/amd.js +++ b/test/form/samples/for-in-scopes/_expected/amd.js @@ -9,7 +9,6 @@ define(function () { 'use strict'; var effect3 = () => console.log( 'effect' ); for ( const foo in { x: effect3() } ) { - // This can be removed } for ( globalVar in { x: 1 } ) {} diff --git a/test/form/samples/for-in-scopes/_expected/cjs.js b/test/form/samples/for-in-scopes/_expected/cjs.js index 5a867c88dbb..9d97b8645b2 100644 --- a/test/form/samples/for-in-scopes/_expected/cjs.js +++ b/test/form/samples/for-in-scopes/_expected/cjs.js @@ -9,7 +9,6 @@ associated(); var effect3 = () => console.log( 'effect' ); for ( const foo in { x: effect3() } ) { - // This can be removed } for ( globalVar in { x: 1 } ) {} diff --git a/test/form/samples/for-in-scopes/_expected/es.js b/test/form/samples/for-in-scopes/_expected/es.js index 2141eb1b3f6..a2ad98b8702 100644 --- a/test/form/samples/for-in-scopes/_expected/es.js +++ b/test/form/samples/for-in-scopes/_expected/es.js @@ -7,7 +7,6 @@ associated(); var effect3 = () => console.log( 'effect' ); for ( const foo in { x: effect3() } ) { - // This can be removed } for ( globalVar in { x: 1 } ) {} diff --git a/test/form/samples/for-in-scopes/_expected/iife.js b/test/form/samples/for-in-scopes/_expected/iife.js index 748a2bb7980..71677721491 100644 --- a/test/form/samples/for-in-scopes/_expected/iife.js +++ b/test/form/samples/for-in-scopes/_expected/iife.js @@ -10,7 +10,6 @@ var effect3 = () => console.log( 'effect' ); for ( const foo in { x: effect3() } ) { - // This can be removed } for ( globalVar in { x: 1 } ) {} diff --git a/test/form/samples/for-in-scopes/_expected/umd.js b/test/form/samples/for-in-scopes/_expected/umd.js index 9e5c9fa4c9e..51ca20910dd 100644 --- a/test/form/samples/for-in-scopes/_expected/umd.js +++ b/test/form/samples/for-in-scopes/_expected/umd.js @@ -13,7 +13,6 @@ var effect3 = () => console.log( 'effect' ); for ( const foo in { x: effect3() } ) { - // This can be removed } for ( globalVar in { x: 1 } ) {} diff --git a/test/form/samples/render-removed-statements/_config.js b/test/form/samples/render-removed-statements/_config.js new file mode 100644 index 00000000000..5c3fac4b9ef --- /dev/null +++ b/test/form/samples/render-removed-statements/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'make sure removed statements do no leave unwanted white-space' +}; diff --git a/test/form/samples/render-removed-statements/_expected/amd.js b/test/form/samples/render-removed-statements/_expected/amd.js new file mode 100644 index 00000000000..fe7a2a9ae91 --- /dev/null +++ b/test/form/samples/render-removed-statements/_expected/amd.js @@ -0,0 +1,24 @@ +define(function () { 'use strict'; + + if (globalVar) { + // lead retained + console.log(1); // trail retained + } + + if (globalVar) { + // lead retained + console.log(1); // trail retained + } + + if (globalVar) { + // lead retained + console.log(1); // trail retained + } + + if (globalVar) { /* retained */ console.log(1);} + + if (globalVar) { /* retained */ console.log(1);} + + if (globalVar) { /* retained */ console.log(1);} + +}); diff --git a/test/form/samples/render-removed-statements/_expected/cjs.js b/test/form/samples/render-removed-statements/_expected/cjs.js new file mode 100644 index 00000000000..04d5100ead4 --- /dev/null +++ b/test/form/samples/render-removed-statements/_expected/cjs.js @@ -0,0 +1,22 @@ +'use strict'; + +if (globalVar) { + // lead retained + console.log(1); // trail retained +} + +if (globalVar) { + // lead retained + console.log(1); // trail retained +} + +if (globalVar) { + // lead retained + console.log(1); // trail retained +} + +if (globalVar) { /* retained */ console.log(1);} + +if (globalVar) { /* retained */ console.log(1);} + +if (globalVar) { /* retained */ console.log(1);} diff --git a/test/form/samples/render-removed-statements/_expected/es.js b/test/form/samples/render-removed-statements/_expected/es.js new file mode 100644 index 00000000000..223074ac981 --- /dev/null +++ b/test/form/samples/render-removed-statements/_expected/es.js @@ -0,0 +1,20 @@ +if (globalVar) { + // lead retained + console.log(1); // trail retained +} + +if (globalVar) { + // lead retained + console.log(1); // trail retained +} + +if (globalVar) { + // lead retained + console.log(1); // trail retained +} + +if (globalVar) { /* retained */ console.log(1);} + +if (globalVar) { /* retained */ console.log(1);} + +if (globalVar) { /* retained */ console.log(1);} diff --git a/test/form/samples/render-removed-statements/_expected/iife.js b/test/form/samples/render-removed-statements/_expected/iife.js new file mode 100644 index 00000000000..3e3cddf1a93 --- /dev/null +++ b/test/form/samples/render-removed-statements/_expected/iife.js @@ -0,0 +1,25 @@ +(function () { + 'use strict'; + + if (globalVar) { + // lead retained + console.log(1); // trail retained + } + + if (globalVar) { + // lead retained + console.log(1); // trail retained + } + + if (globalVar) { + // lead retained + console.log(1); // trail retained + } + + if (globalVar) { /* retained */ console.log(1);} + + if (globalVar) { /* retained */ console.log(1);} + + if (globalVar) { /* retained */ console.log(1);} + +}()); diff --git a/test/form/samples/render-removed-statements/_expected/umd.js b/test/form/samples/render-removed-statements/_expected/umd.js new file mode 100644 index 00000000000..28ca78e5950 --- /dev/null +++ b/test/form/samples/render-removed-statements/_expected/umd.js @@ -0,0 +1,28 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); +}(this, (function () { 'use strict'; + + if (globalVar) { + // lead retained + console.log(1); // trail retained + } + + if (globalVar) { + // lead retained + console.log(1); // trail retained + } + + if (globalVar) { + // lead retained + console.log(1); // trail retained + } + + if (globalVar) { /* retained */ console.log(1);} + + if (globalVar) { /* retained */ console.log(1);} + + if (globalVar) { /* retained */ console.log(1);} + +}))); diff --git a/test/form/samples/render-removed-statements/main.js b/test/form/samples/render-removed-statements/main.js new file mode 100644 index 00000000000..2ea00766e65 --- /dev/null +++ b/test/form/samples/render-removed-statements/main.js @@ -0,0 +1,28 @@ +if (globalVar) { + // lead removed + const x = 1; // trail removed + // lead retained + console.log(1); // trail retained +} + +if (globalVar) { + // lead removed + const x = 1; // trail removed + // lead retained + console.log(1); // trail retained + // lead removed + const y = 1; // trail removed +} + +if (globalVar) { + // lead retained + console.log(1); // trail retained + // lead removed + const y = 1; // trail removed +} + +if (globalVar) { /* removed */ const x = 1; /* retained */ console.log(1);} + +if (globalVar) { /* removed */ const x = 1; /* retained */ console.log(1); /* removed */ const y = 1;} + +if (globalVar) { /* retained */ console.log(1); /* removed */ const y = 1;} diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/amd.js b/test/form/samples/unused-inner-functions-and-classes/_expected/amd.js index e02ef3f263d..17f977ccca3 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/amd.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/amd.js @@ -7,6 +7,7 @@ define(function () { 'use strict'; function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } + return bar(), bog; } @@ -17,7 +18,6 @@ define(function () { 'use strict'; function getClass () { class MyClass {} return MyClass; - } console.log( getClass().name ); diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/cjs.js b/test/form/samples/unused-inner-functions-and-classes/_expected/cjs.js index 4cd7c7da8f0..e7f8857a3e7 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/cjs.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/cjs.js @@ -7,6 +7,7 @@ function bar () { console.log("outer bar"); } function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } + return bar(), bog; } @@ -17,7 +18,6 @@ f(); function getClass () { class MyClass {} return MyClass; - } console.log( getClass().name ); diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/es.js b/test/form/samples/unused-inner-functions-and-classes/_expected/es.js index 7ce1e942250..75a7db67005 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/es.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/es.js @@ -5,6 +5,7 @@ function bar () { console.log("outer bar"); } function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } + return bar(), bog; } @@ -15,7 +16,6 @@ f(); function getClass () { class MyClass {} return MyClass; - } console.log( getClass().name ); diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/iife.js b/test/form/samples/unused-inner-functions-and-classes/_expected/iife.js index 44561eef839..0ec7886c3c6 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/iife.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/iife.js @@ -8,6 +8,7 @@ function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } + return bar(), bog; } @@ -18,7 +19,6 @@ function getClass () { class MyClass {} return MyClass; - } console.log( getClass().name ); diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/umd.js b/test/form/samples/unused-inner-functions-and-classes/_expected/umd.js index 6ce2b352cac..b4b5108571d 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/umd.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/umd.js @@ -11,6 +11,7 @@ function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } + return bar(), bog; } @@ -21,7 +22,6 @@ function getClass () { class MyClass {} return MyClass; - } console.log( getClass().name ); From 2436ee146e1025e65733f7980137f5d0196aac67 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Sun, 28 Jan 2018 17:28:20 +0100 Subject: [PATCH 02/27] Extract BlockStatement rendering to be used for Program nodes with exceptions for IfStatements and ExportDefaultDeclarations for now --- src/Module.ts | 9 ++---- src/ast/nodes/BlockStatement.ts | 21 ++----------- src/ast/nodes/Program.ts | 18 +++++++++-- src/ast/nodes/index.ts | 2 ++ src/utils/renderHelpers.ts | 30 +++++++++++++++++++ .../_expected/amd.js | 4 --- .../_expected/cjs.js | 4 --- .../_expected/es.js | 4 --- .../_expected/iife.js | 4 --- .../_expected/umd.js | 4 --- .../_expected/amd.js | 1 - .../_expected/cjs.js | 1 - .../_expected/es.js | 1 - .../_expected/iife.js | 1 - .../_expected/umd.js | 1 - .../samples/empty-statement/_expected/amd.js | 4 +-- .../samples/empty-statement/_expected/cjs.js | 4 +-- .../samples/empty-statement/_expected/es.js | 4 +-- .../samples/empty-statement/_expected/iife.js | 4 +-- .../samples/empty-statement/_expected/umd.js | 4 +-- .../getter-return-values/_expected/amd.js | 2 -- .../getter-return-values/_expected/cjs.js | 2 -- .../getter-return-values/_expected/es.js | 2 -- .../getter-return-values/_expected/iife.js | 2 -- .../getter-return-values/_expected/umd.js | 2 -- .../_expected/amd.js | 1 + .../_expected/cjs.js | 1 + .../mutate-logical-expression/_expected/es.js | 1 + .../_expected/iife.js | 1 + .../_expected/umd.js | 1 + .../mutations-in-imports/_expected/amd.js | 2 ++ .../mutations-in-imports/_expected/cjs.js | 2 ++ .../mutations-in-imports/_expected/es.js | 2 ++ .../mutations-in-imports/_expected/iife.js | 2 ++ .../mutations-in-imports/_expected/umd.js | 2 ++ test/form/samples/promises/_expected/amd.js | 2 -- test/form/samples/promises/_expected/cjs.js | 2 -- test/form/samples/promises/_expected/es.js | 2 -- test/form/samples/promises/_expected/iife.js | 2 -- test/form/samples/promises/_expected/umd.js | 2 -- .../_expected/amd.js | 7 +++++ .../_expected/cjs.js | 7 +++++ .../render-removed-statements/_expected/es.js | 7 +++++ .../_expected/iife.js | 7 +++++ .../_expected/umd.js | 7 +++++ .../samples/render-removed-statements/main.js | 15 ++++++++++ .../side-effect-es5-classes/_expected/amd.js | 1 - .../side-effect-es5-classes/_expected/cjs.js | 1 - .../side-effect-es5-classes/_expected/es.js | 1 - .../side-effect-es5-classes/_expected/iife.js | 1 - .../side-effect-es5-classes/_expected/umd.js | 1 - .../_expected/amd.js | 1 - .../_expected/cjs.js | 1 - .../_expected/es.js | 1 - .../_expected/iife.js | 1 - .../_expected/umd.js | 1 - .../_expected/amd.js | 1 - .../_expected/cjs.js | 1 - .../_expected/es.js | 1 - .../_expected/iife.js | 1 - .../_expected/umd.js | 1 - .../_expected/amd.js | 4 --- .../_expected/cjs.js | 4 --- .../_expected/es.js | 4 --- .../_expected/iife.js | 4 --- .../_expected/umd.js | 4 --- .../skips-dead-branches-g/_expected/amd.js | 3 +- .../skips-dead-branches-g/_expected/cjs.js | 3 +- .../skips-dead-branches-g/_expected/es.js | 3 +- .../skips-dead-branches-g/_expected/iife.js | 3 +- .../skips-dead-branches-g/_expected/umd.js | 3 +- .../_expected/amd.js | 1 - .../_expected/cjs.js | 1 - .../_expected/es.js | 1 - .../_expected/iife.js | 1 - .../_expected/umd.js | 1 - .../samples/switch-scopes/_expected/amd.js | 1 + .../samples/switch-scopes/_expected/cjs.js | 1 + .../samples/switch-scopes/_expected/es.js | 1 + .../samples/switch-scopes/_expected/iife.js | 1 + .../samples/switch-scopes/_expected/umd.js | 1 + .../samples/this-in-imports/_expected/amd.js | 2 -- .../samples/this-in-imports/_expected/cjs.js | 2 -- .../samples/this-in-imports/_expected/es.js | 2 -- .../samples/this-in-imports/_expected/iife.js | 2 -- .../samples/this-in-imports/_expected/umd.js | 2 -- .../_expected/amd.js | 2 -- .../_expected/cjs.js | 2 -- .../_expected/es.js | 2 -- .../_expected/iife.js | 2 -- .../_expected/umd.js | 2 -- 91 files changed, 138 insertions(+), 152 deletions(-) create mode 100644 src/utils/renderHelpers.ts diff --git a/src/Module.ts b/src/Module.ts index 0fd3f43f053..272974dab06 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -107,7 +107,7 @@ export interface RenderOptions { freeze: boolean; importMechanism?: DynamicImportMechanism; systemBindings: boolean; -}; +} export default class Module { type: 'Module'; @@ -588,10 +588,7 @@ export default class Module { render (options: RenderOptions): MagicString { const magicString = this.magicString.clone(); - - this.ast.body.forEach(node => { - node.render(magicString, options); - }); + this.ast.render(magicString, options); if (this.namespace().needsNamespaceBlock) { magicString.append( @@ -648,7 +645,7 @@ export default class Module { // namespace if (name.length === 1) { return this.namespace(); - // export * from 'external' + // export * from 'external' } else { const module = this.graph.moduleById.get(name.slice(1)); return module.traceExport('*'); diff --git a/src/ast/nodes/BlockStatement.ts b/src/ast/nodes/BlockStatement.ts index 6140d091230..3f26ff2a32e 100644 --- a/src/ast/nodes/BlockStatement.ts +++ b/src/ast/nodes/BlockStatement.ts @@ -7,6 +7,7 @@ import { Node } from './shared/Node'; import { StatementBase, StatementNode } from './shared/Statement'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; +import { renderStatementBlock } from '../../utils/renderHelpers'; export function isBlockStatement (node: Node): node is BlockStatement { return node.type === NodeType.BlockStatement; @@ -63,25 +64,7 @@ export default class BlockStatement extends StatementBase { render (code: MagicString, options: RenderOptions) { if (this.body.length) { - let nextLineBreakPos = code.slice(this.start + 1, this.body[0].start).indexOf('\n'); - let nodeStart = Math.max(0, nextLineBreakPos + 1) + this.start + 1; - let nodeEnd; - for (let nodeIdx = 0; nodeIdx < this.body.length; nodeIdx++) { - const node = this.body[nodeIdx]; - if (nodeIdx === this.body.length - 1) { - nodeEnd = this.end - 1; - } else { - const nextNode = this.body[nodeIdx + 1]; - nextLineBreakPos = code.slice(node.end, nextNode.start).indexOf('\n'); - nodeEnd = Math.max(0, nextLineBreakPos + 1) + node.end; - } - if (!node.included) { - code.remove(nodeStart, nodeEnd); - } else { - node.render(code, options); - } - nodeStart = nodeEnd; - } + renderStatementBlock(this.body, code, this.start + 1, this.end - 1, options); } else { super.render(code, options); } diff --git a/src/ast/nodes/Program.ts b/src/ast/nodes/Program.ts index 2b937cabd1f..608569549ff 100644 --- a/src/ast/nodes/Program.ts +++ b/src/ast/nodes/Program.ts @@ -1,8 +1,22 @@ -import { Node } from './shared/Node'; +import MagicString from 'magic-string'; +import { NodeBase } from './shared/Node'; import { StatementNode } from './shared/Statement'; import { NodeType } from './NodeType'; +import { RenderOptions } from '../../Module'; +import { renderStatementBlock } from '../../utils/renderHelpers'; -export default interface Program extends Node { +export default class Program extends NodeBase { type: NodeType.Program; body: StatementNode[]; + + render (code: MagicString, options: RenderOptions) { + if (this.body.length) { + const lastNodeEnd = this.body[this.body.length - 1].end; + const firstTrailingLineBreakPos = code.slice(lastNodeEnd, this.end).indexOf('\n'); + const end = firstTrailingLineBreakPos === -1 ? this.end : lastNodeEnd + firstTrailingLineBreakPos + 1; + renderStatementBlock(this.body, code, this.start, end, options); + } else { + super.render(code, options); + } + } } diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 042b2cb8971..9fdb09d28df 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -36,6 +36,7 @@ import MethodDefinition from './MethodDefinition'; import NewExpression from './NewExpression'; import ObjectExpression from './ObjectExpression'; import ObjectPattern from './ObjectPattern'; +import Program from './Program'; import Property from './Property'; import RestElement from './RestElement'; import ReturnStatement from './ReturnStatement'; @@ -97,6 +98,7 @@ const nodes: { NewExpression, ObjectExpression, ObjectPattern, + Program, Property, RestElement, ReturnStatement, diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts new file mode 100644 index 00000000000..f734e10adbe --- /dev/null +++ b/src/utils/renderHelpers.ts @@ -0,0 +1,30 @@ +import { Node } from '../ast/nodes/shared/Node'; +import MagicString from 'magic-string'; +import { RenderOptions } from '../Module'; +import { NodeType } from '../ast/nodes/NodeType'; + +export function renderStatementBlock (statements: Node[], code: MagicString, start: number, end: number, options: RenderOptions) { + if (statements.length === 0) return; + let nodeStart = statements[0].start; + // To work around a bug in magic-string when nodeStart = start = 0; + let nextLineBreakPos = nodeStart > start ? code.slice(start, statements[0].start).indexOf('\n') : -1; + nodeStart = Math.max(0, nextLineBreakPos + 1) + start; + + let nodeEnd; + for (let nodeIdx = 0; nodeIdx < statements.length; nodeIdx++) { + const node = statements[nodeIdx]; + if (nodeIdx === statements.length - 1) { + nodeEnd = end; + } else { + const nextNode = statements[nodeIdx + 1]; + nextLineBreakPos = code.slice(node.end, nextNode.start).indexOf('\n'); + nodeEnd = Math.max(0, nextLineBreakPos + 1) + node.end; + } + if (!node.included && node.type !== NodeType.ExportDefaultDeclaration && node.type !== NodeType.IfStatement) { + code.remove(nodeStart, nodeEnd); + } else { + node.render(code, options); + } + nodeStart = nodeEnd; + } +} diff --git a/test/form/samples/arrow-function-return-values/_expected/amd.js b/test/form/samples/arrow-function-return-values/_expected/amd.js index ef42cbfa136..d4407aeed3d 100644 --- a/test/form/samples/arrow-function-return-values/_expected/amd.js +++ b/test/form/samples/arrow-function-return-values/_expected/amd.js @@ -1,18 +1,14 @@ define(function () { 'use strict'; (() => () => console.log( 'effect' ))()(); - (() => () => () => console.log( 'effect' ))()()(); - const retained1 = () => () => console.log( 'effect' ); retained1()(); (() => { return () => console.log( 'effect' ); })()(); - (() => ({ foo: () => console.log( 'effect' ) }))().foo(); - (() => ({ foo: () => ({ bar: () => console.log( 'effect' ) }) }))().foo().bar(); }); diff --git a/test/form/samples/arrow-function-return-values/_expected/cjs.js b/test/form/samples/arrow-function-return-values/_expected/cjs.js index 15e8f61a415..0a34a9d6ed1 100644 --- a/test/form/samples/arrow-function-return-values/_expected/cjs.js +++ b/test/form/samples/arrow-function-return-values/_expected/cjs.js @@ -1,16 +1,12 @@ 'use strict'; (() => () => console.log( 'effect' ))()(); - (() => () => () => console.log( 'effect' ))()()(); - const retained1 = () => () => console.log( 'effect' ); retained1()(); (() => { return () => console.log( 'effect' ); })()(); - (() => ({ foo: () => console.log( 'effect' ) }))().foo(); - (() => ({ foo: () => ({ bar: () => console.log( 'effect' ) }) }))().foo().bar(); diff --git a/test/form/samples/arrow-function-return-values/_expected/es.js b/test/form/samples/arrow-function-return-values/_expected/es.js index e53f8a40dab..a3fd2df3d87 100644 --- a/test/form/samples/arrow-function-return-values/_expected/es.js +++ b/test/form/samples/arrow-function-return-values/_expected/es.js @@ -1,14 +1,10 @@ (() => () => console.log( 'effect' ))()(); - (() => () => () => console.log( 'effect' ))()()(); - const retained1 = () => () => console.log( 'effect' ); retained1()(); (() => { return () => console.log( 'effect' ); })()(); - (() => ({ foo: () => console.log( 'effect' ) }))().foo(); - (() => ({ foo: () => ({ bar: () => console.log( 'effect' ) }) }))().foo().bar(); diff --git a/test/form/samples/arrow-function-return-values/_expected/iife.js b/test/form/samples/arrow-function-return-values/_expected/iife.js index be640aade72..60a07d7709f 100644 --- a/test/form/samples/arrow-function-return-values/_expected/iife.js +++ b/test/form/samples/arrow-function-return-values/_expected/iife.js @@ -2,18 +2,14 @@ 'use strict'; (() => () => console.log( 'effect' ))()(); - (() => () => () => console.log( 'effect' ))()()(); - const retained1 = () => () => console.log( 'effect' ); retained1()(); (() => { return () => console.log( 'effect' ); })()(); - (() => ({ foo: () => console.log( 'effect' ) }))().foo(); - (() => ({ foo: () => ({ bar: () => console.log( 'effect' ) }) }))().foo().bar(); }()); diff --git a/test/form/samples/arrow-function-return-values/_expected/umd.js b/test/form/samples/arrow-function-return-values/_expected/umd.js index f137d9f8d8d..81aa54fa84b 100644 --- a/test/form/samples/arrow-function-return-values/_expected/umd.js +++ b/test/form/samples/arrow-function-return-values/_expected/umd.js @@ -5,18 +5,14 @@ }(this, (function () { 'use strict'; (() => () => console.log( 'effect' ))()(); - (() => () => () => console.log( 'effect' ))()()(); - const retained1 = () => () => console.log( 'effect' ); retained1()(); (() => { return () => console.log( 'effect' ); })()(); - (() => ({ foo: () => console.log( 'effect' ) }))().foo(); - (() => ({ foo: () => ({ bar: () => console.log( 'effect' ) }) }))().foo().bar(); }))); diff --git a/test/form/samples/conditional-expression-paths/_expected/amd.js b/test/form/samples/conditional-expression-paths/_expected/amd.js index 08c33da808a..59fa033ae9a 100644 --- a/test/form/samples/conditional-expression-paths/_expected/amd.js +++ b/test/form/samples/conditional-expression-paths/_expected/amd.js @@ -9,7 +9,6 @@ define(function () { 'use strict'; var b2 = (unknownValue ? foo2 : bar2).x(); foo2.x(); bar2.x(); - var bar4 = { x: () => console.log( 'effect' ) }; var a4 = (bar4).y.z; var b4 = (bar4).y.z; diff --git a/test/form/samples/conditional-expression-paths/_expected/cjs.js b/test/form/samples/conditional-expression-paths/_expected/cjs.js index 22e029faef2..690368250af 100644 --- a/test/form/samples/conditional-expression-paths/_expected/cjs.js +++ b/test/form/samples/conditional-expression-paths/_expected/cjs.js @@ -9,7 +9,6 @@ var a2 = (unknownValue ? foo2 : bar2).x.y.z; var b2 = (unknownValue ? foo2 : bar2).x(); foo2.x(); bar2.x(); - var bar4 = { x: () => console.log( 'effect' ) }; var a4 = (bar4).y.z; var b4 = (bar4).y.z; diff --git a/test/form/samples/conditional-expression-paths/_expected/es.js b/test/form/samples/conditional-expression-paths/_expected/es.js index 849aba2e815..b6b81edd3e5 100644 --- a/test/form/samples/conditional-expression-paths/_expected/es.js +++ b/test/form/samples/conditional-expression-paths/_expected/es.js @@ -7,7 +7,6 @@ var a2 = (unknownValue ? foo2 : bar2).x.y.z; var b2 = (unknownValue ? foo2 : bar2).x(); foo2.x(); bar2.x(); - var bar4 = { x: () => console.log( 'effect' ) }; var a4 = (bar4).y.z; var b4 = (bar4).y.z; diff --git a/test/form/samples/conditional-expression-paths/_expected/iife.js b/test/form/samples/conditional-expression-paths/_expected/iife.js index 010662155e5..b33c0366a02 100644 --- a/test/form/samples/conditional-expression-paths/_expected/iife.js +++ b/test/form/samples/conditional-expression-paths/_expected/iife.js @@ -10,7 +10,6 @@ var b2 = (unknownValue ? foo2 : bar2).x(); foo2.x(); bar2.x(); - var bar4 = { x: () => console.log( 'effect' ) }; var a4 = (bar4).y.z; var b4 = (bar4).y.z; diff --git a/test/form/samples/conditional-expression-paths/_expected/umd.js b/test/form/samples/conditional-expression-paths/_expected/umd.js index 0e29c610ba8..ae73406f8c0 100644 --- a/test/form/samples/conditional-expression-paths/_expected/umd.js +++ b/test/form/samples/conditional-expression-paths/_expected/umd.js @@ -13,7 +13,6 @@ var b2 = (unknownValue ? foo2 : bar2).x(); foo2.x(); bar2.x(); - var bar4 = { x: () => console.log( 'effect' ) }; var a4 = (bar4).y.z; var b4 = (bar4).y.z; diff --git a/test/form/samples/empty-statement/_expected/amd.js b/test/form/samples/empty-statement/_expected/amd.js index d7ee383f28a..6255bc57cbf 100644 --- a/test/form/samples/empty-statement/_expected/amd.js +++ b/test/form/samples/empty-statement/_expected/amd.js @@ -1,7 +1,5 @@ define(function () { 'use strict'; - console.log( 1 ); - - console.log( 2 ); + console.log( 1 );console.log( 2 ); }); diff --git a/test/form/samples/empty-statement/_expected/cjs.js b/test/form/samples/empty-statement/_expected/cjs.js index 2ad8cd21a7d..b54ecd1cf86 100644 --- a/test/form/samples/empty-statement/_expected/cjs.js +++ b/test/form/samples/empty-statement/_expected/cjs.js @@ -1,5 +1,3 @@ 'use strict'; -console.log( 1 ); - -console.log( 2 ); +console.log( 1 );console.log( 2 ); diff --git a/test/form/samples/empty-statement/_expected/es.js b/test/form/samples/empty-statement/_expected/es.js index b149085e8ec..dcc93dc9b24 100644 --- a/test/form/samples/empty-statement/_expected/es.js +++ b/test/form/samples/empty-statement/_expected/es.js @@ -1,3 +1 @@ -console.log( 1 ); - -console.log( 2 ); +console.log( 1 );console.log( 2 ); diff --git a/test/form/samples/empty-statement/_expected/iife.js b/test/form/samples/empty-statement/_expected/iife.js index c9dbff58946..60508d61edf 100644 --- a/test/form/samples/empty-statement/_expected/iife.js +++ b/test/form/samples/empty-statement/_expected/iife.js @@ -1,8 +1,6 @@ (function () { 'use strict'; - console.log( 1 ); - - console.log( 2 ); + console.log( 1 );console.log( 2 ); }()); diff --git a/test/form/samples/empty-statement/_expected/umd.js b/test/form/samples/empty-statement/_expected/umd.js index e97ebffd00d..a1f6dfc10c0 100644 --- a/test/form/samples/empty-statement/_expected/umd.js +++ b/test/form/samples/empty-statement/_expected/umd.js @@ -4,8 +4,6 @@ (factory()); }(this, (function () { 'use strict'; - console.log( 1 ); - - console.log( 2 ); + console.log( 1 );console.log( 2 ); }))); diff --git a/test/form/samples/getter-return-values/_expected/amd.js b/test/form/samples/getter-return-values/_expected/amd.js index 419645f275e..da5dcb9b95d 100644 --- a/test/form/samples/getter-return-values/_expected/amd.js +++ b/test/form/samples/getter-return-values/_expected/amd.js @@ -11,7 +11,6 @@ define(function () { 'use strict'; return {}; } }).foo.bar.baz; - ({ get foo () { console.log( 'effect' ); @@ -23,7 +22,6 @@ define(function () { 'use strict'; return () => console.log( 'effect' ); } }).foo(); - ({ get foo () { console.log( 'effect' ); diff --git a/test/form/samples/getter-return-values/_expected/cjs.js b/test/form/samples/getter-return-values/_expected/cjs.js index 75f11467dc7..70a48fa585a 100644 --- a/test/form/samples/getter-return-values/_expected/cjs.js +++ b/test/form/samples/getter-return-values/_expected/cjs.js @@ -11,7 +11,6 @@ return {}; } }).foo.bar.baz; - ({ get foo () { console.log( 'effect' ); @@ -23,7 +22,6 @@ return () => console.log( 'effect' ); } }).foo(); - ({ get foo () { console.log( 'effect' ); diff --git a/test/form/samples/getter-return-values/_expected/es.js b/test/form/samples/getter-return-values/_expected/es.js index bccc4f1da3c..61ea5587251 100644 --- a/test/form/samples/getter-return-values/_expected/es.js +++ b/test/form/samples/getter-return-values/_expected/es.js @@ -9,7 +9,6 @@ return {}; } }).foo.bar.baz; - ({ get foo () { console.log( 'effect' ); @@ -21,7 +20,6 @@ return () => console.log( 'effect' ); } }).foo(); - ({ get foo () { console.log( 'effect' ); diff --git a/test/form/samples/getter-return-values/_expected/iife.js b/test/form/samples/getter-return-values/_expected/iife.js index 71304bee381..bf86e946681 100644 --- a/test/form/samples/getter-return-values/_expected/iife.js +++ b/test/form/samples/getter-return-values/_expected/iife.js @@ -12,7 +12,6 @@ return {}; } }).foo.bar.baz; - ({ get foo () { console.log( 'effect' ); @@ -24,7 +23,6 @@ return () => console.log( 'effect' ); } }).foo(); - ({ get foo () { console.log( 'effect' ); diff --git a/test/form/samples/getter-return-values/_expected/umd.js b/test/form/samples/getter-return-values/_expected/umd.js index aaefd8664cb..c13eba2f73a 100644 --- a/test/form/samples/getter-return-values/_expected/umd.js +++ b/test/form/samples/getter-return-values/_expected/umd.js @@ -15,7 +15,6 @@ return {}; } }).foo.bar.baz; - ({ get foo () { console.log( 'effect' ); @@ -27,7 +26,6 @@ return () => console.log( 'effect' ); } }).foo(); - ({ get foo () { console.log( 'effect' ); diff --git a/test/form/samples/mutate-logical-expression/_expected/amd.js b/test/form/samples/mutate-logical-expression/_expected/amd.js index 78b1f493e97..19a7293965c 100644 --- a/test/form/samples/mutate-logical-expression/_expected/amd.js +++ b/test/form/samples/mutate-logical-expression/_expected/amd.js @@ -5,6 +5,7 @@ define(['exports'], function (exports) { 'use strict'; logicalAExp.bar = 1; var bExp = {}; + var cExp = {}; var logicalCExp = false || cExp; logicalCExp.bar = 1; diff --git a/test/form/samples/mutate-logical-expression/_expected/cjs.js b/test/form/samples/mutate-logical-expression/_expected/cjs.js index d71593e9193..759ed2588b6 100644 --- a/test/form/samples/mutate-logical-expression/_expected/cjs.js +++ b/test/form/samples/mutate-logical-expression/_expected/cjs.js @@ -7,6 +7,7 @@ var logicalAExp = aExp || true; logicalAExp.bar = 1; var bExp = {}; + var cExp = {}; var logicalCExp = false || cExp; logicalCExp.bar = 1; diff --git a/test/form/samples/mutate-logical-expression/_expected/es.js b/test/form/samples/mutate-logical-expression/_expected/es.js index 6b551512b6d..e72bbf4d7ac 100644 --- a/test/form/samples/mutate-logical-expression/_expected/es.js +++ b/test/form/samples/mutate-logical-expression/_expected/es.js @@ -3,6 +3,7 @@ var logicalAExp = aExp || true; logicalAExp.bar = 1; var bExp = {}; + var cExp = {}; var logicalCExp = false || cExp; logicalCExp.bar = 1; diff --git a/test/form/samples/mutate-logical-expression/_expected/iife.js b/test/form/samples/mutate-logical-expression/_expected/iife.js index 11b30198da7..d48cdfc6caa 100644 --- a/test/form/samples/mutate-logical-expression/_expected/iife.js +++ b/test/form/samples/mutate-logical-expression/_expected/iife.js @@ -6,6 +6,7 @@ var bundle = (function (exports) { logicalAExp.bar = 1; var bExp = {}; + var cExp = {}; var logicalCExp = false || cExp; logicalCExp.bar = 1; diff --git a/test/form/samples/mutate-logical-expression/_expected/umd.js b/test/form/samples/mutate-logical-expression/_expected/umd.js index 5616098c4c0..aed1f136520 100644 --- a/test/form/samples/mutate-logical-expression/_expected/umd.js +++ b/test/form/samples/mutate-logical-expression/_expected/umd.js @@ -9,6 +9,7 @@ logicalAExp.bar = 1; var bExp = {}; + var cExp = {}; var logicalCExp = false || cExp; logicalCExp.bar = 1; diff --git a/test/form/samples/mutations-in-imports/_expected/amd.js b/test/form/samples/mutations-in-imports/_expected/amd.js index 8b38018ee16..eb8467ab3c5 100644 --- a/test/form/samples/mutations-in-imports/_expected/amd.js +++ b/test/form/samples/mutations-in-imports/_expected/amd.js @@ -11,8 +11,10 @@ define(function () { 'use strict'; y.a.b = () => console.log( 'effect' ); x.a.b(); + y$1.a.b = () => console.log( 'effect' ); x$1.a.b(); + y$2.a.b = () => console.log( 'effect' ); x$2.a.b(); diff --git a/test/form/samples/mutations-in-imports/_expected/cjs.js b/test/form/samples/mutations-in-imports/_expected/cjs.js index 910139e5e36..b627117e158 100644 --- a/test/form/samples/mutations-in-imports/_expected/cjs.js +++ b/test/form/samples/mutations-in-imports/_expected/cjs.js @@ -11,7 +11,9 @@ const y$2 = { a: x$2.a }; y.a.b = () => console.log( 'effect' ); x.a.b(); + y$1.a.b = () => console.log( 'effect' ); x$1.a.b(); + y$2.a.b = () => console.log( 'effect' ); x$2.a.b(); diff --git a/test/form/samples/mutations-in-imports/_expected/es.js b/test/form/samples/mutations-in-imports/_expected/es.js index c9ada965a1e..49f53351770 100644 --- a/test/form/samples/mutations-in-imports/_expected/es.js +++ b/test/form/samples/mutations-in-imports/_expected/es.js @@ -9,7 +9,9 @@ const y$2 = { a: x$2.a }; y.a.b = () => console.log( 'effect' ); x.a.b(); + y$1.a.b = () => console.log( 'effect' ); x$1.a.b(); + y$2.a.b = () => console.log( 'effect' ); x$2.a.b(); diff --git a/test/form/samples/mutations-in-imports/_expected/iife.js b/test/form/samples/mutations-in-imports/_expected/iife.js index df58fe73794..45354bd8033 100644 --- a/test/form/samples/mutations-in-imports/_expected/iife.js +++ b/test/form/samples/mutations-in-imports/_expected/iife.js @@ -12,8 +12,10 @@ y.a.b = () => console.log( 'effect' ); x.a.b(); + y$1.a.b = () => console.log( 'effect' ); x$1.a.b(); + y$2.a.b = () => console.log( 'effect' ); x$2.a.b(); diff --git a/test/form/samples/mutations-in-imports/_expected/umd.js b/test/form/samples/mutations-in-imports/_expected/umd.js index 9b3b2b84418..a8aec2a3f1a 100644 --- a/test/form/samples/mutations-in-imports/_expected/umd.js +++ b/test/form/samples/mutations-in-imports/_expected/umd.js @@ -15,8 +15,10 @@ y.a.b = () => console.log( 'effect' ); x.a.b(); + y$1.a.b = () => console.log( 'effect' ); x$1.a.b(); + y$2.a.b = () => console.log( 'effect' ); x$2.a.b(); diff --git a/test/form/samples/promises/_expected/amd.js b/test/form/samples/promises/_expected/amd.js index 033048d7d26..337a238e7e2 100644 --- a/test/form/samples/promises/_expected/amd.js +++ b/test/form/samples/promises/_expected/amd.js @@ -11,9 +11,7 @@ define(['exports'], function (exports) { 'use strict'; const p3 = new Promise( () => { console.info( 'and me too' ); } ); - const p5 = Promise.reject('should be kept for uncaught rejections'); - const allExported = Promise.all([p2, p3]); exports.allExported = allExported; diff --git a/test/form/samples/promises/_expected/cjs.js b/test/form/samples/promises/_expected/cjs.js index 4126838bc13..1b8f7c6e6b3 100644 --- a/test/form/samples/promises/_expected/cjs.js +++ b/test/form/samples/promises/_expected/cjs.js @@ -13,9 +13,7 @@ const p2 = new Promise( () => { const p3 = new Promise( () => { console.info( 'and me too' ); } ); - const p5 = Promise.reject('should be kept for uncaught rejections'); - const allExported = Promise.all([p2, p3]); exports.allExported = allExported; diff --git a/test/form/samples/promises/_expected/es.js b/test/form/samples/promises/_expected/es.js index 4e90de368aa..fbeb7163575 100644 --- a/test/form/samples/promises/_expected/es.js +++ b/test/form/samples/promises/_expected/es.js @@ -9,9 +9,7 @@ const p2 = new Promise( () => { const p3 = new Promise( () => { console.info( 'and me too' ); } ); - const p5 = Promise.reject('should be kept for uncaught rejections'); - const allExported = Promise.all([p2, p3]); export { allExported }; diff --git a/test/form/samples/promises/_expected/iife.js b/test/form/samples/promises/_expected/iife.js index 7127fd8f3bd..4839c233bed 100644 --- a/test/form/samples/promises/_expected/iife.js +++ b/test/form/samples/promises/_expected/iife.js @@ -12,9 +12,7 @@ var bundle = (function (exports) { const p3 = new Promise( () => { console.info( 'and me too' ); } ); - const p5 = Promise.reject('should be kept for uncaught rejections'); - const allExported = Promise.all([p2, p3]); exports.allExported = allExported; diff --git a/test/form/samples/promises/_expected/umd.js b/test/form/samples/promises/_expected/umd.js index f8fd2a4a3c1..786a3fe6672 100644 --- a/test/form/samples/promises/_expected/umd.js +++ b/test/form/samples/promises/_expected/umd.js @@ -15,9 +15,7 @@ const p3 = new Promise( () => { console.info( 'and me too' ); } ); - const p5 = Promise.reject('should be kept for uncaught rejections'); - const allExported = Promise.all([p2, p3]); exports.allExported = allExported; diff --git a/test/form/samples/render-removed-statements/_expected/amd.js b/test/form/samples/render-removed-statements/_expected/amd.js index fe7a2a9ae91..6362ba9d16f 100644 --- a/test/form/samples/render-removed-statements/_expected/amd.js +++ b/test/form/samples/render-removed-statements/_expected/amd.js @@ -1,5 +1,7 @@ define(function () { 'use strict'; + /* header retained */ + if (globalVar) { // lead retained console.log(1); // trail retained @@ -21,4 +23,9 @@ define(function () { 'use strict'; if (globalVar) { /* retained */ console.log(1);} + // lead retained + console.log(1); // trail retained + + /* footer retained */ + }); diff --git a/test/form/samples/render-removed-statements/_expected/cjs.js b/test/form/samples/render-removed-statements/_expected/cjs.js index 04d5100ead4..a69a76dcee0 100644 --- a/test/form/samples/render-removed-statements/_expected/cjs.js +++ b/test/form/samples/render-removed-statements/_expected/cjs.js @@ -1,5 +1,7 @@ 'use strict'; +/* header retained */ + if (globalVar) { // lead retained console.log(1); // trail retained @@ -20,3 +22,8 @@ if (globalVar) { /* retained */ console.log(1);} if (globalVar) { /* retained */ console.log(1);} if (globalVar) { /* retained */ console.log(1);} + +// lead retained +console.log(1); // trail retained + +/* footer retained */ diff --git a/test/form/samples/render-removed-statements/_expected/es.js b/test/form/samples/render-removed-statements/_expected/es.js index 223074ac981..03f271cdf61 100644 --- a/test/form/samples/render-removed-statements/_expected/es.js +++ b/test/form/samples/render-removed-statements/_expected/es.js @@ -1,3 +1,5 @@ +/* header retained */ + if (globalVar) { // lead retained console.log(1); // trail retained @@ -18,3 +20,8 @@ if (globalVar) { /* retained */ console.log(1);} if (globalVar) { /* retained */ console.log(1);} if (globalVar) { /* retained */ console.log(1);} + +// lead retained +console.log(1); // trail retained + +/* footer retained */ diff --git a/test/form/samples/render-removed-statements/_expected/iife.js b/test/form/samples/render-removed-statements/_expected/iife.js index 3e3cddf1a93..dd567cc290a 100644 --- a/test/form/samples/render-removed-statements/_expected/iife.js +++ b/test/form/samples/render-removed-statements/_expected/iife.js @@ -1,6 +1,8 @@ (function () { 'use strict'; + /* header retained */ + if (globalVar) { // lead retained console.log(1); // trail retained @@ -22,4 +24,9 @@ if (globalVar) { /* retained */ console.log(1);} + // lead retained + console.log(1); // trail retained + + /* footer retained */ + }()); diff --git a/test/form/samples/render-removed-statements/_expected/umd.js b/test/form/samples/render-removed-statements/_expected/umd.js index 28ca78e5950..e28847854d9 100644 --- a/test/form/samples/render-removed-statements/_expected/umd.js +++ b/test/form/samples/render-removed-statements/_expected/umd.js @@ -4,6 +4,8 @@ (factory()); }(this, (function () { 'use strict'; + /* header retained */ + if (globalVar) { // lead retained console.log(1); // trail retained @@ -25,4 +27,9 @@ if (globalVar) { /* retained */ console.log(1);} + // lead retained + console.log(1); // trail retained + + /* footer retained */ + }))); diff --git a/test/form/samples/render-removed-statements/main.js b/test/form/samples/render-removed-statements/main.js index 2ea00766e65..44da362f421 100644 --- a/test/form/samples/render-removed-statements/main.js +++ b/test/form/samples/render-removed-statements/main.js @@ -1,3 +1,7 @@ +/* header retained */ + +/* lead removed */ const x = 1; // trail removed + if (globalVar) { // lead removed const x = 1; // trail removed @@ -26,3 +30,14 @@ if (globalVar) { /* removed */ const x = 1; /* retained */ console.log(1);} if (globalVar) { /* removed */ const x = 1; /* retained */ console.log(1); /* removed */ const y = 1;} if (globalVar) { /* retained */ console.log(1); /* removed */ const y = 1;} + +// lead removed +const y = 1; // trail removed + +// lead retained +console.log(1); // trail retained + +// lead removed +const z = 1; // trail removed + +/* footer retained */ diff --git a/test/form/samples/side-effect-es5-classes/_expected/amd.js b/test/form/samples/side-effect-es5-classes/_expected/amd.js index b996fb7336b..32eb3244fc9 100644 --- a/test/form/samples/side-effect-es5-classes/_expected/amd.js +++ b/test/form/samples/side-effect-es5-classes/_expected/amd.js @@ -22,7 +22,6 @@ define(function () { 'use strict'; }; console.log( 'before' ); - var bar = new Bar(5); var baz = new Baz(5); var qux = new Qux(5); diff --git a/test/form/samples/side-effect-es5-classes/_expected/cjs.js b/test/form/samples/side-effect-es5-classes/_expected/cjs.js index 987153ac813..41854b931b7 100644 --- a/test/form/samples/side-effect-es5-classes/_expected/cjs.js +++ b/test/form/samples/side-effect-es5-classes/_expected/cjs.js @@ -22,7 +22,6 @@ var Arrow = ( x ) => { }; console.log( 'before' ); - var bar = new Bar(5); var baz = new Baz(5); var qux = new Qux(5); diff --git a/test/form/samples/side-effect-es5-classes/_expected/es.js b/test/form/samples/side-effect-es5-classes/_expected/es.js index 529afb879de..7c0795bde51 100644 --- a/test/form/samples/side-effect-es5-classes/_expected/es.js +++ b/test/form/samples/side-effect-es5-classes/_expected/es.js @@ -20,7 +20,6 @@ var Arrow = ( x ) => { }; console.log( 'before' ); - var bar = new Bar(5); var baz = new Baz(5); var qux = new Qux(5); diff --git a/test/form/samples/side-effect-es5-classes/_expected/iife.js b/test/form/samples/side-effect-es5-classes/_expected/iife.js index daff1c0b066..0066fe86ac0 100644 --- a/test/form/samples/side-effect-es5-classes/_expected/iife.js +++ b/test/form/samples/side-effect-es5-classes/_expected/iife.js @@ -23,7 +23,6 @@ }; console.log( 'before' ); - var bar = new Bar(5); var baz = new Baz(5); var qux = new Qux(5); diff --git a/test/form/samples/side-effect-es5-classes/_expected/umd.js b/test/form/samples/side-effect-es5-classes/_expected/umd.js index 36c8dc54364..af1549a6dba 100644 --- a/test/form/samples/side-effect-es5-classes/_expected/umd.js +++ b/test/form/samples/side-effect-es5-classes/_expected/umd.js @@ -26,7 +26,6 @@ }; console.log( 'before' ); - var bar = new Bar(5); var baz = new Baz(5); var qux = new Qux(5); diff --git a/test/form/samples/side-effects-call-arguments/_expected/amd.js b/test/form/samples/side-effects-call-arguments/_expected/amd.js index 5c41a57bfb9..a90079ac01e 100644 --- a/test/form/samples/side-effects-call-arguments/_expected/amd.js +++ b/test/form/samples/side-effects-call-arguments/_expected/amd.js @@ -1,7 +1,6 @@ define(function () { 'use strict'; function foo () {} - foo( globalFunction() ); var baz = 2; diff --git a/test/form/samples/side-effects-call-arguments/_expected/cjs.js b/test/form/samples/side-effects-call-arguments/_expected/cjs.js index fbf148f906f..9b76714241b 100644 --- a/test/form/samples/side-effects-call-arguments/_expected/cjs.js +++ b/test/form/samples/side-effects-call-arguments/_expected/cjs.js @@ -1,7 +1,6 @@ 'use strict'; function foo () {} - foo( globalFunction() ); var baz = 2; diff --git a/test/form/samples/side-effects-call-arguments/_expected/es.js b/test/form/samples/side-effects-call-arguments/_expected/es.js index a8950a80e76..ad7a297384b 100644 --- a/test/form/samples/side-effects-call-arguments/_expected/es.js +++ b/test/form/samples/side-effects-call-arguments/_expected/es.js @@ -1,5 +1,4 @@ function foo () {} - foo( globalFunction() ); var baz = 2; diff --git a/test/form/samples/side-effects-call-arguments/_expected/iife.js b/test/form/samples/side-effects-call-arguments/_expected/iife.js index 7eed28c5668..fb4d4535e18 100644 --- a/test/form/samples/side-effects-call-arguments/_expected/iife.js +++ b/test/form/samples/side-effects-call-arguments/_expected/iife.js @@ -2,7 +2,6 @@ 'use strict'; function foo () {} - foo( globalFunction() ); var baz = 2; diff --git a/test/form/samples/side-effects-call-arguments/_expected/umd.js b/test/form/samples/side-effects-call-arguments/_expected/umd.js index 5fc1fde4d11..f8b04986596 100644 --- a/test/form/samples/side-effects-call-arguments/_expected/umd.js +++ b/test/form/samples/side-effects-call-arguments/_expected/umd.js @@ -5,7 +5,6 @@ }(this, (function () { 'use strict'; function foo () {} - foo( globalFunction() ); var baz = 2; diff --git a/test/form/samples/side-effects-getters-and-setters/_expected/amd.js b/test/form/samples/side-effects-getters-and-setters/_expected/amd.js index aaaa2022694..fcc551947a9 100644 --- a/test/form/samples/side-effects-getters-and-setters/_expected/amd.js +++ b/test/form/samples/side-effects-getters-and-setters/_expected/amd.js @@ -9,7 +9,6 @@ define(function () { 'use strict'; return x; } }; - const retained1b = retained1a.effect; const retained1c = retained1a[ 'eff' + 'ect' ]; diff --git a/test/form/samples/side-effects-getters-and-setters/_expected/cjs.js b/test/form/samples/side-effects-getters-and-setters/_expected/cjs.js index 9eb023475b9..9720c94d26b 100644 --- a/test/form/samples/side-effects-getters-and-setters/_expected/cjs.js +++ b/test/form/samples/side-effects-getters-and-setters/_expected/cjs.js @@ -9,7 +9,6 @@ const retained1a = { return x; } }; - const retained1b = retained1a.effect; const retained1c = retained1a[ 'eff' + 'ect' ]; diff --git a/test/form/samples/side-effects-getters-and-setters/_expected/es.js b/test/form/samples/side-effects-getters-and-setters/_expected/es.js index 8362292d56c..bf89ee47a46 100644 --- a/test/form/samples/side-effects-getters-and-setters/_expected/es.js +++ b/test/form/samples/side-effects-getters-and-setters/_expected/es.js @@ -7,7 +7,6 @@ const retained1a = { return x; } }; - const retained1b = retained1a.effect; const retained1c = retained1a[ 'eff' + 'ect' ]; diff --git a/test/form/samples/side-effects-getters-and-setters/_expected/iife.js b/test/form/samples/side-effects-getters-and-setters/_expected/iife.js index aec39303724..53110c0f5a3 100644 --- a/test/form/samples/side-effects-getters-and-setters/_expected/iife.js +++ b/test/form/samples/side-effects-getters-and-setters/_expected/iife.js @@ -10,7 +10,6 @@ return x; } }; - const retained1b = retained1a.effect; const retained1c = retained1a[ 'eff' + 'ect' ]; diff --git a/test/form/samples/side-effects-getters-and-setters/_expected/umd.js b/test/form/samples/side-effects-getters-and-setters/_expected/umd.js index f9d03f83955..9320e1876d8 100644 --- a/test/form/samples/side-effects-getters-and-setters/_expected/umd.js +++ b/test/form/samples/side-effects-getters-and-setters/_expected/umd.js @@ -13,7 +13,6 @@ return x; } }; - const retained1b = retained1a.effect; const retained1c = retained1a[ 'eff' + 'ect' ]; diff --git a/test/form/samples/side-effects-pattern-defaults/_expected/amd.js b/test/form/samples/side-effects-pattern-defaults/_expected/amd.js index 58093071580..85339cc44da 100644 --- a/test/form/samples/side-effects-pattern-defaults/_expected/amd.js +++ b/test/form/samples/side-effects-pattern-defaults/_expected/amd.js @@ -1,13 +1,11 @@ define(function () { 'use strict'; const effect = () => console.log( 'effect' ); - var { x: a2 = effect() } = {}; var { x: a3 = () => {} } = { x: effect }; a3(); var { x: a4 = effect } = {}; a4(); - var b2; ({ x: b2 = effect() } = {}); var b3; @@ -16,13 +14,11 @@ define(function () { 'use strict'; var b4; ({ x: b4 = effect } = {}); b4(); - var [ c2 = effect() ] = []; var [ c3 = () => {} ] = [ effect ]; c3(); var [ c4 = effect ] = []; c4(); - var d2; [ d2 = effect() ] = []; var d3; diff --git a/test/form/samples/side-effects-pattern-defaults/_expected/cjs.js b/test/form/samples/side-effects-pattern-defaults/_expected/cjs.js index c95bb8de5ea..f496cd62cdf 100644 --- a/test/form/samples/side-effects-pattern-defaults/_expected/cjs.js +++ b/test/form/samples/side-effects-pattern-defaults/_expected/cjs.js @@ -1,13 +1,11 @@ 'use strict'; const effect = () => console.log( 'effect' ); - var { x: a2 = effect() } = {}; var { x: a3 = () => {} } = { x: effect }; a3(); var { x: a4 = effect } = {}; a4(); - var b2; ({ x: b2 = effect() } = {}); var b3; @@ -16,13 +14,11 @@ b3(); var b4; ({ x: b4 = effect } = {}); b4(); - var [ c2 = effect() ] = []; var [ c3 = () => {} ] = [ effect ]; c3(); var [ c4 = effect ] = []; c4(); - var d2; [ d2 = effect() ] = []; var d3; diff --git a/test/form/samples/side-effects-pattern-defaults/_expected/es.js b/test/form/samples/side-effects-pattern-defaults/_expected/es.js index 44274d6fa68..b583f866fd6 100644 --- a/test/form/samples/side-effects-pattern-defaults/_expected/es.js +++ b/test/form/samples/side-effects-pattern-defaults/_expected/es.js @@ -1,11 +1,9 @@ const effect = () => console.log( 'effect' ); - var { x: a2 = effect() } = {}; var { x: a3 = () => {} } = { x: effect }; a3(); var { x: a4 = effect } = {}; a4(); - var b2; ({ x: b2 = effect() } = {}); var b3; @@ -14,13 +12,11 @@ b3(); var b4; ({ x: b4 = effect } = {}); b4(); - var [ c2 = effect() ] = []; var [ c3 = () => {} ] = [ effect ]; c3(); var [ c4 = effect ] = []; c4(); - var d2; [ d2 = effect() ] = []; var d3; diff --git a/test/form/samples/side-effects-pattern-defaults/_expected/iife.js b/test/form/samples/side-effects-pattern-defaults/_expected/iife.js index 36a7ade3d7e..4ea4fb74c9c 100644 --- a/test/form/samples/side-effects-pattern-defaults/_expected/iife.js +++ b/test/form/samples/side-effects-pattern-defaults/_expected/iife.js @@ -2,13 +2,11 @@ 'use strict'; const effect = () => console.log( 'effect' ); - var { x: a2 = effect() } = {}; var { x: a3 = () => {} } = { x: effect }; a3(); var { x: a4 = effect } = {}; a4(); - var b2; ({ x: b2 = effect() } = {}); var b3; @@ -17,13 +15,11 @@ var b4; ({ x: b4 = effect } = {}); b4(); - var [ c2 = effect() ] = []; var [ c3 = () => {} ] = [ effect ]; c3(); var [ c4 = effect ] = []; c4(); - var d2; [ d2 = effect() ] = []; var d3; diff --git a/test/form/samples/side-effects-pattern-defaults/_expected/umd.js b/test/form/samples/side-effects-pattern-defaults/_expected/umd.js index 00f4eb91497..3172bc150ba 100644 --- a/test/form/samples/side-effects-pattern-defaults/_expected/umd.js +++ b/test/form/samples/side-effects-pattern-defaults/_expected/umd.js @@ -5,13 +5,11 @@ }(this, (function () { 'use strict'; const effect = () => console.log( 'effect' ); - var { x: a2 = effect() } = {}; var { x: a3 = () => {} } = { x: effect }; a3(); var { x: a4 = effect } = {}; a4(); - var b2; ({ x: b2 = effect() } = {}); var b3; @@ -20,13 +18,11 @@ var b4; ({ x: b4 = effect } = {}); b4(); - var [ c2 = effect() ] = []; var [ c3 = () => {} ] = [ effect ]; c3(); var [ c4 = effect ] = []; c4(); - var d2; [ d2 = effect() ] = []; var d3; diff --git a/test/form/samples/skips-dead-branches-g/_expected/amd.js b/test/form/samples/skips-dead-branches-g/_expected/amd.js index 41371dd60ab..c09e4013738 100644 --- a/test/form/samples/skips-dead-branches-g/_expected/amd.js +++ b/test/form/samples/skips-dead-branches-g/_expected/amd.js @@ -2,9 +2,10 @@ define(function () { 'use strict'; var a = 0; var b = 1; + var x = a; var y = b; console.log( x + y ); -}); \ No newline at end of file +}); diff --git a/test/form/samples/skips-dead-branches-g/_expected/cjs.js b/test/form/samples/skips-dead-branches-g/_expected/cjs.js index 44cffbfd667..e8e7e8da8c2 100644 --- a/test/form/samples/skips-dead-branches-g/_expected/cjs.js +++ b/test/form/samples/skips-dead-branches-g/_expected/cjs.js @@ -2,7 +2,8 @@ var a = 0; var b = 1; + var x = a; var y = b; -console.log( x + y ); \ No newline at end of file +console.log( x + y ); diff --git a/test/form/samples/skips-dead-branches-g/_expected/es.js b/test/form/samples/skips-dead-branches-g/_expected/es.js index 93d519839c6..c181ba24ebc 100644 --- a/test/form/samples/skips-dead-branches-g/_expected/es.js +++ b/test/form/samples/skips-dead-branches-g/_expected/es.js @@ -1,6 +1,7 @@ var a = 0; var b = 1; + var x = a; var y = b; -console.log( x + y ); \ No newline at end of file +console.log( x + y ); diff --git a/test/form/samples/skips-dead-branches-g/_expected/iife.js b/test/form/samples/skips-dead-branches-g/_expected/iife.js index ce654f4f6ca..170088a0846 100644 --- a/test/form/samples/skips-dead-branches-g/_expected/iife.js +++ b/test/form/samples/skips-dead-branches-g/_expected/iife.js @@ -3,9 +3,10 @@ var a = 0; var b = 1; + var x = a; var y = b; console.log( x + y ); -}()); \ No newline at end of file +}()); diff --git a/test/form/samples/skips-dead-branches-g/_expected/umd.js b/test/form/samples/skips-dead-branches-g/_expected/umd.js index 40a0a544539..168aa8eff1d 100644 --- a/test/form/samples/skips-dead-branches-g/_expected/umd.js +++ b/test/form/samples/skips-dead-branches-g/_expected/umd.js @@ -6,9 +6,10 @@ var a = 0; var b = 1; + var x = a; var y = b; console.log( x + y ); -}))); \ No newline at end of file +}))); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js index 4db965ceaa3..382aff4862f 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js @@ -1,7 +1,6 @@ define(function () { 'use strict'; function x () { return 'x' } - assert.equal( x(), 'x' ); }); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js index bac28c19265..87e51bba080 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js @@ -1,5 +1,4 @@ 'use strict'; function x () { return 'x' } - assert.equal( x(), 'x' ); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js index f5b5029659d..fe0fb3f215b 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js @@ -1,3 +1,2 @@ function x () { return 'x' } - assert.equal( x(), 'x' ); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js index f8d69920288..662b2220277 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js @@ -2,7 +2,6 @@ 'use strict'; function x () { return 'x' } - assert.equal( x(), 'x' ); }()); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js index 75d31a1d04b..4730500a2f7 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js @@ -5,7 +5,6 @@ }(this, (function () { 'use strict'; function x () { return 'x' } - assert.equal( x(), 'x' ); }))); diff --git a/test/form/samples/switch-scopes/_expected/amd.js b/test/form/samples/switch-scopes/_expected/amd.js index f8af6ec51dd..b4615ca613e 100644 --- a/test/form/samples/switch-scopes/_expected/amd.js +++ b/test/form/samples/switch-scopes/_expected/amd.js @@ -1,6 +1,7 @@ define(function () { 'use strict'; const x = globalFunction; + switch ( anotherGlobal ) { case 2: x(); diff --git a/test/form/samples/switch-scopes/_expected/cjs.js b/test/form/samples/switch-scopes/_expected/cjs.js index ee73f2e70d7..a56193c4057 100644 --- a/test/form/samples/switch-scopes/_expected/cjs.js +++ b/test/form/samples/switch-scopes/_expected/cjs.js @@ -1,6 +1,7 @@ 'use strict'; const x = globalFunction; + switch ( anotherGlobal ) { case 2: x(); diff --git a/test/form/samples/switch-scopes/_expected/es.js b/test/form/samples/switch-scopes/_expected/es.js index f5cd80e94e6..43d842d3ade 100644 --- a/test/form/samples/switch-scopes/_expected/es.js +++ b/test/form/samples/switch-scopes/_expected/es.js @@ -1,4 +1,5 @@ const x = globalFunction; + switch ( anotherGlobal ) { case 2: x(); diff --git a/test/form/samples/switch-scopes/_expected/iife.js b/test/form/samples/switch-scopes/_expected/iife.js index f52899caedb..8ecee29b379 100644 --- a/test/form/samples/switch-scopes/_expected/iife.js +++ b/test/form/samples/switch-scopes/_expected/iife.js @@ -2,6 +2,7 @@ 'use strict'; const x = globalFunction; + switch ( anotherGlobal ) { case 2: x(); diff --git a/test/form/samples/switch-scopes/_expected/umd.js b/test/form/samples/switch-scopes/_expected/umd.js index bed407c91ef..626ecf4dcb7 100644 --- a/test/form/samples/switch-scopes/_expected/umd.js +++ b/test/form/samples/switch-scopes/_expected/umd.js @@ -5,6 +5,7 @@ }(this, (function () { 'use strict'; const x = globalFunction; + switch ( anotherGlobal ) { case 2: x(); diff --git a/test/form/samples/this-in-imports/_expected/amd.js b/test/form/samples/this-in-imports/_expected/amd.js index 95de6bb26d2..6f996d5bfcc 100644 --- a/test/form/samples/this-in-imports/_expected/amd.js +++ b/test/form/samples/this-in-imports/_expected/amd.js @@ -13,9 +13,7 @@ define(function () { 'use strict'; } const b1 = B(); - const b2 = B$1(); - const b3 = B3(); }); diff --git a/test/form/samples/this-in-imports/_expected/cjs.js b/test/form/samples/this-in-imports/_expected/cjs.js index 279b7d41677..9a6ca99d66d 100644 --- a/test/form/samples/this-in-imports/_expected/cjs.js +++ b/test/form/samples/this-in-imports/_expected/cjs.js @@ -13,7 +13,5 @@ function B3 () { } const b1 = B(); - const b2 = B$1(); - const b3 = B3(); diff --git a/test/form/samples/this-in-imports/_expected/es.js b/test/form/samples/this-in-imports/_expected/es.js index 258bece003f..de669e86f5e 100644 --- a/test/form/samples/this-in-imports/_expected/es.js +++ b/test/form/samples/this-in-imports/_expected/es.js @@ -11,7 +11,5 @@ function B3 () { } const b1 = B(); - const b2 = B$1(); - const b3 = B3(); diff --git a/test/form/samples/this-in-imports/_expected/iife.js b/test/form/samples/this-in-imports/_expected/iife.js index 5af4ce61f8e..cbce86ed71e 100644 --- a/test/form/samples/this-in-imports/_expected/iife.js +++ b/test/form/samples/this-in-imports/_expected/iife.js @@ -14,9 +14,7 @@ } const b1 = B(); - const b2 = B$1(); - const b3 = B3(); }()); diff --git a/test/form/samples/this-in-imports/_expected/umd.js b/test/form/samples/this-in-imports/_expected/umd.js index c629e51e5e2..340ab31185f 100644 --- a/test/form/samples/this-in-imports/_expected/umd.js +++ b/test/form/samples/this-in-imports/_expected/umd.js @@ -17,9 +17,7 @@ } const b1 = B(); - const b2 = B$1(); - const b3 = B3(); }))); diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/amd.js b/test/form/samples/unused-inner-functions-and-classes/_expected/amd.js index 17f977ccca3..e1eb59196ea 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/amd.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/amd.js @@ -2,8 +2,6 @@ define(function () { 'use strict'; function bar () { console.log("outer bar"); } - - function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/cjs.js b/test/form/samples/unused-inner-functions-and-classes/_expected/cjs.js index e7f8857a3e7..cdabcb9329c 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/cjs.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/cjs.js @@ -2,8 +2,6 @@ function bar () { console.log("outer bar"); } - - function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/es.js b/test/form/samples/unused-inner-functions-and-classes/_expected/es.js index 75a7db67005..d9a767b2bc5 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/es.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/es.js @@ -1,7 +1,5 @@ function bar () { console.log("outer bar"); } - - function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/iife.js b/test/form/samples/unused-inner-functions-and-classes/_expected/iife.js index 0ec7886c3c6..7759377c142 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/iife.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/iife.js @@ -3,8 +3,6 @@ function bar () { console.log("outer bar"); } - - function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } diff --git a/test/form/samples/unused-inner-functions-and-classes/_expected/umd.js b/test/form/samples/unused-inner-functions-and-classes/_expected/umd.js index b4b5108571d..d78b0c51b09 100644 --- a/test/form/samples/unused-inner-functions-and-classes/_expected/umd.js +++ b/test/form/samples/unused-inner-functions-and-classes/_expected/umd.js @@ -6,8 +6,6 @@ function bar () { console.log("outer bar"); } - - function Baz() { function bar () { console.log("inner bar"); } function bog () { console.log("inner bog"); } From 48f468360d27eb84f6dacbde728563d5878f765f Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Sun, 28 Jan 2018 18:01:40 +0100 Subject: [PATCH 03/27] Use new logic for switch statements (which works much better than the old logic but can leave trailing comments and line-breaks as the SwitchCase length provided by acorn does not include those) --- src/ast/nodes/SwitchCase.ts | 14 +++++++++++++ .../_expected/amd.js | 15 +++++++++++++ .../_expected/cjs.js | 15 +++++++++++++ .../render-removed-statements/_expected/es.js | 15 +++++++++++++ .../_expected/iife.js | 15 +++++++++++++ .../_expected/umd.js | 15 +++++++++++++ .../samples/render-removed-statements/main.js | 21 +++++++++++++++++++ .../_expected/amd.js | 4 +--- .../_expected/cjs.js | 4 +--- .../_expected/es.js | 4 +--- .../_expected/iife.js | 4 +--- .../_expected/umd.js | 4 +--- 12 files changed, 115 insertions(+), 15 deletions(-) diff --git a/src/ast/nodes/SwitchCase.ts b/src/ast/nodes/SwitchCase.ts index a8f61f496b3..5a1bddb0c3b 100644 --- a/src/ast/nodes/SwitchCase.ts +++ b/src/ast/nodes/SwitchCase.ts @@ -1,6 +1,9 @@ import { ExpressionNode, NodeBase } from './shared/Node'; import { StatementNode } from './shared/Statement'; import { NodeType } from './NodeType'; +import { renderStatementBlock } from '../../utils/renderHelpers'; +import { RenderOptions } from '../../Module'; +import MagicString from 'magic-string'; export default class SwitchCase extends NodeBase { type: NodeType.SwitchCase; @@ -22,4 +25,15 @@ export default class SwitchCase extends NodeBase { }); return addedNewNodes; } + + render (code: MagicString, options: RenderOptions) { + if (this.consequent.length) { + const firstNodeStart = this.consequent[0].start; + const firstLeadingLineBreakPos = code.slice(this.start, firstNodeStart).indexOf('\n'); + const start = firstLeadingLineBreakPos === -1 ? firstNodeStart : firstLeadingLineBreakPos + this.start; + renderStatementBlock(this.consequent, code, start, this.end, options); + } else { + super.render(code, options); + } + } } diff --git a/test/form/samples/render-removed-statements/_expected/amd.js b/test/form/samples/render-removed-statements/_expected/amd.js index 6362ba9d16f..0a6daa0a36f 100644 --- a/test/form/samples/render-removed-statements/_expected/amd.js +++ b/test/form/samples/render-removed-statements/_expected/amd.js @@ -23,6 +23,21 @@ define(function () { 'use strict'; if (globalVar) { /* retained */ console.log(1);} + switch (globalVar) { + case 1: + // lead retained + console.log(1); // trail retained + case 2: + // lead retained + console.log(1); // trail retained + + case 3: + // lead retained + console.log(1); // trail retained + + case 4: /* lead retained */ console.log('3'); // trail retained + } + // lead retained console.log(1); // trail retained diff --git a/test/form/samples/render-removed-statements/_expected/cjs.js b/test/form/samples/render-removed-statements/_expected/cjs.js index a69a76dcee0..7386c84029d 100644 --- a/test/form/samples/render-removed-statements/_expected/cjs.js +++ b/test/form/samples/render-removed-statements/_expected/cjs.js @@ -23,6 +23,21 @@ if (globalVar) { /* retained */ console.log(1);} if (globalVar) { /* retained */ console.log(1);} +switch (globalVar) { + case 1: + // lead retained + console.log(1); // trail retained + case 2: + // lead retained + console.log(1); // trail retained + + case 3: + // lead retained + console.log(1); // trail retained + + case 4: /* lead retained */ console.log('3'); // trail retained +} + // lead retained console.log(1); // trail retained diff --git a/test/form/samples/render-removed-statements/_expected/es.js b/test/form/samples/render-removed-statements/_expected/es.js index 03f271cdf61..27e871001d7 100644 --- a/test/form/samples/render-removed-statements/_expected/es.js +++ b/test/form/samples/render-removed-statements/_expected/es.js @@ -21,6 +21,21 @@ if (globalVar) { /* retained */ console.log(1);} if (globalVar) { /* retained */ console.log(1);} +switch (globalVar) { + case 1: + // lead retained + console.log(1); // trail retained + case 2: + // lead retained + console.log(1); // trail retained + + case 3: + // lead retained + console.log(1); // trail retained + + case 4: /* lead retained */ console.log('3'); // trail retained +} + // lead retained console.log(1); // trail retained diff --git a/test/form/samples/render-removed-statements/_expected/iife.js b/test/form/samples/render-removed-statements/_expected/iife.js index dd567cc290a..027434e9b47 100644 --- a/test/form/samples/render-removed-statements/_expected/iife.js +++ b/test/form/samples/render-removed-statements/_expected/iife.js @@ -24,6 +24,21 @@ if (globalVar) { /* retained */ console.log(1);} + switch (globalVar) { + case 1: + // lead retained + console.log(1); // trail retained + case 2: + // lead retained + console.log(1); // trail retained + + case 3: + // lead retained + console.log(1); // trail retained + + case 4: /* lead retained */ console.log('3'); // trail retained + } + // lead retained console.log(1); // trail retained diff --git a/test/form/samples/render-removed-statements/_expected/umd.js b/test/form/samples/render-removed-statements/_expected/umd.js index e28847854d9..02d133a0dc9 100644 --- a/test/form/samples/render-removed-statements/_expected/umd.js +++ b/test/form/samples/render-removed-statements/_expected/umd.js @@ -27,6 +27,21 @@ if (globalVar) { /* retained */ console.log(1);} + switch (globalVar) { + case 1: + // lead retained + console.log(1); // trail retained + case 2: + // lead retained + console.log(1); // trail retained + + case 3: + // lead retained + console.log(1); // trail retained + + case 4: /* lead retained */ console.log('3'); // trail retained + } + // lead retained console.log(1); // trail retained diff --git a/test/form/samples/render-removed-statements/main.js b/test/form/samples/render-removed-statements/main.js index 44da362f421..72c9cd5a350 100644 --- a/test/form/samples/render-removed-statements/main.js +++ b/test/form/samples/render-removed-statements/main.js @@ -31,6 +31,27 @@ if (globalVar) { /* removed */ const x = 1; /* retained */ console.log(1); /* re if (globalVar) { /* retained */ console.log(1); /* removed */ const y = 1;} +switch (globalVar) { + case 1: + // lead removed + const a = 1; // trail removed + // lead retained + console.log(1); // trail retained + case 2: + // lead removed + const b = 1; // trail removed + // lead retained + console.log(1); // trail retained + // lead removed + const c = 1; + case 3: + // lead retained + console.log(1); // trail retained + // lead removed + const d = 1; + case 4: const e = 1; /* lead retained */ console.log('3') // trail retained +} + // lead removed const y = 1; // trail removed diff --git a/test/form/samples/side-effects-switch-statements/_expected/amd.js b/test/form/samples/side-effects-switch-statements/_expected/amd.js index 7b375a19e7a..1c564b9058d 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/amd.js +++ b/test/form/samples/side-effects-switch-statements/_expected/amd.js @@ -8,19 +8,17 @@ define(function () { 'use strict'; case foo: case bar: effect(); - if ( globalVar > 1 ) { break; } case baz: effect(); default: - + } switch ( globalVar ) { case foo: - break; case bar: effect(); diff --git a/test/form/samples/side-effects-switch-statements/_expected/cjs.js b/test/form/samples/side-effects-switch-statements/_expected/cjs.js index acc644d631f..b38e20d2b8f 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/cjs.js +++ b/test/form/samples/side-effects-switch-statements/_expected/cjs.js @@ -8,19 +8,17 @@ switch ( globalVar ) { case foo: case bar: effect(); - if ( globalVar > 1 ) { break; } case baz: effect(); default: - + } switch ( globalVar ) { case foo: - break; case bar: effect(); diff --git a/test/form/samples/side-effects-switch-statements/_expected/es.js b/test/form/samples/side-effects-switch-statements/_expected/es.js index d1bc62c540a..6df30c21be2 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/es.js +++ b/test/form/samples/side-effects-switch-statements/_expected/es.js @@ -6,19 +6,17 @@ switch ( globalVar ) { case foo: case bar: effect(); - if ( globalVar > 1 ) { break; } case baz: effect(); default: - + } switch ( globalVar ) { case foo: - break; case bar: effect(); diff --git a/test/form/samples/side-effects-switch-statements/_expected/iife.js b/test/form/samples/side-effects-switch-statements/_expected/iife.js index 867452b6314..6273f69b404 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/iife.js +++ b/test/form/samples/side-effects-switch-statements/_expected/iife.js @@ -9,19 +9,17 @@ case foo: case bar: effect(); - if ( globalVar > 1 ) { break; } case baz: effect(); default: - + } switch ( globalVar ) { case foo: - break; case bar: effect(); diff --git a/test/form/samples/side-effects-switch-statements/_expected/umd.js b/test/form/samples/side-effects-switch-statements/_expected/umd.js index 0814462e8f8..7965d940ebf 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/umd.js +++ b/test/form/samples/side-effects-switch-statements/_expected/umd.js @@ -12,19 +12,17 @@ case foo: case bar: effect(); - if ( globalVar > 1 ) { break; } case baz: effect(); default: - + } switch ( globalVar ) { case foo: - break; case bar: effect(); From 152eb29deda3390bc24e78f744ac87ffb02aebc5 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Fri, 2 Feb 2018 06:49:06 +0100 Subject: [PATCH 04/27] * Properly handle multi-line comments after statements * Skip unnecessary calculations --- src/utils/renderHelpers.ts | 58 +++++++++++++------ .../samples/empty-statement/_expected/amd.js | 3 +- .../samples/empty-statement/_expected/cjs.js | 3 +- .../samples/empty-statement/_expected/es.js | 3 +- .../samples/empty-statement/_expected/iife.js | 3 +- .../samples/empty-statement/_expected/umd.js | 3 +- .../_expected/amd.js | 30 ++++++---- .../_expected/cjs.js | 30 ++++++---- .../render-removed-statements/_expected/es.js | 30 ++++++---- .../_expected/iife.js | 30 ++++++---- .../_expected/umd.js | 30 ++++++---- .../samples/render-removed-statements/main.js | 46 ++++++++++----- .../_expected/amd.js | 1 - .../_expected/cjs.js | 1 - .../_expected/es.js | 1 - .../_expected/iife.js | 1 - .../_expected/umd.js | 1 - .../_expected/amd.js | 1 + .../_expected/cjs.js | 1 + .../_expected/es.js | 1 + .../_expected/iife.js | 1 + .../_expected/umd.js | 1 + 22 files changed, 175 insertions(+), 104 deletions(-) diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index f734e10adbe..a583c886d47 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -3,28 +3,50 @@ import MagicString from 'magic-string'; import { RenderOptions } from '../Module'; import { NodeType } from '../ast/nodes/NodeType'; +function findFirstLineBreakOutsideComment (code: string) { + let codeStart = 0; + let commentStart, commentLength, lineBreakPos; + while (true) { + commentStart = code.indexOf('/*'); + lineBreakPos = (~commentStart ? code.slice(0, commentStart) : code).indexOf('\n'); + if (~lineBreakPos || !~commentStart) { + break; + } + code = code.slice(commentStart); + commentLength = code.indexOf('*/') + 2; + code = code.slice(commentLength); + codeStart += commentStart + commentLength; + } + return ~lineBreakPos ? codeStart + lineBreakPos : 0; +} + export function renderStatementBlock (statements: Node[], code: MagicString, start: number, end: number, options: RenderOptions) { if (statements.length === 0) return; - let nodeStart = statements[0].start; - // To work around a bug in magic-string when nodeStart = start = 0; - let nextLineBreakPos = nodeStart > start ? code.slice(start, statements[0].start).indexOf('\n') : -1; - nodeStart = Math.max(0, nextLineBreakPos + 1) + start; + let currentNode, currentNodeStart; + let nextNode = statements[0]; + // TODO we need to work around a bug in magic-string when nodeStart = start = 0 + let nextNodeStart = start + (nextNode.start === start ? 0 : findFirstLineBreakOutsideComment(code.slice(start, nextNode.start))); - let nodeEnd; - for (let nodeIdx = 0; nodeIdx < statements.length; nodeIdx++) { - const node = statements[nodeIdx]; - if (nodeIdx === statements.length - 1) { - nodeEnd = end; - } else { - const nextNode = statements[nodeIdx + 1]; - nextLineBreakPos = code.slice(node.end, nextNode.start).indexOf('\n'); - nodeEnd = Math.max(0, nextLineBreakPos + 1) + node.end; - } - if (!node.included && node.type !== NodeType.ExportDefaultDeclaration && node.type !== NodeType.IfStatement) { - code.remove(nodeStart, nodeEnd); + for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) { + currentNode = nextNode; + currentNodeStart = nextNodeStart; + nextNode = statements[nextIndex]; + if (!currentNode.included || (nextNode !== undefined && !nextNode.included)) { + nextNodeStart = currentNode.end + (findFirstLineBreakOutsideComment(code.slice( + currentNode.end, + nextNode !== undefined ? nextNode.start : end + ))); + if ( + !currentNode.included + && currentNode.type !== NodeType.ExportDefaultDeclaration + && currentNode.type !== NodeType.IfStatement + ) { + code.remove(currentNodeStart, nextNodeStart); + } else { + currentNode.render(code, options); + } } else { - node.render(code, options); + currentNode.render(code, options); } - nodeStart = nodeEnd; } } diff --git a/test/form/samples/empty-statement/_expected/amd.js b/test/form/samples/empty-statement/_expected/amd.js index 6255bc57cbf..6036f2851d3 100644 --- a/test/form/samples/empty-statement/_expected/amd.js +++ b/test/form/samples/empty-statement/_expected/amd.js @@ -1,5 +1,6 @@ define(function () { 'use strict'; - console.log( 1 );console.log( 2 ); + console.log( 1 ); + console.log( 2 ); }); diff --git a/test/form/samples/empty-statement/_expected/cjs.js b/test/form/samples/empty-statement/_expected/cjs.js index b54ecd1cf86..33f9de05030 100644 --- a/test/form/samples/empty-statement/_expected/cjs.js +++ b/test/form/samples/empty-statement/_expected/cjs.js @@ -1,3 +1,4 @@ 'use strict'; -console.log( 1 );console.log( 2 ); +console.log( 1 ); +console.log( 2 ); diff --git a/test/form/samples/empty-statement/_expected/es.js b/test/form/samples/empty-statement/_expected/es.js index dcc93dc9b24..472e544d88c 100644 --- a/test/form/samples/empty-statement/_expected/es.js +++ b/test/form/samples/empty-statement/_expected/es.js @@ -1 +1,2 @@ -console.log( 1 );console.log( 2 ); +console.log( 1 ); +console.log( 2 ); diff --git a/test/form/samples/empty-statement/_expected/iife.js b/test/form/samples/empty-statement/_expected/iife.js index 60508d61edf..08a84a95e53 100644 --- a/test/form/samples/empty-statement/_expected/iife.js +++ b/test/form/samples/empty-statement/_expected/iife.js @@ -1,6 +1,7 @@ (function () { 'use strict'; - console.log( 1 );console.log( 2 ); + console.log( 1 ); + console.log( 2 ); }()); diff --git a/test/form/samples/empty-statement/_expected/umd.js b/test/form/samples/empty-statement/_expected/umd.js index a1f6dfc10c0..0aae43fe29d 100644 --- a/test/form/samples/empty-statement/_expected/umd.js +++ b/test/form/samples/empty-statement/_expected/umd.js @@ -4,6 +4,7 @@ (factory()); }(this, (function () { 'use strict'; - console.log( 1 );console.log( 2 ); + console.log( 1 ); + console.log( 2 ); }))); diff --git a/test/form/samples/render-removed-statements/_expected/amd.js b/test/form/samples/render-removed-statements/_expected/amd.js index 0a6daa0a36f..ead127da7af 100644 --- a/test/form/samples/render-removed-statements/_expected/amd.js +++ b/test/form/samples/render-removed-statements/_expected/amd.js @@ -2,44 +2,50 @@ define(function () { 'use strict'; /* header retained */ + /* lead retained */ + console.log(2); /* trail + retained */ + if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained + } + + if (globalVar) { + console.log(2); } - if (globalVar) { /* retained */ console.log(1);} + if (globalVar) { /* retained */ console.log(2);} - if (globalVar) { /* retained */ console.log(1);} + if (globalVar) { /* retained */ console.log(2);} - if (globalVar) { /* retained */ console.log(1);} + if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { case 1: // lead retained - console.log(1); // trail retained + console.log(2); // trail retained case 2: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 3: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 4: /* lead retained */ console.log('3'); // trail retained } // lead retained - console.log(1); // trail retained + console.log(2); // trail retained /* footer retained */ diff --git a/test/form/samples/render-removed-statements/_expected/cjs.js b/test/form/samples/render-removed-statements/_expected/cjs.js index 7386c84029d..d2f24d06d83 100644 --- a/test/form/samples/render-removed-statements/_expected/cjs.js +++ b/test/form/samples/render-removed-statements/_expected/cjs.js @@ -2,43 +2,49 @@ /* header retained */ +/* lead retained */ +console.log(2); /* trail +retained */ + if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained +} + +if (globalVar) { + console.log(2); } -if (globalVar) { /* retained */ console.log(1);} +if (globalVar) { /* retained */ console.log(2);} -if (globalVar) { /* retained */ console.log(1);} +if (globalVar) { /* retained */ console.log(2);} -if (globalVar) { /* retained */ console.log(1);} +if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { case 1: // lead retained - console.log(1); // trail retained + console.log(2); // trail retained case 2: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 3: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 4: /* lead retained */ console.log('3'); // trail retained } // lead retained -console.log(1); // trail retained +console.log(2); // trail retained /* footer retained */ diff --git a/test/form/samples/render-removed-statements/_expected/es.js b/test/form/samples/render-removed-statements/_expected/es.js index 27e871001d7..da62bf30cce 100644 --- a/test/form/samples/render-removed-statements/_expected/es.js +++ b/test/form/samples/render-removed-statements/_expected/es.js @@ -1,42 +1,48 @@ /* header retained */ +/* lead retained */ +console.log(2); /* trail +retained */ + if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained +} + +if (globalVar) { + console.log(2); } -if (globalVar) { /* retained */ console.log(1);} +if (globalVar) { /* retained */ console.log(2);} -if (globalVar) { /* retained */ console.log(1);} +if (globalVar) { /* retained */ console.log(2);} -if (globalVar) { /* retained */ console.log(1);} +if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { case 1: // lead retained - console.log(1); // trail retained + console.log(2); // trail retained case 2: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 3: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 4: /* lead retained */ console.log('3'); // trail retained } // lead retained -console.log(1); // trail retained +console.log(2); // trail retained /* footer retained */ diff --git a/test/form/samples/render-removed-statements/_expected/iife.js b/test/form/samples/render-removed-statements/_expected/iife.js index 027434e9b47..0d7517f32c4 100644 --- a/test/form/samples/render-removed-statements/_expected/iife.js +++ b/test/form/samples/render-removed-statements/_expected/iife.js @@ -3,44 +3,50 @@ /* header retained */ + /* lead retained */ + console.log(2); /* trail + retained */ + if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained + } + + if (globalVar) { + console.log(2); } - if (globalVar) { /* retained */ console.log(1);} + if (globalVar) { /* retained */ console.log(2);} - if (globalVar) { /* retained */ console.log(1);} + if (globalVar) { /* retained */ console.log(2);} - if (globalVar) { /* retained */ console.log(1);} + if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { case 1: // lead retained - console.log(1); // trail retained + console.log(2); // trail retained case 2: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 3: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 4: /* lead retained */ console.log('3'); // trail retained } // lead retained - console.log(1); // trail retained + console.log(2); // trail retained /* footer retained */ diff --git a/test/form/samples/render-removed-statements/_expected/umd.js b/test/form/samples/render-removed-statements/_expected/umd.js index 02d133a0dc9..88d4c277346 100644 --- a/test/form/samples/render-removed-statements/_expected/umd.js +++ b/test/form/samples/render-removed-statements/_expected/umd.js @@ -6,44 +6,50 @@ /* header retained */ + /* lead retained */ + console.log(2); /* trail + retained */ + if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained + } + + if (globalVar) { + console.log(2); } - if (globalVar) { /* retained */ console.log(1);} + if (globalVar) { /* retained */ console.log(2);} - if (globalVar) { /* retained */ console.log(1);} + if (globalVar) { /* retained */ console.log(2);} - if (globalVar) { /* retained */ console.log(1);} + if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { case 1: // lead retained - console.log(1); // trail retained + console.log(2); // trail retained case 2: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 3: // lead retained - console.log(1); // trail retained - + console.log(2); // trail retained case 4: /* lead retained */ console.log('3'); // trail retained } // lead retained - console.log(1); // trail retained + console.log(2); // trail retained /* footer retained */ diff --git a/test/form/samples/render-removed-statements/main.js b/test/form/samples/render-removed-statements/main.js index 72c9cd5a350..da6a49bdf79 100644 --- a/test/form/samples/render-removed-statements/main.js +++ b/test/form/samples/render-removed-statements/main.js @@ -1,62 +1,76 @@ /* header retained */ -/* lead removed */ const x = 1; // trail removed +/* lead removed */ var a = 1; // trail removed + +/* lead removed */ +var a = 1; /* trail +removed */ + +/* lead retained */ +console.log(2); /* trail +retained */ if (globalVar) { // lead removed - const x = 1; // trail removed + var x = 1; // trail removed // lead retained - console.log(1); // trail retained + console.log(2); // trail retained } if (globalVar) { // lead removed - const x = 1; // trail removed + var x = 1; // trail removed // lead retained - console.log(1); // trail retained + console.log(2); // trail retained // lead removed - const y = 1; // trail removed + var a = 1; // trail removed } if (globalVar) { // lead retained - console.log(1); // trail retained + console.log(2); // trail retained // lead removed - const y = 1; // trail removed + var a = 1; // trail removed +} + +if (globalVar) { + console.log(2); + var a = 1; /* trail + removed */ } -if (globalVar) { /* removed */ const x = 1; /* retained */ console.log(1);} +if (globalVar) { /* removed */ var x = 1; /* retained */ console.log(2);} -if (globalVar) { /* removed */ const x = 1; /* retained */ console.log(1); /* removed */ const y = 1;} +if (globalVar) { /* removed */ var x = 1; /* retained */ console.log(2); /* removed */ var a = 1;} -if (globalVar) { /* retained */ console.log(1); /* removed */ const y = 1;} +if (globalVar) { /* retained */ console.log(2); /* removed */ var a = 1;} switch (globalVar) { case 1: // lead removed const a = 1; // trail removed // lead retained - console.log(1); // trail retained + console.log(2); // trail retained case 2: // lead removed const b = 1; // trail removed // lead retained - console.log(1); // trail retained + console.log(2); // trail retained // lead removed const c = 1; case 3: // lead retained - console.log(1); // trail retained + console.log(2); // trail retained // lead removed const d = 1; case 4: const e = 1; /* lead retained */ console.log('3') // trail retained } // lead removed -const y = 1; // trail removed +var a = 1; // trail removed // lead retained -console.log(1); // trail retained +console.log(2); // trail retained // lead removed const z = 1; // trail removed diff --git a/test/form/samples/side-effects-switch-statements/_expected/amd.js b/test/form/samples/side-effects-switch-statements/_expected/amd.js index 1c564b9058d..d60a8ee0af2 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/amd.js +++ b/test/form/samples/side-effects-switch-statements/_expected/amd.js @@ -14,7 +14,6 @@ define(function () { 'use strict'; case baz: effect(); default: - } switch ( globalVar ) { diff --git a/test/form/samples/side-effects-switch-statements/_expected/cjs.js b/test/form/samples/side-effects-switch-statements/_expected/cjs.js index b38e20d2b8f..d6bcd0340c6 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/cjs.js +++ b/test/form/samples/side-effects-switch-statements/_expected/cjs.js @@ -14,7 +14,6 @@ switch ( globalVar ) { case baz: effect(); default: - } switch ( globalVar ) { diff --git a/test/form/samples/side-effects-switch-statements/_expected/es.js b/test/form/samples/side-effects-switch-statements/_expected/es.js index 6df30c21be2..6c54e6d3dfc 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/es.js +++ b/test/form/samples/side-effects-switch-statements/_expected/es.js @@ -12,7 +12,6 @@ switch ( globalVar ) { case baz: effect(); default: - } switch ( globalVar ) { diff --git a/test/form/samples/side-effects-switch-statements/_expected/iife.js b/test/form/samples/side-effects-switch-statements/_expected/iife.js index 6273f69b404..e1d67ce69bc 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/iife.js +++ b/test/form/samples/side-effects-switch-statements/_expected/iife.js @@ -15,7 +15,6 @@ case baz: effect(); default: - } switch ( globalVar ) { diff --git a/test/form/samples/side-effects-switch-statements/_expected/umd.js b/test/form/samples/side-effects-switch-statements/_expected/umd.js index 7965d940ebf..230294004d2 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/umd.js +++ b/test/form/samples/side-effects-switch-statements/_expected/umd.js @@ -18,7 +18,6 @@ case baz: effect(); default: - } switch ( globalVar ) { diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js index 382aff4862f..4db965ceaa3 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js @@ -1,6 +1,7 @@ define(function () { 'use strict'; function x () { return 'x' } + assert.equal( x(), 'x' ); }); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js index 87e51bba080..bac28c19265 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js @@ -1,4 +1,5 @@ 'use strict'; function x () { return 'x' } + assert.equal( x(), 'x' ); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js index fe0fb3f215b..f5b5029659d 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js @@ -1,2 +1,3 @@ function x () { return 'x' } + assert.equal( x(), 'x' ); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js index 662b2220277..f8d69920288 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js @@ -2,6 +2,7 @@ 'use strict'; function x () { return 'x' } + assert.equal( x(), 'x' ); }()); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js index 4730500a2f7..75d31a1d04b 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js @@ -5,6 +5,7 @@ }(this, (function () { 'use strict'; function x () { return 'x' } + assert.equal( x(), 'x' ); }))); From eae7d962ea87a0ef82ec7c8d9e154c11d637dd3f Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Fri, 2 Feb 2018 13:53:49 +0100 Subject: [PATCH 05/27] Refactor and simplify default export rendering --- src/Module.ts | 5 + src/ast/nodes/ClassDeclaration.ts | 5 + src/ast/nodes/ExportDefaultDeclaration.ts | 121 ++++++------------ src/ast/nodes/FunctionDeclaration.ts | 5 + src/ast/nodes/shared/Node.ts | 7 +- src/ast/variables/ExportDefaultVariable.ts | 11 -- src/utils/renderHelpers.ts | 22 +--- .../tree-shake-default-exports/_config.js | 3 + .../_expected/amd.js | 47 +++++++ .../_expected/cjs.js | 45 +++++++ .../_expected/es.js | 43 +++++++ .../_expected/iife.js | 48 +++++++ .../_expected/umd.js | 51 ++++++++ .../tree-shake-default-exports/main.js | 10 ++ .../tree-shake-default-exports/unused.js | 6 + .../unusedFunction.js | 8 ++ .../unusedSideEffect.js | 6 + .../tree-shake-default-exports/used.js | 6 + .../usedFunction.js | 8 ++ .../usedNamedFunction.js | 8 ++ 20 files changed, 354 insertions(+), 111 deletions(-) create mode 100644 test/form/samples/tree-shake-default-exports/_config.js create mode 100644 test/form/samples/tree-shake-default-exports/_expected/amd.js create mode 100644 test/form/samples/tree-shake-default-exports/_expected/cjs.js create mode 100644 test/form/samples/tree-shake-default-exports/_expected/es.js create mode 100644 test/form/samples/tree-shake-default-exports/_expected/iife.js create mode 100644 test/form/samples/tree-shake-default-exports/_expected/umd.js create mode 100644 test/form/samples/tree-shake-default-exports/main.js create mode 100644 test/form/samples/tree-shake-default-exports/unused.js create mode 100644 test/form/samples/tree-shake-default-exports/unusedFunction.js create mode 100644 test/form/samples/tree-shake-default-exports/unusedSideEffect.js create mode 100644 test/form/samples/tree-shake-default-exports/used.js create mode 100644 test/form/samples/tree-shake-default-exports/usedFunction.js create mode 100644 test/form/samples/tree-shake-default-exports/usedNamedFunction.js diff --git a/src/Module.ts b/src/Module.ts index 272974dab06..362b981ce55 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -109,6 +109,11 @@ export interface RenderOptions { systemBindings: boolean; } +export interface NodeRenderOptions { + start?: number, + end?: number +} + export default class Module { type: 'Module'; graph: Graph; diff --git a/src/ast/nodes/ClassDeclaration.ts b/src/ast/nodes/ClassDeclaration.ts index 992b4422a29..a764ec0e78b 100644 --- a/src/ast/nodes/ClassDeclaration.ts +++ b/src/ast/nodes/ClassDeclaration.ts @@ -4,6 +4,11 @@ import Identifier from './Identifier'; import MagicString from 'magic-string'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; +import { Node } from './shared/Node'; + +export function isClassDeclaration (node: Node): node is ClassDeclaration { + return node.type === NodeType.ClassDeclaration; +} export default class ClassDeclaration extends ClassNode { type: NodeType.ClassDeclaration; diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index dffc8bb8309..950deb675d6 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -1,14 +1,11 @@ import { ExpressionNode, NodeBase } from './shared/Node'; -import ExecutionPathOptions from '../ExecutionPathOptions'; import ExportDefaultVariable from '../variables/ExportDefaultVariable'; -import ClassDeclaration from './ClassDeclaration'; -import FunctionDeclaration from './FunctionDeclaration'; +import ClassDeclaration, { isClassDeclaration } from './ClassDeclaration'; +import FunctionDeclaration, { isFunctionDeclaration } from './FunctionDeclaration'; import Identifier from './Identifier'; import MagicString from 'magic-string'; import { NodeType } from './NodeType'; -import { RenderOptions } from '../../Module'; - -const functionOrClassDeclaration = /^(?:Function|Class)Declaration/; +import { NodeRenderOptions, RenderOptions } from '../../Module'; function buildRegexWithSpaces (re: RegExp) { const spaceOrComment = @@ -45,18 +42,6 @@ export default class ExportDefaultDeclaration extends NodeBase { } } - includeDefaultExport () { - this.included = true; - this.declaration.includeInBundle(); - } - - includeInBundle () { - if (this.declaration.shouldBeIncluded()) { - return this.declaration.includeInBundle(); - } - return false; - } - initialiseNode () { this.isExportDeclaration = true; this._declarationName = @@ -68,74 +53,48 @@ export default class ExportDefaultDeclaration extends NodeBase { ); } - render (code: MagicString, options: RenderOptions) { - const remove = () => { - code.remove( - this.leadingCommentStart || this.start, - this.next || this.end - ); - }; - const removeExportDefault = () => { - code.remove(this.start, declaration_start); - }; - - const treeshakeable = - this.module.graph.treeshake && - !this.included && - !this.declaration.included; - const name = this.variable.getName(); - const statementStr = code.original.slice(this.start, this.end); - + render (code: MagicString, options: RenderOptions, nodeRenderOptions: NodeRenderOptions = {}) { // paren workaround: find first non-whitespace character position after `export default` - const declaration_start = - this.start + statementStr.match(sourceRE.exportDefault)[0].length; - - if (functionOrClassDeclaration.test(this.declaration.type)) { - if (treeshakeable) { - return remove(); - } - - // Add the id to anonymous declarations - if (!(this.declaration).id) { - const id_insertPos = - this.start + statementStr.match(sourceRE.declarationHeader)[0].length; - code.appendLeft(id_insertPos, ` ${name}`); - } - - removeExportDefault(); - - if (options.systemBindings && this.declaration.type === NodeType.ClassDeclaration) { - code.appendRight(this.end, ` exports('default', ${name});`); - } + const declarationStart = this.start + code.original.slice(this.start, this.end).match(sourceRE.exportDefault)[0].length; + + if (isFunctionDeclaration(this.declaration) || isClassDeclaration(this.declaration)) { + this.renderFunctionOrClassDeclaration(code, declarationStart, this.declaration.id === null, options); + } else if (this.variable.getOriginalVariableName() === this.variable.getName()) { + // Remove altogether to prevent re-declaring the same variable + code.remove(nodeRenderOptions.start || this.start, nodeRenderOptions.end || this.end); + return; + } else if (this.variable.included) { + this.renderVariableDeclaration(code, declarationStart, options); } else { - if (treeshakeable) { - const hasEffects = this.declaration.hasEffects( - ExecutionPathOptions.create() - ); - return hasEffects ? removeExportDefault() : remove(); - } + // Remove `export default`, the rest is rendered for side-effects + code.remove(this.start, declarationStart); + } + super.render(code, options); + } - // Prevent `var foo = foo` - if (this.variable.getOriginalVariableName() === name) { - return remove(); - } + private renderFunctionOrClassDeclaration (code: MagicString, declarationStart: number, needsId: boolean, options: RenderOptions) { + const name = this.variable.getName(); + // Remove `export default` + code.remove(this.start, declarationStart); - // Only output `var foo =` if `foo` is used - if (this.included) { - const systemBinding = options.systemBindings ? `exports('${this.variable.exportName}', ` : ''; - code.overwrite( - this.start, - declaration_start, - `${this.module.graph.varOrConst} ${name} = ${systemBinding}` - ); - if (systemBinding) { - code.prependRight(this.end - 1, ')'); - } - } else { - removeExportDefault(); - } + if (needsId) { + const idInsertPos = this.start + code.original.slice(this.start, this.end).match(sourceRE.declarationHeader)[0].length; + code.appendLeft(idInsertPos, ` ${name}`); } + if (options.systemBindings && isClassDeclaration(this.declaration)) { + code.appendRight(this.end, ` exports('default', ${name});`); + } + } - super.render(code, options); + private renderVariableDeclaration (code: MagicString, declarationStart: number, options: RenderOptions) { + const systemBinding = options.systemBindings ? `exports('${this.variable.exportName}', ` : ''; + code.overwrite( + this.start, + declarationStart, + `${this.module.graph.varOrConst} ${this.variable.getName()} = ${systemBinding}` + ); + if (systemBinding) { + code.prependRight(this.end - 1, ')'); + } } } diff --git a/src/ast/nodes/FunctionDeclaration.ts b/src/ast/nodes/FunctionDeclaration.ts index 3670eb42499..0419b060ecf 100644 --- a/src/ast/nodes/FunctionDeclaration.ts +++ b/src/ast/nodes/FunctionDeclaration.ts @@ -3,6 +3,11 @@ import Scope from '../scopes/Scope'; import MagicString from 'magic-string'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; +import { Node } from './shared/Node'; + +export function isFunctionDeclaration (node: Node): node is FunctionDeclaration { + return node.type === NodeType.FunctionDeclaration; +} export default class FunctionDeclaration extends FunctionNode { type: NodeType.FunctionDeclaration; diff --git a/src/ast/nodes/shared/Node.ts b/src/ast/nodes/shared/Node.ts index 185034a47a3..98fe3ee2f21 100644 --- a/src/ast/nodes/shared/Node.ts +++ b/src/ast/nodes/shared/Node.ts @@ -1,7 +1,7 @@ import { locate } from 'locate-character'; import ExecutionPathOptions from '../../ExecutionPathOptions'; import Scope from '../../scopes/Scope'; -import Module, { RenderOptions } from '../../../Module'; +import Module, { NodeRenderOptions, RenderOptions } from '../../../Module'; import MagicString from 'magic-string'; import Variable from '../../variables/Variable'; import { ExpressionEntity, ForEachReturnExpressionCallback, SomeReturnExpressionCallback } from './Expression'; @@ -64,7 +64,7 @@ export interface Node extends Entity { */ initialise (parentScope: Scope): void; initialiseAndDeclare (parentScope: Scope, kind: string, init: ExpressionEntity | null): void; - render(code: MagicString, options: RenderOptions): void; + render(code: MagicString, options: RenderOptions, nodeRenderOptions?: NodeRenderOptions): void; /** * Start a new execution path to determine if this node has an effect on the bundle and @@ -225,9 +225,8 @@ export class NodeBase implements ExpressionNode { shouldBeIncluded () { return ( - this.included || - this.hasEffects(ExecutionPathOptions.create()) || this.hasIncludedChild() + || this.hasEffects(ExecutionPathOptions.create()) ); } diff --git a/src/ast/variables/ExportDefaultVariable.ts b/src/ast/variables/ExportDefaultVariable.ts index b0e389d453f..2c549ce90e7 100644 --- a/src/ast/variables/ExportDefaultVariable.ts +++ b/src/ast/variables/ExportDefaultVariable.ts @@ -9,7 +9,6 @@ export default class ExportDefaultVariable extends LocalVariable { isDefault: true; hasId: boolean; private _original: Variable; - declarations: Set; constructor (name: string, exportDefaultDeclaration: ExportDefaultDeclaration) { super(name, exportDefaultDeclaration, exportDefaultDeclaration.declaration); @@ -35,16 +34,6 @@ export default class ExportDefaultVariable extends LocalVariable { return this._original && this._original.getName(); } - includeVariable () { - if (!super.includeVariable()) { - return false; - } - this.declarations.forEach(declaration => - declaration.includeDefaultExport() - ); - return true; - } - setOriginalVariable (original: Variable) { this._original = original; } diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index a583c886d47..14c0d7ea7c4 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -31,22 +31,14 @@ export function renderStatementBlock (statements: Node[], code: MagicString, sta currentNode = nextNode; currentNodeStart = nextNodeStart; nextNode = statements[nextIndex]; - if (!currentNode.included || (nextNode !== undefined && !nextNode.included)) { - nextNodeStart = currentNode.end + (findFirstLineBreakOutsideComment(code.slice( - currentNode.end, - nextNode !== undefined ? nextNode.start : end - ))); - if ( - !currentNode.included - && currentNode.type !== NodeType.ExportDefaultDeclaration - && currentNode.type !== NodeType.IfStatement - ) { - code.remove(currentNodeStart, nextNodeStart); - } else { - currentNode.render(code, options); - } + nextNodeStart = currentNode.end + (findFirstLineBreakOutsideComment(code.slice( + currentNode.end, + nextNode !== undefined ? nextNode.start : end + ))); + if (!currentNode.included && currentNode.type !== NodeType.IfStatement) { + code.remove(currentNodeStart, nextNodeStart); } else { - currentNode.render(code, options); + currentNode.render(code, options, {start: currentNodeStart, end:nextNodeStart}); } } } diff --git a/test/form/samples/tree-shake-default-exports/_config.js b/test/form/samples/tree-shake-default-exports/_config.js new file mode 100644 index 00000000000..8b7be460d61 --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'properly remove unused default exports' +}; diff --git a/test/form/samples/tree-shake-default-exports/_expected/amd.js b/test/form/samples/tree-shake-default-exports/_expected/amd.js new file mode 100644 index 00000000000..706a333675e --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/_expected/amd.js @@ -0,0 +1,47 @@ +define(function () { 'use strict'; + + /* header 1 */ + + /* footer 1 */ + + /* header 2 */ + + /* footer 2 */ + + /* header 3*/ + + /* leading retained */ + console.log( 'side-effect' ) || 43; // trailing retained + + /* footer 3 */ + + /* header 4 */ + + /* leading retained */ + var importedValue = 42; // trailing retained + + /* footer 4 */ + + /* header 5 */ + + /* leading retained */ + function importedUsedFunction () { + console.log( 'unnamed' ); + } // trailing retained + + /* footer 5 */ + + /* header 6 */ + + /* leading retained */ + function usedNamedFunction () { + console.log( 'named' ); + } // trailing retained + + /* footer 6 */ + + console.log(importedValue); + importedUsedFunction(); + usedNamedFunction(); + +}); diff --git a/test/form/samples/tree-shake-default-exports/_expected/cjs.js b/test/form/samples/tree-shake-default-exports/_expected/cjs.js new file mode 100644 index 00000000000..9c8f6384180 --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/_expected/cjs.js @@ -0,0 +1,45 @@ +'use strict'; + +/* header 1 */ + +/* footer 1 */ + +/* header 2 */ + +/* footer 2 */ + +/* header 3*/ + +/* leading retained */ +console.log( 'side-effect' ) || 43; // trailing retained + +/* footer 3 */ + +/* header 4 */ + +/* leading retained */ +var importedValue = 42; // trailing retained + +/* footer 4 */ + +/* header 5 */ + +/* leading retained */ +function importedUsedFunction () { + console.log( 'unnamed' ); +} // trailing retained + +/* footer 5 */ + +/* header 6 */ + +/* leading retained */ +function usedNamedFunction () { + console.log( 'named' ); +} // trailing retained + +/* footer 6 */ + +console.log(importedValue); +importedUsedFunction(); +usedNamedFunction(); diff --git a/test/form/samples/tree-shake-default-exports/_expected/es.js b/test/form/samples/tree-shake-default-exports/_expected/es.js new file mode 100644 index 00000000000..86240dbd0ed --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/_expected/es.js @@ -0,0 +1,43 @@ +/* header 1 */ + +/* footer 1 */ + +/* header 2 */ + +/* footer 2 */ + +/* header 3*/ + +/* leading retained */ +console.log( 'side-effect' ) || 43; // trailing retained + +/* footer 3 */ + +/* header 4 */ + +/* leading retained */ +var importedValue = 42; // trailing retained + +/* footer 4 */ + +/* header 5 */ + +/* leading retained */ +function importedUsedFunction () { + console.log( 'unnamed' ); +} // trailing retained + +/* footer 5 */ + +/* header 6 */ + +/* leading retained */ +function usedNamedFunction () { + console.log( 'named' ); +} // trailing retained + +/* footer 6 */ + +console.log(importedValue); +importedUsedFunction(); +usedNamedFunction(); diff --git a/test/form/samples/tree-shake-default-exports/_expected/iife.js b/test/form/samples/tree-shake-default-exports/_expected/iife.js new file mode 100644 index 00000000000..5fac47c6218 --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/_expected/iife.js @@ -0,0 +1,48 @@ +(function () { + 'use strict'; + + /* header 1 */ + + /* footer 1 */ + + /* header 2 */ + + /* footer 2 */ + + /* header 3*/ + + /* leading retained */ + console.log( 'side-effect' ) || 43; // trailing retained + + /* footer 3 */ + + /* header 4 */ + + /* leading retained */ + var importedValue = 42; // trailing retained + + /* footer 4 */ + + /* header 5 */ + + /* leading retained */ + function importedUsedFunction () { + console.log( 'unnamed' ); + } // trailing retained + + /* footer 5 */ + + /* header 6 */ + + /* leading retained */ + function usedNamedFunction () { + console.log( 'named' ); + } // trailing retained + + /* footer 6 */ + + console.log(importedValue); + importedUsedFunction(); + usedNamedFunction(); + +}()); diff --git a/test/form/samples/tree-shake-default-exports/_expected/umd.js b/test/form/samples/tree-shake-default-exports/_expected/umd.js new file mode 100644 index 00000000000..298e97264c8 --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/_expected/umd.js @@ -0,0 +1,51 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); +}(this, (function () { 'use strict'; + + /* header 1 */ + + /* footer 1 */ + + /* header 2 */ + + /* footer 2 */ + + /* header 3*/ + + /* leading retained */ + console.log( 'side-effect' ) || 43; // trailing retained + + /* footer 3 */ + + /* header 4 */ + + /* leading retained */ + var importedValue = 42; // trailing retained + + /* footer 4 */ + + /* header 5 */ + + /* leading retained */ + function importedUsedFunction () { + console.log( 'unnamed' ); + } // trailing retained + + /* footer 5 */ + + /* header 6 */ + + /* leading retained */ + function usedNamedFunction () { + console.log( 'named' ); + } // trailing retained + + /* footer 6 */ + + console.log(importedValue); + importedUsedFunction(); + usedNamedFunction(); + +}))); diff --git a/test/form/samples/tree-shake-default-exports/main.js b/test/form/samples/tree-shake-default-exports/main.js new file mode 100644 index 00000000000..4e39b10f699 --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/main.js @@ -0,0 +1,10 @@ +import './unused.js'; +import './unusedFunction.js'; +import './unusedSideEffect.js'; +import importedValue from './used.js'; +import importedUsedFunction from './usedFunction.js'; +import importedUsedNamedFunction from './usedNamedFunction.js'; + +console.log(importedValue); +importedUsedFunction(); +importedUsedNamedFunction(); diff --git a/test/form/samples/tree-shake-default-exports/unused.js b/test/form/samples/tree-shake-default-exports/unused.js new file mode 100644 index 00000000000..66946a932ae --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/unused.js @@ -0,0 +1,6 @@ +/* header 1 */ + +/* leading removed */ +export default 43; // trailing removed + +/* footer 1 */ diff --git a/test/form/samples/tree-shake-default-exports/unusedFunction.js b/test/form/samples/tree-shake-default-exports/unusedFunction.js new file mode 100644 index 00000000000..bd90e096faa --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/unusedFunction.js @@ -0,0 +1,8 @@ +/* header 2 */ + +/* leading removed */ +export default function () { + console.log( 'unused' ); +}; // trailing removed + +/* footer 2 */ diff --git a/test/form/samples/tree-shake-default-exports/unusedSideEffect.js b/test/form/samples/tree-shake-default-exports/unusedSideEffect.js new file mode 100644 index 00000000000..957cf170b12 --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/unusedSideEffect.js @@ -0,0 +1,6 @@ +/* header 3*/ + +/* leading retained */ +export default console.log( 'side-effect' ) || 43; // trailing retained + +/* footer 3 */ diff --git a/test/form/samples/tree-shake-default-exports/used.js b/test/form/samples/tree-shake-default-exports/used.js new file mode 100644 index 00000000000..d2f1de99b3e --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/used.js @@ -0,0 +1,6 @@ +/* header 4 */ + +/* leading retained */ +export default 42; // trailing retained + +/* footer 4 */ diff --git a/test/form/samples/tree-shake-default-exports/usedFunction.js b/test/form/samples/tree-shake-default-exports/usedFunction.js new file mode 100644 index 00000000000..91baa843894 --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/usedFunction.js @@ -0,0 +1,8 @@ +/* header 5 */ + +/* leading retained */ +export default function () { + console.log( 'unnamed' ); +} // trailing retained + +/* footer 5 */ diff --git a/test/form/samples/tree-shake-default-exports/usedNamedFunction.js b/test/form/samples/tree-shake-default-exports/usedNamedFunction.js new file mode 100644 index 00000000000..7e1d70befbe --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/usedNamedFunction.js @@ -0,0 +1,8 @@ +/* header 6 */ + +/* leading retained */ +export default function usedNamedFunction () { + console.log( 'named' ); +} // trailing retained + +/* footer 6 */ From c345fb595da915454157bf9b672d5e51605f35d3 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Fri, 2 Feb 2018 16:05:10 +0100 Subject: [PATCH 06/27] Clean up code, improve performance and resolve #1850 --- src/ast/nodes/ExportDefaultDeclaration.ts | 46 ++++++++++--------- src/utils/renderHelpers.ts | 16 +++---- .../_expected/amd.js | 27 +++++++++++ .../_expected/cjs.js | 27 +++++++++++ .../_expected/es.js | 27 +++++++++++ .../_expected/iife.js | 27 +++++++++++ .../_expected/umd.js | 27 +++++++++++ .../main.js | 4 ++ .../spacelessFn.js | 3 ++ .../spacelessGenerator.js | 3 ++ .../_expected/amd.js | 2 +- .../_expected/cjs.js | 2 +- .../_expected/es.js | 2 +- .../_expected/iife.js | 2 +- .../_expected/umd.js | 2 +- .../unusedSideEffect.js | 2 +- 16 files changed, 183 insertions(+), 36 deletions(-) create mode 100644 test/form/samples/export-default-anonymous-declarations/spacelessFn.js create mode 100644 test/form/samples/export-default-anonymous-declarations/spacelessGenerator.js diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index 950deb675d6..f3ae8464433 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -6,25 +6,24 @@ import Identifier from './Identifier'; import MagicString from 'magic-string'; import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; +import { findFirstOccurrenceOutsideComment } from '../../utils/renderHelpers'; -function buildRegexWithSpaces (re: RegExp) { - const spaceOrComment = - '(?:' + - [ - /\s/.source, // Space - /\/\/.*[\n\r]/.source, // Single line comment - /\/\*[^]*?\*\//.source // Multiline comment. There is [^] instead of . because it also matches \n - ].join('|') + - ')'; - return new RegExp(re.source.replace(/\s|\\s/g, spaceOrComment), re.flags); +// The header ends at the first white-space or comment after "default" +function getDeclarationStart (code: string) { + const headerLength = findFirstOccurrenceOutsideComment(code, 'default') + 7; + return headerLength + code.slice(headerLength).search(/\S|\/\*/); } -const sourceRE = { - exportDefault: buildRegexWithSpaces(/^ *export +default */), - declarationHeader: buildRegexWithSpaces( - /^ *export +default +(?:(?:async +)?function(?: *\*)?|class)/ - ) -}; +function getIdInsertPosition (code: string, declarationKeyword: string) { + const declarationEnd = findFirstOccurrenceOutsideComment(code, declarationKeyword) + declarationKeyword.length; + code = code.slice(declarationEnd); + code = code.slice(0, findFirstOccurrenceOutsideComment(code, '{')); + const generatorStarPos = findFirstOccurrenceOutsideComment(code, '*'); + if (generatorStarPos === 0) { + return declarationEnd + (code[0] === '*' ? 1 : 0); + } + return declarationEnd + generatorStarPos + 1; +} export default class ExportDefaultDeclaration extends NodeBase { type: NodeType.ExportDefaultDeclaration; @@ -54,11 +53,12 @@ export default class ExportDefaultDeclaration extends NodeBase { } render (code: MagicString, options: RenderOptions, nodeRenderOptions: NodeRenderOptions = {}) { - // paren workaround: find first non-whitespace character position after `export default` - const declarationStart = this.start + code.original.slice(this.start, this.end).match(sourceRE.exportDefault)[0].length; + const declarationStart = this.start + getDeclarationStart(code.original.slice(this.start, this.end)); - if (isFunctionDeclaration(this.declaration) || isClassDeclaration(this.declaration)) { - this.renderFunctionOrClassDeclaration(code, declarationStart, this.declaration.id === null, options); + if (isFunctionDeclaration(this.declaration)) { + this.renderDeclaration(code, declarationStart, 'function', this.declaration.id === null, options); + } else if (isClassDeclaration(this.declaration)) { + this.renderDeclaration(code, declarationStart, 'class', this.declaration.id === null, options); } else if (this.variable.getOriginalVariableName() === this.variable.getName()) { // Remove altogether to prevent re-declaring the same variable code.remove(nodeRenderOptions.start || this.start, nodeRenderOptions.end || this.end); @@ -72,13 +72,15 @@ export default class ExportDefaultDeclaration extends NodeBase { super.render(code, options); } - private renderFunctionOrClassDeclaration (code: MagicString, declarationStart: number, needsId: boolean, options: RenderOptions) { + private renderDeclaration ( + code: MagicString, declarationStart: number, declarationKeyword: string, needsId: boolean, options: RenderOptions + ) { const name = this.variable.getName(); // Remove `export default` code.remove(this.start, declarationStart); if (needsId) { - const idInsertPos = this.start + code.original.slice(this.start, this.end).match(sourceRE.declarationHeader)[0].length; + const idInsertPos = declarationStart + getIdInsertPosition(code.original.slice(declarationStart, this.end), declarationKeyword); code.appendLeft(idInsertPos, ` ${name}`); } if (options.systemBindings && isClassDeclaration(this.declaration)) { diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index 14c0d7ea7c4..907524cb072 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -3,12 +3,14 @@ import MagicString from 'magic-string'; import { RenderOptions } from '../Module'; import { NodeType } from '../ast/nodes/NodeType'; -function findFirstLineBreakOutsideComment (code: string) { +// Note that if the string is not found, "0" is returned instead of e.g. "-1" +// as this seems to work best for the main use case +export function findFirstOccurrenceOutsideComment (code: string, searchString: string) { let codeStart = 0; let commentStart, commentLength, lineBreakPos; while (true) { commentStart = code.indexOf('/*'); - lineBreakPos = (~commentStart ? code.slice(0, commentStart) : code).indexOf('\n'); + lineBreakPos = (~commentStart ? code.slice(0, commentStart) : code).indexOf(searchString); if (~lineBreakPos || !~commentStart) { break; } @@ -24,17 +26,15 @@ export function renderStatementBlock (statements: Node[], code: MagicString, sta if (statements.length === 0) return; let currentNode, currentNodeStart; let nextNode = statements[0]; - // TODO we need to work around a bug in magic-string when nodeStart = start = 0 - let nextNodeStart = start + (nextNode.start === start ? 0 : findFirstLineBreakOutsideComment(code.slice(start, nextNode.start))); + let nextNodeStart = start + findFirstOccurrenceOutsideComment(code.original.slice(start, nextNode.start), '\n'); for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) { currentNode = nextNode; currentNodeStart = nextNodeStart; nextNode = statements[nextIndex]; - nextNodeStart = currentNode.end + (findFirstLineBreakOutsideComment(code.slice( - currentNode.end, - nextNode !== undefined ? nextNode.start : end - ))); + nextNodeStart = currentNode.end + (findFirstOccurrenceOutsideComment(code.original.slice( + currentNode.end, nextNode !== undefined ? nextNode.start : end + ), '\n')); if (!currentNode.included && currentNode.type !== NodeType.IfStatement) { code.remove(currentNodeStart, nextNodeStart); } else { diff --git a/test/form/samples/export-default-anonymous-declarations/_expected/amd.js b/test/form/samples/export-default-anonymous-declarations/_expected/amd.js index 2ba42f7cdfa..7afc55c0998 100644 --- a/test/form/samples/export-default-anonymous-declarations/_expected/amd.js +++ b/test/form/samples/export-default-anonymous-declarations/_expected/amd.js @@ -1,5 +1,9 @@ define(function () { 'use strict'; + // jsjjjsjjjjsjs + + /* jsjjddjksj */ // Too many comments lol + function Fn //iian iaouns @@ -12,6 +16,11 @@ define(function () { 'use strict'; console.log("Foo"); } + // jsjjjsjjjjsjs + + /* jsjjddjksj + */ // Too many comments lol + async /* [no LineTerminator here] */ function Async //iian iaouns @@ -21,6 +30,10 @@ define(function () { 'use strict'; console.log("Foo"); } + // jsjjjsjjjjsjs + + /* jsjjddjksj */ // Too many comments lol + function /* oiasnpiueno */ @@ -38,6 +51,10 @@ define(function () { 'use strict'; console.log("Foo"); } + // jsjjjsjjjjsjs + + /* jsjjddjksj */ // Too many comments lol + class Class /* oiasnpiueno */ @@ -55,9 +72,19 @@ define(function () { 'use strict'; } } + /* 2 */function spacelessFn/* 3 */()/* 4 */{ + console.log("Foo"); + } + + function* spacelessGenerator(){ + console.log("Foo"); + } + Fn(); Async(); Generator(); new Class(); + spacelessFn(); + spacelessGenerator(); }); diff --git a/test/form/samples/export-default-anonymous-declarations/_expected/cjs.js b/test/form/samples/export-default-anonymous-declarations/_expected/cjs.js index 8e2bb6ea484..b2831342e27 100644 --- a/test/form/samples/export-default-anonymous-declarations/_expected/cjs.js +++ b/test/form/samples/export-default-anonymous-declarations/_expected/cjs.js @@ -1,5 +1,9 @@ 'use strict'; +// jsjjjsjjjjsjs + +/* jsjjddjksj */ // Too many comments lol + function Fn //iian iaouns @@ -12,6 +16,11 @@ function Fn console.log("Foo"); } +// jsjjjsjjjjsjs + +/* jsjjddjksj +*/ // Too many comments lol + async /* [no LineTerminator here] */ function Async //iian iaouns @@ -21,6 +30,10 @@ async /* [no LineTerminator here] */ function Async console.log("Foo"); } +// jsjjjsjjjjsjs + +/* jsjjddjksj */ // Too many comments lol + function /* oiasnpiueno */ @@ -38,6 +51,10 @@ function console.log("Foo"); } +// jsjjjsjjjjsjs + +/* jsjjddjksj */ // Too many comments lol + class Class /* oiasnpiueno */ @@ -55,7 +72,17 @@ class Class } } +/* 2 */function spacelessFn/* 3 */()/* 4 */{ + console.log("Foo"); +} + +function* spacelessGenerator(){ + console.log("Foo"); +} + Fn(); Async(); Generator(); new Class(); +spacelessFn(); +spacelessGenerator(); diff --git a/test/form/samples/export-default-anonymous-declarations/_expected/es.js b/test/form/samples/export-default-anonymous-declarations/_expected/es.js index cad076b17cb..3440800bbb5 100644 --- a/test/form/samples/export-default-anonymous-declarations/_expected/es.js +++ b/test/form/samples/export-default-anonymous-declarations/_expected/es.js @@ -1,3 +1,7 @@ +// jsjjjsjjjjsjs + +/* jsjjddjksj */ // Too many comments lol + function Fn //iian iaouns @@ -10,6 +14,11 @@ function Fn console.log("Foo"); } +// jsjjjsjjjjsjs + +/* jsjjddjksj +*/ // Too many comments lol + async /* [no LineTerminator here] */ function Async //iian iaouns @@ -19,6 +28,10 @@ async /* [no LineTerminator here] */ function Async console.log("Foo"); } +// jsjjjsjjjjsjs + +/* jsjjddjksj */ // Too many comments lol + function /* oiasnpiueno */ @@ -36,6 +49,10 @@ function console.log("Foo"); } +// jsjjjsjjjjsjs + +/* jsjjddjksj */ // Too many comments lol + class Class /* oiasnpiueno */ @@ -53,7 +70,17 @@ class Class } } +/* 2 */function spacelessFn/* 3 */()/* 4 */{ + console.log("Foo"); +} + +function* spacelessGenerator(){ + console.log("Foo"); +} + Fn(); Async(); Generator(); new Class(); +spacelessFn(); +spacelessGenerator(); diff --git a/test/form/samples/export-default-anonymous-declarations/_expected/iife.js b/test/form/samples/export-default-anonymous-declarations/_expected/iife.js index c4bc9e40e03..333f54e91fd 100644 --- a/test/form/samples/export-default-anonymous-declarations/_expected/iife.js +++ b/test/form/samples/export-default-anonymous-declarations/_expected/iife.js @@ -1,6 +1,10 @@ (function () { 'use strict'; + // jsjjjsjjjjsjs + + /* jsjjddjksj */ // Too many comments lol + function Fn //iian iaouns @@ -13,6 +17,11 @@ console.log("Foo"); } + // jsjjjsjjjjsjs + + /* jsjjddjksj + */ // Too many comments lol + async /* [no LineTerminator here] */ function Async //iian iaouns @@ -22,6 +31,10 @@ console.log("Foo"); } + // jsjjjsjjjjsjs + + /* jsjjddjksj */ // Too many comments lol + function /* oiasnpiueno */ @@ -39,6 +52,10 @@ console.log("Foo"); } + // jsjjjsjjjjsjs + + /* jsjjddjksj */ // Too many comments lol + class Class /* oiasnpiueno */ @@ -56,9 +73,19 @@ } } + /* 2 */function spacelessFn/* 3 */()/* 4 */{ + console.log("Foo"); + } + + function* spacelessGenerator(){ + console.log("Foo"); + } + Fn(); Async(); Generator(); new Class(); + spacelessFn(); + spacelessGenerator(); }()); diff --git a/test/form/samples/export-default-anonymous-declarations/_expected/umd.js b/test/form/samples/export-default-anonymous-declarations/_expected/umd.js index e2b9d95b115..36013b7c1d6 100644 --- a/test/form/samples/export-default-anonymous-declarations/_expected/umd.js +++ b/test/form/samples/export-default-anonymous-declarations/_expected/umd.js @@ -4,6 +4,10 @@ (factory()); }(this, (function () { 'use strict'; + // jsjjjsjjjjsjs + + /* jsjjddjksj */ // Too many comments lol + function Fn //iian iaouns @@ -16,6 +20,11 @@ console.log("Foo"); } + // jsjjjsjjjjsjs + + /* jsjjddjksj + */ // Too many comments lol + async /* [no LineTerminator here] */ function Async //iian iaouns @@ -25,6 +34,10 @@ console.log("Foo"); } + // jsjjjsjjjjsjs + + /* jsjjddjksj */ // Too many comments lol + function /* oiasnpiueno */ @@ -42,6 +55,10 @@ console.log("Foo"); } + // jsjjjsjjjjsjs + + /* jsjjddjksj */ // Too many comments lol + class Class /* oiasnpiueno */ @@ -59,9 +76,19 @@ } } + /* 2 */function spacelessFn/* 3 */()/* 4 */{ + console.log("Foo"); + } + + function* spacelessGenerator(){ + console.log("Foo"); + } + Fn(); Async(); Generator(); new Class(); + spacelessFn(); + spacelessGenerator(); }))); diff --git a/test/form/samples/export-default-anonymous-declarations/main.js b/test/form/samples/export-default-anonymous-declarations/main.js index 27a74fe5de1..333b08835e7 100644 --- a/test/form/samples/export-default-anonymous-declarations/main.js +++ b/test/form/samples/export-default-anonymous-declarations/main.js @@ -2,8 +2,12 @@ import Fn from "./fn.js" import Async from "./async.js"; import Generator from "./generator.js"; import Class from "./class.js"; +import spacelessFn from "./spacelessFn.js" +import spacelessGenerator from "./spacelessGenerator.js"; Fn(); Async(); Generator(); new Class(); +spacelessFn(); +spacelessGenerator(); diff --git a/test/form/samples/export-default-anonymous-declarations/spacelessFn.js b/test/form/samples/export-default-anonymous-declarations/spacelessFn.js new file mode 100644 index 00000000000..34c4552d54b --- /dev/null +++ b/test/form/samples/export-default-anonymous-declarations/spacelessFn.js @@ -0,0 +1,3 @@ +export/* 1 */default/* 2 */function/* 3 */()/* 4 */{ + console.log("Foo"); +} diff --git a/test/form/samples/export-default-anonymous-declarations/spacelessGenerator.js b/test/form/samples/export-default-anonymous-declarations/spacelessGenerator.js new file mode 100644 index 00000000000..1fb8a88221d --- /dev/null +++ b/test/form/samples/export-default-anonymous-declarations/spacelessGenerator.js @@ -0,0 +1,3 @@ +export default function*(){ + console.log("Foo"); +} diff --git a/test/form/samples/tree-shake-default-exports/_expected/amd.js b/test/form/samples/tree-shake-default-exports/_expected/amd.js index 706a333675e..8823e6c192f 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/amd.js +++ b/test/form/samples/tree-shake-default-exports/_expected/amd.js @@ -11,7 +11,7 @@ define(function () { 'use strict'; /* header 3*/ /* leading retained */ - console.log( 'side-effect' ) || 43; // trailing retained + /*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained /* footer 3 */ diff --git a/test/form/samples/tree-shake-default-exports/_expected/cjs.js b/test/form/samples/tree-shake-default-exports/_expected/cjs.js index 9c8f6384180..49d36508215 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/cjs.js +++ b/test/form/samples/tree-shake-default-exports/_expected/cjs.js @@ -11,7 +11,7 @@ /* header 3*/ /* leading retained */ -console.log( 'side-effect' ) || 43; // trailing retained +/*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained /* footer 3 */ diff --git a/test/form/samples/tree-shake-default-exports/_expected/es.js b/test/form/samples/tree-shake-default-exports/_expected/es.js index 86240dbd0ed..a94fe7d1925 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/es.js +++ b/test/form/samples/tree-shake-default-exports/_expected/es.js @@ -9,7 +9,7 @@ /* header 3*/ /* leading retained */ -console.log( 'side-effect' ) || 43; // trailing retained +/*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained /* footer 3 */ diff --git a/test/form/samples/tree-shake-default-exports/_expected/iife.js b/test/form/samples/tree-shake-default-exports/_expected/iife.js index 5fac47c6218..c293fc1d170 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/iife.js +++ b/test/form/samples/tree-shake-default-exports/_expected/iife.js @@ -12,7 +12,7 @@ /* header 3*/ /* leading retained */ - console.log( 'side-effect' ) || 43; // trailing retained + /*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained /* footer 3 */ diff --git a/test/form/samples/tree-shake-default-exports/_expected/umd.js b/test/form/samples/tree-shake-default-exports/_expected/umd.js index 298e97264c8..3a37572d61b 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/umd.js +++ b/test/form/samples/tree-shake-default-exports/_expected/umd.js @@ -15,7 +15,7 @@ /* header 3*/ /* leading retained */ - console.log( 'side-effect' ) || 43; // trailing retained + /*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained /* footer 3 */ diff --git a/test/form/samples/tree-shake-default-exports/unusedSideEffect.js b/test/form/samples/tree-shake-default-exports/unusedSideEffect.js index 957cf170b12..aed581dbcd2 100644 --- a/test/form/samples/tree-shake-default-exports/unusedSideEffect.js +++ b/test/form/samples/tree-shake-default-exports/unusedSideEffect.js @@ -1,6 +1,6 @@ /* header 3*/ /* leading retained */ -export default console.log( 'side-effect' ) || 43; // trailing retained +export default /*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained /* footer 3 */ From 7781b5f43dae03024eedbacdbb3883b62377e475 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Fri, 2 Feb 2018 16:37:16 +0100 Subject: [PATCH 07/27] Resolve #1772 --- src/ast/nodes/ExportDefaultDeclaration.ts | 24 +++++++++++++++---- src/ast/nodes/ObjectExpression.ts | 6 ++++- .../_expected/amd.js | 22 +++++++++++++++-- .../_expected/cjs.js | 22 +++++++++++++++-- .../_expected/es.js | 22 +++++++++++++++-- .../_expected/iife.js | 22 +++++++++++++++-- .../_expected/umd.js | 22 +++++++++++++++-- .../tree-shake-default-exports/main.js | 2 ++ .../unusedSideEffect.js | 4 ++-- .../unusedSideEffectObject1.js | 8 +++++++ .../unusedSideEffectObject2.js | 8 +++++++ 11 files changed, 144 insertions(+), 18 deletions(-) create mode 100644 test/form/samples/tree-shake-default-exports/unusedSideEffectObject1.js create mode 100644 test/form/samples/tree-shake-default-exports/unusedSideEffectObject2.js diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index f3ae8464433..7b99329c4c3 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -7,6 +7,7 @@ import MagicString from 'magic-string'; import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; import { findFirstOccurrenceOutsideComment } from '../../utils/renderHelpers'; +import { isObjectExpression } from './ObjectExpression'; // The header ends at the first white-space or comment after "default" function getDeclarationStart (code: string) { @@ -25,6 +26,8 @@ function getIdInsertPosition (code: string, declarationKeyword: string) { return declarationEnd + generatorStarPos + 1; } +const needsToBeWrapped = isObjectExpression; + export default class ExportDefaultDeclaration extends NodeBase { type: NodeType.ExportDefaultDeclaration; declaration: FunctionDeclaration | ClassDeclaration | ExpressionNode; @@ -56,9 +59,9 @@ export default class ExportDefaultDeclaration extends NodeBase { const declarationStart = this.start + getDeclarationStart(code.original.slice(this.start, this.end)); if (isFunctionDeclaration(this.declaration)) { - this.renderDeclaration(code, declarationStart, 'function', this.declaration.id === null, options); + this.renderNamedDeclaration(code, declarationStart, 'function', this.declaration.id === null, options); } else if (isClassDeclaration(this.declaration)) { - this.renderDeclaration(code, declarationStart, 'class', this.declaration.id === null, options); + this.renderNamedDeclaration(code, declarationStart, 'class', this.declaration.id === null, options); } else if (this.variable.getOriginalVariableName() === this.variable.getName()) { // Remove altogether to prevent re-declaring the same variable code.remove(nodeRenderOptions.start || this.start, nodeRenderOptions.end || this.end); @@ -66,13 +69,12 @@ export default class ExportDefaultDeclaration extends NodeBase { } else if (this.variable.included) { this.renderVariableDeclaration(code, declarationStart, options); } else { - // Remove `export default`, the rest is rendered for side-effects - code.remove(this.start, declarationStart); + this.renderForSideEffects(code, declarationStart); } super.render(code, options); } - private renderDeclaration ( + private renderNamedDeclaration ( code: MagicString, declarationStart: number, declarationKeyword: string, needsId: boolean, options: RenderOptions ) { const name = this.variable.getName(); @@ -99,4 +101,16 @@ export default class ExportDefaultDeclaration extends NodeBase { code.prependRight(this.end - 1, ')'); } } + + private renderForSideEffects (code: MagicString, declarationStart: number) { + code.remove(this.start, declarationStart); + if (needsToBeWrapped(this.declaration)) { + code.appendLeft(declarationStart, '('); + if (code.original[this.end - 1] === ';') { + code.prependRight(this.end - 1, ')'); + } else { + code.prependRight(this.end, ');'); + } + } + } } diff --git a/src/ast/nodes/ObjectExpression.ts b/src/ast/nodes/ObjectExpression.ts index e975e5c216b..bd0f4c52220 100644 --- a/src/ast/nodes/ObjectExpression.ts +++ b/src/ast/nodes/ObjectExpression.ts @@ -5,7 +5,7 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import Identifier from './Identifier'; import { ExpressionEntity, ForEachReturnExpressionCallback, SomeReturnExpressionCallback } from './shared/Expression'; import { UNKNOWN_VALUE } from '../values'; -import { NodeBase } from './shared/Node'; +import { Node, NodeBase } from './shared/Node'; import { NodeType } from './NodeType'; const PROPERTY_KINDS_READ = ['init', 'get']; @@ -22,6 +22,10 @@ export const UNKNOWN_OBJECT_EXPRESSION: ExpressionEntity = { toString: () => '[[UNKNOWN OBJECT]]' }; +export function isObjectExpression (node: Node): node is ObjectExpression { + return node.type === NodeType.ObjectExpression; +} + export default class ObjectExpression extends NodeBase { type: NodeType.ObjectExpression; properties: Property[]; diff --git a/test/form/samples/tree-shake-default-exports/_expected/amd.js b/test/form/samples/tree-shake-default-exports/_expected/amd.js index 8823e6c192f..821fe4ae4e8 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/amd.js +++ b/test/form/samples/tree-shake-default-exports/_expected/amd.js @@ -8,10 +8,10 @@ define(function () { 'use strict'; /* footer 2 */ - /* header 3*/ + /* header 3 */ /* leading retained */ - /*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained + /*#__KEEP__*/ console.log( 'side-effect' ) || 43; // trailing retained /* footer 3 */ @@ -40,6 +40,24 @@ define(function () { 'use strict'; /* footer 6 */ + /* header 7 */ + + /* leading retained */ +( { + effect: console.log( 'side-effect' ) || 43 + }); // trailing retained + + /* footer 7 */ + + /* header 8 */ + + /* leading retained */ +( { + effect: console.log( 'side-effect' ) || 43 + }); // trailing retained + + /* footer 8 */ + console.log(importedValue); importedUsedFunction(); usedNamedFunction(); diff --git a/test/form/samples/tree-shake-default-exports/_expected/cjs.js b/test/form/samples/tree-shake-default-exports/_expected/cjs.js index 49d36508215..dd663acba8d 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/cjs.js +++ b/test/form/samples/tree-shake-default-exports/_expected/cjs.js @@ -8,10 +8,10 @@ /* footer 2 */ -/* header 3*/ +/* header 3 */ /* leading retained */ -/*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained +/*#__KEEP__*/ console.log( 'side-effect' ) || 43; // trailing retained /* footer 3 */ @@ -40,6 +40,24 @@ function usedNamedFunction () { /* footer 6 */ +/* header 7 */ + +/* leading retained */ +({ + effect: console.log( 'side-effect' ) || 43 +}); // trailing retained + +/* footer 7 */ + +/* header 8 */ + +/* leading retained */ +({ + effect: console.log( 'side-effect' ) || 43 +}); // trailing retained + +/* footer 8 */ + console.log(importedValue); importedUsedFunction(); usedNamedFunction(); diff --git a/test/form/samples/tree-shake-default-exports/_expected/es.js b/test/form/samples/tree-shake-default-exports/_expected/es.js index a94fe7d1925..ea5ffcb4f83 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/es.js +++ b/test/form/samples/tree-shake-default-exports/_expected/es.js @@ -6,10 +6,10 @@ /* footer 2 */ -/* header 3*/ +/* header 3 */ /* leading retained */ -/*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained +/*#__KEEP__*/ console.log( 'side-effect' ) || 43; // trailing retained /* footer 3 */ @@ -38,6 +38,24 @@ function usedNamedFunction () { /* footer 6 */ +/* header 7 */ + +/* leading retained */ +({ + effect: console.log( 'side-effect' ) || 43 +}); // trailing retained + +/* footer 7 */ + +/* header 8 */ + +/* leading retained */ +({ + effect: console.log( 'side-effect' ) || 43 +}); // trailing retained + +/* footer 8 */ + console.log(importedValue); importedUsedFunction(); usedNamedFunction(); diff --git a/test/form/samples/tree-shake-default-exports/_expected/iife.js b/test/form/samples/tree-shake-default-exports/_expected/iife.js index c293fc1d170..96fc01d67fd 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/iife.js +++ b/test/form/samples/tree-shake-default-exports/_expected/iife.js @@ -9,10 +9,10 @@ /* footer 2 */ - /* header 3*/ + /* header 3 */ /* leading retained */ - /*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained + /*#__KEEP__*/ console.log( 'side-effect' ) || 43; // trailing retained /* footer 3 */ @@ -41,6 +41,24 @@ /* footer 6 */ + /* header 7 */ + + /* leading retained */ +( { + effect: console.log( 'side-effect' ) || 43 + }); // trailing retained + + /* footer 7 */ + + /* header 8 */ + + /* leading retained */ +( { + effect: console.log( 'side-effect' ) || 43 + }); // trailing retained + + /* footer 8 */ + console.log(importedValue); importedUsedFunction(); usedNamedFunction(); diff --git a/test/form/samples/tree-shake-default-exports/_expected/umd.js b/test/form/samples/tree-shake-default-exports/_expected/umd.js index 3a37572d61b..75c1c97dba3 100644 --- a/test/form/samples/tree-shake-default-exports/_expected/umd.js +++ b/test/form/samples/tree-shake-default-exports/_expected/umd.js @@ -12,10 +12,10 @@ /* footer 2 */ - /* header 3*/ + /* header 3 */ /* leading retained */ - /*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained + /*#__KEEP__*/ console.log( 'side-effect' ) || 43; // trailing retained /* footer 3 */ @@ -44,6 +44,24 @@ /* footer 6 */ + /* header 7 */ + + /* leading retained */ +( { + effect: console.log( 'side-effect' ) || 43 + }); // trailing retained + + /* footer 7 */ + + /* header 8 */ + + /* leading retained */ +( { + effect: console.log( 'side-effect' ) || 43 + }); // trailing retained + + /* footer 8 */ + console.log(importedValue); importedUsedFunction(); usedNamedFunction(); diff --git a/test/form/samples/tree-shake-default-exports/main.js b/test/form/samples/tree-shake-default-exports/main.js index 4e39b10f699..6bfc65ec33f 100644 --- a/test/form/samples/tree-shake-default-exports/main.js +++ b/test/form/samples/tree-shake-default-exports/main.js @@ -4,6 +4,8 @@ import './unusedSideEffect.js'; import importedValue from './used.js'; import importedUsedFunction from './usedFunction.js'; import importedUsedNamedFunction from './usedNamedFunction.js'; +import './unusedSideEffectObject1.js'; +import './unusedSideEffectObject2.js'; console.log(importedValue); importedUsedFunction(); diff --git a/test/form/samples/tree-shake-default-exports/unusedSideEffect.js b/test/form/samples/tree-shake-default-exports/unusedSideEffect.js index aed581dbcd2..eebc7d8cf04 100644 --- a/test/form/samples/tree-shake-default-exports/unusedSideEffect.js +++ b/test/form/samples/tree-shake-default-exports/unusedSideEffect.js @@ -1,6 +1,6 @@ -/* header 3*/ +/* header 3 */ /* leading retained */ -export default /*#__KEEP__*/ globalFunction( 'side-effect' ) || 43; // trailing retained +export default /*#__KEEP__*/ console.log( 'side-effect' ) || 43; // trailing retained /* footer 3 */ diff --git a/test/form/samples/tree-shake-default-exports/unusedSideEffectObject1.js b/test/form/samples/tree-shake-default-exports/unusedSideEffectObject1.js new file mode 100644 index 00000000000..f6ffdf6936e --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/unusedSideEffectObject1.js @@ -0,0 +1,8 @@ +/* header 7 */ + +/* leading retained */ +export default { + effect: console.log( 'side-effect' ) || 43 +} // trailing retained + +/* footer 7 */ diff --git a/test/form/samples/tree-shake-default-exports/unusedSideEffectObject2.js b/test/form/samples/tree-shake-default-exports/unusedSideEffectObject2.js new file mode 100644 index 00000000000..b2c884dd46e --- /dev/null +++ b/test/form/samples/tree-shake-default-exports/unusedSideEffectObject2.js @@ -0,0 +1,8 @@ +/* header 8 */ + +/* leading retained */ +export default { + effect: console.log( 'side-effect' ) || 43 +}; // trailing retained + +/* footer 8 */ From 698f3a2de69630192c0fae4a3cb2461a2ad1cbe3 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Fri, 2 Feb 2018 17:53:11 +0100 Subject: [PATCH 08/27] Remove "statement" concept and other remains of old positioning logic --- src/Module.ts | 11 ++----- src/ast/comment.ts | 4 --- src/ast/enhance.ts | 20 +------------ src/ast/nodes/BlockStatement.ts | 11 ++----- src/ast/nodes/BreakStatement.ts | 4 +-- src/ast/nodes/ClassDeclaration.ts | 13 ++------- src/ast/nodes/DoWhileStatement.ts | 7 ++--- src/ast/nodes/EmptyStatement.ts | 4 +-- src/ast/nodes/ExportAllDeclaration.ts | 6 ++-- src/ast/nodes/ExportDefaultDeclaration.ts | 4 +-- src/ast/nodes/ExportNamedDeclaration.ts | 8 ++--- src/ast/nodes/ExpressionStatement.ts | 12 ++++---- src/ast/nodes/ForInStatement.ts | 7 ++--- src/ast/nodes/ForOfStatement.ts | 7 ++--- src/ast/nodes/ForStatement.ts | 7 ++--- src/ast/nodes/FunctionDeclaration.ts | 13 --------- src/ast/nodes/IfStatement.ts | 29 ++++++++++++------- src/ast/nodes/ImportDeclaration.ts | 6 ++-- src/ast/nodes/LabeledStatement.ts | 6 ++-- src/ast/nodes/Program.ts | 12 +++----- src/ast/nodes/ReturnStatement.ts | 5 ++-- src/ast/nodes/SwitchCase.ts | 16 +++++----- src/ast/nodes/SwitchStatement.ts | 5 ++-- src/ast/nodes/ThrowStatement.ts | 5 ++-- src/ast/nodes/VariableDeclaration.ts | 14 +++++---- src/ast/nodes/WhileStatement.ts | 7 ++--- src/ast/nodes/index.ts | 3 +- src/ast/nodes/shared/Node.ts | 5 ---- src/ast/nodes/shared/Statement.ts | 18 ------------ src/utils/renderHelpers.ts | 5 ++-- .../comment-before-import/_expected/amd.js | 4 ++- .../comment-before-import/_expected/cjs.js | 4 ++- .../comment-before-import/_expected/es.js | 4 ++- .../comment-before-import/_expected/iife.js | 4 ++- .../comment-before-import/_expected/umd.js | 4 ++- .../_expected/amd.js | 5 +++- .../_expected/cjs.js | 5 +++- .../render-removed-statements/_expected/es.js | 5 +++- .../_expected/iife.js | 5 +++- .../_expected/umd.js | 5 +++- .../samples/render-removed-statements/main.js | 25 +++++++++------- .../sequence-expression/_expected/amd.js | 1 - .../sequence-expression/_expected/cjs.js | 1 - .../sequence-expression/_expected/es.js | 1 - .../sequence-expression/_expected/iife.js | 1 - .../sequence-expression/_expected/umd.js | 1 - .../skips-dead-branches-c/_expected/amd.js | 3 +- .../skips-dead-branches-c/_expected/cjs.js | 3 +- .../skips-dead-branches-c/_expected/es.js | 3 +- .../skips-dead-branches-c/_expected/iife.js | 3 +- .../skips-dead-branches-c/_expected/umd.js | 3 +- .../skips-dead-branches-d/_expected/amd.js | 3 +- .../skips-dead-branches-d/_expected/cjs.js | 3 +- .../skips-dead-branches-d/_expected/es.js | 3 +- .../skips-dead-branches-d/_expected/iife.js | 3 +- .../skips-dead-branches-d/_expected/umd.js | 3 +- .../skips-dead-branches-e/_expected/amd.js | 3 +- .../skips-dead-branches-e/_expected/cjs.js | 3 +- .../skips-dead-branches-e/_expected/es.js | 3 +- .../skips-dead-branches-e/_expected/iife.js | 3 +- .../skips-dead-branches-e/_expected/umd.js | 3 +- .../skips-dead-branches-f/_expected/amd.js | 3 +- .../skips-dead-branches-f/_expected/cjs.js | 3 +- .../skips-dead-branches-f/_expected/es.js | 3 +- .../skips-dead-branches-f/_expected/iife.js | 3 +- .../skips-dead-branches-f/_expected/umd.js | 3 +- 66 files changed, 165 insertions(+), 244 deletions(-) delete mode 100644 src/ast/comment.ts delete mode 100644 src/ast/nodes/shared/Statement.ts diff --git a/src/Module.ts b/src/Module.ts index 362b981ce55..68a308b2458 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -38,7 +38,7 @@ import { isTemplateLiteral } from './ast/nodes/TemplateLiteral'; import { isLiteral } from './ast/nodes/Literal'; import Chunk, { DynamicImportMechanism } from './Chunk'; -export interface IdMap { [key: string]: string; } +export interface IdMap {[key: string]: string;} export interface CommentDescription { block: boolean; @@ -374,20 +374,13 @@ export default class Module { } private analyse () { - enhance(this.ast, this, this.comments, this.dynamicImports); - - // discover this module's imports and exports - let lastNode: Node; - + enhance(this.ast, this, this.dynamicImports); this.ast.body.forEach(node => { if ((node).isImportDeclaration) { this.addImport(node); } else if ((node).isExportDeclaration) { this.addExport((node)); } - - if (lastNode) lastNode.next = node.leadingCommentStart || node.start; - lastNode = node; }); } diff --git a/src/ast/comment.ts b/src/ast/comment.ts deleted file mode 100644 index 98df0874c65..00000000000 --- a/src/ast/comment.ts +++ /dev/null @@ -1,4 +0,0 @@ -export default interface Comment { - start: number; - end: number; -} \ No newline at end of file diff --git a/src/ast/enhance.ts b/src/ast/enhance.ts index 4fa7c7ef03b..6b2d1a47af6 100644 --- a/src/ast/enhance.ts +++ b/src/ast/enhance.ts @@ -3,31 +3,13 @@ import UnknownNode from './nodes/UnknownNode'; import keys from './keys'; import { Node } from './nodes/shared/Node'; import Module from '../Module'; -import Comment from './comment'; import MagicString from 'magic-string'; import Import from './nodes/Import'; -const newline = /\n/; - -export default function enhance (ast: any, module: Module, comments: Comment[], dynamicImportReturnList: Import[]) { +export default function enhance (ast: any, module: Module, dynamicImportReturnList: Import[]) { enhanceNode(ast, {}, module, module.magicString, dynamicImportReturnList); - let comment = comments.shift(); - for (const node of ast.body) { - if (comment && comment.start < node.start) { - node.leadingCommentStart = comment.start; - } - - while (comment && comment.end < node.end) comment = comments.shift(); - - // if the next comment is on the same line as the end of the node, - // treat is as a trailing comment - if (comment && !newline.test(module.code.slice(node.end, comment.start))) { - node.trailingCommentEnd = comment.end; // TODO is node.trailingCommentEnd used anywhere? - comment = comments.shift(); - } - node.initialise(module.scope); } } diff --git a/src/ast/nodes/BlockStatement.ts b/src/ast/nodes/BlockStatement.ts index 3f26ff2a32e..3a651cfd4ba 100644 --- a/src/ast/nodes/BlockStatement.ts +++ b/src/ast/nodes/BlockStatement.ts @@ -3,8 +3,7 @@ import { UNKNOWN_EXPRESSION } from '../values'; import ExecutionPathOptions from '../ExecutionPathOptions'; import Scope from '../scopes/Scope'; import MagicString from 'magic-string'; -import { Node } from './shared/Node'; -import { StatementBase, StatementNode } from './shared/Statement'; +import { Node, NodeBase } from './shared/Node'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; import { renderStatementBlock } from '../../utils/renderHelpers'; @@ -13,10 +12,10 @@ export function isBlockStatement (node: Node): node is BlockStatement { return node.type === NodeType.BlockStatement; } -export default class BlockStatement extends StatementBase { +export default class BlockStatement extends NodeBase { type: NodeType.BlockStatement; scope: Scope; - body: StatementNode[]; + body: Node[]; bindImplicitReturnExpressionToScope () { const lastStatement = this.body[this.body.length - 1]; @@ -49,12 +48,8 @@ export default class BlockStatement extends StatementBase { } initialiseChildren (_parentScope: Scope) { - let lastNode; for (const node of this.body) { node.initialise(this.scope); - - if (lastNode) lastNode.next = node.start; - lastNode = node; } } diff --git a/src/ast/nodes/BreakStatement.ts b/src/ast/nodes/BreakStatement.ts index 700cbfcd2b4..f44e3b8f919 100644 --- a/src/ast/nodes/BreakStatement.ts +++ b/src/ast/nodes/BreakStatement.ts @@ -1,9 +1,9 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import Identifier from './Identifier'; -import { StatementBase } from './shared/Statement'; import { NodeType } from './NodeType'; +import { NodeBase } from './shared/Node'; -export default class BreakStatement extends StatementBase { +export default class BreakStatement extends NodeBase { type: NodeType.BreakStatement; label: Identifier | null; diff --git a/src/ast/nodes/ClassDeclaration.ts b/src/ast/nodes/ClassDeclaration.ts index a764ec0e78b..7123659740c 100644 --- a/src/ast/nodes/ClassDeclaration.ts +++ b/src/ast/nodes/ClassDeclaration.ts @@ -21,16 +21,9 @@ export default class ClassDeclaration extends ClassNode { } render (code: MagicString, options: RenderOptions) { - if (!this.module.graph.treeshake || this.included) { - if (options.systemBindings && this.id.variable.exportName) { - code.appendRight(this.end, ` exports('${this.id.variable.exportName}', ${this.id.variable.getName()});`); - } - super.render(code, options); - } else { - code.remove( - this.leadingCommentStart || this.start, - this.next || this.end - ); + if (options.systemBindings && this.id.variable.exportName) { + code.appendRight(this.end, ` exports('${this.id.variable.exportName}', ${this.id.variable.getName()});`); } + super.render(code, options); } } diff --git a/src/ast/nodes/DoWhileStatement.ts b/src/ast/nodes/DoWhileStatement.ts index 72e1c8f653a..e0d968806c3 100644 --- a/src/ast/nodes/DoWhileStatement.ts +++ b/src/ast/nodes/DoWhileStatement.ts @@ -1,11 +1,10 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; -import { StatementBase, StatementNode } from './shared/Statement'; -import { ExpressionNode } from './shared/Node'; +import { ExpressionNode, NodeBase, Node } from './shared/Node'; import { NodeType } from './NodeType'; -export default class DoWhileStatement extends StatementBase { +export default class DoWhileStatement extends NodeBase { type: NodeType.DoWhileStatement; - body: StatementNode; + body: Node; test: ExpressionNode; hasEffects (options: ExecutionPathOptions): boolean { diff --git a/src/ast/nodes/EmptyStatement.ts b/src/ast/nodes/EmptyStatement.ts index 08f039cd26a..e3f7e0dc5da 100644 --- a/src/ast/nodes/EmptyStatement.ts +++ b/src/ast/nodes/EmptyStatement.ts @@ -1,9 +1,9 @@ import MagicString from 'magic-string'; -import { StatementBase } from './shared/Statement'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; +import { NodeBase } from './shared/Node'; -export default class EmptyStatement extends StatementBase { +export default class EmptyStatement extends NodeBase { type: NodeType.EmptyStatement; render (code: MagicString, _options: RenderOptions) { diff --git a/src/ast/nodes/ExportAllDeclaration.ts b/src/ast/nodes/ExportAllDeclaration.ts index 4870a92305c..3efd90a1535 100644 --- a/src/ast/nodes/ExportAllDeclaration.ts +++ b/src/ast/nodes/ExportAllDeclaration.ts @@ -2,7 +2,7 @@ import { NodeBase } from './shared/Node'; import Literal from './Literal'; import MagicString from 'magic-string'; import { NodeType } from './NodeType'; -import { RenderOptions } from '../../Module'; +import { NodeRenderOptions, RenderOptions } from '../../Module'; export default class ExportAllDeclaration extends NodeBase { type: NodeType.ExportAllDeclaration; @@ -13,7 +13,7 @@ export default class ExportAllDeclaration extends NodeBase { this.isExportDeclaration = true; } - render (code: MagicString, _options: RenderOptions) { - code.remove(this.leadingCommentStart || this.start, this.next || this.end); + render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { + code.remove(start || this.start, end || this.end); } } diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index 7b99329c4c3..ccdc3c6a1e7 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -55,7 +55,7 @@ export default class ExportDefaultDeclaration extends NodeBase { ); } - render (code: MagicString, options: RenderOptions, nodeRenderOptions: NodeRenderOptions = {}) { + render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { const declarationStart = this.start + getDeclarationStart(code.original.slice(this.start, this.end)); if (isFunctionDeclaration(this.declaration)) { @@ -64,7 +64,7 @@ export default class ExportDefaultDeclaration extends NodeBase { this.renderNamedDeclaration(code, declarationStart, 'class', this.declaration.id === null, options); } else if (this.variable.getOriginalVariableName() === this.variable.getName()) { // Remove altogether to prevent re-declaring the same variable - code.remove(nodeRenderOptions.start || this.start, nodeRenderOptions.end || this.end); + code.remove(start || this.start, end || this.end); return; } else if (this.variable.included) { this.renderVariableDeclaration(code, declarationStart, options); diff --git a/src/ast/nodes/ExportNamedDeclaration.ts b/src/ast/nodes/ExportNamedDeclaration.ts index 205e18c459d..899a4f06ca7 100644 --- a/src/ast/nodes/ExportNamedDeclaration.ts +++ b/src/ast/nodes/ExportNamedDeclaration.ts @@ -7,7 +7,7 @@ import FunctionDeclaration from './FunctionDeclaration'; import ClassDeclaration from './ClassDeclaration'; import VariableDeclaration from './VariableDeclaration'; import { NodeType } from './NodeType'; -import { RenderOptions } from '../../Module'; +import { NodeRenderOptions, RenderOptions } from '../../Module'; export default class ExportNamedDeclaration extends NodeBase { type: NodeType.ExportNamedDeclaration; @@ -30,14 +30,12 @@ export default class ExportNamedDeclaration extends NodeBase { this.isExportDeclaration = true; } - render (code: MagicString, options: RenderOptions) { + render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { if (this.declaration) { code.remove(this.start, this.declaration.start); this.declaration.render(code, options); } else { - const start = this.leadingCommentStart || this.start; - const end = this.next || this.end; - code.remove(start, end); + code.remove(start || this.start, end || this.end); } } } diff --git a/src/ast/nodes/ExpressionStatement.ts b/src/ast/nodes/ExpressionStatement.ts index cfe4ef03ce8..64cda3c2027 100644 --- a/src/ast/nodes/ExpressionStatement.ts +++ b/src/ast/nodes/ExpressionStatement.ts @@ -1,13 +1,13 @@ import MagicString from 'magic-string'; -import { StatementBase } from './shared/Statement'; import Scope from '../scopes/Scope'; import { RenderOptions } from '../../Module'; +import { NodeBase } from './shared/Node'; -export default class ExpressionStatement extends StatementBase { +export default class ExpressionStatement extends NodeBase { directive?: string; - initialiseNode(_parentScope: Scope){ - if (this.directive && this.directive !== 'use strict' && this.parent.type === "Program") { + initialiseNode (_parentScope: Scope) { + if (this.directive && this.directive !== 'use strict' && this.parent.type === 'Program') { this.module.warn( // This is necessary, because either way (deleting or not) can lead to errors. { code: 'MODULE_LEVEL_DIRECTIVE', @@ -20,9 +20,9 @@ export default class ExpressionStatement extends StatementBase { return super.initialiseNode(_parentScope); } - shouldBeIncluded() { + shouldBeIncluded () { if (this.directive && this.directive !== 'use strict') - return this.parent.type !== "Program"; + return this.parent.type !== 'Program'; return super.shouldBeIncluded(); } diff --git a/src/ast/nodes/ForInStatement.ts b/src/ast/nodes/ForInStatement.ts index 2465834b584..5fbd58e0d6d 100644 --- a/src/ast/nodes/ForInStatement.ts +++ b/src/ast/nodes/ForInStatement.ts @@ -3,16 +3,15 @@ import VariableDeclaration from './VariableDeclaration'; import Scope from '../scopes/Scope'; import ExecutionPathOptions from '../ExecutionPathOptions'; import BlockStatement from './BlockStatement'; -import { StatementBase, StatementNode } from './shared/Statement'; import { PatternNode } from './shared/Pattern'; import { NodeType } from './NodeType'; -import { ExpressionNode } from './shared/Node'; +import { ExpressionNode, NodeBase, Node } from './shared/Node'; -export default class ForInStatement extends StatementBase { +export default class ForInStatement extends NodeBase { type: NodeType.ForInStatement; left: VariableDeclaration | PatternNode; right: ExpressionNode; - body: StatementNode; + body: Node; hasEffects (options: ExecutionPathOptions): boolean { return ( diff --git a/src/ast/nodes/ForOfStatement.ts b/src/ast/nodes/ForOfStatement.ts index b1da0f9af0a..ece7326078c 100644 --- a/src/ast/nodes/ForOfStatement.ts +++ b/src/ast/nodes/ForOfStatement.ts @@ -3,16 +3,15 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import VariableDeclaration from './VariableDeclaration'; import Scope from '../scopes/Scope'; import BlockStatement from './BlockStatement'; -import { StatementBase, StatementNode } from './shared/Statement'; import { PatternNode } from './shared/Pattern'; import { NodeType } from './NodeType'; -import { ExpressionNode } from './shared/Node'; +import { ExpressionNode, NodeBase, Node } from './shared/Node'; -export default class ForOfStatement extends StatementBase { +export default class ForOfStatement extends NodeBase { type: NodeType.ForOfStatement; left: VariableDeclaration | PatternNode; right: ExpressionNode; - body: StatementNode; + body: Node; bindNode () { this.left.reassignPath([], ExecutionPathOptions.create()); diff --git a/src/ast/nodes/ForStatement.ts b/src/ast/nodes/ForStatement.ts index 035931bb2f2..bfec2498065 100644 --- a/src/ast/nodes/ForStatement.ts +++ b/src/ast/nodes/ForStatement.ts @@ -2,16 +2,15 @@ import BlockScope from '../scopes/BlockScope'; import VariableDeclaration from './VariableDeclaration'; import ExecutionPathOptions from '../ExecutionPathOptions'; import Scope from '../scopes/Scope'; -import { StatementBase, StatementNode } from './shared/Statement'; import { NodeType } from './NodeType'; -import { ExpressionNode } from './shared/Node'; +import { ExpressionNode, NodeBase, Node } from './shared/Node'; -export default class ForStatement extends StatementBase { +export default class ForStatement extends NodeBase { type: NodeType.ForStatement; init: VariableDeclaration | ExpressionNode | null; test: ExpressionNode | null; update: ExpressionNode | null; - body: StatementNode; + body: Node; hasEffects (options: ExecutionPathOptions): boolean { return ( diff --git a/src/ast/nodes/FunctionDeclaration.ts b/src/ast/nodes/FunctionDeclaration.ts index 0419b060ecf..56149908e3b 100644 --- a/src/ast/nodes/FunctionDeclaration.ts +++ b/src/ast/nodes/FunctionDeclaration.ts @@ -1,8 +1,6 @@ import FunctionNode from './shared/FunctionNode'; import Scope from '../scopes/Scope'; -import MagicString from 'magic-string'; import { NodeType } from './NodeType'; -import { RenderOptions } from '../../Module'; import { Node } from './shared/Node'; export function isFunctionDeclaration (node: Node): node is FunctionDeclaration { @@ -19,15 +17,4 @@ export default class FunctionDeclaration extends FunctionNode { ); this.body.initialiseAndReplaceScope(new Scope({ parent: this.scope })); } - - render (code: MagicString, options: RenderOptions) { - if (!this.module.graph.treeshake || this.included) { - super.render(code, options); - } else { - code.remove( - this.leadingCommentStart || this.start, - this.next || this.end - ); - } - } } diff --git a/src/ast/nodes/IfStatement.ts b/src/ast/nodes/IfStatement.ts index 79d578e6004..8b204562e4c 100644 --- a/src/ast/nodes/IfStatement.ts +++ b/src/ast/nodes/IfStatement.ts @@ -1,12 +1,11 @@ import extractNames from '../utils/extractNames'; import { UNKNOWN_VALUE } from '../values'; import Scope from '../scopes/Scope'; -import { ExpressionNode, Node } from './shared/Node'; +import { ExpressionNode, Node, NodeBase } from './shared/Node'; import { isVariableDeclaration } from './VariableDeclaration'; import MagicString from 'magic-string'; -import { StatementBase, StatementNode } from './shared/Statement'; import { NodeType } from './NodeType'; -import { RenderOptions } from '../../Module'; +import { NodeRenderOptions, RenderOptions } from '../../Module'; // Statement types which may contain if-statements as direct children. const statementsWithIfStatements = new Set([ @@ -18,7 +17,7 @@ const statementsWithIfStatements = new Set([ 'WhileStatement' ]); -function getHoistedVars (node: StatementNode, scope: Scope) { +function getHoistedVars (node: Node, scope: Scope) { const hoistedVars: string[] = []; function visit (node: Node) { @@ -41,14 +40,14 @@ function getHoistedVars (node: StatementNode, scope: Scope) { return hoistedVars; } -export default class IfStatement extends StatementBase { +export default class IfStatement extends NodeBase { type: NodeType.IfStatement; test: ExpressionNode; - consequent: StatementNode; - alternate: StatementNode | null; + consequent: Node; + alternate: Node | null; - testValue: any; - hoistedVars: string[]; + private testValue: any; + private hoistedVars?: string[]; initialiseChildren (parentScope: Scope) { super.initialiseChildren(parentScope); @@ -70,7 +69,11 @@ export default class IfStatement extends StatementBase { } } - render (code: MagicString, options: RenderOptions) { + initialiseNode () { + this.hoistedVars = []; + } + + render (code: MagicString, options: RenderOptions, { end }: NodeRenderOptions = {}) { if (this.module.graph.treeshake) { if (this.testValue === UNKNOWN_VALUE) { super.render(code, options); @@ -104,7 +107,7 @@ export default class IfStatement extends StatementBase { } else { code.remove( this.start, - this.alternate ? this.alternate.start : this.next || this.end + this.alternate ? this.alternate.start : end || this.end ); if (this.alternate) { @@ -118,4 +121,8 @@ export default class IfStatement extends StatementBase { super.render(code, options); } } + + shouldBeIncluded () { + return this.hoistedVars.length > 0 || super.shouldBeIncluded(); + } } diff --git a/src/ast/nodes/ImportDeclaration.ts b/src/ast/nodes/ImportDeclaration.ts index 6fc9387d3fe..f326799f8c8 100644 --- a/src/ast/nodes/ImportDeclaration.ts +++ b/src/ast/nodes/ImportDeclaration.ts @@ -5,7 +5,7 @@ import ImportDefaultSpecifier from './ImportDefaultSpecifier'; import ImportNamespaceSpecifier from './ImportNamespaceSpecifier'; import MagicString from 'magic-string'; import { NodeType } from './NodeType'; -import { RenderOptions } from '../../Module'; +import { NodeRenderOptions, RenderOptions } from '../../Module'; export default class ImportDeclaration extends NodeBase { type: NodeType.ImportDeclaration; @@ -19,7 +19,7 @@ export default class ImportDeclaration extends NodeBase { this.isImportDeclaration = true; } - render (code: MagicString, _options: RenderOptions) { - code.remove(this.start, this.next || this.end); + render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { + code.remove(start || this.start, end || this.end); } } diff --git a/src/ast/nodes/LabeledStatement.ts b/src/ast/nodes/LabeledStatement.ts index 461d35fad27..f35ad26b6d9 100644 --- a/src/ast/nodes/LabeledStatement.ts +++ b/src/ast/nodes/LabeledStatement.ts @@ -1,12 +1,12 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import Identifier from './Identifier'; -import { StatementBase, StatementNode } from './shared/Statement'; import { NodeType } from './NodeType'; +import { NodeBase, Node } from './shared/Node'; -export default class LabeledStatement extends StatementBase { +export default class LabeledStatement extends NodeBase { type: NodeType.LabeledStatement; label: Identifier; - body: StatementNode; + body: Node; hasEffects (options: ExecutionPathOptions) { return this.body.hasEffects( diff --git a/src/ast/nodes/Program.ts b/src/ast/nodes/Program.ts index 608569549ff..309ee2846ac 100644 --- a/src/ast/nodes/Program.ts +++ b/src/ast/nodes/Program.ts @@ -1,20 +1,16 @@ import MagicString from 'magic-string'; -import { NodeBase } from './shared/Node'; -import { StatementNode } from './shared/Statement'; +import { NodeBase, Node } from './shared/Node'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; import { renderStatementBlock } from '../../utils/renderHelpers'; export default class Program extends NodeBase { - type: NodeType.Program; - body: StatementNode[]; + type: NodeType.Program; + body: Node[]; render (code: MagicString, options: RenderOptions) { if (this.body.length) { - const lastNodeEnd = this.body[this.body.length - 1].end; - const firstTrailingLineBreakPos = code.slice(lastNodeEnd, this.end).indexOf('\n'); - const end = firstTrailingLineBreakPos === -1 ? this.end : lastNodeEnd + firstTrailingLineBreakPos + 1; - renderStatementBlock(this.body, code, this.start, end, options); + renderStatementBlock(this.body, code, this.start, this.end, options); } else { super.render(code, options); } diff --git a/src/ast/nodes/ReturnStatement.ts b/src/ast/nodes/ReturnStatement.ts index 2bcecb32f31..3e08a17aca0 100644 --- a/src/ast/nodes/ReturnStatement.ts +++ b/src/ast/nodes/ReturnStatement.ts @@ -1,10 +1,9 @@ import { UNKNOWN_EXPRESSION } from '../values'; import ExecutionPathOptions from '../ExecutionPathOptions'; -import { StatementBase } from './shared/Statement'; import { NodeType } from './NodeType'; -import { ExpressionNode } from './shared/Node'; +import { ExpressionNode, NodeBase } from './shared/Node'; -export default class ReturnStatement extends StatementBase { +export default class ReturnStatement extends NodeBase { type: NodeType.ReturnStatement; argument: ExpressionNode | null; diff --git a/src/ast/nodes/SwitchCase.ts b/src/ast/nodes/SwitchCase.ts index 5a1bddb0c3b..275c85f6f2b 100644 --- a/src/ast/nodes/SwitchCase.ts +++ b/src/ast/nodes/SwitchCase.ts @@ -1,14 +1,13 @@ -import { ExpressionNode, NodeBase } from './shared/Node'; -import { StatementNode } from './shared/Statement'; +import { ExpressionNode, NodeBase, Node } from './shared/Node'; import { NodeType } from './NodeType'; -import { renderStatementBlock } from '../../utils/renderHelpers'; +import { findFirstOccurrenceOutsideComment, renderStatementBlock } from '../../utils/renderHelpers'; import { RenderOptions } from '../../Module'; import MagicString from 'magic-string'; export default class SwitchCase extends NodeBase { type: NodeType.SwitchCase; test: ExpressionNode | null; - consequent: StatementNode[]; + consequent: Node[]; includeInBundle () { let addedNewNodes = !this.included; @@ -28,10 +27,11 @@ export default class SwitchCase extends NodeBase { render (code: MagicString, options: RenderOptions) { if (this.consequent.length) { - const firstNodeStart = this.consequent[0].start; - const firstLeadingLineBreakPos = code.slice(this.start, firstNodeStart).indexOf('\n'); - const start = firstLeadingLineBreakPos === -1 ? firstNodeStart : firstLeadingLineBreakPos + this.start; - renderStatementBlock(this.consequent, code, start, this.end, options); + const testEnd = this.test + ? this.test.end + : this.start + findFirstOccurrenceOutsideComment(code.original.slice(this.start, this.end), 'default') + 7; + const consequentStart = testEnd + findFirstOccurrenceOutsideComment(code.original.slice(testEnd, this.end), ':') + 1; + renderStatementBlock(this.consequent, code, consequentStart, this.end, options); } else { super.render(code, options); } diff --git a/src/ast/nodes/SwitchStatement.ts b/src/ast/nodes/SwitchStatement.ts index a546f92cc02..7a93007c7c3 100644 --- a/src/ast/nodes/SwitchStatement.ts +++ b/src/ast/nodes/SwitchStatement.ts @@ -2,11 +2,10 @@ import BlockScope from '../scopes/BlockScope'; import SwitchCase from './SwitchCase'; import ExecutionPathOptions from '../ExecutionPathOptions'; import Scope from '../scopes/Scope'; -import { StatementBase } from './shared/Statement'; import { NodeType } from './NodeType'; -import { ExpressionNode } from './shared/Node'; +import { ExpressionNode, NodeBase } from './shared/Node'; -export default class SwitchStatement extends StatementBase { +export default class SwitchStatement extends NodeBase { type: NodeType.SwitchStatement; discriminant: ExpressionNode; cases: SwitchCase[]; diff --git a/src/ast/nodes/ThrowStatement.ts b/src/ast/nodes/ThrowStatement.ts index 4d1f93f9376..ef172096cd9 100644 --- a/src/ast/nodes/ThrowStatement.ts +++ b/src/ast/nodes/ThrowStatement.ts @@ -1,9 +1,8 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; -import { StatementBase } from './shared/Statement'; import { NodeType } from './NodeType'; -import { ExpressionNode } from './shared/Node'; +import { ExpressionNode, NodeBase } from './shared/Node'; -export default class ThrowStatement extends StatementBase { +export default class ThrowStatement extends NodeBase { type: NodeType.ThrowStatement; argument: ExpressionNode; diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index e57c7a7f72c..b4a29dc7cb7 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -9,7 +9,7 @@ import MagicString from 'magic-string'; import { ObjectPath } from '../variables/VariableReassignmentTracker'; import { isIdentifier } from './Identifier'; import { NodeType } from './NodeType'; -import { RenderOptions } from '../../Module'; +import { NodeRenderOptions, RenderOptions } from '../../Module'; function getSeparator (code: string, start: number) { let c = start; @@ -73,7 +73,7 @@ export default class VariableDeclaration extends NodeBase { ); } - render (code: MagicString, options: RenderOptions) { + render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { const treeshake = this.module.graph.treeshake; let shouldSeparate = false; @@ -97,7 +97,8 @@ export default class VariableDeclaration extends NodeBase { if (isIdentifier(declarator.id)) { const variable = this.scope.findVariable(declarator.id.name); - const isExportedAndReassigned = variable.safeName && variable.safeName.indexOf('.') !== -1 && variable.exportName && variable.isReassigned; + const isExportedAndReassigned = variable.safeName && variable.safeName.indexOf( + '.') !== -1 && variable.exportName && variable.isReassigned; if (options.systemBindings && variable.exportName && declarator.init) { code.prependLeft(declarator.init.start, `exports('${variable.exportName}', `); @@ -122,7 +123,8 @@ export default class VariableDeclaration extends NodeBase { extractNames(declarator.id).forEach(name => { const variable = this.scope.findVariable(name); - const isExportedAndReassigned = variable.safeName && variable.safeName.indexOf('.') !== -1 && variable.exportName && variable.isReassigned; + const isExportedAndReassigned = variable.safeName && variable.safeName.indexOf( + '.') !== -1 && variable.exportName && variable.isReassigned; if (isExportedAndReassigned) { // code.overwrite( c, declarator.start, prefix ); @@ -154,8 +156,8 @@ export default class VariableDeclaration extends NodeBase { if (treeshake && empty) { code.remove( - this.leadingCommentStart || this.start, - this.next || this.end + start || this.start, + end || this.end ); } else { // always include a semi-colon (https://github.com/rollup/rollup/pull/1013), diff --git a/src/ast/nodes/WhileStatement.ts b/src/ast/nodes/WhileStatement.ts index 8fbd857b183..cb82c8a6358 100644 --- a/src/ast/nodes/WhileStatement.ts +++ b/src/ast/nodes/WhileStatement.ts @@ -1,12 +1,11 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; -import { StatementBase, StatementNode } from './shared/Statement'; import { NodeType } from './NodeType'; -import { ExpressionNode } from './shared/Node'; +import { ExpressionNode, NodeBase, Node } from './shared/Node'; -export default class WhileStatement extends StatementBase { +export default class WhileStatement extends NodeBase { type: NodeType.WhileStatement; test: ExpressionNode; - body: StatementNode; + body: Node; hasEffects (options: ExecutionPathOptions): boolean { return ( diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 9fdb09d28df..934377d51ad 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -54,7 +54,6 @@ import VariableDeclarator from './VariableDeclarator'; import VariableDeclaration from './VariableDeclaration'; import WhileStatement from './WhileStatement'; import YieldExpression from './YieldExpression'; -import { StatementBase } from './shared/Statement'; import { NodeBase } from './shared/Node'; const nodes: { @@ -110,7 +109,7 @@ const nodes: { TemplateLiteral, ThisExpression, ThrowStatement, - TryStatement: StatementBase, + TryStatement: NodeBase, UnaryExpression, UpdateExpression, VariableDeclarator, diff --git a/src/ast/nodes/shared/Node.ts b/src/ast/nodes/shared/Node.ts index 98fe3ee2f21..3c71a8e502a 100644 --- a/src/ast/nodes/shared/Node.ts +++ b/src/ast/nodes/shared/Node.ts @@ -14,9 +14,7 @@ export interface Node extends Entity { end: number; included: boolean; keys: string[]; - leadingCommentStart: number; module: Module; - next: number; parent: Node | { type?: string }; start: number; type: string; @@ -85,9 +83,6 @@ export class NodeBase implements ExpressionNode { scope: Scope; start: number; end: number; - leadingCommentStart: number; - trailingCommentEnd: number; - next: number; module: Module; parent: Node | { type?: string }; __enhanced: boolean; diff --git a/src/ast/nodes/shared/Statement.ts b/src/ast/nodes/shared/Statement.ts deleted file mode 100644 index 4548ee4890f..00000000000 --- a/src/ast/nodes/shared/Statement.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { NodeBase, Node } from './Node'; -import MagicString from 'magic-string'; -import { RenderOptions } from '../../../Module'; - -export interface StatementNode extends Node {} - -export class StatementBase extends NodeBase implements StatementNode { - render (code: MagicString, options: RenderOptions) { - if (!this.module.graph.treeshake || this.included) { - super.render(code, options); - } else { - code.remove( - this.leadingCommentStart || this.start, - this.next || this.end - ); - } - } -} diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index 907524cb072..33b339ff51a 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -1,7 +1,6 @@ import { Node } from '../ast/nodes/shared/Node'; import MagicString from 'magic-string'; import { RenderOptions } from '../Module'; -import { NodeType } from '../ast/nodes/NodeType'; // Note that if the string is not found, "0" is returned instead of e.g. "-1" // as this seems to work best for the main use case @@ -35,10 +34,10 @@ export function renderStatementBlock (statements: Node[], code: MagicString, sta nextNodeStart = currentNode.end + (findFirstOccurrenceOutsideComment(code.original.slice( currentNode.end, nextNode !== undefined ? nextNode.start : end ), '\n')); - if (!currentNode.included && currentNode.type !== NodeType.IfStatement) { + if (!currentNode.included) { code.remove(currentNodeStart, nextNodeStart); } else { - currentNode.render(code, options, {start: currentNodeStart, end:nextNodeStart}); + currentNode.render(code, options, { start: currentNodeStart, end: nextNodeStart }); } } } diff --git a/test/form/samples/comment-before-import/_expected/amd.js b/test/form/samples/comment-before-import/_expected/amd.js index 8ee578297b5..95d9a9cc3aa 100644 --- a/test/form/samples/comment-before-import/_expected/amd.js +++ b/test/form/samples/comment-before-import/_expected/amd.js @@ -4,9 +4,11 @@ define(function () { 'use strict'; var bar = 21; // foo.js + var foo = bar * 2; // main.js + console.log( foo ); -}); \ No newline at end of file +}); diff --git a/test/form/samples/comment-before-import/_expected/cjs.js b/test/form/samples/comment-before-import/_expected/cjs.js index 04e5550e3b8..27c89b4ee9e 100644 --- a/test/form/samples/comment-before-import/_expected/cjs.js +++ b/test/form/samples/comment-before-import/_expected/cjs.js @@ -4,7 +4,9 @@ var bar = 21; // foo.js + var foo = bar * 2; // main.js -console.log( foo ); \ No newline at end of file + +console.log( foo ); diff --git a/test/form/samples/comment-before-import/_expected/es.js b/test/form/samples/comment-before-import/_expected/es.js index 1c21cb39cff..6109f4d83c8 100644 --- a/test/form/samples/comment-before-import/_expected/es.js +++ b/test/form/samples/comment-before-import/_expected/es.js @@ -2,7 +2,9 @@ var bar = 21; // foo.js + var foo = bar * 2; // main.js -console.log( foo ); \ No newline at end of file + +console.log( foo ); diff --git a/test/form/samples/comment-before-import/_expected/iife.js b/test/form/samples/comment-before-import/_expected/iife.js index 7d1e8f99394..7f209da4263 100644 --- a/test/form/samples/comment-before-import/_expected/iife.js +++ b/test/form/samples/comment-before-import/_expected/iife.js @@ -5,9 +5,11 @@ var bar = 21; // foo.js + var foo = bar * 2; // main.js + console.log( foo ); -}()); \ No newline at end of file +}()); diff --git a/test/form/samples/comment-before-import/_expected/umd.js b/test/form/samples/comment-before-import/_expected/umd.js index 9d407005cc7..b0cde703cee 100644 --- a/test/form/samples/comment-before-import/_expected/umd.js +++ b/test/form/samples/comment-before-import/_expected/umd.js @@ -8,9 +8,11 @@ var bar = 21; // foo.js + var foo = bar * 2; // main.js + console.log( foo ); -}))); \ No newline at end of file +}))); diff --git a/test/form/samples/render-removed-statements/_expected/amd.js b/test/form/samples/render-removed-statements/_expected/amd.js index ead127da7af..62a1b78960c 100644 --- a/test/form/samples/render-removed-statements/_expected/amd.js +++ b/test/form/samples/render-removed-statements/_expected/amd.js @@ -41,7 +41,10 @@ define(function () { 'use strict'; case 3: // lead retained console.log(2); // trail retained - case 4: /* lead retained */ console.log('3'); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained + default: + /* lead retained */ + console.log(2); // trail retained } // lead retained diff --git a/test/form/samples/render-removed-statements/_expected/cjs.js b/test/form/samples/render-removed-statements/_expected/cjs.js index d2f24d06d83..9b310070b4a 100644 --- a/test/form/samples/render-removed-statements/_expected/cjs.js +++ b/test/form/samples/render-removed-statements/_expected/cjs.js @@ -41,7 +41,10 @@ switch (globalVar) { case 3: // lead retained console.log(2); // trail retained - case 4: /* lead retained */ console.log('3'); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained + default: + /* lead retained */ + console.log(2); // trail retained } // lead retained diff --git a/test/form/samples/render-removed-statements/_expected/es.js b/test/form/samples/render-removed-statements/_expected/es.js index da62bf30cce..1526f28c284 100644 --- a/test/form/samples/render-removed-statements/_expected/es.js +++ b/test/form/samples/render-removed-statements/_expected/es.js @@ -39,7 +39,10 @@ switch (globalVar) { case 3: // lead retained console.log(2); // trail retained - case 4: /* lead retained */ console.log('3'); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained + default: + /* lead retained */ + console.log(2); // trail retained } // lead retained diff --git a/test/form/samples/render-removed-statements/_expected/iife.js b/test/form/samples/render-removed-statements/_expected/iife.js index 0d7517f32c4..94df2c94a58 100644 --- a/test/form/samples/render-removed-statements/_expected/iife.js +++ b/test/form/samples/render-removed-statements/_expected/iife.js @@ -42,7 +42,10 @@ case 3: // lead retained console.log(2); // trail retained - case 4: /* lead retained */ console.log('3'); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained + default: + /* lead retained */ + console.log(2); // trail retained } // lead retained diff --git a/test/form/samples/render-removed-statements/_expected/umd.js b/test/form/samples/render-removed-statements/_expected/umd.js index 88d4c277346..1aed0a0d876 100644 --- a/test/form/samples/render-removed-statements/_expected/umd.js +++ b/test/form/samples/render-removed-statements/_expected/umd.js @@ -45,7 +45,10 @@ case 3: // lead retained console.log(2); // trail retained - case 4: /* lead retained */ console.log('3'); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained + default: + /* lead retained */ + console.log(2); // trail retained } // lead retained diff --git a/test/form/samples/render-removed-statements/main.js b/test/form/samples/render-removed-statements/main.js index da6a49bdf79..c89a78633b7 100644 --- a/test/form/samples/render-removed-statements/main.js +++ b/test/form/samples/render-removed-statements/main.js @@ -12,14 +12,14 @@ retained */ if (globalVar) { // lead removed - var x = 1; // trail removed + var a = 1; // trail removed // lead retained console.log(2); // trail retained } if (globalVar) { // lead removed - var x = 1; // trail removed + var a = 1; // trail removed // lead retained console.log(2); // trail retained // lead removed @@ -39,31 +39,36 @@ if (globalVar) { removed */ } -if (globalVar) { /* removed */ var x = 1; /* retained */ console.log(2);} +if (globalVar) { /* removed */ var a = 1; /* retained */ console.log(2);} -if (globalVar) { /* removed */ var x = 1; /* retained */ console.log(2); /* removed */ var a = 1;} +if (globalVar) { /* removed */ var a = 1; /* retained */ console.log(2); /* removed */ var a = 1;} if (globalVar) { /* retained */ console.log(2); /* removed */ var a = 1;} switch (globalVar) { case 1: // lead removed - const a = 1; // trail removed + var a = 1; // trail removed // lead retained console.log(2); // trail retained case 2: // lead removed - const b = 1; // trail removed + var a = 1; // trail removed // lead retained console.log(2); // trail retained // lead removed - const c = 1; + var a = 1; case 3: // lead retained console.log(2); // trail retained // lead removed - const d = 1; - case 4: const e = 1; /* lead retained */ console.log('3') // trail retained + var a = 1; + case 4: var a = 1; /* lead retained */ console.log('3') // trail retained + default: + /* lead removed */ + var a = 1; // trail removed + /* lead retained */ + console.log(2); // trail retained } // lead removed @@ -73,6 +78,6 @@ var a = 1; // trail removed console.log(2); // trail retained // lead removed -const z = 1; // trail removed +var a = 1; // trail removed /* footer retained */ diff --git a/test/form/samples/sequence-expression/_expected/amd.js b/test/form/samples/sequence-expression/_expected/amd.js index d611db56d40..1bb396422fc 100644 --- a/test/form/samples/sequence-expression/_expected/amd.js +++ b/test/form/samples/sequence-expression/_expected/amd.js @@ -13,7 +13,6 @@ define(function () { 'use strict'; var d = (2); console.log(d); - // should infer value // should keep f import var e = (foo$1()); diff --git a/test/form/samples/sequence-expression/_expected/cjs.js b/test/form/samples/sequence-expression/_expected/cjs.js index 411b417a05d..aae14522bca 100644 --- a/test/form/samples/sequence-expression/_expected/cjs.js +++ b/test/form/samples/sequence-expression/_expected/cjs.js @@ -13,7 +13,6 @@ var b = (foo()); var d = (2); console.log(d); -// should infer value // should keep f import var e = (foo$1()); diff --git a/test/form/samples/sequence-expression/_expected/es.js b/test/form/samples/sequence-expression/_expected/es.js index 34fe97a3298..a8781ec0593 100644 --- a/test/form/samples/sequence-expression/_expected/es.js +++ b/test/form/samples/sequence-expression/_expected/es.js @@ -11,7 +11,6 @@ var b = (foo()); var d = (2); console.log(d); -// should infer value // should keep f import var e = (foo$1()); diff --git a/test/form/samples/sequence-expression/_expected/iife.js b/test/form/samples/sequence-expression/_expected/iife.js index 6bc76179c50..d77362f8477 100644 --- a/test/form/samples/sequence-expression/_expected/iife.js +++ b/test/form/samples/sequence-expression/_expected/iife.js @@ -14,7 +14,6 @@ var d = (2); console.log(d); - // should infer value // should keep f import var e = (foo$1()); diff --git a/test/form/samples/sequence-expression/_expected/umd.js b/test/form/samples/sequence-expression/_expected/umd.js index 518622dc5cb..4a1ef40d623 100644 --- a/test/form/samples/sequence-expression/_expected/umd.js +++ b/test/form/samples/sequence-expression/_expected/umd.js @@ -17,7 +17,6 @@ var d = (2); console.log(d); - // should infer value // should keep f import var e = (foo$1()); diff --git a/test/form/samples/skips-dead-branches-c/_expected/amd.js b/test/form/samples/skips-dead-branches-c/_expected/amd.js index 9dc50f528f3..ee0987c254d 100644 --- a/test/form/samples/skips-dead-branches-c/_expected/amd.js +++ b/test/form/samples/skips-dead-branches-c/_expected/amd.js @@ -3,7 +3,6 @@ define(function () { 'use strict'; function bar () { console.log( 'this should be included' ); } - bar(); -}); \ No newline at end of file +}); diff --git a/test/form/samples/skips-dead-branches-c/_expected/cjs.js b/test/form/samples/skips-dead-branches-c/_expected/cjs.js index d6aa952d0e6..a979cc52820 100644 --- a/test/form/samples/skips-dead-branches-c/_expected/cjs.js +++ b/test/form/samples/skips-dead-branches-c/_expected/cjs.js @@ -3,5 +3,4 @@ function bar () { console.log( 'this should be included' ); } - -bar(); \ No newline at end of file +bar(); diff --git a/test/form/samples/skips-dead-branches-c/_expected/es.js b/test/form/samples/skips-dead-branches-c/_expected/es.js index f39bfec65a9..c24eeda81be 100644 --- a/test/form/samples/skips-dead-branches-c/_expected/es.js +++ b/test/form/samples/skips-dead-branches-c/_expected/es.js @@ -1,5 +1,4 @@ function bar () { console.log( 'this should be included' ); } - -bar(); \ No newline at end of file +bar(); diff --git a/test/form/samples/skips-dead-branches-c/_expected/iife.js b/test/form/samples/skips-dead-branches-c/_expected/iife.js index 8d6dcb52c0c..fe8653ab50d 100644 --- a/test/form/samples/skips-dead-branches-c/_expected/iife.js +++ b/test/form/samples/skips-dead-branches-c/_expected/iife.js @@ -4,7 +4,6 @@ function bar () { console.log( 'this should be included' ); } - bar(); -}()); \ No newline at end of file +}()); diff --git a/test/form/samples/skips-dead-branches-c/_expected/umd.js b/test/form/samples/skips-dead-branches-c/_expected/umd.js index 67588d41402..3a8711191a7 100644 --- a/test/form/samples/skips-dead-branches-c/_expected/umd.js +++ b/test/form/samples/skips-dead-branches-c/_expected/umd.js @@ -7,7 +7,6 @@ function bar () { console.log( 'this should be included' ); } - bar(); -}))); \ No newline at end of file +}))); diff --git a/test/form/samples/skips-dead-branches-d/_expected/amd.js b/test/form/samples/skips-dead-branches-d/_expected/amd.js index 9dc50f528f3..ee0987c254d 100644 --- a/test/form/samples/skips-dead-branches-d/_expected/amd.js +++ b/test/form/samples/skips-dead-branches-d/_expected/amd.js @@ -3,7 +3,6 @@ define(function () { 'use strict'; function bar () { console.log( 'this should be included' ); } - bar(); -}); \ No newline at end of file +}); diff --git a/test/form/samples/skips-dead-branches-d/_expected/cjs.js b/test/form/samples/skips-dead-branches-d/_expected/cjs.js index d6aa952d0e6..a979cc52820 100644 --- a/test/form/samples/skips-dead-branches-d/_expected/cjs.js +++ b/test/form/samples/skips-dead-branches-d/_expected/cjs.js @@ -3,5 +3,4 @@ function bar () { console.log( 'this should be included' ); } - -bar(); \ No newline at end of file +bar(); diff --git a/test/form/samples/skips-dead-branches-d/_expected/es.js b/test/form/samples/skips-dead-branches-d/_expected/es.js index f39bfec65a9..c24eeda81be 100644 --- a/test/form/samples/skips-dead-branches-d/_expected/es.js +++ b/test/form/samples/skips-dead-branches-d/_expected/es.js @@ -1,5 +1,4 @@ function bar () { console.log( 'this should be included' ); } - -bar(); \ No newline at end of file +bar(); diff --git a/test/form/samples/skips-dead-branches-d/_expected/iife.js b/test/form/samples/skips-dead-branches-d/_expected/iife.js index 8d6dcb52c0c..fe8653ab50d 100644 --- a/test/form/samples/skips-dead-branches-d/_expected/iife.js +++ b/test/form/samples/skips-dead-branches-d/_expected/iife.js @@ -4,7 +4,6 @@ function bar () { console.log( 'this should be included' ); } - bar(); -}()); \ No newline at end of file +}()); diff --git a/test/form/samples/skips-dead-branches-d/_expected/umd.js b/test/form/samples/skips-dead-branches-d/_expected/umd.js index 67588d41402..3a8711191a7 100644 --- a/test/form/samples/skips-dead-branches-d/_expected/umd.js +++ b/test/form/samples/skips-dead-branches-d/_expected/umd.js @@ -7,7 +7,6 @@ function bar () { console.log( 'this should be included' ); } - bar(); -}))); \ No newline at end of file +}))); diff --git a/test/form/samples/skips-dead-branches-e/_expected/amd.js b/test/form/samples/skips-dead-branches-e/_expected/amd.js index 9dc50f528f3..ee0987c254d 100644 --- a/test/form/samples/skips-dead-branches-e/_expected/amd.js +++ b/test/form/samples/skips-dead-branches-e/_expected/amd.js @@ -3,7 +3,6 @@ define(function () { 'use strict'; function bar () { console.log( 'this should be included' ); } - bar(); -}); \ No newline at end of file +}); diff --git a/test/form/samples/skips-dead-branches-e/_expected/cjs.js b/test/form/samples/skips-dead-branches-e/_expected/cjs.js index d6aa952d0e6..a979cc52820 100644 --- a/test/form/samples/skips-dead-branches-e/_expected/cjs.js +++ b/test/form/samples/skips-dead-branches-e/_expected/cjs.js @@ -3,5 +3,4 @@ function bar () { console.log( 'this should be included' ); } - -bar(); \ No newline at end of file +bar(); diff --git a/test/form/samples/skips-dead-branches-e/_expected/es.js b/test/form/samples/skips-dead-branches-e/_expected/es.js index f39bfec65a9..c24eeda81be 100644 --- a/test/form/samples/skips-dead-branches-e/_expected/es.js +++ b/test/form/samples/skips-dead-branches-e/_expected/es.js @@ -1,5 +1,4 @@ function bar () { console.log( 'this should be included' ); } - -bar(); \ No newline at end of file +bar(); diff --git a/test/form/samples/skips-dead-branches-e/_expected/iife.js b/test/form/samples/skips-dead-branches-e/_expected/iife.js index 8d6dcb52c0c..fe8653ab50d 100644 --- a/test/form/samples/skips-dead-branches-e/_expected/iife.js +++ b/test/form/samples/skips-dead-branches-e/_expected/iife.js @@ -4,7 +4,6 @@ function bar () { console.log( 'this should be included' ); } - bar(); -}()); \ No newline at end of file +}()); diff --git a/test/form/samples/skips-dead-branches-e/_expected/umd.js b/test/form/samples/skips-dead-branches-e/_expected/umd.js index 67588d41402..3a8711191a7 100644 --- a/test/form/samples/skips-dead-branches-e/_expected/umd.js +++ b/test/form/samples/skips-dead-branches-e/_expected/umd.js @@ -7,7 +7,6 @@ function bar () { console.log( 'this should be included' ); } - bar(); -}))); \ No newline at end of file +}))); diff --git a/test/form/samples/skips-dead-branches-f/_expected/amd.js b/test/form/samples/skips-dead-branches-f/_expected/amd.js index 9dc50f528f3..ee0987c254d 100644 --- a/test/form/samples/skips-dead-branches-f/_expected/amd.js +++ b/test/form/samples/skips-dead-branches-f/_expected/amd.js @@ -3,7 +3,6 @@ define(function () { 'use strict'; function bar () { console.log( 'this should be included' ); } - bar(); -}); \ No newline at end of file +}); diff --git a/test/form/samples/skips-dead-branches-f/_expected/cjs.js b/test/form/samples/skips-dead-branches-f/_expected/cjs.js index d6aa952d0e6..a979cc52820 100644 --- a/test/form/samples/skips-dead-branches-f/_expected/cjs.js +++ b/test/form/samples/skips-dead-branches-f/_expected/cjs.js @@ -3,5 +3,4 @@ function bar () { console.log( 'this should be included' ); } - -bar(); \ No newline at end of file +bar(); diff --git a/test/form/samples/skips-dead-branches-f/_expected/es.js b/test/form/samples/skips-dead-branches-f/_expected/es.js index f39bfec65a9..c24eeda81be 100644 --- a/test/form/samples/skips-dead-branches-f/_expected/es.js +++ b/test/form/samples/skips-dead-branches-f/_expected/es.js @@ -1,5 +1,4 @@ function bar () { console.log( 'this should be included' ); } - -bar(); \ No newline at end of file +bar(); diff --git a/test/form/samples/skips-dead-branches-f/_expected/iife.js b/test/form/samples/skips-dead-branches-f/_expected/iife.js index 8d6dcb52c0c..fe8653ab50d 100644 --- a/test/form/samples/skips-dead-branches-f/_expected/iife.js +++ b/test/form/samples/skips-dead-branches-f/_expected/iife.js @@ -4,7 +4,6 @@ function bar () { console.log( 'this should be included' ); } - bar(); -}()); \ No newline at end of file +}()); diff --git a/test/form/samples/skips-dead-branches-f/_expected/umd.js b/test/form/samples/skips-dead-branches-f/_expected/umd.js index 67588d41402..3a8711191a7 100644 --- a/test/form/samples/skips-dead-branches-f/_expected/umd.js +++ b/test/form/samples/skips-dead-branches-f/_expected/umd.js @@ -7,7 +7,6 @@ function bar () { console.log( 'this should be included' ); } - bar(); -}))); \ No newline at end of file +}))); From a395faf100a17d2fe9f5859d5e4ae48eba13a5bd Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Sat, 3 Feb 2018 17:08:44 +0100 Subject: [PATCH 09/27] When checking for symbols other than line-breaks, check for both kinds of comments --- src/ast/nodes/ExportDefaultDeclaration.ts | 10 +++--- src/utils/renderHelpers.ts | 36 +++++++++++++++---- .../samples/render-removed-statements/main.js | 2 +- .../usedFunction.js | 3 +- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index ccdc3c6a1e7..6248c616aae 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -20,10 +20,10 @@ function getIdInsertPosition (code: string, declarationKeyword: string) { code = code.slice(declarationEnd); code = code.slice(0, findFirstOccurrenceOutsideComment(code, '{')); const generatorStarPos = findFirstOccurrenceOutsideComment(code, '*'); - if (generatorStarPos === 0) { - return declarationEnd + (code[0] === '*' ? 1 : 0); + if (~generatorStarPos) { + return declarationEnd + generatorStarPos + 1; } - return declarationEnd + generatorStarPos + 1; + return declarationEnd; } const needsToBeWrapped = isObjectExpression; @@ -69,7 +69,7 @@ export default class ExportDefaultDeclaration extends NodeBase { } else if (this.variable.included) { this.renderVariableDeclaration(code, declarationStart, options); } else { - this.renderForSideEffects(code, declarationStart); + this.renderForSideEffectsOnly(code, declarationStart); } super.render(code, options); } @@ -102,7 +102,7 @@ export default class ExportDefaultDeclaration extends NodeBase { } } - private renderForSideEffects (code: MagicString, declarationStart: number) { + private renderForSideEffectsOnly (code: MagicString, declarationStart: number) { code.remove(this.start, declarationStart); if (needsToBeWrapped(this.declaration)) { code.appendLeft(declarationStart, '('); diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index 33b339ff51a..8e074b5d0cf 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -2,17 +2,41 @@ import { Node } from '../ast/nodes/shared/Node'; import MagicString from 'magic-string'; import { RenderOptions } from '../Module'; -// Note that if the string is not found, "0" is returned instead of e.g. "-1" -// as this seems to work best for the main use case export function findFirstOccurrenceOutsideComment (code: string, searchString: string) { let codeStart = 0; let commentStart, commentLength, lineBreakPos; while (true) { - commentStart = code.indexOf('/*'); + commentStart = code.indexOf('/'); lineBreakPos = (~commentStart ? code.slice(0, commentStart) : code).indexOf(searchString); if (~lineBreakPos || !~commentStart) { break; } + code = code.slice(commentStart + 1); + codeStart += commentStart + 1; + if (code[0] === '*') { + commentLength = code.indexOf('*/') + 2; + } else if (code[0] === '/') { + commentLength = code.indexOf('\n') + 1; + } else { + continue; + } + code = code.slice(commentLength); + codeStart += commentLength; + } + return ~lineBreakPos ? codeStart + lineBreakPos : -1; +} + +// Note that if the string is not found, "0" is returned instead of e.g. "-1" as this works best +// for the main use case +function findFirstLineBreakOutsideComment (code: string) { + let codeStart = 0; + let commentStart, commentLength, lineBreakPos; + while (true) { + commentStart = code.indexOf('/*'); + lineBreakPos = (~commentStart ? code.slice(0, commentStart) : code).indexOf('\n'); + if (~lineBreakPos || !~commentStart) { + break; + } code = code.slice(commentStart); commentLength = code.indexOf('*/') + 2; code = code.slice(commentLength); @@ -25,15 +49,15 @@ export function renderStatementBlock (statements: Node[], code: MagicString, sta if (statements.length === 0) return; let currentNode, currentNodeStart; let nextNode = statements[0]; - let nextNodeStart = start + findFirstOccurrenceOutsideComment(code.original.slice(start, nextNode.start), '\n'); + let nextNodeStart = start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start)); for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) { currentNode = nextNode; currentNodeStart = nextNodeStart; nextNode = statements[nextIndex]; - nextNodeStart = currentNode.end + (findFirstOccurrenceOutsideComment(code.original.slice( + nextNodeStart = currentNode.end + (findFirstLineBreakOutsideComment(code.original.slice( currentNode.end, nextNode !== undefined ? nextNode.start : end - ), '\n')); + ))); if (!currentNode.included) { code.remove(currentNodeStart, nextNodeStart); } else { diff --git a/test/form/samples/render-removed-statements/main.js b/test/form/samples/render-removed-statements/main.js index c89a78633b7..ea36bdb65dd 100644 --- a/test/form/samples/render-removed-statements/main.js +++ b/test/form/samples/render-removed-statements/main.js @@ -63,7 +63,7 @@ switch (globalVar) { console.log(2); // trail retained // lead removed var a = 1; - case 4: var a = 1; /* lead retained */ console.log('3') // trail retained + case 4: /* lead removed */ var a = 1; /* lead retained */ console.log('3'); // trail retained default: /* lead removed */ var a = 1; // trail removed diff --git a/test/form/samples/tree-shake-default-exports/usedFunction.js b/test/form/samples/tree-shake-default-exports/usedFunction.js index 91baa843894..f943d901b8d 100644 --- a/test/form/samples/tree-shake-default-exports/usedFunction.js +++ b/test/form/samples/tree-shake-default-exports/usedFunction.js @@ -1,7 +1,8 @@ /* header 5 */ /* leading retained */ -export default function () { +export /* default */ // default +default function () { console.log( 'unnamed' ); } // trailing retained From de9acd0fbc28d997c394d23a158d3102f8896c98 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Tue, 6 Feb 2018 06:43:07 +0100 Subject: [PATCH 10/27] First draft for variable declarations --- src/ast/nodes/BlockStatement.ts | 4 +- src/ast/nodes/ExportDefaultDeclaration.ts | 4 +- src/ast/nodes/ExportNamedDeclaration.ts | 10 +- src/ast/nodes/ForInStatement.ts | 4 + src/ast/nodes/ForOfStatement.ts | 4 + src/ast/nodes/ForStatement.ts | 4 + src/ast/nodes/Program.ts | 4 +- src/ast/nodes/SwitchCase.ts | 4 +- src/ast/nodes/VariableDeclaration.ts | 163 ++++++------------ src/utils/renderHelpers.ts | 51 +++++- .../assignment-to-exports/_expected/amd.js | 26 ++- .../assignment-to-exports/_expected/cjs.js | 26 ++- .../assignment-to-exports/_expected/es.js | 27 ++- .../assignment-to-exports/_expected/iife.js | 26 ++- .../assignment-to-exports/_expected/umd.js | 26 ++- .../samples/assignment-to-exports/main.js | 27 ++- .../_expected/amd.js | 7 +- .../_expected/cjs.js | 7 +- .../_expected/es.js | 7 +- .../_expected/iife.js | 7 +- .../_expected/umd.js | 7 +- .../samples/no-treeshake/_expected/amd.js | 3 +- .../samples/no-treeshake/_expected/cjs.js | 3 +- .../form/samples/no-treeshake/_expected/es.js | 3 +- .../samples/no-treeshake/_expected/iife.js | 3 +- .../samples/no-treeshake/_expected/umd.js | 3 +- .../render-removed-declarations/_config.js | 3 + .../_expected/amd.js | 21 +++ .../_expected/cjs.js | 19 ++ .../_expected/es.js | 17 ++ .../_expected/iife.js | 22 +++ .../_expected/umd.js | 25 +++ .../render-removed-declarations/main.js | 21 +++ .../string-indentation-b/_expected/amd.js | 4 +- .../string-indentation-b/_expected/cjs.js | 4 +- .../string-indentation-b/_expected/es.js | 4 +- .../string-indentation-b/_expected/iife.js | 4 +- .../string-indentation-b/_expected/umd.js | 4 +- 38 files changed, 424 insertions(+), 184 deletions(-) create mode 100644 test/form/samples/render-removed-declarations/_config.js create mode 100644 test/form/samples/render-removed-declarations/_expected/amd.js create mode 100644 test/form/samples/render-removed-declarations/_expected/cjs.js create mode 100644 test/form/samples/render-removed-declarations/_expected/es.js create mode 100644 test/form/samples/render-removed-declarations/_expected/iife.js create mode 100644 test/form/samples/render-removed-declarations/_expected/umd.js create mode 100644 test/form/samples/render-removed-declarations/main.js diff --git a/src/ast/nodes/BlockStatement.ts b/src/ast/nodes/BlockStatement.ts index 3a651cfd4ba..d2fb3caf9ff 100644 --- a/src/ast/nodes/BlockStatement.ts +++ b/src/ast/nodes/BlockStatement.ts @@ -6,7 +6,7 @@ import MagicString from 'magic-string'; import { Node, NodeBase } from './shared/Node'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; -import { renderStatementBlock } from '../../utils/renderHelpers'; +import { renderStatementList } from '../../utils/renderHelpers'; export function isBlockStatement (node: Node): node is BlockStatement { return node.type === NodeType.BlockStatement; @@ -59,7 +59,7 @@ export default class BlockStatement extends NodeBase { render (code: MagicString, options: RenderOptions) { if (this.body.length) { - renderStatementBlock(this.body, code, this.start + 1, this.end - 1, options); + renderStatementList(this.body, code, this.start + 1, this.end - 1, options); } else { super.render(code, options); } diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index 6248c616aae..fe37a2ae009 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -9,10 +9,10 @@ import { NodeRenderOptions, RenderOptions } from '../../Module'; import { findFirstOccurrenceOutsideComment } from '../../utils/renderHelpers'; import { isObjectExpression } from './ObjectExpression'; -// The header ends at the first white-space or comment after "default" +// The header ends at the first non-white-space after "default" function getDeclarationStart (code: string) { const headerLength = findFirstOccurrenceOutsideComment(code, 'default') + 7; - return headerLength + code.slice(headerLength).search(/\S|\/\*/); + return headerLength + code.slice(headerLength).search(/\S/); } function getIdInsertPosition (code: string, declarationKeyword: string) { diff --git a/src/ast/nodes/ExportNamedDeclaration.ts b/src/ast/nodes/ExportNamedDeclaration.ts index 899a4f06ca7..01d30e151d1 100644 --- a/src/ast/nodes/ExportNamedDeclaration.ts +++ b/src/ast/nodes/ExportNamedDeclaration.ts @@ -1,4 +1,4 @@ -import { NodeBase } from './shared/Node'; +import { NodeBase, Node } from './shared/Node'; import ExecutionPathOptions from '../ExecutionPathOptions'; import Literal from './Literal'; import MagicString from 'magic-string'; @@ -31,11 +31,11 @@ export default class ExportNamedDeclaration extends NodeBase { } render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { - if (this.declaration) { - code.remove(this.start, this.declaration.start); - this.declaration.render(code, options); - } else { + if (this.declaration === null) { code.remove(start || this.start, end || this.end); + } else { + code.remove(this.start, this.declaration.start); + (this.declaration).render(code, options, { start, end }); } } } diff --git a/src/ast/nodes/ForInStatement.ts b/src/ast/nodes/ForInStatement.ts index 5fbd58e0d6d..8c69241615b 100644 --- a/src/ast/nodes/ForInStatement.ts +++ b/src/ast/nodes/ForInStatement.ts @@ -7,6 +7,10 @@ import { PatternNode } from './shared/Pattern'; import { NodeType } from './NodeType'; import { ExpressionNode, NodeBase, Node } from './shared/Node'; +export function isForInStatement (node: Node): node is ForInStatement { + return node.type === NodeType.ForInStatement; +} + export default class ForInStatement extends NodeBase { type: NodeType.ForInStatement; left: VariableDeclaration | PatternNode; diff --git a/src/ast/nodes/ForOfStatement.ts b/src/ast/nodes/ForOfStatement.ts index ece7326078c..f3d0eaf31e3 100644 --- a/src/ast/nodes/ForOfStatement.ts +++ b/src/ast/nodes/ForOfStatement.ts @@ -7,6 +7,10 @@ import { PatternNode } from './shared/Pattern'; import { NodeType } from './NodeType'; import { ExpressionNode, NodeBase, Node } from './shared/Node'; +export function isForOfStatement (node: Node): node is ForOfStatement { + return node.type === NodeType.ForOfStatement; +} + export default class ForOfStatement extends NodeBase { type: NodeType.ForOfStatement; left: VariableDeclaration | PatternNode; diff --git a/src/ast/nodes/ForStatement.ts b/src/ast/nodes/ForStatement.ts index bfec2498065..2bbd7963a8c 100644 --- a/src/ast/nodes/ForStatement.ts +++ b/src/ast/nodes/ForStatement.ts @@ -5,6 +5,10 @@ import Scope from '../scopes/Scope'; import { NodeType } from './NodeType'; import { ExpressionNode, NodeBase, Node } from './shared/Node'; +export function isForStatement (node: Node): node is ForStatement { + return node.type === NodeType.ForStatement; +} + export default class ForStatement extends NodeBase { type: NodeType.ForStatement; init: VariableDeclaration | ExpressionNode | null; diff --git a/src/ast/nodes/Program.ts b/src/ast/nodes/Program.ts index 309ee2846ac..136e9614e90 100644 --- a/src/ast/nodes/Program.ts +++ b/src/ast/nodes/Program.ts @@ -2,7 +2,7 @@ import MagicString from 'magic-string'; import { NodeBase, Node } from './shared/Node'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; -import { renderStatementBlock } from '../../utils/renderHelpers'; +import { renderStatementList } from '../../utils/renderHelpers'; export default class Program extends NodeBase { type: NodeType.Program; @@ -10,7 +10,7 @@ export default class Program extends NodeBase { render (code: MagicString, options: RenderOptions) { if (this.body.length) { - renderStatementBlock(this.body, code, this.start, this.end, options); + renderStatementList(this.body, code, this.start, this.end, options); } else { super.render(code, options); } diff --git a/src/ast/nodes/SwitchCase.ts b/src/ast/nodes/SwitchCase.ts index 275c85f6f2b..46bca53608e 100644 --- a/src/ast/nodes/SwitchCase.ts +++ b/src/ast/nodes/SwitchCase.ts @@ -1,6 +1,6 @@ import { ExpressionNode, NodeBase, Node } from './shared/Node'; import { NodeType } from './NodeType'; -import { findFirstOccurrenceOutsideComment, renderStatementBlock } from '../../utils/renderHelpers'; +import { findFirstOccurrenceOutsideComment, renderStatementList } from '../../utils/renderHelpers'; import { RenderOptions } from '../../Module'; import MagicString from 'magic-string'; @@ -31,7 +31,7 @@ export default class SwitchCase extends NodeBase { ? this.test.end : this.start + findFirstOccurrenceOutsideComment(code.original.slice(this.start, this.end), 'default') + 7; const consequentStart = testEnd + findFirstOccurrenceOutsideComment(code.original.slice(testEnd, this.end), ':') + 1; - renderStatementBlock(this.consequent, code, consequentStart, this.end, options); + renderStatementList(this.consequent, code, consequentStart, this.end, options); } else { super.render(code, options); } diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index b4a29dc7cb7..f346c950461 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -1,30 +1,26 @@ import { Node, NodeBase } from './shared/Node'; -import extractNames from '../utils/extractNames'; import ExecutionPathOptions from '../ExecutionPathOptions'; import VariableDeclarator from './VariableDeclarator'; -import ForInStatement from './ForInStatement'; -import ForOfStatement from './ForOfStatement'; -import ForStatement from './ForStatement'; import MagicString from 'magic-string'; import { ObjectPath } from '../variables/VariableReassignmentTracker'; -import { isIdentifier } from './Identifier'; import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; - -function getSeparator (code: string, start: number) { - let c = start; - - while (c > 0 && code[c - 1] !== '\n') { - c -= 1; - if (code[c] === ';' || code[c] === '{') return '; '; - } - - const lineStart = code.slice(c, start).match(/^\s*/)[0]; - - return `;\n${lineStart}`; +import { getCommaSeparatedNodesWithBoundaries } from '../../utils/renderHelpers'; +import { isIdentifier } from './Identifier'; +import { isForStatement } from './ForStatement'; +import { isForOfStatement } from './ForOfStatement'; +import { isForInStatement } from './ForInStatement'; +import Variable from '../variables/Variable'; + +function isDeclarationInForLoop (node: Node): boolean { + const parent = node.parent; + return (isForStatement(parent) && parent.init === node) + || ((isForOfStatement(parent) || isForInStatement(parent)) && parent.left === node); } -const forStatement = /^For(?:Of|In)?Statement/; +function isReassignedPartOfExportsObject (variable: Variable): boolean { + return variable.safeName && variable.safeName.indexOf('.') !== -1 && variable.exportName && variable.isReassigned; +} export function isVariableDeclaration (node: Node): node is VariableDeclaration { return node.type === NodeType.VariableDeclaration; @@ -74,102 +70,51 @@ export default class VariableDeclaration extends NodeBase { } render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { - const treeshake = this.module.graph.treeshake; - - let shouldSeparate = false; - let separator; - - if (this.scope.isModuleScope && !forStatement.test(this.parent.type)) { - shouldSeparate = true; - separator = getSeparator(this.module.code, this.start); + let declarationsEnd = this.end; + if (code.original[declarationsEnd - 1] === ';') { + declarationsEnd--; + code.overwrite(declarationsEnd, declarationsEnd + 1, ''); } - - let c = this.start; - let empty = true; - let lastSystemWrap = false; - let curSystemWrap = false; - - for (let i = 0; i < this.declarations.length; i += 1) { - const declarator = this.declarations[i]; - - const prefix = empty ? '' : separator; // TODO indentation - - if (isIdentifier(declarator.id)) { - const variable = this.scope.findVariable(declarator.id.name); - - const isExportedAndReassigned = variable.safeName && variable.safeName.indexOf( - '.') !== -1 && variable.exportName && variable.isReassigned; - - if (options.systemBindings && variable.exportName && declarator.init) { - code.prependLeft(declarator.init.start, `exports('${variable.exportName}', `); - curSystemWrap = true; - } - - if (isExportedAndReassigned) { - if (declarator.init) { - if (shouldSeparate) code.overwrite(c, declarator.start, (lastSystemWrap ? ')' : '') + prefix); - c = declarator.end; - empty = false; - } - } else if (!treeshake || variable.included) { - if (shouldSeparate) - code.overwrite(c, declarator.start, `${lastSystemWrap ? ')' : ''}${prefix}${this.kind} `); // TODO indentation - c = declarator.end; - empty = false; - } - } else { - const exportAssignments: any[] = []; - let isIncluded = false; - - extractNames(declarator.id).forEach(name => { - const variable = this.scope.findVariable(name); - const isExportedAndReassigned = variable.safeName && variable.safeName.indexOf( - '.') !== -1 && variable.exportName && variable.isReassigned; - - if (isExportedAndReassigned) { - // code.overwrite( c, declarator.start, prefix ); - // c = declarator.end; - // empty = false; - exportAssignments.push('TODO'); - } else if (declarator.included) { - isIncluded = true; - } - }); - - if (!treeshake || isIncluded) { - if (shouldSeparate) - code.overwrite(c, declarator.start, `${lastSystemWrap ? ')' : ''}${prefix}${this.kind} `); // TODO indentation - c = declarator.end; - empty = false; - } - - if (exportAssignments.length) { - throw new Error('TODO'); + const nodesWithBoundaries = getCommaSeparatedNodesWithBoundaries( + this.declarations, code, this.start + this.kind.length - 1, declarationsEnd + ); + // Make sure the first node overwrites "var " with whatever is appropriate + nodesWithBoundaries[0].start = this.start; + let isInDeclaration = false; + let hasRenderedContent = false; + let hasOpenSystemBinding = false; + let renderedContentEnd; + for (const { node, start, contentStart, end } of nodesWithBoundaries) { + if (!node.included || (isIdentifier(node.id) && isReassignedPartOfExportsObject(node.id.variable) && node.init === null)) { + code.remove(start, end); + continue; + } + if (isIdentifier(node.id) && isReassignedPartOfExportsObject(node.id.variable)) { + code.overwrite(start, contentStart, (hasOpenSystemBinding ? ')' : '') + (hasRenderedContent ? '; ' : '')); + isInDeclaration = false; + hasOpenSystemBinding = false; + } else if (!isInDeclaration) { + code.overwrite(start, contentStart, (hasOpenSystemBinding ? ')' : '') + (hasRenderedContent ? '; ' : '') + this.kind + ' '); + isInDeclaration = true; + hasOpenSystemBinding = false; + if (options.systemBindings && node.init !== null && isIdentifier(node.id) && node.id.variable.exportName) { + code.prependLeft(node.init.start, `exports('${node.id.variable.exportName}', `); + hasOpenSystemBinding = true; } + } else if (hasOpenSystemBinding) { + code.overwrite(start, contentStart, '), '); + hasOpenSystemBinding = false; } - - declarator.render(code, options); - - lastSystemWrap = curSystemWrap; - curSystemWrap = false; + node.render(code, options); + renderedContentEnd = end; + hasRenderedContent = true; } - - if (treeshake && empty) { - code.remove( - start || this.start, - end || this.end - ); - } else { - // always include a semi-colon (https://github.com/rollup/rollup/pull/1013), - // unless it's a var declaration in a loop head - const needsSemicolon = - !forStatement.test(this.parent.type) || this === (this.parent).body; - - if (this.end > c) { - code.overwrite(c, this.end, (lastSystemWrap ? ')' : '') + (needsSemicolon ? ';' : '')); - } else if (needsSemicolon) { - this.insertSemicolon(code); + if (hasRenderedContent) { + if (!isDeclarationInForLoop(this)) { + code.appendLeft(renderedContentEnd, (hasOpenSystemBinding ? ')' : '') + ';'); } + } else { + code.remove(start || this.start, end || this.end); } } } diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index 8e074b5d0cf..94ad452db19 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -28,7 +28,7 @@ export function findFirstOccurrenceOutsideComment (code: string, searchString: s // Note that if the string is not found, "0" is returned instead of e.g. "-1" as this works best // for the main use case -function findFirstLineBreakOutsideComment (code: string) { +export function findFirstLineBreakOutsideComment (code: string) { let codeStart = 0; let commentStart, commentLength, lineBreakPos; while (true) { @@ -45,7 +45,7 @@ function findFirstLineBreakOutsideComment (code: string) { return ~lineBreakPos ? codeStart + lineBreakPos : 0; } -export function renderStatementBlock (statements: Node[], code: MagicString, start: number, end: number, options: RenderOptions) { +export function renderStatementList (statements: Node[], code: MagicString, start: number, end: number, options: RenderOptions) { if (statements.length === 0) return; let currentNode, currentNodeStart; let nextNode = statements[0]; @@ -55,13 +55,48 @@ export function renderStatementBlock (statements: Node[], code: MagicString, sta currentNode = nextNode; currentNodeStart = nextNodeStart; nextNode = statements[nextIndex]; - nextNodeStart = currentNode.end + (findFirstLineBreakOutsideComment(code.original.slice( - currentNode.end, nextNode !== undefined ? nextNode.start : end - ))); - if (!currentNode.included) { - code.remove(currentNodeStart, nextNodeStart); - } else { + nextNodeStart = currentNode.end + findFirstLineBreakOutsideComment( + code.original.slice(currentNode.end, nextNode === undefined ? end : nextNode.start) + ); + if (currentNode.included) { currentNode.render(code, options, { start: currentNodeStart, end: nextNodeStart }); + } else { + code.remove(currentNodeStart, nextNodeStart); } } } + +// This assumes that the first character is not part of the first node +export function getCommaSeparatedNodesWithBoundaries ( + nodes: N[], + code: MagicString, + start: number, + end: number +): ({ + node: N; + start: number; + contentStart: number; + end: number; +})[] { + const splitUpNodes = []; + let currentNode, currentNodeStart, currentNodeContentStart; + let nextNode = nodes[0]; + let nextNodeStart = start; + + for (let nextIndex = 1; nextIndex <= nodes.length; nextIndex++) { + currentNode = nextNode; + currentNodeStart = nextNodeStart; + nextNode = nodes[nextIndex]; + nextNodeStart = nextNode === undefined ? end : currentNode.end + findFirstOccurrenceOutsideComment( + code.original.slice(currentNode.end, nextNode.start), ',' + ); + // Each node starts with a non-content character e.g. ","; that way we can always safely code.overwrite(start, contentStart, ..) + currentNodeContentStart = currentNodeStart + 1; + // We remove leading spaces (but not other white-space) to avoid double spaces when rendering + currentNodeContentStart += code.original.slice(currentNodeContentStart, nextNodeStart).search(/[^ ]/); + splitUpNodes.push({ + node: currentNode, start: currentNodeStart, end: nextNodeStart, contentStart: currentNodeContentStart + }); + } + return splitUpNodes; +} diff --git a/test/form/samples/assignment-to-exports/_expected/amd.js b/test/form/samples/assignment-to-exports/_expected/amd.js index 6f8d4d86676..105bbafaa28 100644 --- a/test/form/samples/assignment-to-exports/_expected/amd.js +++ b/test/form/samples/assignment-to-exports/_expected/amd.js @@ -1,6 +1,30 @@ define(['exports'], function (exports) { 'use strict'; - exports.foo = 1; + // Unassigned export + var foo1; + + // Reassigned uninitialised export + exports.bar1 = 1; + + // Reassigned initialised export + exports.baz1 = 1; + exports.baz1 = 2; + + // Unassigned export + var kept1, foo2, kept2; + + // Reassigned uninitialised export + var kept1, kept2; + exports.bar2 = 1; + + // Reassigned initialised export + var kept1; exports.baz2 = 1; var kept2; + exports.baz2 = 2; + + console.log( kept1, kept2 ); + + exports.foo1 = foo1; + exports.foo2 = foo2; Object.defineProperty(exports, '__esModule', { value: true }); diff --git a/test/form/samples/assignment-to-exports/_expected/cjs.js b/test/form/samples/assignment-to-exports/_expected/cjs.js index 9de421531cc..ea5ad72b662 100644 --- a/test/form/samples/assignment-to-exports/_expected/cjs.js +++ b/test/form/samples/assignment-to-exports/_expected/cjs.js @@ -2,4 +2,28 @@ Object.defineProperty(exports, '__esModule', { value: true }); -exports.foo = 1; +// Unassigned export +var foo1; + +// Reassigned uninitialised export +exports.bar1 = 1; + +// Reassigned initialised export +exports.baz1 = 1; +exports.baz1 = 2; + +// Unassigned export +var kept1, foo2, kept2; + +// Reassigned uninitialised export +var kept1, kept2; +exports.bar2 = 1; + +// Reassigned initialised export +var kept1; exports.baz2 = 1; var kept2; +exports.baz2 = 2; + +console.log( kept1, kept2 ); + +exports.foo1 = foo1; +exports.foo2 = foo2; diff --git a/test/form/samples/assignment-to-exports/_expected/es.js b/test/form/samples/assignment-to-exports/_expected/es.js index e6c6e5f6876..787c9ea84bb 100644 --- a/test/form/samples/assignment-to-exports/_expected/es.js +++ b/test/form/samples/assignment-to-exports/_expected/es.js @@ -1,4 +1,25 @@ -var foo; -foo = 1; +// Unassigned export +var foo1; -export { foo }; +// Reassigned uninitialised export +bar1 = 1; +var bar1; // this will be removed for non ES6 bundles + +// Reassigned initialised export +var baz1 = 1; +baz1 = 2; + +// Unassigned export +var kept1, foo2, kept2; + +// Reassigned uninitialised export +var kept1, bar2, kept2; +bar2 = 1; + +// Reassigned initialised export +var kept1, baz2 = 1, kept2; +baz2 = 2; + +console.log( kept1, kept2 ); + +export { foo1, bar1, baz1, foo2, bar2, baz2 }; diff --git a/test/form/samples/assignment-to-exports/_expected/iife.js b/test/form/samples/assignment-to-exports/_expected/iife.js index 037bd6f5167..1d7410999bd 100644 --- a/test/form/samples/assignment-to-exports/_expected/iife.js +++ b/test/form/samples/assignment-to-exports/_expected/iife.js @@ -1,7 +1,31 @@ var bundle = (function (exports) { 'use strict'; - exports.foo = 1; + // Unassigned export + var foo1; + + // Reassigned uninitialised export + exports.bar1 = 1; + + // Reassigned initialised export + exports.baz1 = 1; + exports.baz1 = 2; + + // Unassigned export + var kept1, foo2, kept2; + + // Reassigned uninitialised export + var kept1, kept2; + exports.bar2 = 1; + + // Reassigned initialised export + var kept1; exports.baz2 = 1; var kept2; + exports.baz2 = 2; + + console.log( kept1, kept2 ); + + exports.foo1 = foo1; + exports.foo2 = foo2; return exports; diff --git a/test/form/samples/assignment-to-exports/_expected/umd.js b/test/form/samples/assignment-to-exports/_expected/umd.js index 626cf8d319f..aa6fa0c8ccd 100644 --- a/test/form/samples/assignment-to-exports/_expected/umd.js +++ b/test/form/samples/assignment-to-exports/_expected/umd.js @@ -4,7 +4,31 @@ (factory((global.bundle = {}))); }(this, (function (exports) { 'use strict'; - exports.foo = 1; + // Unassigned export + var foo1; + + // Reassigned uninitialised export + exports.bar1 = 1; + + // Reassigned initialised export + exports.baz1 = 1; + exports.baz1 = 2; + + // Unassigned export + var kept1, foo2, kept2; + + // Reassigned uninitialised export + var kept1, kept2; + exports.bar2 = 1; + + // Reassigned initialised export + var kept1; exports.baz2 = 1; var kept2; + exports.baz2 = 2; + + console.log( kept1, kept2 ); + + exports.foo1 = foo1; + exports.foo2 = foo2; Object.defineProperty(exports, '__esModule', { value: true }); diff --git a/test/form/samples/assignment-to-exports/main.js b/test/form/samples/assignment-to-exports/main.js index bd12ed8037e..d86f2ee5a1e 100644 --- a/test/form/samples/assignment-to-exports/main.js +++ b/test/form/samples/assignment-to-exports/main.js @@ -1,2 +1,25 @@ -export var foo; -foo = 1; +// Unassigned export +export var foo1; + +// Reassigned uninitialised export +bar1 = 1; +export var bar1; // this will be removed for non ES6 bundles + +// Reassigned initialised export +export var baz1 = 1; +baz1 = 2; + +// Unassigned export +var kept1, foo2, kept2; + +// Reassigned uninitialised export +var kept1, bar2, kept2; +bar2 = 1; + +// Reassigned initialised export +var kept1, baz2 = 1, kept2; +baz2 = 2; + +export { foo2, bar2, baz2 }; + +console.log( kept1, kept2 ); diff --git a/test/form/samples/duplicated-var-declarations/_expected/amd.js b/test/form/samples/duplicated-var-declarations/_expected/amd.js index b43e2a4c96f..727a84d0fe3 100644 --- a/test/form/samples/duplicated-var-declarations/_expected/amd.js +++ b/test/form/samples/duplicated-var-declarations/_expected/amd.js @@ -1,14 +1,11 @@ define(function () { 'use strict'; - var a = 1; - var b = 2; + var a = 1, b = 2; assert.equal( a, 1 ); assert.equal( b, 2 ); - var a = 3; - var b = 4; - var c = 5; + var a = 3, b = 4, c = 5; assert.equal( a, 3 ); assert.equal( b, 4 ); diff --git a/test/form/samples/duplicated-var-declarations/_expected/cjs.js b/test/form/samples/duplicated-var-declarations/_expected/cjs.js index e47b61a58e9..913b84ff604 100644 --- a/test/form/samples/duplicated-var-declarations/_expected/cjs.js +++ b/test/form/samples/duplicated-var-declarations/_expected/cjs.js @@ -1,14 +1,11 @@ 'use strict'; -var a = 1; -var b = 2; +var a = 1, b = 2; assert.equal( a, 1 ); assert.equal( b, 2 ); -var a = 3; -var b = 4; -var c = 5; +var a = 3, b = 4, c = 5; assert.equal( a, 3 ); assert.equal( b, 4 ); diff --git a/test/form/samples/duplicated-var-declarations/_expected/es.js b/test/form/samples/duplicated-var-declarations/_expected/es.js index cacf6d2d9a3..1eabb5b53b3 100644 --- a/test/form/samples/duplicated-var-declarations/_expected/es.js +++ b/test/form/samples/duplicated-var-declarations/_expected/es.js @@ -1,12 +1,9 @@ -var a = 1; -var b = 2; +var a = 1, b = 2; assert.equal( a, 1 ); assert.equal( b, 2 ); -var a = 3; -var b = 4; -var c = 5; +var a = 3, b = 4, c = 5; assert.equal( a, 3 ); assert.equal( b, 4 ); diff --git a/test/form/samples/duplicated-var-declarations/_expected/iife.js b/test/form/samples/duplicated-var-declarations/_expected/iife.js index 106066a0a1a..8251bd3d75e 100644 --- a/test/form/samples/duplicated-var-declarations/_expected/iife.js +++ b/test/form/samples/duplicated-var-declarations/_expected/iife.js @@ -1,15 +1,12 @@ (function () { 'use strict'; - var a = 1; - var b = 2; + var a = 1, b = 2; assert.equal( a, 1 ); assert.equal( b, 2 ); - var a = 3; - var b = 4; - var c = 5; + var a = 3, b = 4, c = 5; assert.equal( a, 3 ); assert.equal( b, 4 ); diff --git a/test/form/samples/duplicated-var-declarations/_expected/umd.js b/test/form/samples/duplicated-var-declarations/_expected/umd.js index 45747992b75..6a288c92447 100644 --- a/test/form/samples/duplicated-var-declarations/_expected/umd.js +++ b/test/form/samples/duplicated-var-declarations/_expected/umd.js @@ -4,15 +4,12 @@ (factory()); }(this, (function () { 'use strict'; - var a = 1; - var b = 2; + var a = 1, b = 2; assert.equal( a, 1 ); assert.equal( b, 2 ); - var a = 3; - var b = 4; - var c = 5; + var a = 3, b = 4, c = 5; assert.equal( a, 3 ); assert.equal( b, 4 ); diff --git a/test/form/samples/no-treeshake/_expected/amd.js b/test/form/samples/no-treeshake/_expected/amd.js index 691c6221e8b..5a10b8c64a2 100644 --- a/test/form/samples/no-treeshake/_expected/amd.js +++ b/test/form/samples/no-treeshake/_expected/amd.js @@ -16,8 +16,7 @@ define(['exports', 'external'], function (exports, external) { 'use strict'; const moreExternal = external.more; - var create = Object.create; - var getPrototypeOf = Object.getPrototypeOf; + var create = Object.create, getPrototypeOf = Object.getPrototypeOf; exports.baz = baz; exports.create = create; diff --git a/test/form/samples/no-treeshake/_expected/cjs.js b/test/form/samples/no-treeshake/_expected/cjs.js index 45cc11b12e7..53fce965345 100644 --- a/test/form/samples/no-treeshake/_expected/cjs.js +++ b/test/form/samples/no-treeshake/_expected/cjs.js @@ -20,8 +20,7 @@ function baz () { const moreExternal = external.more; -var create = Object.create; -var getPrototypeOf = Object.getPrototypeOf; +var create = Object.create, getPrototypeOf = Object.getPrototypeOf; exports.baz = baz; exports.create = create; diff --git a/test/form/samples/no-treeshake/_expected/es.js b/test/form/samples/no-treeshake/_expected/es.js index 1515c4f5536..48e3035d91b 100644 --- a/test/form/samples/no-treeshake/_expected/es.js +++ b/test/form/samples/no-treeshake/_expected/es.js @@ -16,7 +16,6 @@ function baz () { const moreExternal = more; -var create = Object.create; -var getPrototypeOf = Object.getPrototypeOf; +var create = Object.create, getPrototypeOf = Object.getPrototypeOf; export { baz, create, getPrototypeOf, quux as strange }; diff --git a/test/form/samples/no-treeshake/_expected/iife.js b/test/form/samples/no-treeshake/_expected/iife.js index 92036bae0c7..060a647e7d8 100644 --- a/test/form/samples/no-treeshake/_expected/iife.js +++ b/test/form/samples/no-treeshake/_expected/iife.js @@ -17,8 +17,7 @@ var stirred = (function (exports,external) { const moreExternal = external.more; - var create = Object.create; - var getPrototypeOf = Object.getPrototypeOf; + var create = Object.create, getPrototypeOf = Object.getPrototypeOf; exports.baz = baz; exports.create = create; diff --git a/test/form/samples/no-treeshake/_expected/umd.js b/test/form/samples/no-treeshake/_expected/umd.js index 41b58682586..05f355ea6c2 100644 --- a/test/form/samples/no-treeshake/_expected/umd.js +++ b/test/form/samples/no-treeshake/_expected/umd.js @@ -20,8 +20,7 @@ const moreExternal = external.more; - var create = Object.create; - var getPrototypeOf = Object.getPrototypeOf; + var create = Object.create, getPrototypeOf = Object.getPrototypeOf; exports.baz = baz; exports.create = create; diff --git a/test/form/samples/render-removed-declarations/_config.js b/test/form/samples/render-removed-declarations/_config.js new file mode 100644 index 00000000000..36bcb953f3d --- /dev/null +++ b/test/form/samples/render-removed-declarations/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'renders tree-shaken variable declarations' +}; diff --git a/test/form/samples/render-removed-declarations/_expected/amd.js b/test/form/samples/render-removed-declarations/_expected/amd.js new file mode 100644 index 00000000000..c7a45d873e1 --- /dev/null +++ b/test/form/samples/render-removed-declarations/_expected/amd.js @@ -0,0 +1,21 @@ +define(function () { 'use strict'; + + // Middle removed + var kept1 = 1, kept2 = 3; // retained comment + var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; + var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; + + // Start and end removed + var kept1 = 2; // retained comment + var kept1 = 2; // retained comment + var kept1 = 2; // retained comment + var /* retained */ kept1 = 2 /* retained */; + var /* retained */kept1 = 2/* retained */; + + // Missing semicolons + var kept1 = 1; // retained comment + var kept1 = 1; // retained comment + + console.log( kept1, kept2 ); + +}); diff --git a/test/form/samples/render-removed-declarations/_expected/cjs.js b/test/form/samples/render-removed-declarations/_expected/cjs.js new file mode 100644 index 00000000000..51fcf02ca67 --- /dev/null +++ b/test/form/samples/render-removed-declarations/_expected/cjs.js @@ -0,0 +1,19 @@ +'use strict'; + +// Middle removed +var kept1 = 1, kept2 = 3; // retained comment +var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; +var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; + +// Start and end removed +var kept1 = 2; // retained comment +var kept1 = 2; // retained comment +var kept1 = 2; // retained comment +var /* retained */ kept1 = 2 /* retained */; +var /* retained */kept1 = 2/* retained */; + +// Missing semicolons +var kept1 = 1; // retained comment +var kept1 = 1; // retained comment + +console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/es.js b/test/form/samples/render-removed-declarations/_expected/es.js new file mode 100644 index 00000000000..9a5df38c689 --- /dev/null +++ b/test/form/samples/render-removed-declarations/_expected/es.js @@ -0,0 +1,17 @@ +// Middle removed +var kept1 = 1, kept2 = 3; // retained comment +var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; +var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; + +// Start and end removed +var kept1 = 2; // retained comment +var kept1 = 2; // retained comment +var kept1 = 2; // retained comment +var /* retained */ kept1 = 2 /* retained */; +var /* retained */kept1 = 2/* retained */; + +// Missing semicolons +var kept1 = 1; // retained comment +var kept1 = 1; // retained comment + +console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/iife.js b/test/form/samples/render-removed-declarations/_expected/iife.js new file mode 100644 index 00000000000..0f501f8208a --- /dev/null +++ b/test/form/samples/render-removed-declarations/_expected/iife.js @@ -0,0 +1,22 @@ +(function () { + 'use strict'; + + // Middle removed + var kept1 = 1, kept2 = 3; // retained comment + var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; + var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; + + // Start and end removed + var kept1 = 2; // retained comment + var kept1 = 2; // retained comment + var kept1 = 2; // retained comment + var /* retained */ kept1 = 2 /* retained */; + var /* retained */kept1 = 2/* retained */; + + // Missing semicolons + var kept1 = 1; // retained comment + var kept1 = 1; // retained comment + + console.log( kept1, kept2 ); + +}()); diff --git a/test/form/samples/render-removed-declarations/_expected/umd.js b/test/form/samples/render-removed-declarations/_expected/umd.js new file mode 100644 index 00000000000..f686ecba5aa --- /dev/null +++ b/test/form/samples/render-removed-declarations/_expected/umd.js @@ -0,0 +1,25 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); +}(this, (function () { 'use strict'; + + // Middle removed + var kept1 = 1, kept2 = 3; // retained comment + var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; + var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; + + // Start and end removed + var kept1 = 2; // retained comment + var kept1 = 2; // retained comment + var kept1 = 2; // retained comment + var /* retained */ kept1 = 2 /* retained */; + var /* retained */kept1 = 2/* retained */; + + // Missing semicolons + var kept1 = 1; // retained comment + var kept1 = 1; // retained comment + + console.log( kept1, kept2 ); + +}))); diff --git a/test/form/samples/render-removed-declarations/main.js b/test/form/samples/render-removed-declarations/main.js new file mode 100644 index 00000000000..e9bbc9784c8 --- /dev/null +++ b/test/form/samples/render-removed-declarations/main.js @@ -0,0 +1,21 @@ +// Middle removed +var kept1 = 1, removed1 = 2, kept2 = 3; // retained comment +var /* retained */ kept1 = 1 /* retained */, /* removed */ removed1 = 2 /* removed */, /* retained */ kept2 = 3 /* retained */; +var/* retained */kept1 = 1/* retained */,/* removed */removed1 = 2/* removed */,/* retained */kept2 = 3/* retained */; + +// Start and end removed +var removed1 = 1, kept1 = 2, removed2 = 3; // retained comment +var/* retained */removed1 = 1,kept1 = 2, removed2 = 3; // retained comment +var// removed +removed1 = 1,kept1 = 2, removed2 = 3; // retained comment +var /* removed */ removed1 = 1 /* removed */, /* retained */ kept1 = 2 /* retained */, /* removed */ removed2 = 3 /* removed */; +var/* removed */removed1 = 1/* removed */,/* retained */kept1 = 2/* retained */,/* removed */removed2 = 3/* removed */; + +// Missing semicolons +var kept1 = 1 // retained comment +var kept1 = 1, removed1 = 2 // retained comment + +// Everything removed +var removed1 = 1; + +console.log( kept1, kept2 ); diff --git a/test/form/samples/string-indentation-b/_expected/amd.js b/test/form/samples/string-indentation-b/_expected/amd.js index 2eb44c97c16..2daf4553a67 100644 --- a/test/form/samples/string-indentation-b/_expected/amd.js +++ b/test/form/samples/string-indentation-b/_expected/amd.js @@ -1,7 +1,7 @@ define(function () { 'use strict'; - var a = 'a'; - var b = 'b'; + var a = 'a', + b = 'b'; assert.equal( a, 'a' ); assert.equal( b, 'b' ); diff --git a/test/form/samples/string-indentation-b/_expected/cjs.js b/test/form/samples/string-indentation-b/_expected/cjs.js index 8432e6e13a2..41ae600f442 100644 --- a/test/form/samples/string-indentation-b/_expected/cjs.js +++ b/test/form/samples/string-indentation-b/_expected/cjs.js @@ -1,7 +1,7 @@ 'use strict'; -var a = 'a'; -var b = 'b'; +var a = 'a', + b = 'b'; assert.equal( a, 'a' ); assert.equal( b, 'b' ); diff --git a/test/form/samples/string-indentation-b/_expected/es.js b/test/form/samples/string-indentation-b/_expected/es.js index 6cd3b5a9b59..e0a7210c91a 100644 --- a/test/form/samples/string-indentation-b/_expected/es.js +++ b/test/form/samples/string-indentation-b/_expected/es.js @@ -1,5 +1,5 @@ -var a = 'a'; -var b = 'b'; +var a = 'a', + b = 'b'; assert.equal( a, 'a' ); assert.equal( b, 'b' ); diff --git a/test/form/samples/string-indentation-b/_expected/iife.js b/test/form/samples/string-indentation-b/_expected/iife.js index 6907cdb926d..4261ea90ab2 100644 --- a/test/form/samples/string-indentation-b/_expected/iife.js +++ b/test/form/samples/string-indentation-b/_expected/iife.js @@ -1,8 +1,8 @@ (function () { 'use strict'; - var a = 'a'; - var b = 'b'; + var a = 'a', + b = 'b'; assert.equal( a, 'a' ); assert.equal( b, 'b' ); diff --git a/test/form/samples/string-indentation-b/_expected/umd.js b/test/form/samples/string-indentation-b/_expected/umd.js index 47597be8f5e..e86eb38ea14 100644 --- a/test/form/samples/string-indentation-b/_expected/umd.js +++ b/test/form/samples/string-indentation-b/_expected/umd.js @@ -4,8 +4,8 @@ (factory()); }(this, (function () { 'use strict'; - var a = 'a'; - var b = 'b'; + var a = 'a', + b = 'b'; assert.equal( a, 'a' ); assert.equal( b, 'b' ); From ed77a008ca36e260603ff459d4085813d74bf510 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Tue, 6 Feb 2018 07:38:46 +0100 Subject: [PATCH 11/27] * Simplify declaration rendering logic * Move responsibility to suppress semicolon to parent --- src/Module.ts | 5 ++- src/ast/nodes/ForInStatement.ts | 10 ++++- src/ast/nodes/ForOfStatement.ts | 10 ++++- src/ast/nodes/ForStatement.ts | 9 +++++ src/ast/nodes/VariableDeclaration.ts | 40 +++++++++---------- src/ast/nodes/shared/Node.ts | 4 +- .../_expected/amd.js | 2 +- .../_expected/cjs.js | 2 +- .../_expected/es.js | 2 +- .../_expected/iife.js | 2 +- .../_expected/umd.js | 2 +- .../string-indentation-b/_expected/amd.js | 2 +- .../string-indentation-b/_expected/cjs.js | 2 +- .../string-indentation-b/_expected/es.js | 2 +- .../string-indentation-b/_expected/iife.js | 2 +- .../string-indentation-b/_expected/umd.js | 2 +- 16 files changed, 62 insertions(+), 36 deletions(-) diff --git a/src/Module.ts b/src/Module.ts index 68a308b2458..5835cd0dd21 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -111,9 +111,12 @@ export interface RenderOptions { export interface NodeRenderOptions { start?: number, - end?: number + end?: number, + noSemicolon?: boolean } +export const NO_SEMICOLON: NodeRenderOptions = { noSemicolon: true }; + export default class Module { type: 'Module'; graph: Graph; diff --git a/src/ast/nodes/ForInStatement.ts b/src/ast/nodes/ForInStatement.ts index 8c69241615b..dd60e03d99e 100644 --- a/src/ast/nodes/ForInStatement.ts +++ b/src/ast/nodes/ForInStatement.ts @@ -6,6 +6,8 @@ import BlockStatement from './BlockStatement'; import { PatternNode } from './shared/Pattern'; import { NodeType } from './NodeType'; import { ExpressionNode, NodeBase, Node } from './shared/Node'; +import { NO_SEMICOLON, RenderOptions } from '../../Module'; +import MagicString from 'magic-string'; export function isForInStatement (node: Node): node is ForInStatement { return node.type === NodeType.ForInStatement; @@ -37,7 +39,7 @@ export default class ForInStatement extends NodeBase { includeInBundle () { let addedNewNodes = super.includeInBundle(); - if (this.left.includeWithAllDeclarations()) { + if (this.left.includeWithAllDeclaredVariables()) { addedNewNodes = true; } return addedNewNodes; @@ -46,4 +48,10 @@ export default class ForInStatement extends NodeBase { initialiseScope (parentScope: Scope) { this.scope = new BlockScope({ parent: parentScope }); } + + render (code: MagicString, options: RenderOptions) { + this.left.render(code, options, NO_SEMICOLON); + this.right.render(code, options, NO_SEMICOLON); + this.body.render(code, options); + } } diff --git a/src/ast/nodes/ForOfStatement.ts b/src/ast/nodes/ForOfStatement.ts index f3d0eaf31e3..8e6ff5a527b 100644 --- a/src/ast/nodes/ForOfStatement.ts +++ b/src/ast/nodes/ForOfStatement.ts @@ -6,6 +6,8 @@ import BlockStatement from './BlockStatement'; import { PatternNode } from './shared/Pattern'; import { NodeType } from './NodeType'; import { ExpressionNode, NodeBase, Node } from './shared/Node'; +import { NO_SEMICOLON, RenderOptions } from '../../Module'; +import MagicString from 'magic-string'; export function isForOfStatement (node: Node): node is ForOfStatement { return node.type === NodeType.ForOfStatement; @@ -33,7 +35,7 @@ export default class ForOfStatement extends NodeBase { includeInBundle () { let addedNewNodes = super.includeInBundle(); - if (this.left.includeWithAllDeclarations()) { + if (this.left.includeWithAllDeclaredVariables()) { addedNewNodes = true; } return addedNewNodes; @@ -50,4 +52,10 @@ export default class ForOfStatement extends NodeBase { initialiseScope (parentScope: Scope) { this.scope = new BlockScope({ parent: parentScope }); } + + render (code: MagicString, options: RenderOptions) { + this.left.render(code, options, NO_SEMICOLON); + this.right.render(code, options, NO_SEMICOLON); + this.body.render(code, options); + } } diff --git a/src/ast/nodes/ForStatement.ts b/src/ast/nodes/ForStatement.ts index 2bbd7963a8c..01307f2df1c 100644 --- a/src/ast/nodes/ForStatement.ts +++ b/src/ast/nodes/ForStatement.ts @@ -4,6 +4,8 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import Scope from '../scopes/Scope'; import { NodeType } from './NodeType'; import { ExpressionNode, NodeBase, Node } from './shared/Node'; +import { NO_SEMICOLON, RenderOptions } from '../../Module'; +import MagicString from 'magic-string'; export function isForStatement (node: Node): node is ForStatement { return node.type === NodeType.ForStatement; @@ -35,4 +37,11 @@ export default class ForStatement extends NodeBase { initialiseScope (parentScope: Scope) { this.scope = new BlockScope({ parent: parentScope }); } + + render (code: MagicString, options: RenderOptions) { + if (this.init) this.init.render(code, options, NO_SEMICOLON); + if (this.test) this.test.render(code, options, NO_SEMICOLON); + if (this.update) this.update.render(code, options, NO_SEMICOLON); + this.body.render(code, options); + } } diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index f346c950461..b8244dff612 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -7,17 +7,8 @@ import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; import { getCommaSeparatedNodesWithBoundaries } from '../../utils/renderHelpers'; import { isIdentifier } from './Identifier'; -import { isForStatement } from './ForStatement'; -import { isForOfStatement } from './ForOfStatement'; -import { isForInStatement } from './ForInStatement'; import Variable from '../variables/Variable'; -function isDeclarationInForLoop (node: Node): boolean { - const parent = node.parent; - return (isForStatement(parent) && parent.init === node) - || ((isForOfStatement(parent) || isForInStatement(parent)) && parent.left === node); -} - function isReassignedPartOfExportsObject (variable: Variable): boolean { return variable.safeName && variable.safeName.indexOf('.') !== -1 && variable.exportName && variable.isReassigned; } @@ -39,7 +30,7 @@ export default class VariableDeclaration extends NodeBase { return false; } - includeWithAllDeclarations () { + includeWithAllDeclaredVariables () { let addedNewNodes = !this.included; this.included = true; this.declarations.forEach(declarator => { @@ -69,7 +60,7 @@ export default class VariableDeclaration extends NodeBase { ); } - render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { + render (code: MagicString, options: RenderOptions, { start, end, noSemicolon }: NodeRenderOptions = {}) { let declarationsEnd = this.end; if (code.original[declarationsEnd - 1] === ';') { declarationsEnd--; @@ -89,28 +80,35 @@ export default class VariableDeclaration extends NodeBase { code.remove(start, end); continue; } + let separatorString = hasOpenSystemBinding ? ')' : ''; + hasOpenSystemBinding = false; if (isIdentifier(node.id) && isReassignedPartOfExportsObject(node.id.variable)) { - code.overwrite(start, contentStart, (hasOpenSystemBinding ? ')' : '') + (hasRenderedContent ? '; ' : '')); + if (hasRenderedContent) { + separatorString += '; '; + } isInDeclaration = false; - hasOpenSystemBinding = false; - } else if (!isInDeclaration) { - code.overwrite(start, contentStart, (hasOpenSystemBinding ? ')' : '') + (hasRenderedContent ? '; ' : '') + this.kind + ' '); - isInDeclaration = true; - hasOpenSystemBinding = false; + } else { if (options.systemBindings && node.init !== null && isIdentifier(node.id) && node.id.variable.exportName) { code.prependLeft(node.init.start, `exports('${node.id.variable.exportName}', `); hasOpenSystemBinding = true; } - } else if (hasOpenSystemBinding) { - code.overwrite(start, contentStart, '), '); - hasOpenSystemBinding = false; + if (isInDeclaration) { + separatorString += ', '; + } else { + isInDeclaration = true; + if (hasRenderedContent) { + separatorString += '; '; + } + separatorString += `${this.kind} `; + } } + code.overwrite(start, contentStart, separatorString); node.render(code, options); renderedContentEnd = end; hasRenderedContent = true; } if (hasRenderedContent) { - if (!isDeclarationInForLoop(this)) { + if (!noSemicolon) { code.appendLeft(renderedContentEnd, (hasOpenSystemBinding ? ')' : '') + ';'); } } else { diff --git a/src/ast/nodes/shared/Node.ts b/src/ast/nodes/shared/Node.ts index 3c71a8e502a..ed61ba3b33e 100644 --- a/src/ast/nodes/shared/Node.ts +++ b/src/ast/nodes/shared/Node.ts @@ -50,7 +50,7 @@ export interface Node extends Entity { * declarations to only include nodes for declarators that have an effect. Necessary * for for-loops that do not use a declared loop variable. */ - includeWithAllDeclarations(): boolean; + includeWithAllDeclaredVariables(): boolean; /** * Assign a scope to this node and make sure all children have the right scopes. @@ -166,7 +166,7 @@ export class NodeBase implements ExpressionNode { return addedNewNodes; } - includeWithAllDeclarations () { + includeWithAllDeclaredVariables () { return this.includeInBundle(); } diff --git a/test/form/samples/render-removed-declarations/_expected/amd.js b/test/form/samples/render-removed-declarations/_expected/amd.js index c7a45d873e1..82ecda21032 100644 --- a/test/form/samples/render-removed-declarations/_expected/amd.js +++ b/test/form/samples/render-removed-declarations/_expected/amd.js @@ -3,7 +3,7 @@ define(function () { 'use strict'; // Middle removed var kept1 = 1, kept2 = 3; // retained comment var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; - var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; + var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; // Start and end removed var kept1 = 2; // retained comment diff --git a/test/form/samples/render-removed-declarations/_expected/cjs.js b/test/form/samples/render-removed-declarations/_expected/cjs.js index 51fcf02ca67..48588fea73d 100644 --- a/test/form/samples/render-removed-declarations/_expected/cjs.js +++ b/test/form/samples/render-removed-declarations/_expected/cjs.js @@ -3,7 +3,7 @@ // Middle removed var kept1 = 1, kept2 = 3; // retained comment var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; -var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; +var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; // Start and end removed var kept1 = 2; // retained comment diff --git a/test/form/samples/render-removed-declarations/_expected/es.js b/test/form/samples/render-removed-declarations/_expected/es.js index 9a5df38c689..f8521c118d5 100644 --- a/test/form/samples/render-removed-declarations/_expected/es.js +++ b/test/form/samples/render-removed-declarations/_expected/es.js @@ -1,7 +1,7 @@ // Middle removed var kept1 = 1, kept2 = 3; // retained comment var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; -var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; +var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; // Start and end removed var kept1 = 2; // retained comment diff --git a/test/form/samples/render-removed-declarations/_expected/iife.js b/test/form/samples/render-removed-declarations/_expected/iife.js index 0f501f8208a..28627497de2 100644 --- a/test/form/samples/render-removed-declarations/_expected/iife.js +++ b/test/form/samples/render-removed-declarations/_expected/iife.js @@ -4,7 +4,7 @@ // Middle removed var kept1 = 1, kept2 = 3; // retained comment var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; - var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; + var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; // Start and end removed var kept1 = 2; // retained comment diff --git a/test/form/samples/render-removed-declarations/_expected/umd.js b/test/form/samples/render-removed-declarations/_expected/umd.js index f686ecba5aa..b47f2db1ede 100644 --- a/test/form/samples/render-removed-declarations/_expected/umd.js +++ b/test/form/samples/render-removed-declarations/_expected/umd.js @@ -7,7 +7,7 @@ // Middle removed var kept1 = 1, kept2 = 3; // retained comment var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; - var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */; + var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; // Start and end removed var kept1 = 2; // retained comment diff --git a/test/form/samples/string-indentation-b/_expected/amd.js b/test/form/samples/string-indentation-b/_expected/amd.js index 2daf4553a67..90a083a3e67 100644 --- a/test/form/samples/string-indentation-b/_expected/amd.js +++ b/test/form/samples/string-indentation-b/_expected/amd.js @@ -1,6 +1,6 @@ define(function () { 'use strict'; - var a = 'a', + var a = 'a', b = 'b'; assert.equal( a, 'a' ); diff --git a/test/form/samples/string-indentation-b/_expected/cjs.js b/test/form/samples/string-indentation-b/_expected/cjs.js index 41ae600f442..d972e6bb36a 100644 --- a/test/form/samples/string-indentation-b/_expected/cjs.js +++ b/test/form/samples/string-indentation-b/_expected/cjs.js @@ -1,6 +1,6 @@ 'use strict'; -var a = 'a', +var a = 'a', b = 'b'; assert.equal( a, 'a' ); diff --git a/test/form/samples/string-indentation-b/_expected/es.js b/test/form/samples/string-indentation-b/_expected/es.js index e0a7210c91a..150a00619d7 100644 --- a/test/form/samples/string-indentation-b/_expected/es.js +++ b/test/form/samples/string-indentation-b/_expected/es.js @@ -1,4 +1,4 @@ -var a = 'a', +var a = 'a', b = 'b'; assert.equal( a, 'a' ); diff --git a/test/form/samples/string-indentation-b/_expected/iife.js b/test/form/samples/string-indentation-b/_expected/iife.js index 4261ea90ab2..3809b3e7c99 100644 --- a/test/form/samples/string-indentation-b/_expected/iife.js +++ b/test/form/samples/string-indentation-b/_expected/iife.js @@ -1,7 +1,7 @@ (function () { 'use strict'; - var a = 'a', + var a = 'a', b = 'b'; assert.equal( a, 'a' ); diff --git a/test/form/samples/string-indentation-b/_expected/umd.js b/test/form/samples/string-indentation-b/_expected/umd.js index e86eb38ea14..9c069010183 100644 --- a/test/form/samples/string-indentation-b/_expected/umd.js +++ b/test/form/samples/string-indentation-b/_expected/umd.js @@ -4,7 +4,7 @@ (factory()); }(this, (function () { 'use strict'; - var a = 'a', + var a = 'a', b = 'b'; assert.equal( a, 'a' ); From d2720f6c33fbf448de96970e0802867a28e30918 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Tue, 6 Feb 2018 08:11:50 +0100 Subject: [PATCH 12/27] Prevent trailing white-space --- src/ast/nodes/VariableDeclaration.ts | 11 +++++++---- .../samples/string-indentation-b/_expected/amd.js | 2 +- .../samples/string-indentation-b/_expected/cjs.js | 2 +- .../form/samples/string-indentation-b/_expected/es.js | 2 +- .../samples/string-indentation-b/_expected/iife.js | 2 +- .../samples/string-indentation-b/_expected/umd.js | 2 +- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index b8244dff612..81802ef9592 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -84,7 +84,7 @@ export default class VariableDeclaration extends NodeBase { hasOpenSystemBinding = false; if (isIdentifier(node.id) && isReassignedPartOfExportsObject(node.id.variable)) { if (hasRenderedContent) { - separatorString += '; '; + separatorString += ';'; } isInDeclaration = false; } else { @@ -93,15 +93,18 @@ export default class VariableDeclaration extends NodeBase { hasOpenSystemBinding = true; } if (isInDeclaration) { - separatorString += ', '; + separatorString += ','; } else { - isInDeclaration = true; if (hasRenderedContent) { separatorString += '; '; } - separatorString += `${this.kind} `; + separatorString += `${this.kind}`; + isInDeclaration = true; } } + if (separatorString !== '' && /\S/.test(code.original[contentStart])) { + separatorString += ' '; + } code.overwrite(start, contentStart, separatorString); node.render(code, options); renderedContentEnd = end; diff --git a/test/form/samples/string-indentation-b/_expected/amd.js b/test/form/samples/string-indentation-b/_expected/amd.js index 90a083a3e67..2daf4553a67 100644 --- a/test/form/samples/string-indentation-b/_expected/amd.js +++ b/test/form/samples/string-indentation-b/_expected/amd.js @@ -1,6 +1,6 @@ define(function () { 'use strict'; - var a = 'a', + var a = 'a', b = 'b'; assert.equal( a, 'a' ); diff --git a/test/form/samples/string-indentation-b/_expected/cjs.js b/test/form/samples/string-indentation-b/_expected/cjs.js index d972e6bb36a..41ae600f442 100644 --- a/test/form/samples/string-indentation-b/_expected/cjs.js +++ b/test/form/samples/string-indentation-b/_expected/cjs.js @@ -1,6 +1,6 @@ 'use strict'; -var a = 'a', +var a = 'a', b = 'b'; assert.equal( a, 'a' ); diff --git a/test/form/samples/string-indentation-b/_expected/es.js b/test/form/samples/string-indentation-b/_expected/es.js index 150a00619d7..e0a7210c91a 100644 --- a/test/form/samples/string-indentation-b/_expected/es.js +++ b/test/form/samples/string-indentation-b/_expected/es.js @@ -1,4 +1,4 @@ -var a = 'a', +var a = 'a', b = 'b'; assert.equal( a, 'a' ); diff --git a/test/form/samples/string-indentation-b/_expected/iife.js b/test/form/samples/string-indentation-b/_expected/iife.js index 3809b3e7c99..4261ea90ab2 100644 --- a/test/form/samples/string-indentation-b/_expected/iife.js +++ b/test/form/samples/string-indentation-b/_expected/iife.js @@ -1,7 +1,7 @@ (function () { 'use strict'; - var a = 'a', + var a = 'a', b = 'b'; assert.equal( a, 'a' ); diff --git a/test/form/samples/string-indentation-b/_expected/umd.js b/test/form/samples/string-indentation-b/_expected/umd.js index 9c069010183..e86eb38ea14 100644 --- a/test/form/samples/string-indentation-b/_expected/umd.js +++ b/test/form/samples/string-indentation-b/_expected/umd.js @@ -4,7 +4,7 @@ (factory()); }(this, (function () { 'use strict'; - var a = 'a', + var a = 'a', b = 'b'; assert.equal( a, 'a' ); From 6bb3829b10d12903ed18acdf12d8054093dbddf7 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Tue, 6 Feb 2018 08:42:02 +0100 Subject: [PATCH 13/27] Remove line-breaks after declaration key-word --- src/ast/nodes/VariableDeclaration.ts | 3 +- .../render-removed-declarations/_config.js | 3 +- .../_expected/amd.js | 31 +++++++++------- .../_expected/cjs.js | 3 ++ .../_expected/es.js | 3 ++ .../_expected/iife.js | 33 +++++++++-------- .../_expected/umd.js | 37 ++++++++++--------- .../render-removed-declarations/main.js | 6 +++ 8 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index 81802ef9592..35e5fb7cc73 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -75,7 +75,7 @@ export default class VariableDeclaration extends NodeBase { let hasRenderedContent = false; let hasOpenSystemBinding = false; let renderedContentEnd; - for (const { node, start, contentStart, end } of nodesWithBoundaries) { + for (let { node, start, contentStart, end } of nodesWithBoundaries) { if (!node.included || (isIdentifier(node.id) && isReassignedPartOfExportsObject(node.id.variable) && node.init === null)) { code.remove(start, end); continue; @@ -99,6 +99,7 @@ export default class VariableDeclaration extends NodeBase { separatorString += '; '; } separatorString += `${this.kind}`; + contentStart += code.original.slice(contentStart, node.end).search(/\S/); isInDeclaration = true; } } diff --git a/test/form/samples/render-removed-declarations/_config.js b/test/form/samples/render-removed-declarations/_config.js index 36bcb953f3d..d57b9174a54 100644 --- a/test/form/samples/render-removed-declarations/_config.js +++ b/test/form/samples/render-removed-declarations/_config.js @@ -1,3 +1,4 @@ module.exports = { - description: 'renders tree-shaken variable declarations' + description: 'renders tree-shaken variable declarations', + solo: true }; diff --git a/test/form/samples/render-removed-declarations/_expected/amd.js b/test/form/samples/render-removed-declarations/_expected/amd.js index 82ecda21032..651324994e0 100644 --- a/test/form/samples/render-removed-declarations/_expected/amd.js +++ b/test/form/samples/render-removed-declarations/_expected/amd.js @@ -1,21 +1,24 @@ define(function () { 'use strict'; - // Middle removed - var kept1 = 1, kept2 = 3; // retained comment - var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; - var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; + // Middle removed + var kept1 = 1, kept2 = 3; // retained comment + var kept1 = 1, + kept2 = 3; + var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; + var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; - // Start and end removed - var kept1 = 2; // retained comment - var kept1 = 2; // retained comment - var kept1 = 2; // retained comment - var /* retained */ kept1 = 2 /* retained */; - var /* retained */kept1 = 2/* retained */; + // Start and end removed + var kept1 = 2; // retained comment + var kept1 = 2; + var kept1 = 2; // retained comment + var kept1 = 2; // retained comment + var /* retained */ kept1 = 2 /* retained */; + var /* retained */kept1 = 2/* retained */; - // Missing semicolons - var kept1 = 1; // retained comment - var kept1 = 1; // retained comment + // Missing semicolons + var kept1 = 1; // retained comment + var kept1 = 1; // retained comment - console.log( kept1, kept2 ); + console.log( kept1, kept2 ); }); diff --git a/test/form/samples/render-removed-declarations/_expected/cjs.js b/test/form/samples/render-removed-declarations/_expected/cjs.js index 48588fea73d..9adae58a9d3 100644 --- a/test/form/samples/render-removed-declarations/_expected/cjs.js +++ b/test/form/samples/render-removed-declarations/_expected/cjs.js @@ -2,11 +2,14 @@ // Middle removed var kept1 = 1, kept2 = 3; // retained comment +var kept1 = 1, + kept2 = 3; var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; // Start and end removed var kept1 = 2; // retained comment +var kept1 = 2; var kept1 = 2; // retained comment var kept1 = 2; // retained comment var /* retained */ kept1 = 2 /* retained */; diff --git a/test/form/samples/render-removed-declarations/_expected/es.js b/test/form/samples/render-removed-declarations/_expected/es.js index f8521c118d5..1bce3ddcb22 100644 --- a/test/form/samples/render-removed-declarations/_expected/es.js +++ b/test/form/samples/render-removed-declarations/_expected/es.js @@ -1,10 +1,13 @@ // Middle removed var kept1 = 1, kept2 = 3; // retained comment +var kept1 = 1, + kept2 = 3; var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; // Start and end removed var kept1 = 2; // retained comment +var kept1 = 2; var kept1 = 2; // retained comment var kept1 = 2; // retained comment var /* retained */ kept1 = 2 /* retained */; diff --git a/test/form/samples/render-removed-declarations/_expected/iife.js b/test/form/samples/render-removed-declarations/_expected/iife.js index 28627497de2..e3896ab6db0 100644 --- a/test/form/samples/render-removed-declarations/_expected/iife.js +++ b/test/form/samples/render-removed-declarations/_expected/iife.js @@ -1,22 +1,25 @@ (function () { - 'use strict'; + 'use strict'; - // Middle removed - var kept1 = 1, kept2 = 3; // retained comment - var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; - var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; + // Middle removed + var kept1 = 1, kept2 = 3; // retained comment + var kept1 = 1, + kept2 = 3; + var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; + var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; - // Start and end removed - var kept1 = 2; // retained comment - var kept1 = 2; // retained comment - var kept1 = 2; // retained comment - var /* retained */ kept1 = 2 /* retained */; - var /* retained */kept1 = 2/* retained */; + // Start and end removed + var kept1 = 2; // retained comment + var kept1 = 2; + var kept1 = 2; // retained comment + var kept1 = 2; // retained comment + var /* retained */ kept1 = 2 /* retained */; + var /* retained */kept1 = 2/* retained */; - // Missing semicolons - var kept1 = 1; // retained comment - var kept1 = 1; // retained comment + // Missing semicolons + var kept1 = 1; // retained comment + var kept1 = 1; // retained comment - console.log( kept1, kept2 ); + console.log( kept1, kept2 ); }()); diff --git a/test/form/samples/render-removed-declarations/_expected/umd.js b/test/form/samples/render-removed-declarations/_expected/umd.js index b47f2db1ede..450544cfd35 100644 --- a/test/form/samples/render-removed-declarations/_expected/umd.js +++ b/test/form/samples/render-removed-declarations/_expected/umd.js @@ -1,25 +1,28 @@ (function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? factory() : - typeof define === 'function' && define.amd ? define(factory) : - (factory()); + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + (factory()); }(this, (function () { 'use strict'; - // Middle removed - var kept1 = 1, kept2 = 3; // retained comment - var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; - var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; + // Middle removed + var kept1 = 1, kept2 = 3; // retained comment + var kept1 = 1, + kept2 = 3; + var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; + var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; - // Start and end removed - var kept1 = 2; // retained comment - var kept1 = 2; // retained comment - var kept1 = 2; // retained comment - var /* retained */ kept1 = 2 /* retained */; - var /* retained */kept1 = 2/* retained */; + // Start and end removed + var kept1 = 2; // retained comment + var kept1 = 2; + var kept1 = 2; // retained comment + var kept1 = 2; // retained comment + var /* retained */ kept1 = 2 /* retained */; + var /* retained */kept1 = 2/* retained */; - // Missing semicolons - var kept1 = 1; // retained comment - var kept1 = 1; // retained comment + // Missing semicolons + var kept1 = 1; // retained comment + var kept1 = 1; // retained comment - console.log( kept1, kept2 ); + console.log( kept1, kept2 ); }))); diff --git a/test/form/samples/render-removed-declarations/main.js b/test/form/samples/render-removed-declarations/main.js index e9bbc9784c8..a8561e8cf22 100644 --- a/test/form/samples/render-removed-declarations/main.js +++ b/test/form/samples/render-removed-declarations/main.js @@ -1,10 +1,16 @@ // Middle removed var kept1 = 1, removed1 = 2, kept2 = 3; // retained comment +var kept1 = 1, + removed1 = 2, + kept2 = 3; var /* retained */ kept1 = 1 /* retained */, /* removed */ removed1 = 2 /* removed */, /* retained */ kept2 = 3 /* retained */; var/* retained */kept1 = 1/* retained */,/* removed */removed1 = 2/* removed */,/* retained */kept2 = 3/* retained */; // Start and end removed var removed1 = 1, kept1 = 2, removed2 = 3; // retained comment +var removed1 = 1, + kept1 = 2, + removed2 = 3; var/* retained */removed1 = 1,kept1 = 2, removed2 = 3; // retained comment var// removed removed1 = 1,kept1 = 2, removed2 = 3; // retained comment From 2a570a207e025817f61de6c4df8ea0d6aebaa620 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Tue, 6 Feb 2018 08:49:44 +0100 Subject: [PATCH 14/27] Resolve #1937 --- .../samples/render-removed-declarations/_config.js | 3 +-- .../tree-shake-variable-declarations/_config.js | 8 ++++++++ .../tree-shake-variable-declarations/main.js | 14 ++++++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 test/function/samples/tree-shake-variable-declarations/_config.js create mode 100644 test/function/samples/tree-shake-variable-declarations/main.js diff --git a/test/form/samples/render-removed-declarations/_config.js b/test/form/samples/render-removed-declarations/_config.js index d57b9174a54..36bcb953f3d 100644 --- a/test/form/samples/render-removed-declarations/_config.js +++ b/test/form/samples/render-removed-declarations/_config.js @@ -1,4 +1,3 @@ module.exports = { - description: 'renders tree-shaken variable declarations', - solo: true + description: 'renders tree-shaken variable declarations' }; diff --git a/test/function/samples/tree-shake-variable-declarations/_config.js b/test/function/samples/tree-shake-variable-declarations/_config.js new file mode 100644 index 00000000000..4ba7953d61d --- /dev/null +++ b/test/function/samples/tree-shake-variable-declarations/_config.js @@ -0,0 +1,8 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'remove unused variables from declarations (#1937)', + exports ( exports ) { + assert.deepEqual( exports(), [ 0.07 ] ); + } +}; diff --git a/test/function/samples/tree-shake-variable-declarations/main.js b/test/function/samples/tree-shake-variable-declarations/main.js new file mode 100644 index 00000000000..4f698c9bee2 --- /dev/null +++ b/test/function/samples/tree-shake-variable-declarations/main.js @@ -0,0 +1,14 @@ +const FONT_HINGE_SIZE = 0.07; +const BACK_HINGE_SIZE = 0.16; + +function PointerGauge () { + const backHinge = BACK_HINGE_SIZE, + fontHinge = FONT_HINGE_SIZE; + + return [ + //backHinge, + fontHinge + ] +} + +export default PointerGauge; From 3588a4a201b520396075d4ea427ce99fa6ff9039 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Tue, 6 Feb 2018 09:05:27 +0100 Subject: [PATCH 15/27] Resolve #1831 --- .../tree-shake-variable-declarations-2/_config.js | 8 ++++++++ .../samples/tree-shake-variable-declarations-2/main.js | 10 ++++++++++ 2 files changed, 18 insertions(+) create mode 100644 test/function/samples/tree-shake-variable-declarations-2/_config.js create mode 100644 test/function/samples/tree-shake-variable-declarations-2/main.js diff --git a/test/function/samples/tree-shake-variable-declarations-2/_config.js b/test/function/samples/tree-shake-variable-declarations-2/_config.js new file mode 100644 index 00000000000..6d276caa8e1 --- /dev/null +++ b/test/function/samples/tree-shake-variable-declarations-2/_config.js @@ -0,0 +1,8 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'remove unused variables from declarations (#1831)', + code: function ( code ) { + assert.ok( code.search( /var\s+\/\/not\sused\s+a/ ) >= 0 ); + } +}; diff --git a/test/function/samples/tree-shake-variable-declarations-2/main.js b/test/function/samples/tree-shake-variable-declarations-2/main.js new file mode 100644 index 00000000000..fd7e6a7c459 --- /dev/null +++ b/test/function/samples/tree-shake-variable-declarations-2/main.js @@ -0,0 +1,10 @@ +class Test { + constructor() { + var testFn = function test(){}, //not used + a = 'test'; + + // testFn(); + console.log(a) + } +} +export default Test From 9ff220f055b9b0765e61b4b6d19c220987ece652 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Wed, 7 Feb 2018 07:23:14 +0100 Subject: [PATCH 16/27] Resolve #1943 --- src/Chunk.ts | 2 +- src/ast/nodes/ClassDeclaration.ts | 5 +++- src/ast/nodes/FunctionDeclaration.ts | 5 +++- src/ast/scopes/Scope.ts | 2 +- src/ast/variables/Variable.ts | 7 ++--- .../_config.js | 4 +++ .../_expected/amd.js | 22 ++++++++++++++++ .../_expected/cjs.js | 20 ++++++++++++++ .../_expected/es.js | 13 ++++++++++ .../_expected/iife.js | 23 ++++++++++++++++ .../_expected/umd.js | 26 +++++++++++++++++++ .../main.js | 11 ++++++++ 12 files changed, 133 insertions(+), 7 deletions(-) create mode 100644 test/form/samples/reassigned-exported-functions-and-classes/_config.js create mode 100644 test/form/samples/reassigned-exported-functions-and-classes/_expected/amd.js create mode 100644 test/form/samples/reassigned-exported-functions-and-classes/_expected/cjs.js create mode 100644 test/form/samples/reassigned-exported-functions-and-classes/_expected/es.js create mode 100644 test/form/samples/reassigned-exported-functions-and-classes/_expected/iife.js create mode 100644 test/form/samples/reassigned-exported-functions-and-classes/_expected/umd.js create mode 100644 test/form/samples/reassigned-exported-functions-and-classes/main.js diff --git a/src/Chunk.ts b/src/Chunk.ts index 21913fbbffc..added86717a 100644 --- a/src/Chunk.ts +++ b/src/Chunk.ts @@ -517,7 +517,7 @@ export default class Chunk { forOwn(module.scope.variables, variable => { if (!(variable).isDefault || !(variable).hasId) { let safeName; - if (es || system || !variable.isReassigned) { + if (es || system || !variable.isReassigned || variable.isId) { safeName = getSafeName(variable.name); } else { const safeExportName = this.exportedVariables.get(variable); diff --git a/src/ast/nodes/ClassDeclaration.ts b/src/ast/nodes/ClassDeclaration.ts index 7123659740c..507aba37f95 100644 --- a/src/ast/nodes/ClassDeclaration.ts +++ b/src/ast/nodes/ClassDeclaration.ts @@ -16,7 +16,10 @@ export default class ClassDeclaration extends ClassNode { initialiseChildren (parentScope: Scope) { // Class declarations are like let declarations: Not hoisted, can be reassigned, cannot be redeclared - this.id && this.id.initialiseAndDeclare(parentScope, 'class', this); + if (this.id) { + this.id.initialiseAndDeclare(parentScope, 'class', this); + this.id.variable.isId = true; + } super.initialiseChildren(parentScope); } diff --git a/src/ast/nodes/FunctionDeclaration.ts b/src/ast/nodes/FunctionDeclaration.ts index 56149908e3b..af3552f8fad 100644 --- a/src/ast/nodes/FunctionDeclaration.ts +++ b/src/ast/nodes/FunctionDeclaration.ts @@ -11,7 +11,10 @@ export default class FunctionDeclaration extends FunctionNode { type: NodeType.FunctionDeclaration; initialiseChildren (parentScope: Scope) { - this.id && this.id.initialiseAndDeclare(parentScope, 'function', this); + if (this.id !== null) { + this.id.initialiseAndDeclare(parentScope, 'function', this); + this.id.variable.isId = true; + } this.params.forEach(param => param.initialiseAndDeclare(this.scope, 'parameter', null) ); diff --git a/src/ast/scopes/Scope.ts b/src/ast/scopes/Scope.ts index 6a13cee44e1..0bb1d986072 100644 --- a/src/ast/scopes/Scope.ts +++ b/src/ast/scopes/Scope.ts @@ -86,7 +86,7 @@ export default class Scope { const declaration = this.variables[key]; // we can disregard exports.foo etc - if (declaration.exportName && declaration.isReassigned) return; + if (declaration.exportName && declaration.isReassigned && !declaration.isId) return; let name = declaration.getName(true); diff --git a/src/ast/variables/Variable.ts b/src/ast/variables/Variable.ts index 3ce053cd7b4..fb34257f050 100644 --- a/src/ast/variables/Variable.ts +++ b/src/ast/variables/Variable.ts @@ -12,6 +12,7 @@ export default class Variable implements ExpressionEntity { isGlobal?: boolean; isNamespace?: boolean; isReassigned: boolean; + isId: boolean; name: string; reexported?: boolean; safeName: string; @@ -37,9 +38,9 @@ export default class Variable implements ExpressionEntity { ) { } getName (reset?: boolean): string { - if (reset && this.safeName && this.safeName !== this.name && - this.safeName[this.name.length] === '$' && - this.safeName[this.name.length + 1] === '$') { + if (reset && this.safeName && this.safeName !== this.name && + this.safeName[this.name.length] === '$' && + this.safeName[this.name.length + 1] === '$') { this.safeName = undefined; return this.name; } diff --git a/test/form/samples/reassigned-exported-functions-and-classes/_config.js b/test/form/samples/reassigned-exported-functions-and-classes/_config.js new file mode 100644 index 00000000000..3f84a3334e9 --- /dev/null +++ b/test/form/samples/reassigned-exported-functions-and-classes/_config.js @@ -0,0 +1,4 @@ +module.exports = { + description: 'use legal names for exported functions and classed (#1943)', + options: { output: { name: 'bundle' } } +}; diff --git a/test/form/samples/reassigned-exported-functions-and-classes/_expected/amd.js b/test/form/samples/reassigned-exported-functions-and-classes/_expected/amd.js new file mode 100644 index 00000000000..958265c0ec2 --- /dev/null +++ b/test/form/samples/reassigned-exported-functions-and-classes/_expected/amd.js @@ -0,0 +1,22 @@ +define(['exports'], function (exports) { 'use strict'; + + function foo () {} + foo = 1; + + var bar = 1; + function bar () {} + + function baz () {} + var baz = 1; + + class quux {} + quux = 1; + + exports.foo = foo; + exports.bar = bar; + exports.baz = baz; + exports.quux = quux; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}); diff --git a/test/form/samples/reassigned-exported-functions-and-classes/_expected/cjs.js b/test/form/samples/reassigned-exported-functions-and-classes/_expected/cjs.js new file mode 100644 index 00000000000..c423dac4dd9 --- /dev/null +++ b/test/form/samples/reassigned-exported-functions-and-classes/_expected/cjs.js @@ -0,0 +1,20 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +function foo () {} +foo = 1; + +var bar = 1; +function bar () {} + +function baz () {} +var baz = 1; + +class quux {} +quux = 1; + +exports.foo = foo; +exports.bar = bar; +exports.baz = baz; +exports.quux = quux; diff --git a/test/form/samples/reassigned-exported-functions-and-classes/_expected/es.js b/test/form/samples/reassigned-exported-functions-and-classes/_expected/es.js new file mode 100644 index 00000000000..a6b01d3071a --- /dev/null +++ b/test/form/samples/reassigned-exported-functions-and-classes/_expected/es.js @@ -0,0 +1,13 @@ +function foo () {} +foo = 1; + +var bar = 1; +function bar () {} + +function baz () {} +var baz = 1; + +class quux {} +quux = 1; + +export { foo, bar, baz, quux }; diff --git a/test/form/samples/reassigned-exported-functions-and-classes/_expected/iife.js b/test/form/samples/reassigned-exported-functions-and-classes/_expected/iife.js new file mode 100644 index 00000000000..ef1b89f8337 --- /dev/null +++ b/test/form/samples/reassigned-exported-functions-and-classes/_expected/iife.js @@ -0,0 +1,23 @@ +var bundle = (function (exports) { + 'use strict'; + + function foo () {} + foo = 1; + + var bar = 1; + function bar () {} + + function baz () {} + var baz = 1; + + class quux {} + quux = 1; + + exports.foo = foo; + exports.bar = bar; + exports.baz = baz; + exports.quux = quux; + + return exports; + +}({})); diff --git a/test/form/samples/reassigned-exported-functions-and-classes/_expected/umd.js b/test/form/samples/reassigned-exported-functions-and-classes/_expected/umd.js new file mode 100644 index 00000000000..c84cdb4bcdf --- /dev/null +++ b/test/form/samples/reassigned-exported-functions-and-classes/_expected/umd.js @@ -0,0 +1,26 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (factory((global.bundle = {}))); +}(this, (function (exports) { 'use strict'; + + function foo () {} + foo = 1; + + var bar = 1; + function bar () {} + + function baz () {} + var baz = 1; + + class quux {} + quux = 1; + + exports.foo = foo; + exports.bar = bar; + exports.baz = baz; + exports.quux = quux; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/test/form/samples/reassigned-exported-functions-and-classes/main.js b/test/form/samples/reassigned-exported-functions-and-classes/main.js new file mode 100644 index 00000000000..edcab98e7e2 --- /dev/null +++ b/test/form/samples/reassigned-exported-functions-and-classes/main.js @@ -0,0 +1,11 @@ +export function foo () {} +foo = 1; + +export var bar = 1; +function bar () {} + +export function baz () {} +var baz = 1; + +export class quux {} +quux = 1; From 6b30972c4d9c2a88a120daf38a305ad2ec54a5b9 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Thu, 8 Feb 2018 07:12:44 +0100 Subject: [PATCH 17/27] =?UTF-8?q?Include=20line-breaks=20with=20the=20prev?= =?UTF-8?q?ious=20statement=20instead=20of=20the=20next=E2=80=94even=20tho?= =?UTF-8?q?ugh=20it=20can=20produce=20less=20nice=20code=E2=80=94as=20othe?= =?UTF-8?q?rwise,=20it=20was=20not=20guaranteed=20each=20single=20line=20c?= =?UTF-8?q?omment=20was=20properly=20closed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/utils/renderHelpers.ts | 8 +++----- .../samples/empty-statement/_expected/amd.js | 3 +-- .../samples/empty-statement/_expected/cjs.js | 3 +-- .../samples/empty-statement/_expected/es.js | 3 +-- .../samples/empty-statement/_expected/iife.js | 3 +-- .../samples/empty-statement/_expected/umd.js | 3 +-- .../_expected/amd.js | 16 ++++++++++++---- .../_expected/cjs.js | 16 ++++++++++++---- .../render-removed-statements/_expected/es.js | 16 ++++++++++++---- .../_expected/iife.js | 16 ++++++++++++---- .../_expected/umd.js | 16 ++++++++++++---- .../samples/render-removed-statements/main.js | 19 ++++++++++++++----- .../_expected/amd.js | 1 + .../_expected/cjs.js | 1 + .../_expected/es.js | 1 + .../_expected/iife.js | 1 + .../_expected/umd.js | 1 + .../_expected/amd.js | 1 - .../_expected/cjs.js | 1 - .../_expected/es.js | 1 - .../_expected/iife.js | 1 - .../_expected/umd.js | 1 - 22 files changed, 87 insertions(+), 45 deletions(-) diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index 94ad452db19..cfd9d275faf 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -26,8 +26,6 @@ export function findFirstOccurrenceOutsideComment (code: string, searchString: s return ~lineBreakPos ? codeStart + lineBreakPos : -1; } -// Note that if the string is not found, "0" is returned instead of e.g. "-1" as this works best -// for the main use case export function findFirstLineBreakOutsideComment (code: string) { let codeStart = 0; let commentStart, commentLength, lineBreakPos; @@ -42,14 +40,14 @@ export function findFirstLineBreakOutsideComment (code: string) { code = code.slice(commentLength); codeStart += commentStart + commentLength; } - return ~lineBreakPos ? codeStart + lineBreakPos : 0; + return ~lineBreakPos ? codeStart + lineBreakPos : -1; } export function renderStatementList (statements: Node[], code: MagicString, start: number, end: number, options: RenderOptions) { if (statements.length === 0) return; let currentNode, currentNodeStart; let nextNode = statements[0]; - let nextNodeStart = start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start)); + let nextNodeStart = start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start)) + 1; for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) { currentNode = nextNode; @@ -57,7 +55,7 @@ export function renderStatementList (statements: Node[], code: MagicString, star nextNode = statements[nextIndex]; nextNodeStart = currentNode.end + findFirstLineBreakOutsideComment( code.original.slice(currentNode.end, nextNode === undefined ? end : nextNode.start) - ); + ) + 1; if (currentNode.included) { currentNode.render(code, options, { start: currentNodeStart, end: nextNodeStart }); } else { diff --git a/test/form/samples/empty-statement/_expected/amd.js b/test/form/samples/empty-statement/_expected/amd.js index 6036f2851d3..6255bc57cbf 100644 --- a/test/form/samples/empty-statement/_expected/amd.js +++ b/test/form/samples/empty-statement/_expected/amd.js @@ -1,6 +1,5 @@ define(function () { 'use strict'; - console.log( 1 ); - console.log( 2 ); + console.log( 1 );console.log( 2 ); }); diff --git a/test/form/samples/empty-statement/_expected/cjs.js b/test/form/samples/empty-statement/_expected/cjs.js index 33f9de05030..b54ecd1cf86 100644 --- a/test/form/samples/empty-statement/_expected/cjs.js +++ b/test/form/samples/empty-statement/_expected/cjs.js @@ -1,4 +1,3 @@ 'use strict'; -console.log( 1 ); -console.log( 2 ); +console.log( 1 );console.log( 2 ); diff --git a/test/form/samples/empty-statement/_expected/es.js b/test/form/samples/empty-statement/_expected/es.js index 472e544d88c..dcc93dc9b24 100644 --- a/test/form/samples/empty-statement/_expected/es.js +++ b/test/form/samples/empty-statement/_expected/es.js @@ -1,2 +1 @@ -console.log( 1 ); -console.log( 2 ); +console.log( 1 );console.log( 2 ); diff --git a/test/form/samples/empty-statement/_expected/iife.js b/test/form/samples/empty-statement/_expected/iife.js index 08a84a95e53..60508d61edf 100644 --- a/test/form/samples/empty-statement/_expected/iife.js +++ b/test/form/samples/empty-statement/_expected/iife.js @@ -1,7 +1,6 @@ (function () { 'use strict'; - console.log( 1 ); - console.log( 2 ); + console.log( 1 );console.log( 2 ); }()); diff --git a/test/form/samples/empty-statement/_expected/umd.js b/test/form/samples/empty-statement/_expected/umd.js index 0aae43fe29d..a1f6dfc10c0 100644 --- a/test/form/samples/empty-statement/_expected/umd.js +++ b/test/form/samples/empty-statement/_expected/umd.js @@ -4,7 +4,6 @@ (factory()); }(this, (function () { 'use strict'; - console.log( 1 ); - console.log( 2 ); + console.log( 1 );console.log( 2 ); }))); diff --git a/test/form/samples/render-removed-statements/_expected/amd.js b/test/form/samples/render-removed-statements/_expected/amd.js index 62a1b78960c..7013d74aff9 100644 --- a/test/form/samples/render-removed-statements/_expected/amd.js +++ b/test/form/samples/render-removed-statements/_expected/amd.js @@ -1,11 +1,18 @@ define(function () { 'use strict'; /* header retained */ + /* lead + retained */ console.log(2); // trail retained + console.log(2); // trail retained /* lead retained */ console.log(2); /* trail + retained */ /* trail retained */ + console.log(2); // trail retained + console.log(2); + if (globalVar) { // lead retained console.log(2); // trail retained @@ -32,17 +39,18 @@ define(function () { 'use strict'; if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { - case 1: + case 1: // retained // lead retained console.log(2); // trail retained - case 2: + case 2: // retained // lead retained console.log(2); // trail retained - case 3: + case 3: // retained // lead retained console.log(2); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained - default: + default: // retained /* lead retained */ console.log(2); // trail retained } diff --git a/test/form/samples/render-removed-statements/_expected/cjs.js b/test/form/samples/render-removed-statements/_expected/cjs.js index 9b310070b4a..7fb1ca3cc73 100644 --- a/test/form/samples/render-removed-statements/_expected/cjs.js +++ b/test/form/samples/render-removed-statements/_expected/cjs.js @@ -1,11 +1,18 @@ 'use strict'; /* header retained */ + /* lead +retained */ console.log(2); // trail retained +console.log(2); // trail retained /* lead retained */ console.log(2); /* trail +retained */ /* trail retained */ +console.log(2); // trail retained + console.log(2); + if (globalVar) { // lead retained console.log(2); // trail retained @@ -32,17 +39,18 @@ if (globalVar) { /* retained */ console.log(2);} if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { - case 1: + case 1: // retained // lead retained console.log(2); // trail retained - case 2: + case 2: // retained // lead retained console.log(2); // trail retained - case 3: + case 3: // retained // lead retained console.log(2); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained - default: + default: // retained /* lead retained */ console.log(2); // trail retained } diff --git a/test/form/samples/render-removed-statements/_expected/es.js b/test/form/samples/render-removed-statements/_expected/es.js index 1526f28c284..b57d32defa2 100644 --- a/test/form/samples/render-removed-statements/_expected/es.js +++ b/test/form/samples/render-removed-statements/_expected/es.js @@ -1,9 +1,16 @@ /* header retained */ + /* lead +retained */ console.log(2); // trail retained +console.log(2); // trail retained /* lead retained */ console.log(2); /* trail +retained */ /* trail retained */ +console.log(2); // trail retained + console.log(2); + if (globalVar) { // lead retained console.log(2); // trail retained @@ -30,17 +37,18 @@ if (globalVar) { /* retained */ console.log(2);} if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { - case 1: + case 1: // retained // lead retained console.log(2); // trail retained - case 2: + case 2: // retained // lead retained console.log(2); // trail retained - case 3: + case 3: // retained // lead retained console.log(2); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained - default: + default: // retained /* lead retained */ console.log(2); // trail retained } diff --git a/test/form/samples/render-removed-statements/_expected/iife.js b/test/form/samples/render-removed-statements/_expected/iife.js index 94df2c94a58..007910f88f0 100644 --- a/test/form/samples/render-removed-statements/_expected/iife.js +++ b/test/form/samples/render-removed-statements/_expected/iife.js @@ -2,11 +2,18 @@ 'use strict'; /* header retained */ + /* lead + retained */ console.log(2); // trail retained + console.log(2); // trail retained /* lead retained */ console.log(2); /* trail + retained */ /* trail retained */ + console.log(2); // trail retained + console.log(2); + if (globalVar) { // lead retained console.log(2); // trail retained @@ -33,17 +40,18 @@ if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { - case 1: + case 1: // retained // lead retained console.log(2); // trail retained - case 2: + case 2: // retained // lead retained console.log(2); // trail retained - case 3: + case 3: // retained // lead retained console.log(2); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained - default: + default: // retained /* lead retained */ console.log(2); // trail retained } diff --git a/test/form/samples/render-removed-statements/_expected/umd.js b/test/form/samples/render-removed-statements/_expected/umd.js index 1aed0a0d876..4aaf0be6697 100644 --- a/test/form/samples/render-removed-statements/_expected/umd.js +++ b/test/form/samples/render-removed-statements/_expected/umd.js @@ -5,11 +5,18 @@ }(this, (function () { 'use strict'; /* header retained */ + /* lead + retained */ console.log(2); // trail retained + console.log(2); // trail retained /* lead retained */ console.log(2); /* trail + retained */ /* trail retained */ + console.log(2); // trail retained + console.log(2); + if (globalVar) { // lead retained console.log(2); // trail retained @@ -36,17 +43,18 @@ if (globalVar) { /* retained */ console.log(2);} switch (globalVar) { - case 1: + case 1: // retained // lead retained console.log(2); // trail retained - case 2: + case 2: // retained // lead retained console.log(2); // trail retained - case 3: + case 3: // retained // lead retained console.log(2); // trail retained + case 4: /* lead retained */ console.log('3'); // trail retained - default: + default: // retained /* lead retained */ console.log(2); // trail retained } diff --git a/test/form/samples/render-removed-statements/main.js b/test/form/samples/render-removed-statements/main.js index ea36bdb65dd..24e73c94ba2 100644 --- a/test/form/samples/render-removed-statements/main.js +++ b/test/form/samples/render-removed-statements/main.js @@ -2,14 +2,24 @@ /* lead removed */ var a = 1; // trail removed +/* lead removed */ +var a = 1; /* lead +retained */ console.log(2); // trail retained + /* lead removed */ var a = 1; /* trail +removed */ /* trail removed */ +console.log(2); // trail retained /* lead retained */ console.log(2); /* trail +retained */ /* trail retained */ +console.log(2); // trail retained +var a = 1; console.log(2); + if (globalVar) { // lead removed var a = 1; // trail removed @@ -46,25 +56,24 @@ if (globalVar) { /* removed */ var a = 1; /* retained */ console.log(2); /* remo if (globalVar) { /* retained */ console.log(2); /* removed */ var a = 1;} switch (globalVar) { - case 1: + case 1: // retained // lead removed var a = 1; // trail removed // lead retained console.log(2); // trail retained - case 2: + case 2: // retained // lead removed var a = 1; // trail removed // lead retained console.log(2); // trail retained // lead removed - var a = 1; - case 3: + var a = 1; case 3: // retained // lead retained console.log(2); // trail retained // lead removed var a = 1; case 4: /* lead removed */ var a = 1; /* lead retained */ console.log('3'); // trail retained - default: + default: // retained /* lead removed */ var a = 1; // trail removed /* lead retained */ diff --git a/test/form/samples/side-effects-switch-statements/_expected/amd.js b/test/form/samples/side-effects-switch-statements/_expected/amd.js index d60a8ee0af2..1c564b9058d 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/amd.js +++ b/test/form/samples/side-effects-switch-statements/_expected/amd.js @@ -14,6 +14,7 @@ define(function () { 'use strict'; case baz: effect(); default: + } switch ( globalVar ) { diff --git a/test/form/samples/side-effects-switch-statements/_expected/cjs.js b/test/form/samples/side-effects-switch-statements/_expected/cjs.js index d6bcd0340c6..b38e20d2b8f 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/cjs.js +++ b/test/form/samples/side-effects-switch-statements/_expected/cjs.js @@ -14,6 +14,7 @@ switch ( globalVar ) { case baz: effect(); default: + } switch ( globalVar ) { diff --git a/test/form/samples/side-effects-switch-statements/_expected/es.js b/test/form/samples/side-effects-switch-statements/_expected/es.js index 6c54e6d3dfc..6df30c21be2 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/es.js +++ b/test/form/samples/side-effects-switch-statements/_expected/es.js @@ -12,6 +12,7 @@ switch ( globalVar ) { case baz: effect(); default: + } switch ( globalVar ) { diff --git a/test/form/samples/side-effects-switch-statements/_expected/iife.js b/test/form/samples/side-effects-switch-statements/_expected/iife.js index e1d67ce69bc..6273f69b404 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/iife.js +++ b/test/form/samples/side-effects-switch-statements/_expected/iife.js @@ -15,6 +15,7 @@ case baz: effect(); default: + } switch ( globalVar ) { diff --git a/test/form/samples/side-effects-switch-statements/_expected/umd.js b/test/form/samples/side-effects-switch-statements/_expected/umd.js index 230294004d2..7965d940ebf 100644 --- a/test/form/samples/side-effects-switch-statements/_expected/umd.js +++ b/test/form/samples/side-effects-switch-statements/_expected/umd.js @@ -18,6 +18,7 @@ case baz: effect(); default: + } switch ( globalVar ) { diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js index 4db965ceaa3..382aff4862f 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/amd.js @@ -1,7 +1,6 @@ define(function () { 'use strict'; function x () { return 'x' } - assert.equal( x(), 'x' ); }); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js index bac28c19265..87e51bba080 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/cjs.js @@ -1,5 +1,4 @@ 'use strict'; function x () { return 'x' } - assert.equal( x(), 'x' ); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js index f5b5029659d..fe0fb3f215b 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/es.js @@ -1,3 +1,2 @@ function x () { return 'x' } - assert.equal( x(), 'x' ); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js index f8d69920288..662b2220277 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/iife.js @@ -2,7 +2,6 @@ 'use strict'; function x () { return 'x' } - assert.equal( x(), 'x' ); }()); diff --git a/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js b/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js index 75d31a1d04b..4730500a2f7 100644 --- a/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js +++ b/test/form/samples/spacing-after-function-with-semicolon/_expected/umd.js @@ -5,7 +5,6 @@ }(this, (function () { 'use strict'; function x () { return 'x' } - assert.equal( x(), 'x' ); }))); From 103e16f130c2a92b283560a22b459fbfe6d99656 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Sun, 11 Feb 2018 13:55:35 +0100 Subject: [PATCH 18/27] Rework declaration handling to associate comments after a comma but before a line-break with the previous declarator --- src/ast/nodes/VariableDeclaration.ts | 85 +++++++++++++------ src/utils/renderHelpers.ts | 36 +++++--- .../_config.js | 4 + .../render-named-export-declarations/main.js | 11 +++ .../_expected/amd.js | 63 +++++++++++--- .../_expected/cjs.js | 63 +++++++++++--- .../_expected/es.js | 63 +++++++++++--- .../_expected/iife.js | 63 +++++++++++--- .../_expected/umd.js | 63 +++++++++++--- .../render-removed-declarations/main.js | 68 +++++++++++---- .../_config.js | 2 +- 11 files changed, 396 insertions(+), 125 deletions(-) create mode 100644 test/form/samples/render-named-export-declarations/_config.js create mode 100644 test/form/samples/render-named-export-declarations/main.js diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index 35e5fb7cc73..beb225c22c4 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -5,7 +5,7 @@ import MagicString from 'magic-string'; import { ObjectPath } from '../variables/VariableReassignmentTracker'; import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; -import { getCommaSeparatedNodesWithBoundaries } from '../../utils/renderHelpers'; +import { getCommaSeparatedNodesWithSeparators } from '../../utils/renderHelpers'; import { isIdentifier } from './Identifier'; import Variable from '../variables/Variable'; @@ -61,27 +61,30 @@ export default class VariableDeclaration extends NodeBase { } render (code: MagicString, options: RenderOptions, { start, end, noSemicolon }: NodeRenderOptions = {}) { - let declarationsEnd = this.end; - if (code.original[declarationsEnd - 1] === ';') { - declarationsEnd--; - code.overwrite(declarationsEnd, declarationsEnd + 1, ''); - } - const nodesWithBoundaries = getCommaSeparatedNodesWithBoundaries( - this.declarations, code, this.start + this.kind.length - 1, declarationsEnd + const separatedNodes = getCommaSeparatedNodesWithSeparators( + this.declarations, + code, + this.start + this.kind.length, + this.end - (code.original[this.end - 1] === ';' ? 1 : 0) ); - // Make sure the first node overwrites "var " with whatever is appropriate - nodesWithBoundaries[0].start = this.start; + let renderedContentEnd; + if (/\n\s*$/.test(code.slice(this.start, separatedNodes[0].start))) { + renderedContentEnd = this.start + this.kind.length; + } else { + renderedContentEnd = separatedNodes[0].start; + } + let lastSeparatorPos = renderedContentEnd - 1; + code.remove(this.start, lastSeparatorPos); let isInDeclaration = false; let hasRenderedContent = false; - let hasOpenSystemBinding = false; - let renderedContentEnd; - for (let { node, start, contentStart, end } of nodesWithBoundaries) { + let separatorString = '', leadingString, nextSeparatorString; + for (let { node, start, separator, end } of separatedNodes) { if (!node.included || (isIdentifier(node.id) && isReassignedPartOfExportsObject(node.id.variable) && node.init === null)) { code.remove(start, end); continue; } - let separatorString = hasOpenSystemBinding ? ')' : ''; - hasOpenSystemBinding = false; + leadingString = ''; + nextSeparatorString = ''; if (isIdentifier(node.id) && isReassignedPartOfExportsObject(node.id.variable)) { if (hasRenderedContent) { separatorString += ';'; @@ -90,33 +93,65 @@ export default class VariableDeclaration extends NodeBase { } else { if (options.systemBindings && node.init !== null && isIdentifier(node.id) && node.id.variable.exportName) { code.prependLeft(node.init.start, `exports('${node.id.variable.exportName}', `); - hasOpenSystemBinding = true; + nextSeparatorString += ')'; } if (isInDeclaration) { separatorString += ','; } else { if (hasRenderedContent) { - separatorString += '; '; + separatorString += ';'; } - separatorString += `${this.kind}`; - contentStart += code.original.slice(contentStart, node.end).search(/\S/); + leadingString += `${this.kind} `; isInDeclaration = true; } } - if (separatorString !== '' && /\S/.test(code.original[contentStart])) { - separatorString += ' '; + if (renderedContentEnd === lastSeparatorPos + 1) { + code.overwrite(lastSeparatorPos, renderedContentEnd, separatorString + leadingString); + } else { + code.overwrite(lastSeparatorPos, lastSeparatorPos + 1, separatorString); + code.appendLeft(renderedContentEnd, leadingString); } - code.overwrite(start, contentStart, separatorString); node.render(code, options); renderedContentEnd = end; hasRenderedContent = true; + lastSeparatorPos = separator; + separatorString = nextSeparatorString; } if (hasRenderedContent) { - if (!noSemicolon) { - code.appendLeft(renderedContentEnd, (hasOpenSystemBinding ? ')' : '') + ';'); - } + this.renderDeclarationEnd(code, separatorString, lastSeparatorPos, renderedContentEnd, !noSemicolon); } else { code.remove(start || this.start, end || this.end); } } + + private renderDeclarationEnd ( + code: MagicString, + separatorString: string, + lastSeparatorPos: number, + renderedContentEnd: number, + addSemicolon: boolean + ) { + if (code.original[this.end - 1] === ';') { + code.remove(this.end - 1, this.end); + } + if (addSemicolon) { + separatorString += ';'; + } + if (lastSeparatorPos !== null) { + let actualContentEnd = lastSeparatorPos + code.original.slice(lastSeparatorPos, renderedContentEnd).search(/\s*$/); + // Do not remove trailing white-space if we might remove an essential comment-closing line-break + if (code.original[actualContentEnd] === '\n' && code.original[this.end] !== '\n') { + actualContentEnd = renderedContentEnd; + } + if (actualContentEnd === lastSeparatorPos + 1) { + code.overwrite(lastSeparatorPos, renderedContentEnd, separatorString); + } else { + code.overwrite(lastSeparatorPos, lastSeparatorPos + 1, separatorString); + code.remove(actualContentEnd, renderedContentEnd); + } + } else { + code.appendLeft(renderedContentEnd, separatorString); + } + return separatorString; + } } diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index cfd9d275faf..dc6f59fbdc2 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -65,7 +65,7 @@ export function renderStatementList (statements: Node[], code: MagicString, star } // This assumes that the first character is not part of the first node -export function getCommaSeparatedNodesWithBoundaries ( +export function getCommaSeparatedNodesWithSeparators ( nodes: N[], code: MagicString, start: number, @@ -73,28 +73,36 @@ export function getCommaSeparatedNodesWithBoundaries ( ): ({ node: N; start: number; - contentStart: number; + separator: number | null; end: number; })[] { const splitUpNodes = []; - let currentNode, currentNodeStart, currentNodeContentStart; + let currentNode, currentNodeStart, separator; let nextNode = nodes[0]; - let nextNodeStart = start; + let nextNodeStart = start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start)) + 1; + nextNodeStart += code.original.slice(nextNodeStart, nextNode.start + 1).search(/\S/); for (let nextIndex = 1; nextIndex <= nodes.length; nextIndex++) { currentNode = nextNode; currentNodeStart = nextNodeStart; nextNode = nodes[nextIndex]; - nextNodeStart = nextNode === undefined ? end : currentNode.end + findFirstOccurrenceOutsideComment( - code.original.slice(currentNode.end, nextNode.start), ',' - ); - // Each node starts with a non-content character e.g. ","; that way we can always safely code.overwrite(start, contentStart, ..) - currentNodeContentStart = currentNodeStart + 1; - // We remove leading spaces (but not other white-space) to avoid double spaces when rendering - currentNodeContentStart += code.original.slice(currentNodeContentStart, nextNodeStart).search(/[^ ]/); - splitUpNodes.push({ - node: currentNode, start: currentNodeStart, end: nextNodeStart, contentStart: currentNodeContentStart - }); + + if (nextNode === undefined) { + splitUpNodes.push({ + node: currentNode, start: currentNodeStart, end, separator: null + }); + } else { + separator = currentNode.end + findFirstOccurrenceOutsideComment( + code.original.slice(currentNode.end, nextNode.start), ',' + ); + nextNodeStart = separator + 1 + findFirstLineBreakOutsideComment( + code.original.slice(separator + 1, nextNode.start) + ) + 1; + nextNodeStart += code.original.slice(nextNodeStart, nextNode.start + 1).search(/\S/); + splitUpNodes.push({ + node: currentNode, start: currentNodeStart, end: nextNodeStart, separator + }); + } } return splitUpNodes; } diff --git a/test/form/samples/render-named-export-declarations/_config.js b/test/form/samples/render-named-export-declarations/_config.js new file mode 100644 index 00000000000..33a285aa2f1 --- /dev/null +++ b/test/form/samples/render-named-export-declarations/_config.js @@ -0,0 +1,4 @@ +module.exports = { + description: 'renders named export declarations', + options: { name: 'bundle' } +}; diff --git a/test/form/samples/render-named-export-declarations/main.js b/test/form/samples/render-named-export-declarations/main.js new file mode 100644 index 00000000000..105a7c72cd2 --- /dev/null +++ b/test/form/samples/render-named-export-declarations/main.js @@ -0,0 +1,11 @@ +export var aFoo, aBar; +aBar = 2; + +export var bFoo, bBar; +bFoo = 2; + +export var cFoo, cBar = 1; +cBar = 2; + +export var dFoo = 1, dBar; +dFoo = 2; diff --git a/test/form/samples/render-removed-declarations/_expected/amd.js b/test/form/samples/render-removed-declarations/_expected/amd.js index 651324994e0..903379b1cb5 100644 --- a/test/form/samples/render-removed-declarations/_expected/amd.js +++ b/test/form/samples/render-removed-declarations/_expected/amd.js @@ -1,23 +1,58 @@ define(function () { 'use strict'; - // Middle removed - var kept1 = 1, kept2 = 3; // retained comment + // -> Middle removed + var kept1 = 1, kept2 = 3; + + // with comments + var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; // retained + + // without spaces + var kept1 = 1,kept2 = 3; + + // with comments without spaces + var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */;// retained + + // with line-breaks var kept1 = 1, kept2 = 3; - var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; - var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; - // Start and end removed - var kept1 = 2; // retained comment + // with line-breaks and comments + var /* retained */ kept1 = 1, // retained + /* retained */ kept2 = 3; // retained + + // mixed + var kept1 = 1, // retained + kept2 = 3; + + // -> Start and end removed var kept1 = 2; - var kept1 = 2; // retained comment - var kept1 = 2; // retained comment - var /* retained */ kept1 = 2 /* retained */; - var /* retained */kept1 = 2/* retained */; - - // Missing semicolons - var kept1 = 1; // retained comment - var kept1 = 1; // retained comment + + // with comments + var /* retained */ kept1 = 2 /* retained */; // retained + + // without spaces + var kept1 = 2; + + // with comments without spaces + var /* retained */kept1 = 2/* retained */;// retained + + // with line-breaks + var kept1 = 2; + + // with line-breaks and comments + var /* retained */ kept1 = 2; // retained + + // mixed + var // retained + kept1 = 2; // retained + + // -> Missing semicolons + var kept1 = 1; // retained + var kept1 = 1; // retained + + // -> No line-break after declaration + var kept1 = 1; // retained + console.log(1); console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/cjs.js b/test/form/samples/render-removed-declarations/_expected/cjs.js index 9adae58a9d3..3a97d57b2a7 100644 --- a/test/form/samples/render-removed-declarations/_expected/cjs.js +++ b/test/form/samples/render-removed-declarations/_expected/cjs.js @@ -1,22 +1,57 @@ 'use strict'; -// Middle removed -var kept1 = 1, kept2 = 3; // retained comment +// -> Middle removed +var kept1 = 1, kept2 = 3; + +// with comments +var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; // retained + +// without spaces +var kept1 = 1,kept2 = 3; + +// with comments without spaces +var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */;// retained + +// with line-breaks var kept1 = 1, kept2 = 3; -var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; -var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; -// Start and end removed -var kept1 = 2; // retained comment +// with line-breaks and comments +var /* retained */ kept1 = 1, // retained + /* retained */ kept2 = 3; // retained + +// mixed +var kept1 = 1, // retained + kept2 = 3; + +// -> Start and end removed var kept1 = 2; -var kept1 = 2; // retained comment -var kept1 = 2; // retained comment -var /* retained */ kept1 = 2 /* retained */; -var /* retained */kept1 = 2/* retained */; - -// Missing semicolons -var kept1 = 1; // retained comment -var kept1 = 1; // retained comment + +// with comments +var /* retained */ kept1 = 2 /* retained */; // retained + +// without spaces +var kept1 = 2; + +// with comments without spaces +var /* retained */kept1 = 2/* retained */;// retained + +// with line-breaks +var kept1 = 2; + +// with line-breaks and comments +var /* retained */ kept1 = 2; // retained + +// mixed +var // retained + kept1 = 2; // retained + +// -> Missing semicolons +var kept1 = 1; // retained +var kept1 = 1; // retained + +// -> No line-break after declaration +var kept1 = 1; // retained + console.log(1); console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/es.js b/test/form/samples/render-removed-declarations/_expected/es.js index 1bce3ddcb22..4dcddb25723 100644 --- a/test/form/samples/render-removed-declarations/_expected/es.js +++ b/test/form/samples/render-removed-declarations/_expected/es.js @@ -1,20 +1,55 @@ -// Middle removed -var kept1 = 1, kept2 = 3; // retained comment +// -> Middle removed +var kept1 = 1, kept2 = 3; + +// with comments +var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; // retained + +// without spaces +var kept1 = 1,kept2 = 3; + +// with comments without spaces +var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */;// retained + +// with line-breaks var kept1 = 1, kept2 = 3; -var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; -var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; -// Start and end removed -var kept1 = 2; // retained comment +// with line-breaks and comments +var /* retained */ kept1 = 1, // retained + /* retained */ kept2 = 3; // retained + +// mixed +var kept1 = 1, // retained + kept2 = 3; + +// -> Start and end removed var kept1 = 2; -var kept1 = 2; // retained comment -var kept1 = 2; // retained comment -var /* retained */ kept1 = 2 /* retained */; -var /* retained */kept1 = 2/* retained */; - -// Missing semicolons -var kept1 = 1; // retained comment -var kept1 = 1; // retained comment + +// with comments +var /* retained */ kept1 = 2 /* retained */; // retained + +// without spaces +var kept1 = 2; + +// with comments without spaces +var /* retained */kept1 = 2/* retained */;// retained + +// with line-breaks +var kept1 = 2; + +// with line-breaks and comments +var /* retained */ kept1 = 2; // retained + +// mixed +var // retained + kept1 = 2; // retained + +// -> Missing semicolons +var kept1 = 1; // retained +var kept1 = 1; // retained + +// -> No line-break after declaration +var kept1 = 1; // retained + console.log(1); console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/iife.js b/test/form/samples/render-removed-declarations/_expected/iife.js index e3896ab6db0..e99fc5c258c 100644 --- a/test/form/samples/render-removed-declarations/_expected/iife.js +++ b/test/form/samples/render-removed-declarations/_expected/iife.js @@ -1,24 +1,59 @@ (function () { 'use strict'; - // Middle removed - var kept1 = 1, kept2 = 3; // retained comment + // -> Middle removed + var kept1 = 1, kept2 = 3; + + // with comments + var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; // retained + + // without spaces + var kept1 = 1,kept2 = 3; + + // with comments without spaces + var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */;// retained + + // with line-breaks var kept1 = 1, kept2 = 3; - var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; - var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; - // Start and end removed - var kept1 = 2; // retained comment + // with line-breaks and comments + var /* retained */ kept1 = 1, // retained + /* retained */ kept2 = 3; // retained + + // mixed + var kept1 = 1, // retained + kept2 = 3; + + // -> Start and end removed var kept1 = 2; - var kept1 = 2; // retained comment - var kept1 = 2; // retained comment - var /* retained */ kept1 = 2 /* retained */; - var /* retained */kept1 = 2/* retained */; - - // Missing semicolons - var kept1 = 1; // retained comment - var kept1 = 1; // retained comment + + // with comments + var /* retained */ kept1 = 2 /* retained */; // retained + + // without spaces + var kept1 = 2; + + // with comments without spaces + var /* retained */kept1 = 2/* retained */;// retained + + // with line-breaks + var kept1 = 2; + + // with line-breaks and comments + var /* retained */ kept1 = 2; // retained + + // mixed + var // retained + kept1 = 2; // retained + + // -> Missing semicolons + var kept1 = 1; // retained + var kept1 = 1; // retained + + // -> No line-break after declaration + var kept1 = 1; // retained + console.log(1); console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/umd.js b/test/form/samples/render-removed-declarations/_expected/umd.js index 450544cfd35..02e98a1a6a0 100644 --- a/test/form/samples/render-removed-declarations/_expected/umd.js +++ b/test/form/samples/render-removed-declarations/_expected/umd.js @@ -4,24 +4,59 @@ (factory()); }(this, (function () { 'use strict'; - // Middle removed - var kept1 = 1, kept2 = 3; // retained comment + // -> Middle removed + var kept1 = 1, kept2 = 3; + + // with comments + var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; // retained + + // without spaces + var kept1 = 1,kept2 = 3; + + // with comments without spaces + var /* retained */kept1 = 1/* retained */,/* retained */kept2 = 3/* retained */;// retained + + // with line-breaks var kept1 = 1, kept2 = 3; - var /* retained */ kept1 = 1 /* retained */, /* retained */ kept2 = 3 /* retained */; - var /* retained */kept1 = 1/* retained */, /* retained */kept2 = 3/* retained */; - // Start and end removed - var kept1 = 2; // retained comment + // with line-breaks and comments + var /* retained */ kept1 = 1, // retained + /* retained */ kept2 = 3; // retained + + // mixed + var kept1 = 1, // retained + kept2 = 3; + + // -> Start and end removed var kept1 = 2; - var kept1 = 2; // retained comment - var kept1 = 2; // retained comment - var /* retained */ kept1 = 2 /* retained */; - var /* retained */kept1 = 2/* retained */; - - // Missing semicolons - var kept1 = 1; // retained comment - var kept1 = 1; // retained comment + + // with comments + var /* retained */ kept1 = 2 /* retained */; // retained + + // without spaces + var kept1 = 2; + + // with comments without spaces + var /* retained */kept1 = 2/* retained */;// retained + + // with line-breaks + var kept1 = 2; + + // with line-breaks and comments + var /* retained */ kept1 = 2; // retained + + // mixed + var // retained + kept1 = 2; // retained + + // -> Missing semicolons + var kept1 = 1; // retained + var kept1 = 1; // retained + + // -> No line-break after declaration + var kept1 = 1; // retained + console.log(1); console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/main.js b/test/form/samples/render-removed-declarations/main.js index a8561e8cf22..bccb4738640 100644 --- a/test/form/samples/render-removed-declarations/main.js +++ b/test/form/samples/render-removed-declarations/main.js @@ -1,27 +1,65 @@ -// Middle removed -var kept1 = 1, removed1 = 2, kept2 = 3; // retained comment +// -> Middle removed +var kept1 = 1, removed1 = 2, kept2 = 3; + +// with comments +var /* retained */ kept1 = 1 /* retained */, /* removed */ removed1 = 2 /* removed */, /* retained */ kept2 = 3 /* retained */; // retained + +// without spaces +var kept1 = 1,removed1 = 2,kept2 = 3; + +// with comments without spaces +var/* retained */kept1 = 1/* retained */,/* removed */removed1 = 2/* removed */,/* retained */kept2 = 3/* retained */;// retained + +// with line-breaks var kept1 = 1, removed1 = 2, kept2 = 3; -var /* retained */ kept1 = 1 /* retained */, /* removed */ removed1 = 2 /* removed */, /* retained */ kept2 = 3 /* retained */; -var/* retained */kept1 = 1/* retained */,/* removed */removed1 = 2/* removed */,/* retained */kept2 = 3/* retained */; -// Start and end removed -var removed1 = 1, kept1 = 2, removed2 = 3; // retained comment +// with line-breaks and comments +var /* retained */ kept1 = 1, // retained + /* removed */ removed1 = 2, // removed + /* retained */ kept2 = 3; // retained + +// mixed +var kept1 = 1, // retained + removed1 = 2, kept2 = 3; + +// -> Start and end removed +var removed1 = 1, kept1 = 2, removed2 = 3; + +// with comments +var /* removed */ removed1 = 1 /* removed */, /* retained */ kept1 = 2 /* retained */, /* removed */ removed2 = 3 /* removed */; // retained + +// without spaces +var removed1 = 1,kept1 = 2,removed2 = 3; + +// with comments without spaces +var/* removed */removed1 = 1/* removed */,/* retained */kept1 = 2/* retained */,/* removed */removed2 = 3/* removed */;// retained + +// with line-breaks var removed1 = 1, kept1 = 2, removed2 = 3; -var/* retained */removed1 = 1,kept1 = 2, removed2 = 3; // retained comment -var// removed -removed1 = 1,kept1 = 2, removed2 = 3; // retained comment -var /* removed */ removed1 = 1 /* removed */, /* retained */ kept1 = 2 /* retained */, /* removed */ removed2 = 3 /* removed */; -var/* removed */removed1 = 1/* removed */,/* retained */kept1 = 2/* retained */,/* removed */removed2 = 3/* removed */; -// Missing semicolons -var kept1 = 1 // retained comment -var kept1 = 1, removed1 = 2 // retained comment +// with line-breaks and comments +var /* removed */ removed1 = 1, // removed + /* retained */ kept1 = 2, // retained + /* removed */ removed2 = 3; + +// mixed +var // retained + removed1 = 1, kept1 = 2, // retained + removed2 = 3; + +// -> Missing semicolons +var kept1 = 1 // retained +var kept1 = 1, removed1 = 2 // retained + +// -> No line-break after declaration +var kept1 = 1, // retained + removed1 = 2;console.log(1); -// Everything removed +// -> Everything removed var removed1 = 1; console.log( kept1, kept2 ); diff --git a/test/function/samples/tree-shake-variable-declarations-2/_config.js b/test/function/samples/tree-shake-variable-declarations-2/_config.js index 6d276caa8e1..40ccf45aea3 100644 --- a/test/function/samples/tree-shake-variable-declarations-2/_config.js +++ b/test/function/samples/tree-shake-variable-declarations-2/_config.js @@ -3,6 +3,6 @@ var assert = require( 'assert' ); module.exports = { description: 'remove unused variables from declarations (#1831)', code: function ( code ) { - assert.ok( code.search( /var\s+\/\/not\sused\s+a/ ) >= 0 ); + assert.ok( code.search( /var a = 'test'/ ) >= 0 ); } }; From 377fe90f05ed34344bd524499f84a831dd9148ca Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Sun, 11 Feb 2018 14:20:08 +0100 Subject: [PATCH 19/27] Fix TypeScript test --- src/ast/nodes/VariableDeclaration.ts | 6 ++--- .../_expected/amd.js | 22 ++++++++++++++++ .../_expected/cjs.js | 20 ++++++++++++++ .../_expected/es.js | 13 ++++++++++ .../_expected/iife.js | 23 ++++++++++++++++ .../_expected/umd.js | 26 +++++++++++++++++++ 6 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 test/form/samples/render-named-export-declarations/_expected/amd.js create mode 100644 test/form/samples/render-named-export-declarations/_expected/cjs.js create mode 100644 test/form/samples/render-named-export-declarations/_expected/es.js create mode 100644 test/form/samples/render-named-export-declarations/_expected/iife.js create mode 100644 test/form/samples/render-named-export-declarations/_expected/umd.js diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index beb225c22c4..63a5473b45c 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -60,7 +60,7 @@ export default class VariableDeclaration extends NodeBase { ); } - render (code: MagicString, options: RenderOptions, { start, end, noSemicolon }: NodeRenderOptions = {}) { + render (code: MagicString, options: RenderOptions, nodeRenderOptions: NodeRenderOptions = {}) { const separatedNodes = getCommaSeparatedNodesWithSeparators( this.declarations, code, @@ -118,9 +118,9 @@ export default class VariableDeclaration extends NodeBase { separatorString = nextSeparatorString; } if (hasRenderedContent) { - this.renderDeclarationEnd(code, separatorString, lastSeparatorPos, renderedContentEnd, !noSemicolon); + this.renderDeclarationEnd(code, separatorString, lastSeparatorPos, renderedContentEnd, !nodeRenderOptions.noSemicolon); } else { - code.remove(start || this.start, end || this.end); + code.remove(nodeRenderOptions.start || this.start, nodeRenderOptions.end || this.end); } } diff --git a/test/form/samples/render-named-export-declarations/_expected/amd.js b/test/form/samples/render-named-export-declarations/_expected/amd.js new file mode 100644 index 00000000000..69e4e761995 --- /dev/null +++ b/test/form/samples/render-named-export-declarations/_expected/amd.js @@ -0,0 +1,22 @@ +define(['exports'], function (exports) { 'use strict'; + + var aFoo; + exports.aBar = 2; + + var bBar; + exports.bFoo = 2; + + var cFoo; exports.cBar = 1; + exports.cBar = 2; + + exports.dFoo = 1; var dBar; + exports.dFoo = 2; + + exports.aFoo = aFoo; + exports.bBar = bBar; + exports.cFoo = cFoo; + exports.dBar = dBar; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}); diff --git a/test/form/samples/render-named-export-declarations/_expected/cjs.js b/test/form/samples/render-named-export-declarations/_expected/cjs.js new file mode 100644 index 00000000000..f5fac90e0ce --- /dev/null +++ b/test/form/samples/render-named-export-declarations/_expected/cjs.js @@ -0,0 +1,20 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +var aFoo; +exports.aBar = 2; + +var bBar; +exports.bFoo = 2; + +var cFoo; exports.cBar = 1; +exports.cBar = 2; + +exports.dFoo = 1; var dBar; +exports.dFoo = 2; + +exports.aFoo = aFoo; +exports.bBar = bBar; +exports.cFoo = cFoo; +exports.dBar = dBar; diff --git a/test/form/samples/render-named-export-declarations/_expected/es.js b/test/form/samples/render-named-export-declarations/_expected/es.js new file mode 100644 index 00000000000..865541a4e3a --- /dev/null +++ b/test/form/samples/render-named-export-declarations/_expected/es.js @@ -0,0 +1,13 @@ +var aFoo, aBar; +aBar = 2; + +var bFoo, bBar; +bFoo = 2; + +var cFoo, cBar = 1; +cBar = 2; + +var dFoo = 1, dBar; +dFoo = 2; + +export { aFoo, aBar, bFoo, bBar, cFoo, cBar, dFoo, dBar }; diff --git a/test/form/samples/render-named-export-declarations/_expected/iife.js b/test/form/samples/render-named-export-declarations/_expected/iife.js new file mode 100644 index 00000000000..5ed079c97f0 --- /dev/null +++ b/test/form/samples/render-named-export-declarations/_expected/iife.js @@ -0,0 +1,23 @@ +var bundle = (function (exports) { + 'use strict'; + + var aFoo; + exports.aBar = 2; + + var bBar; + exports.bFoo = 2; + + var cFoo; exports.cBar = 1; + exports.cBar = 2; + + exports.dFoo = 1; var dBar; + exports.dFoo = 2; + + exports.aFoo = aFoo; + exports.bBar = bBar; + exports.cFoo = cFoo; + exports.dBar = dBar; + + return exports; + +}({})); diff --git a/test/form/samples/render-named-export-declarations/_expected/umd.js b/test/form/samples/render-named-export-declarations/_expected/umd.js new file mode 100644 index 00000000000..394da8eaad4 --- /dev/null +++ b/test/form/samples/render-named-export-declarations/_expected/umd.js @@ -0,0 +1,26 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (factory((global.bundle = {}))); +}(this, (function (exports) { 'use strict'; + + var aFoo; + exports.aBar = 2; + + var bBar; + exports.bFoo = 2; + + var cFoo; exports.cBar = 1; + exports.cBar = 2; + + exports.dFoo = 1; var dBar; + exports.dFoo = 2; + + exports.aFoo = aFoo; + exports.bBar = bBar; + exports.cFoo = cFoo; + exports.dBar = dBar; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); From 495f97a7e1b269b8fdd5942ae6cc59879cce63ed Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Mon, 12 Feb 2018 07:37:11 +0100 Subject: [PATCH 20/27] * Improve some names * Get rid of unnecessary defaults * Replace tilde operator --- src/Module.ts | 4 ++-- src/ast/nodes/ExportAllDeclaration.ts | 2 +- src/ast/nodes/ExportDefaultDeclaration.ts | 8 ++++---- src/ast/nodes/ExportNamedDeclaration.ts | 2 +- src/ast/nodes/ImportDeclaration.ts | 2 +- src/ast/nodes/VariableDeclaration.ts | 12 ++++++------ src/ast/variables/NamespaceVariable.ts | 2 +- src/ast/variables/Variable.ts | 8 ++++++-- src/utils/defaults.ts | 2 +- src/utils/mergeOptions.ts | 2 +- src/utils/renderHelpers.ts | 14 +++++++------- 11 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/Module.ts b/src/Module.ts index 5835cd0dd21..30b04967e80 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -259,7 +259,7 @@ export default class Module { // export { name } from './other' if (source) { - if (!~this.sources.indexOf(source)) this.sources.push(source); + if (this.sources.indexOf(source) === -1) this.sources.push(source); if (node.type === NodeType.ExportAllDeclaration) { // Store `export * from '...'` statements in an array of delegates. @@ -351,7 +351,7 @@ export default class Module { private addImport (node: ImportDeclaration) { const source = node.source.value; - if (!~this.sources.indexOf(source)) this.sources.push(source); + if (this.sources.indexOf(source) === -1) this.sources.push(source); node.specifiers.forEach(specifier => { const localName = specifier.local.name; diff --git a/src/ast/nodes/ExportAllDeclaration.ts b/src/ast/nodes/ExportAllDeclaration.ts index 3efd90a1535..d99f1eed0e1 100644 --- a/src/ast/nodes/ExportAllDeclaration.ts +++ b/src/ast/nodes/ExportAllDeclaration.ts @@ -14,6 +14,6 @@ export default class ExportAllDeclaration extends NodeBase { } render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { - code.remove(start || this.start, end || this.end); + code.remove(start, end); } } diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index fe37a2ae009..751fcef7381 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -20,10 +20,10 @@ function getIdInsertPosition (code: string, declarationKeyword: string) { code = code.slice(declarationEnd); code = code.slice(0, findFirstOccurrenceOutsideComment(code, '{')); const generatorStarPos = findFirstOccurrenceOutsideComment(code, '*'); - if (~generatorStarPos) { - return declarationEnd + generatorStarPos + 1; + if (generatorStarPos === -1) { + return declarationEnd; } - return declarationEnd; + return declarationEnd + generatorStarPos + 1; } const needsToBeWrapped = isObjectExpression; @@ -64,7 +64,7 @@ export default class ExportDefaultDeclaration extends NodeBase { this.renderNamedDeclaration(code, declarationStart, 'class', this.declaration.id === null, options); } else if (this.variable.getOriginalVariableName() === this.variable.getName()) { // Remove altogether to prevent re-declaring the same variable - code.remove(start || this.start, end || this.end); + code.remove(start, end); return; } else if (this.variable.included) { this.renderVariableDeclaration(code, declarationStart, options); diff --git a/src/ast/nodes/ExportNamedDeclaration.ts b/src/ast/nodes/ExportNamedDeclaration.ts index 01d30e151d1..0480869b4c5 100644 --- a/src/ast/nodes/ExportNamedDeclaration.ts +++ b/src/ast/nodes/ExportNamedDeclaration.ts @@ -32,7 +32,7 @@ export default class ExportNamedDeclaration extends NodeBase { render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { if (this.declaration === null) { - code.remove(start || this.start, end || this.end); + code.remove(start, end); } else { code.remove(this.start, this.declaration.start); (this.declaration).render(code, options, { start, end }); diff --git a/src/ast/nodes/ImportDeclaration.ts b/src/ast/nodes/ImportDeclaration.ts index f326799f8c8..6d64d62f696 100644 --- a/src/ast/nodes/ImportDeclaration.ts +++ b/src/ast/nodes/ImportDeclaration.ts @@ -20,6 +20,6 @@ export default class ImportDeclaration extends NodeBase { } render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { - code.remove(start || this.start, end || this.end); + code.remove(start, end); } } diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index 63a5473b45c..1b05827c776 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -9,7 +9,7 @@ import { getCommaSeparatedNodesWithSeparators } from '../../utils/renderHelpers' import { isIdentifier } from './Identifier'; import Variable from '../variables/Variable'; -function isReassignedPartOfExportsObject (variable: Variable): boolean { +function isReassignedExportsMember (variable: Variable): boolean { return variable.safeName && variable.safeName.indexOf('.') !== -1 && variable.exportName && variable.isReassigned; } @@ -60,7 +60,7 @@ export default class VariableDeclaration extends NodeBase { ); } - render (code: MagicString, options: RenderOptions, nodeRenderOptions: NodeRenderOptions = {}) { + render (code: MagicString, options: RenderOptions, { start = this.start, end = this.end, noSemicolon }: NodeRenderOptions = {}) { const separatedNodes = getCommaSeparatedNodesWithSeparators( this.declarations, code, @@ -79,13 +79,13 @@ export default class VariableDeclaration extends NodeBase { let hasRenderedContent = false; let separatorString = '', leadingString, nextSeparatorString; for (let { node, start, separator, end } of separatedNodes) { - if (!node.included || (isIdentifier(node.id) && isReassignedPartOfExportsObject(node.id.variable) && node.init === null)) { + if (!node.included || (isIdentifier(node.id) && isReassignedExportsMember(node.id.variable) && node.init === null)) { code.remove(start, end); continue; } leadingString = ''; nextSeparatorString = ''; - if (isIdentifier(node.id) && isReassignedPartOfExportsObject(node.id.variable)) { + if (isIdentifier(node.id) && isReassignedExportsMember(node.id.variable)) { if (hasRenderedContent) { separatorString += ';'; } @@ -118,9 +118,9 @@ export default class VariableDeclaration extends NodeBase { separatorString = nextSeparatorString; } if (hasRenderedContent) { - this.renderDeclarationEnd(code, separatorString, lastSeparatorPos, renderedContentEnd, !nodeRenderOptions.noSemicolon); + this.renderDeclarationEnd(code, separatorString, lastSeparatorPos, renderedContentEnd, !noSemicolon); } else { - code.remove(nodeRenderOptions.start || this.start, nodeRenderOptions.end || this.end); + code.remove(start, end); } } diff --git a/src/ast/variables/NamespaceVariable.ts b/src/ast/variables/NamespaceVariable.ts index 2b712c1b245..fa27126c99e 100644 --- a/src/ast/variables/NamespaceVariable.ts +++ b/src/ast/variables/NamespaceVariable.ts @@ -52,7 +52,7 @@ export default class NamespaceVariable extends Variable { return `${indentString}get ${name} () { return ${original.getName()}; }`; } - if (legacy && ~reservedWords.indexOf(name)) name = `'${name}'`; + if (legacy && reservedWords.indexOf(name) !== -1) name = `'${name}'`; return `${indentString}${name}: ${original.getName()}`; }); diff --git a/src/ast/variables/Variable.ts b/src/ast/variables/Variable.ts index fb34257f050..35de04ad0d3 100644 --- a/src/ast/variables/Variable.ts +++ b/src/ast/variables/Variable.ts @@ -38,9 +38,13 @@ export default class Variable implements ExpressionEntity { ) { } getName (reset?: boolean): string { - if (reset && this.safeName && this.safeName !== this.name && + if ( + reset && + this.safeName && + this.safeName !== this.name && this.safeName[this.name.length] === '$' && - this.safeName[this.name.length + 1] === '$') { + this.safeName[this.name.length + 1] === '$' + ) { this.safeName = undefined; return this.name; } diff --git a/src/utils/defaults.ts b/src/utils/defaults.ts index 128ff10ca54..77444162d34 100644 --- a/src/utils/defaults.ts +++ b/src/utils/defaults.ts @@ -20,7 +20,7 @@ function findFile (file: string, preserveSymlinks: boolean): string | void { const name = basename(file); const files = readdirSync(dirname(file)); - if (~files.indexOf(name)) return file; + if (files.indexOf(name) !== -1) return file; } } catch (err) { // suppress diff --git a/src/utils/mergeOptions.ts b/src/utils/mergeOptions.ts index 9ec8dea8f40..85552c2b8eb 100644 --- a/src/utils/mergeOptions.ts +++ b/src/utils/mergeOptions.ts @@ -107,7 +107,7 @@ export default function mergeOptions ({ } if (typeof configExternal === 'function') { - inputOptions.external = (id, ...rest: any[]) => configExternal(id, ...rest) || ~commandExternal.indexOf(id); + inputOptions.external = (id, ...rest: any[]) => configExternal(id, ...rest) || commandExternal.indexOf(id) !== -1; } else { inputOptions.external = (configExternal || []).concat(commandExternal); } diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index dc6f59fbdc2..70011ea7970 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -4,11 +4,11 @@ import { RenderOptions } from '../Module'; export function findFirstOccurrenceOutsideComment (code: string, searchString: string) { let codeStart = 0; - let commentStart, commentLength, lineBreakPos; + let commentStart, commentLength, searchPos; while (true) { commentStart = code.indexOf('/'); - lineBreakPos = (~commentStart ? code.slice(0, commentStart) : code).indexOf(searchString); - if (~lineBreakPos || !~commentStart) { + searchPos = (commentStart === -1 ? code : code.slice(0, commentStart)).indexOf(searchString); + if (searchPos !== -1 || commentStart === -1) { break; } code = code.slice(commentStart + 1); @@ -23,7 +23,7 @@ export function findFirstOccurrenceOutsideComment (code: string, searchString: s code = code.slice(commentLength); codeStart += commentLength; } - return ~lineBreakPos ? codeStart + lineBreakPos : -1; + return searchPos === -1 ? -1 : codeStart + searchPos; } export function findFirstLineBreakOutsideComment (code: string) { @@ -31,8 +31,8 @@ export function findFirstLineBreakOutsideComment (code: string) { let commentStart, commentLength, lineBreakPos; while (true) { commentStart = code.indexOf('/*'); - lineBreakPos = (~commentStart ? code.slice(0, commentStart) : code).indexOf('\n'); - if (~lineBreakPos || !~commentStart) { + lineBreakPos = (commentStart !== -1 ? code.slice(0, commentStart) : code).indexOf('\n'); + if (lineBreakPos !== -1 || commentStart === -1) { break; } code = code.slice(commentStart); @@ -40,7 +40,7 @@ export function findFirstLineBreakOutsideComment (code: string) { code = code.slice(commentLength); codeStart += commentStart + commentLength; } - return ~lineBreakPos ? codeStart + lineBreakPos : -1; + return lineBreakPos === -1 ? -1 : codeStart + lineBreakPos; } export function renderStatementList (statements: Node[], code: MagicString, start: number, end: number, options: RenderOptions) { From acaea3d331053d95e58d589eb8e561e88573a462 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Mon, 12 Feb 2018 08:26:30 +0100 Subject: [PATCH 21/27] * Reintroduce statement concept as an alias * Rename noSemicolon -> isStatement --- src/Module.ts | 4 ++-- src/ast/nodes/BlockStatement.ts | 6 +++--- src/ast/nodes/BreakStatement.ts | 4 ++-- src/ast/nodes/DoWhileStatement.ts | 6 +++--- src/ast/nodes/EmptyStatement.ts | 4 ++-- src/ast/nodes/ExpressionStatement.ts | 4 ++-- src/ast/nodes/ForInStatement.ts | 6 +++--- src/ast/nodes/ForOfStatement.ts | 6 +++--- src/ast/nodes/ForStatement.ts | 6 +++--- src/ast/nodes/IfStatement.ts | 16 ++++++++-------- src/ast/nodes/LabeledStatement.ts | 6 +++--- src/ast/nodes/Program.ts | 4 ++-- src/ast/nodes/ReturnStatement.ts | 4 ++-- src/ast/nodes/SwitchCase.ts | 4 ++-- src/ast/nodes/SwitchStatement.ts | 4 ++-- src/ast/nodes/ThrowStatement.ts | 4 ++-- src/ast/nodes/VariableDeclaration.ts | 4 ++-- src/ast/nodes/WhileStatement.ts | 6 +++--- src/ast/nodes/index.ts | 4 ++-- src/ast/nodes/shared/Node.ts | 4 ++++ 20 files changed, 55 insertions(+), 51 deletions(-) diff --git a/src/Module.ts b/src/Module.ts index 30b04967e80..38f42e2226e 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -112,10 +112,10 @@ export interface RenderOptions { export interface NodeRenderOptions { start?: number, end?: number, - noSemicolon?: boolean + isStatement?: boolean } -export const NO_SEMICOLON: NodeRenderOptions = { noSemicolon: true }; +export const NO_SEMICOLON: NodeRenderOptions = { isStatement: true }; export default class Module { type: 'Module'; diff --git a/src/ast/nodes/BlockStatement.ts b/src/ast/nodes/BlockStatement.ts index d2fb3caf9ff..c3be0a65efb 100644 --- a/src/ast/nodes/BlockStatement.ts +++ b/src/ast/nodes/BlockStatement.ts @@ -3,7 +3,7 @@ import { UNKNOWN_EXPRESSION } from '../values'; import ExecutionPathOptions from '../ExecutionPathOptions'; import Scope from '../scopes/Scope'; import MagicString from 'magic-string'; -import { Node, NodeBase } from './shared/Node'; +import { Node, StatementBase, StatementNode } from './shared/Node'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; import { renderStatementList } from '../../utils/renderHelpers'; @@ -12,10 +12,10 @@ export function isBlockStatement (node: Node): node is BlockStatement { return node.type === NodeType.BlockStatement; } -export default class BlockStatement extends NodeBase { +export default class BlockStatement extends StatementBase { type: NodeType.BlockStatement; scope: Scope; - body: Node[]; + body: StatementNode[]; bindImplicitReturnExpressionToScope () { const lastStatement = this.body[this.body.length - 1]; diff --git a/src/ast/nodes/BreakStatement.ts b/src/ast/nodes/BreakStatement.ts index f44e3b8f919..02b7d604f6e 100644 --- a/src/ast/nodes/BreakStatement.ts +++ b/src/ast/nodes/BreakStatement.ts @@ -1,9 +1,9 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import Identifier from './Identifier'; import { NodeType } from './NodeType'; -import { NodeBase } from './shared/Node'; +import { StatementBase } from './shared/Node'; -export default class BreakStatement extends NodeBase { +export default class BreakStatement extends StatementBase { type: NodeType.BreakStatement; label: Identifier | null; diff --git a/src/ast/nodes/DoWhileStatement.ts b/src/ast/nodes/DoWhileStatement.ts index e0d968806c3..691bd0be019 100644 --- a/src/ast/nodes/DoWhileStatement.ts +++ b/src/ast/nodes/DoWhileStatement.ts @@ -1,10 +1,10 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; -import { ExpressionNode, NodeBase, Node } from './shared/Node'; +import { ExpressionNode, StatementNode, StatementBase } from './shared/Node'; import { NodeType } from './NodeType'; -export default class DoWhileStatement extends NodeBase { +export default class DoWhileStatement extends StatementBase { type: NodeType.DoWhileStatement; - body: Node; + body: StatementNode; test: ExpressionNode; hasEffects (options: ExecutionPathOptions): boolean { diff --git a/src/ast/nodes/EmptyStatement.ts b/src/ast/nodes/EmptyStatement.ts index e3f7e0dc5da..563a371e327 100644 --- a/src/ast/nodes/EmptyStatement.ts +++ b/src/ast/nodes/EmptyStatement.ts @@ -1,9 +1,9 @@ import MagicString from 'magic-string'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; -import { NodeBase } from './shared/Node'; +import { StatementBase } from './shared/Node'; -export default class EmptyStatement extends NodeBase { +export default class EmptyStatement extends StatementBase { type: NodeType.EmptyStatement; render (code: MagicString, _options: RenderOptions) { diff --git a/src/ast/nodes/ExpressionStatement.ts b/src/ast/nodes/ExpressionStatement.ts index 64cda3c2027..ce384cd44ae 100644 --- a/src/ast/nodes/ExpressionStatement.ts +++ b/src/ast/nodes/ExpressionStatement.ts @@ -1,9 +1,9 @@ import MagicString from 'magic-string'; import Scope from '../scopes/Scope'; import { RenderOptions } from '../../Module'; -import { NodeBase } from './shared/Node'; +import { StatementBase } from './shared/Node'; -export default class ExpressionStatement extends NodeBase { +export default class ExpressionStatement extends StatementBase { directive?: string; initialiseNode (_parentScope: Scope) { diff --git a/src/ast/nodes/ForInStatement.ts b/src/ast/nodes/ForInStatement.ts index dd60e03d99e..79326193ab0 100644 --- a/src/ast/nodes/ForInStatement.ts +++ b/src/ast/nodes/ForInStatement.ts @@ -5,7 +5,7 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import BlockStatement from './BlockStatement'; import { PatternNode } from './shared/Pattern'; import { NodeType } from './NodeType'; -import { ExpressionNode, NodeBase, Node } from './shared/Node'; +import { ExpressionNode, Node, StatementBase, StatementNode } from './shared/Node'; import { NO_SEMICOLON, RenderOptions } from '../../Module'; import MagicString from 'magic-string'; @@ -13,11 +13,11 @@ export function isForInStatement (node: Node): node is ForInStatement { return node.type === NodeType.ForInStatement; } -export default class ForInStatement extends NodeBase { +export default class ForInStatement extends StatementBase { type: NodeType.ForInStatement; left: VariableDeclaration | PatternNode; right: ExpressionNode; - body: Node; + body: StatementNode; hasEffects (options: ExecutionPathOptions): boolean { return ( diff --git a/src/ast/nodes/ForOfStatement.ts b/src/ast/nodes/ForOfStatement.ts index 8e6ff5a527b..22b69a298ab 100644 --- a/src/ast/nodes/ForOfStatement.ts +++ b/src/ast/nodes/ForOfStatement.ts @@ -5,7 +5,7 @@ import Scope from '../scopes/Scope'; import BlockStatement from './BlockStatement'; import { PatternNode } from './shared/Pattern'; import { NodeType } from './NodeType'; -import { ExpressionNode, NodeBase, Node } from './shared/Node'; +import { ExpressionNode, Node, StatementBase, StatementNode } from './shared/Node'; import { NO_SEMICOLON, RenderOptions } from '../../Module'; import MagicString from 'magic-string'; @@ -13,11 +13,11 @@ export function isForOfStatement (node: Node): node is ForOfStatement { return node.type === NodeType.ForOfStatement; } -export default class ForOfStatement extends NodeBase { +export default class ForOfStatement extends StatementBase { type: NodeType.ForOfStatement; left: VariableDeclaration | PatternNode; right: ExpressionNode; - body: Node; + body: StatementNode; bindNode () { this.left.reassignPath([], ExecutionPathOptions.create()); diff --git a/src/ast/nodes/ForStatement.ts b/src/ast/nodes/ForStatement.ts index 01307f2df1c..4bebcf9a8ba 100644 --- a/src/ast/nodes/ForStatement.ts +++ b/src/ast/nodes/ForStatement.ts @@ -3,7 +3,7 @@ import VariableDeclaration from './VariableDeclaration'; import ExecutionPathOptions from '../ExecutionPathOptions'; import Scope from '../scopes/Scope'; import { NodeType } from './NodeType'; -import { ExpressionNode, NodeBase, Node } from './shared/Node'; +import { ExpressionNode, Node, StatementBase, StatementNode } from './shared/Node'; import { NO_SEMICOLON, RenderOptions } from '../../Module'; import MagicString from 'magic-string'; @@ -11,12 +11,12 @@ export function isForStatement (node: Node): node is ForStatement { return node.type === NodeType.ForStatement; } -export default class ForStatement extends NodeBase { +export default class ForStatement extends StatementBase { type: NodeType.ForStatement; init: VariableDeclaration | ExpressionNode | null; test: ExpressionNode | null; update: ExpressionNode | null; - body: Node; + body: StatementNode; hasEffects (options: ExecutionPathOptions): boolean { return ( diff --git a/src/ast/nodes/IfStatement.ts b/src/ast/nodes/IfStatement.ts index 8b204562e4c..f6d5527d6b5 100644 --- a/src/ast/nodes/IfStatement.ts +++ b/src/ast/nodes/IfStatement.ts @@ -1,11 +1,11 @@ import extractNames from '../utils/extractNames'; import { UNKNOWN_VALUE } from '../values'; import Scope from '../scopes/Scope'; -import { ExpressionNode, Node, NodeBase } from './shared/Node'; +import { ExpressionNode, Node, StatementBase, StatementNode } from './shared/Node'; import { isVariableDeclaration } from './VariableDeclaration'; import MagicString from 'magic-string'; import { NodeType } from './NodeType'; -import { NodeRenderOptions, RenderOptions } from '../../Module'; +import { RenderOptions } from '../../Module'; // Statement types which may contain if-statements as direct children. const statementsWithIfStatements = new Set([ @@ -17,7 +17,7 @@ const statementsWithIfStatements = new Set([ 'WhileStatement' ]); -function getHoistedVars (node: Node, scope: Scope) { +function getHoistedVars (node: StatementNode, scope: Scope) { const hoistedVars: string[] = []; function visit (node: Node) { @@ -40,11 +40,11 @@ function getHoistedVars (node: Node, scope: Scope) { return hoistedVars; } -export default class IfStatement extends NodeBase { +export default class IfStatement extends StatementBase { type: NodeType.IfStatement; test: ExpressionNode; - consequent: Node; - alternate: Node | null; + consequent: StatementNode; + alternate: StatementNode | null; private testValue: any; private hoistedVars?: string[]; @@ -73,7 +73,7 @@ export default class IfStatement extends NodeBase { this.hoistedVars = []; } - render (code: MagicString, options: RenderOptions, { end }: NodeRenderOptions = {}) { + render (code: MagicString, options: RenderOptions) { if (this.module.graph.treeshake) { if (this.testValue === UNKNOWN_VALUE) { super.render(code, options); @@ -107,7 +107,7 @@ export default class IfStatement extends NodeBase { } else { code.remove( this.start, - this.alternate ? this.alternate.start : end || this.end + this.alternate ? this.alternate.start : this.end ); if (this.alternate) { diff --git a/src/ast/nodes/LabeledStatement.ts b/src/ast/nodes/LabeledStatement.ts index f35ad26b6d9..52f8178e806 100644 --- a/src/ast/nodes/LabeledStatement.ts +++ b/src/ast/nodes/LabeledStatement.ts @@ -1,12 +1,12 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import Identifier from './Identifier'; import { NodeType } from './NodeType'; -import { NodeBase, Node } from './shared/Node'; +import { StatementBase, StatementNode } from './shared/Node'; -export default class LabeledStatement extends NodeBase { +export default class LabeledStatement extends StatementBase { type: NodeType.LabeledStatement; label: Identifier; - body: Node; + body: StatementNode; hasEffects (options: ExecutionPathOptions) { return this.body.hasEffects( diff --git a/src/ast/nodes/Program.ts b/src/ast/nodes/Program.ts index 136e9614e90..b2e0455d445 100644 --- a/src/ast/nodes/Program.ts +++ b/src/ast/nodes/Program.ts @@ -1,12 +1,12 @@ import MagicString from 'magic-string'; -import { NodeBase, Node } from './shared/Node'; +import { NodeBase, StatementNode } from './shared/Node'; import { NodeType } from './NodeType'; import { RenderOptions } from '../../Module'; import { renderStatementList } from '../../utils/renderHelpers'; export default class Program extends NodeBase { type: NodeType.Program; - body: Node[]; + body: StatementNode[]; render (code: MagicString, options: RenderOptions) { if (this.body.length) { diff --git a/src/ast/nodes/ReturnStatement.ts b/src/ast/nodes/ReturnStatement.ts index 3e08a17aca0..797a13b29f7 100644 --- a/src/ast/nodes/ReturnStatement.ts +++ b/src/ast/nodes/ReturnStatement.ts @@ -1,9 +1,9 @@ import { UNKNOWN_EXPRESSION } from '../values'; import ExecutionPathOptions from '../ExecutionPathOptions'; import { NodeType } from './NodeType'; -import { ExpressionNode, NodeBase } from './shared/Node'; +import { ExpressionNode, StatementBase } from './shared/Node'; -export default class ReturnStatement extends NodeBase { +export default class ReturnStatement extends StatementBase { type: NodeType.ReturnStatement; argument: ExpressionNode | null; diff --git a/src/ast/nodes/SwitchCase.ts b/src/ast/nodes/SwitchCase.ts index 46bca53608e..8e4d29b98d9 100644 --- a/src/ast/nodes/SwitchCase.ts +++ b/src/ast/nodes/SwitchCase.ts @@ -1,4 +1,4 @@ -import { ExpressionNode, NodeBase, Node } from './shared/Node'; +import { ExpressionNode, NodeBase, StatementNode } from './shared/Node'; import { NodeType } from './NodeType'; import { findFirstOccurrenceOutsideComment, renderStatementList } from '../../utils/renderHelpers'; import { RenderOptions } from '../../Module'; @@ -7,7 +7,7 @@ import MagicString from 'magic-string'; export default class SwitchCase extends NodeBase { type: NodeType.SwitchCase; test: ExpressionNode | null; - consequent: Node[]; + consequent: StatementNode[]; includeInBundle () { let addedNewNodes = !this.included; diff --git a/src/ast/nodes/SwitchStatement.ts b/src/ast/nodes/SwitchStatement.ts index 7a93007c7c3..c730f78d658 100644 --- a/src/ast/nodes/SwitchStatement.ts +++ b/src/ast/nodes/SwitchStatement.ts @@ -3,9 +3,9 @@ import SwitchCase from './SwitchCase'; import ExecutionPathOptions from '../ExecutionPathOptions'; import Scope from '../scopes/Scope'; import { NodeType } from './NodeType'; -import { ExpressionNode, NodeBase } from './shared/Node'; +import { ExpressionNode, StatementBase } from './shared/Node'; -export default class SwitchStatement extends NodeBase { +export default class SwitchStatement extends StatementBase { type: NodeType.SwitchStatement; discriminant: ExpressionNode; cases: SwitchCase[]; diff --git a/src/ast/nodes/ThrowStatement.ts b/src/ast/nodes/ThrowStatement.ts index ef172096cd9..f010013ee4e 100644 --- a/src/ast/nodes/ThrowStatement.ts +++ b/src/ast/nodes/ThrowStatement.ts @@ -1,8 +1,8 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import { NodeType } from './NodeType'; -import { ExpressionNode, NodeBase } from './shared/Node'; +import { ExpressionNode, StatementBase } from './shared/Node'; -export default class ThrowStatement extends NodeBase { +export default class ThrowStatement extends StatementBase { type: NodeType.ThrowStatement; argument: ExpressionNode; diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index 1b05827c776..2dfe9ec0f01 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -60,7 +60,7 @@ export default class VariableDeclaration extends NodeBase { ); } - render (code: MagicString, options: RenderOptions, { start = this.start, end = this.end, noSemicolon }: NodeRenderOptions = {}) { + render (code: MagicString, options: RenderOptions, { start = this.start, end = this.end, isStatement }: NodeRenderOptions = {}) { const separatedNodes = getCommaSeparatedNodesWithSeparators( this.declarations, code, @@ -118,7 +118,7 @@ export default class VariableDeclaration extends NodeBase { separatorString = nextSeparatorString; } if (hasRenderedContent) { - this.renderDeclarationEnd(code, separatorString, lastSeparatorPos, renderedContentEnd, !noSemicolon); + this.renderDeclarationEnd(code, separatorString, lastSeparatorPos, renderedContentEnd, !isStatement); } else { code.remove(start, end); } diff --git a/src/ast/nodes/WhileStatement.ts b/src/ast/nodes/WhileStatement.ts index cb82c8a6358..ba7187b0451 100644 --- a/src/ast/nodes/WhileStatement.ts +++ b/src/ast/nodes/WhileStatement.ts @@ -1,11 +1,11 @@ import ExecutionPathOptions from '../ExecutionPathOptions'; import { NodeType } from './NodeType'; -import { ExpressionNode, NodeBase, Node } from './shared/Node'; +import { ExpressionNode, StatementBase, StatementNode } from './shared/Node'; -export default class WhileStatement extends NodeBase { +export default class WhileStatement extends StatementBase { type: NodeType.WhileStatement; test: ExpressionNode; - body: Node; + body: StatementNode; hasEffects (options: ExecutionPathOptions): boolean { return ( diff --git a/src/ast/nodes/index.ts b/src/ast/nodes/index.ts index 934377d51ad..08aae447688 100644 --- a/src/ast/nodes/index.ts +++ b/src/ast/nodes/index.ts @@ -54,7 +54,7 @@ import VariableDeclarator from './VariableDeclarator'; import VariableDeclaration from './VariableDeclaration'; import WhileStatement from './WhileStatement'; import YieldExpression from './YieldExpression'; -import { NodeBase } from './shared/Node'; +import { NodeBase, StatementBase } from './shared/Node'; const nodes: { [name: string]: typeof NodeBase @@ -109,7 +109,7 @@ const nodes: { TemplateLiteral, ThisExpression, ThrowStatement, - TryStatement: NodeBase, + TryStatement: StatementBase, UnaryExpression, UpdateExpression, VariableDeclarator, diff --git a/src/ast/nodes/shared/Node.ts b/src/ast/nodes/shared/Node.ts index ed61ba3b33e..71b682620eb 100644 --- a/src/ast/nodes/shared/Node.ts +++ b/src/ast/nodes/shared/Node.ts @@ -74,6 +74,8 @@ export interface Node extends Entity { someChild(callback: (node: Node) => boolean): boolean; } +export interface StatementNode extends Node {} + export interface ExpressionNode extends ExpressionEntity, Node {} export class NodeBase implements ExpressionNode { @@ -250,3 +252,5 @@ export class NodeBase implements ExpressionNode { return this.module.code.slice(this.start, this.end); } } + +export { NodeBase as StatementBase }; From d45a74cb0b383367d3e87e982d4a52c0b73eba76 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Tue, 13 Feb 2018 07:55:31 +0100 Subject: [PATCH 22/27] Reduce number of necessary slices by supplying start indices --- src/ast/nodes/ExportDefaultDeclaration.ts | 21 ++++---- src/ast/nodes/SwitchCase.ts | 4 +- src/utils/renderHelpers.ts | 64 +++++++++++------------ 3 files changed, 43 insertions(+), 46 deletions(-) diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index 751fcef7381..530874fac26 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -9,16 +9,18 @@ import { NodeRenderOptions, RenderOptions } from '../../Module'; import { findFirstOccurrenceOutsideComment } from '../../utils/renderHelpers'; import { isObjectExpression } from './ObjectExpression'; +const WHITESPACE = /\s/; + // The header ends at the first non-white-space after "default" -function getDeclarationStart (code: string) { - const headerLength = findFirstOccurrenceOutsideComment(code, 'default') + 7; - return headerLength + code.slice(headerLength).search(/\S/); +function getDeclarationStart (code: string, start = 0) { + start = findFirstOccurrenceOutsideComment(code, 'default', start) + 7; + while (WHITESPACE.test(code[start])) start++; + return start; } -function getIdInsertPosition (code: string, declarationKeyword: string) { - const declarationEnd = findFirstOccurrenceOutsideComment(code, declarationKeyword) + declarationKeyword.length; - code = code.slice(declarationEnd); - code = code.slice(0, findFirstOccurrenceOutsideComment(code, '{')); +function getIdInsertPosition (code: string, declarationKeyword: string, start = 0) { + const declarationEnd = findFirstOccurrenceOutsideComment(code, declarationKeyword, start) + declarationKeyword.length; + code = code.slice(declarationEnd, findFirstOccurrenceOutsideComment(code, '{', declarationEnd)); const generatorStarPos = findFirstOccurrenceOutsideComment(code, '*'); if (generatorStarPos === -1) { return declarationEnd; @@ -56,7 +58,7 @@ export default class ExportDefaultDeclaration extends NodeBase { } render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { - const declarationStart = this.start + getDeclarationStart(code.original.slice(this.start, this.end)); + const declarationStart = getDeclarationStart(code.original, this.start); if (isFunctionDeclaration(this.declaration)) { this.renderNamedDeclaration(code, declarationStart, 'function', this.declaration.id === null, options); @@ -82,8 +84,7 @@ export default class ExportDefaultDeclaration extends NodeBase { code.remove(this.start, declarationStart); if (needsId) { - const idInsertPos = declarationStart + getIdInsertPosition(code.original.slice(declarationStart, this.end), declarationKeyword); - code.appendLeft(idInsertPos, ` ${name}`); + code.appendLeft(getIdInsertPosition(code.original, declarationKeyword, declarationStart), ` ${name}`); } if (options.systemBindings && isClassDeclaration(this.declaration)) { code.appendRight(this.end, ` exports('default', ${name});`); diff --git a/src/ast/nodes/SwitchCase.ts b/src/ast/nodes/SwitchCase.ts index 8e4d29b98d9..dbfcc5a8400 100644 --- a/src/ast/nodes/SwitchCase.ts +++ b/src/ast/nodes/SwitchCase.ts @@ -29,8 +29,8 @@ export default class SwitchCase extends NodeBase { if (this.consequent.length) { const testEnd = this.test ? this.test.end - : this.start + findFirstOccurrenceOutsideComment(code.original.slice(this.start, this.end), 'default') + 7; - const consequentStart = testEnd + findFirstOccurrenceOutsideComment(code.original.slice(testEnd, this.end), ':') + 1; + : findFirstOccurrenceOutsideComment(code.original, 'default', this.start) + 7; + const consequentStart = findFirstOccurrenceOutsideComment(code.original, ':', testEnd) + 1; renderStatementList(this.consequent, code, consequentStart, this.end, options); } else { super.render(code, options); diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index 70011ea7970..bdaf4c28646 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -2,45 +2,41 @@ import { Node } from '../ast/nodes/shared/Node'; import MagicString from 'magic-string'; import { RenderOptions } from '../Module'; -export function findFirstOccurrenceOutsideComment (code: string, searchString: string) { - let codeStart = 0; - let commentStart, commentLength, searchPos; +const NON_WHITESPACE = /\S/; + +// It is the responsibility of the caller to make sure this is not searching a potentially very long comment-less +// string for a comment; experiments show, however, that this is only relevant for about 1000+ characters +export function findFirstOccurrenceOutsideComment (code: string, searchString: string, start: number = 0) { + let commentStart, searchPos; while (true) { - commentStart = code.indexOf('/'); - searchPos = (commentStart === -1 ? code : code.slice(0, commentStart)).indexOf(searchString); - if (searchPos !== -1 || commentStart === -1) { - break; - } - code = code.slice(commentStart + 1); - codeStart += commentStart + 1; - if (code[0] === '*') { - commentLength = code.indexOf('*/') + 2; - } else if (code[0] === '/') { - commentLength = code.indexOf('\n') + 1; - } else { - continue; + commentStart = code.indexOf('/', start); + searchPos = code.indexOf(searchString, start); + if (commentStart === -1) break; + if (searchPos >= commentStart) { + searchPos = -1; + } else if (searchPos !== -1) break; + start = commentStart + 1; + if (code[start] === '*') { + start = code.indexOf('*/', start) + 2; + } else if (code[start] === '/') { + start = code.indexOf('\n', start) + 1; } - code = code.slice(commentLength); - codeStart += commentLength; } - return searchPos === -1 ? -1 : codeStart + searchPos; + return searchPos; } -export function findFirstLineBreakOutsideComment (code: string) { - let codeStart = 0; - let commentStart, commentLength, lineBreakPos; +function findFirstLineBreakOutsideComment (code: string, start: number = 0) { + let commentStart, lineBreakPos; while (true) { - commentStart = code.indexOf('/*'); - lineBreakPos = (commentStart !== -1 ? code.slice(0, commentStart) : code).indexOf('\n'); - if (lineBreakPos !== -1 || commentStart === -1) { - break; - } - code = code.slice(commentStart); - commentLength = code.indexOf('*/') + 2; - code = code.slice(commentLength); - codeStart += commentStart + commentLength; + commentStart = code.indexOf('/*', start); + lineBreakPos = code.indexOf('\n', start); + if (commentStart === -1) break; + if (lineBreakPos >= commentStart) { + lineBreakPos = -1; + } else if (lineBreakPos !== -1) break; + start = code.indexOf('*/', commentStart) + 2; } - return lineBreakPos === -1 ? -1 : codeStart + lineBreakPos; + return lineBreakPos; } export function renderStatementList (statements: Node[], code: MagicString, start: number, end: number, options: RenderOptions) { @@ -80,7 +76,7 @@ export function getCommaSeparatedNodesWithSeparators ( let currentNode, currentNodeStart, separator; let nextNode = nodes[0]; let nextNodeStart = start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start)) + 1; - nextNodeStart += code.original.slice(nextNodeStart, nextNode.start + 1).search(/\S/); + nextNodeStart += code.original.slice(nextNodeStart, nextNode.start + 1).search(NON_WHITESPACE); for (let nextIndex = 1; nextIndex <= nodes.length; nextIndex++) { currentNode = nextNode; @@ -98,7 +94,7 @@ export function getCommaSeparatedNodesWithSeparators ( nextNodeStart = separator + 1 + findFirstLineBreakOutsideComment( code.original.slice(separator + 1, nextNode.start) ) + 1; - nextNodeStart += code.original.slice(nextNodeStart, nextNode.start + 1).search(/\S/); + nextNodeStart += code.original.slice(nextNodeStart, nextNode.start + 1).search(NON_WHITESPACE); splitUpNodes.push({ node: currentNode, start: currentNodeStart, end: nextNodeStart, separator }); From adeebc23f8f990b86073e2dce6ae177d633443f6 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Tue, 13 Feb 2018 08:41:02 +0100 Subject: [PATCH 23/27] Only calculate boundaries if necessary --- src/ast/nodes/ExportAllDeclaration.ts | 2 ++ src/ast/nodes/ExportDefaultDeclaration.ts | 2 ++ src/ast/nodes/ExportNamedDeclaration.ts | 8 +++---- src/ast/nodes/ImportDeclaration.ts | 2 ++ src/ast/nodes/shared/Node.ts | 1 + src/utils/renderHelpers.ts | 27 ++++++++++++++++------- 6 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/ast/nodes/ExportAllDeclaration.ts b/src/ast/nodes/ExportAllDeclaration.ts index d99f1eed0e1..f9fefa46a0c 100644 --- a/src/ast/nodes/ExportAllDeclaration.ts +++ b/src/ast/nodes/ExportAllDeclaration.ts @@ -8,9 +8,11 @@ export default class ExportAllDeclaration extends NodeBase { type: NodeType.ExportAllDeclaration; source: Literal; isExportDeclaration: true; + needsBoundaries: true; initialiseNode () { this.isExportDeclaration = true; + this.needsBoundaries = true; } render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index 530874fac26..0b5898c8c87 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -33,6 +33,7 @@ const needsToBeWrapped = isObjectExpression; export default class ExportDefaultDeclaration extends NodeBase { type: NodeType.ExportDefaultDeclaration; declaration: FunctionDeclaration | ClassDeclaration | ExpressionNode; + needsBoundaries: true; private _declarationName: string; isExportDeclaration: true; @@ -48,6 +49,7 @@ export default class ExportDefaultDeclaration extends NodeBase { initialiseNode () { this.isExportDeclaration = true; + this.needsBoundaries = true; this._declarationName = ((this.declaration).id && (this.declaration).id.name) || (this.declaration).name; diff --git a/src/ast/nodes/ExportNamedDeclaration.ts b/src/ast/nodes/ExportNamedDeclaration.ts index 0480869b4c5..446b27c6f54 100644 --- a/src/ast/nodes/ExportNamedDeclaration.ts +++ b/src/ast/nodes/ExportNamedDeclaration.ts @@ -15,6 +15,7 @@ export default class ExportNamedDeclaration extends NodeBase { specifiers: ExportSpecifier[]; source: Literal | null; + needsBoundaries: true; isExportDeclaration: true; bindChildren () { @@ -26,10 +27,6 @@ export default class ExportNamedDeclaration extends NodeBase { return this.declaration && this.declaration.hasEffects(options); } - initialiseNode () { - this.isExportDeclaration = true; - } - render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { if (this.declaration === null) { code.remove(start, end); @@ -39,3 +36,6 @@ export default class ExportNamedDeclaration extends NodeBase { } } } + +ExportNamedDeclaration.prototype.needsBoundaries = true; +ExportNamedDeclaration.prototype.isExportDeclaration = true; diff --git a/src/ast/nodes/ImportDeclaration.ts b/src/ast/nodes/ImportDeclaration.ts index 6d64d62f696..4e772ff03db 100644 --- a/src/ast/nodes/ImportDeclaration.ts +++ b/src/ast/nodes/ImportDeclaration.ts @@ -12,11 +12,13 @@ export default class ImportDeclaration extends NodeBase { isImportDeclaration: true; specifiers: (ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier)[]; source: Literal; + needsBoundaries: true; bindChildren () { } initialiseNode () { this.isImportDeclaration = true; + this.needsBoundaries = true; } render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { diff --git a/src/ast/nodes/shared/Node.ts b/src/ast/nodes/shared/Node.ts index 71b682620eb..abd47a653cd 100644 --- a/src/ast/nodes/shared/Node.ts +++ b/src/ast/nodes/shared/Node.ts @@ -15,6 +15,7 @@ export interface Node extends Entity { included: boolean; keys: string[]; module: Module; + needsBoundaries?: boolean; parent: Node | { type?: string }; start: number; type: string; diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index bdaf4c28646..a425d74124e 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -41,21 +41,32 @@ function findFirstLineBreakOutsideComment (code: string, start: number = 0) { export function renderStatementList (statements: Node[], code: MagicString, start: number, end: number, options: RenderOptions) { if (statements.length === 0) return; - let currentNode, currentNodeStart; + let currentNode, currentNodeStart, currentNodeNeedsBoundaries, nextNodeStart; let nextNode = statements[0]; - let nextNodeStart = start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start)) + 1; + let nextNodeNeedsBoundaries = !nextNode.included || nextNode.needsBoundaries; + if (nextNodeNeedsBoundaries) { + nextNodeStart = start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start)) + 1; + } for (let nextIndex = 1; nextIndex <= statements.length; nextIndex++) { currentNode = nextNode; currentNodeStart = nextNodeStart; + currentNodeNeedsBoundaries = nextNodeNeedsBoundaries; nextNode = statements[nextIndex]; - nextNodeStart = currentNode.end + findFirstLineBreakOutsideComment( - code.original.slice(currentNode.end, nextNode === undefined ? end : nextNode.start) - ) + 1; - if (currentNode.included) { - currentNode.render(code, options, { start: currentNodeStart, end: nextNodeStart }); + nextNodeNeedsBoundaries = nextNode === undefined ? false : !nextNode.included || nextNode.needsBoundaries; + if (currentNodeNeedsBoundaries || nextNodeNeedsBoundaries) { + nextNodeStart = currentNode.end + findFirstLineBreakOutsideComment( + code.original.slice(currentNode.end, nextNode === undefined ? end : nextNode.start) + ) + 1; + if (currentNode.included) { + currentNodeNeedsBoundaries + ? currentNode.render(code, options, { start: currentNodeStart, end: nextNodeStart }) + : currentNode.render(code, options); + } else { + code.remove(currentNodeStart, nextNodeStart); + } } else { - code.remove(currentNodeStart, nextNodeStart); + currentNode.render(code, options); } } } From 8ecadf2f94d12ab174de45fd82b2b8bd985044e3 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Tue, 13 Feb 2018 08:46:59 +0100 Subject: [PATCH 24/27] Store flags for AST nodes directly on the prototype --- src/ast/nodes/ExportAllDeclaration.ts | 8 +++----- src/ast/nodes/ExportDefaultDeclaration.ts | 18 ++++++++++-------- src/ast/nodes/ImportDeclaration.ts | 11 +++++------ 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/ast/nodes/ExportAllDeclaration.ts b/src/ast/nodes/ExportAllDeclaration.ts index f9fefa46a0c..b7704158b43 100644 --- a/src/ast/nodes/ExportAllDeclaration.ts +++ b/src/ast/nodes/ExportAllDeclaration.ts @@ -10,12 +10,10 @@ export default class ExportAllDeclaration extends NodeBase { isExportDeclaration: true; needsBoundaries: true; - initialiseNode () { - this.isExportDeclaration = true; - this.needsBoundaries = true; - } - render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { code.remove(start, end); } } + +ExportAllDeclaration.prototype.needsBoundaries = true; +ExportAllDeclaration.prototype.isExportDeclaration = true; diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index 0b5898c8c87..7fe08f37576 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -33,28 +33,27 @@ const needsToBeWrapped = isObjectExpression; export default class ExportDefaultDeclaration extends NodeBase { type: NodeType.ExportDefaultDeclaration; declaration: FunctionDeclaration | ClassDeclaration | ExpressionNode; - needsBoundaries: true; - private _declarationName: string; + needsBoundaries: true; isExportDeclaration: true; variable: ExportDefaultVariable; + private declarationName: string; + bindNode () { - if (this._declarationName) { + if (this.declarationName) { this.variable.setOriginalVariable( - this.scope.findVariable(this._declarationName) + this.scope.findVariable(this.declarationName) ); } } initialiseNode () { - this.isExportDeclaration = true; - this.needsBoundaries = true; - this._declarationName = + this.declarationName = ((this.declaration).id && (this.declaration).id.name) || (this.declaration).name; this.variable = this.scope.addExportDefaultDeclaration( - this._declarationName || this.module.basename(), + this.declarationName || this.module.basename(), this ); } @@ -117,3 +116,6 @@ export default class ExportDefaultDeclaration extends NodeBase { } } } + +ExportDefaultDeclaration.prototype.needsBoundaries = true; +ExportDefaultDeclaration.prototype.isExportDeclaration = true; diff --git a/src/ast/nodes/ImportDeclaration.ts b/src/ast/nodes/ImportDeclaration.ts index 4e772ff03db..3706626f0ca 100644 --- a/src/ast/nodes/ImportDeclaration.ts +++ b/src/ast/nodes/ImportDeclaration.ts @@ -9,19 +9,18 @@ import { NodeRenderOptions, RenderOptions } from '../../Module'; export default class ImportDeclaration extends NodeBase { type: NodeType.ImportDeclaration; - isImportDeclaration: true; specifiers: (ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier)[]; source: Literal; + + isImportDeclaration: true; needsBoundaries: true; bindChildren () { } - initialiseNode () { - this.isImportDeclaration = true; - this.needsBoundaries = true; - } - render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { code.remove(start, end); } } + +ImportDeclaration.prototype.isImportDeclaration = true; +ImportDeclaration.prototype.needsBoundaries = true; From 114149f386007b1f9c77d35cab5c12265dc892d4 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Wed, 14 Feb 2018 06:11:26 +0100 Subject: [PATCH 25/27] Improve variable declaration performance --- src/Module.ts | 4 +- src/ast/nodes/ExportAllDeclaration.ts | 3 +- src/ast/nodes/ExportDefaultDeclaration.ts | 3 +- src/ast/nodes/ExportNamedDeclaration.ts | 3 +- src/ast/nodes/ImportDeclaration.ts | 3 +- src/ast/nodes/VariableDeclaration.ts | 38 +++++++++++---- src/utils/object.ts | 4 +- src/utils/renderHelpers.ts | 46 +++++++++---------- .../_expected/amd.js | 2 +- .../_expected/cjs.js | 2 +- .../_expected/es.js | 2 +- .../_expected/iife.js | 2 +- .../_expected/umd.js | 2 +- 13 files changed, 67 insertions(+), 47 deletions(-) diff --git a/src/Module.ts b/src/Module.ts index 38f42e2226e..4aa1136fae3 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -112,10 +112,10 @@ export interface RenderOptions { export interface NodeRenderOptions { start?: number, end?: number, - isStatement?: boolean + isNoStatement?: boolean } -export const NO_SEMICOLON: NodeRenderOptions = { isStatement: true }; +export const NO_SEMICOLON: NodeRenderOptions = { isNoStatement: true }; export default class Module { type: 'Module'; diff --git a/src/ast/nodes/ExportAllDeclaration.ts b/src/ast/nodes/ExportAllDeclaration.ts index b7704158b43..402c40b0dba 100644 --- a/src/ast/nodes/ExportAllDeclaration.ts +++ b/src/ast/nodes/ExportAllDeclaration.ts @@ -3,6 +3,7 @@ import Literal from './Literal'; import MagicString from 'magic-string'; import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; +import { BLANK } from '../../utils/object'; export default class ExportAllDeclaration extends NodeBase { type: NodeType.ExportAllDeclaration; @@ -10,7 +11,7 @@ export default class ExportAllDeclaration extends NodeBase { isExportDeclaration: true; needsBoundaries: true; - render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { + render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = BLANK) { code.remove(start, end); } } diff --git a/src/ast/nodes/ExportDefaultDeclaration.ts b/src/ast/nodes/ExportDefaultDeclaration.ts index 7fe08f37576..ca57ead1d91 100644 --- a/src/ast/nodes/ExportDefaultDeclaration.ts +++ b/src/ast/nodes/ExportDefaultDeclaration.ts @@ -8,6 +8,7 @@ import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; import { findFirstOccurrenceOutsideComment } from '../../utils/renderHelpers'; import { isObjectExpression } from './ObjectExpression'; +import { BLANK } from '../../utils/object'; const WHITESPACE = /\s/; @@ -58,7 +59,7 @@ export default class ExportDefaultDeclaration extends NodeBase { ); } - render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { + render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = BLANK) { const declarationStart = getDeclarationStart(code.original, this.start); if (isFunctionDeclaration(this.declaration)) { diff --git a/src/ast/nodes/ExportNamedDeclaration.ts b/src/ast/nodes/ExportNamedDeclaration.ts index 446b27c6f54..4669db26103 100644 --- a/src/ast/nodes/ExportNamedDeclaration.ts +++ b/src/ast/nodes/ExportNamedDeclaration.ts @@ -8,6 +8,7 @@ import ClassDeclaration from './ClassDeclaration'; import VariableDeclaration from './VariableDeclaration'; import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; +import { BLANK } from '../../utils/object'; export default class ExportNamedDeclaration extends NodeBase { type: NodeType.ExportNamedDeclaration; @@ -27,7 +28,7 @@ export default class ExportNamedDeclaration extends NodeBase { return this.declaration && this.declaration.hasEffects(options); } - render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = {}) { + render (code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = BLANK) { if (this.declaration === null) { code.remove(start, end); } else { diff --git a/src/ast/nodes/ImportDeclaration.ts b/src/ast/nodes/ImportDeclaration.ts index 3706626f0ca..d630f7654b8 100644 --- a/src/ast/nodes/ImportDeclaration.ts +++ b/src/ast/nodes/ImportDeclaration.ts @@ -6,6 +6,7 @@ import ImportNamespaceSpecifier from './ImportNamespaceSpecifier'; import MagicString from 'magic-string'; import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; +import { BLANK } from '../../utils/object'; export default class ImportDeclaration extends NodeBase { type: NodeType.ImportDeclaration; @@ -17,7 +18,7 @@ export default class ImportDeclaration extends NodeBase { bindChildren () { } - render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = {}) { + render (code: MagicString, _options: RenderOptions, { start, end }: NodeRenderOptions = BLANK) { code.remove(start, end); } } diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index 2dfe9ec0f01..bd4a0efafce 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -5,9 +5,10 @@ import MagicString from 'magic-string'; import { ObjectPath } from '../variables/VariableReassignmentTracker'; import { NodeType } from './NodeType'; import { NodeRenderOptions, RenderOptions } from '../../Module'; -import { getCommaSeparatedNodesWithSeparators } from '../../utils/renderHelpers'; +import { getCommaSeparatedNodesWithBoundaries } from '../../utils/renderHelpers'; import { isIdentifier } from './Identifier'; import Variable from '../variables/Variable'; +import { BLANK } from '../../utils/object'; function isReassignedExportsMember (variable: Variable): boolean { return variable.safeName && variable.safeName.indexOf('.') !== -1 && variable.exportName && variable.isReassigned; @@ -60,14 +61,31 @@ export default class VariableDeclaration extends NodeBase { ); } - render (code: MagicString, options: RenderOptions, { start = this.start, end = this.end, isStatement }: NodeRenderOptions = {}) { - const separatedNodes = getCommaSeparatedNodesWithSeparators( + render (code: MagicString, options: RenderOptions, nodeRenderOptions: NodeRenderOptions = BLANK) { + if (this.declarations.every(declarator => declarator.included && ( + !declarator.id.variable || !declarator.id.variable.exportName + )) + ) { + for (const declarator of this.declarations) { + declarator.render(code, options); + if (!nodeRenderOptions.isNoStatement && code.original[this.end - 1] !== ';') { + code.appendLeft(this.end, ';'); + } + } + } else { + this.renderReplacedDeclarations(code, options, nodeRenderOptions); + } + } + + private renderReplacedDeclarations ( + code: MagicString, options: RenderOptions, { start = this.start, end = this.end, isNoStatement }: NodeRenderOptions) { + const separatedNodes = getCommaSeparatedNodesWithBoundaries( this.declarations, code, this.start + this.kind.length, this.end - (code.original[this.end - 1] === ';' ? 1 : 0) ); - let renderedContentEnd; + let actualContentEnd, renderedContentEnd; if (/\n\s*$/.test(code.slice(this.start, separatedNodes[0].start))) { renderedContentEnd = this.start + this.kind.length; } else { @@ -78,7 +96,7 @@ export default class VariableDeclaration extends NodeBase { let isInDeclaration = false; let hasRenderedContent = false; let separatorString = '', leadingString, nextSeparatorString; - for (let { node, start, separator, end } of separatedNodes) { + for (const { node, start, separator, contentEnd, end } of separatedNodes) { if (!node.included || (isIdentifier(node.id) && isReassignedExportsMember(node.id.variable) && node.init === null)) { code.remove(start, end); continue; @@ -112,13 +130,14 @@ export default class VariableDeclaration extends NodeBase { code.appendLeft(renderedContentEnd, leadingString); } node.render(code, options); + actualContentEnd = contentEnd; renderedContentEnd = end; hasRenderedContent = true; lastSeparatorPos = separator; separatorString = nextSeparatorString; } if (hasRenderedContent) { - this.renderDeclarationEnd(code, separatorString, lastSeparatorPos, renderedContentEnd, !isStatement); + this.renderDeclarationEnd(code, separatorString, lastSeparatorPos, actualContentEnd, renderedContentEnd, !isNoStatement); } else { code.remove(start, end); } @@ -128,6 +147,7 @@ export default class VariableDeclaration extends NodeBase { code: MagicString, separatorString: string, lastSeparatorPos: number, + actualContentEnd: number, renderedContentEnd: number, addSemicolon: boolean ) { @@ -138,10 +158,8 @@ export default class VariableDeclaration extends NodeBase { separatorString += ';'; } if (lastSeparatorPos !== null) { - let actualContentEnd = lastSeparatorPos + code.original.slice(lastSeparatorPos, renderedContentEnd).search(/\s*$/); - // Do not remove trailing white-space if we might remove an essential comment-closing line-break - if (code.original[actualContentEnd] === '\n' && code.original[this.end] !== '\n') { - actualContentEnd = renderedContentEnd; + if (code.original[this.end] === '\n' && code.original[actualContentEnd - 1] === '\n') { + actualContentEnd--; } if (actualContentEnd === lastSeparatorPos + 1) { code.overwrite(lastSeparatorPos, renderedContentEnd, separatorString); diff --git a/src/utils/object.ts b/src/utils/object.ts index 7b1efbd14d2..868300fcae6 100644 --- a/src/utils/object.ts +++ b/src/utils/object.ts @@ -4,11 +4,13 @@ export function blank () { return Object.create(null); } +export const BLANK = blank(); + export function forOwn (object: { [key: string]: T }, func: (value: T, key: string) => void) { Object.keys(object).forEach(key => func(object[key], key)); } -export function assign (target: T, source: U): T & U +export function assign (target: T, source: U): T & U export function assign (target: any, ...sources: any[]): any { sources.forEach(source => { for (const key in source) { diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index a425d74124e..1c20dc998da 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -2,10 +2,6 @@ import { Node } from '../ast/nodes/shared/Node'; import MagicString from 'magic-string'; import { RenderOptions } from '../Module'; -const NON_WHITESPACE = /\S/; - -// It is the responsibility of the caller to make sure this is not searching a potentially very long comment-less -// string for a comment; experiments show, however, that this is only relevant for about 1000+ characters export function findFirstOccurrenceOutsideComment (code: string, searchString: string, start: number = 0) { let commentStart, searchPos; while (true) { @@ -72,7 +68,7 @@ export function renderStatementList (statements: Node[], code: MagicString, star } // This assumes that the first character is not part of the first node -export function getCommaSeparatedNodesWithSeparators ( +export function getCommaSeparatedNodesWithBoundaries ( nodes: N[], code: MagicString, start: number, @@ -81,35 +77,35 @@ export function getCommaSeparatedNodesWithSeparators ( node: N; start: number; separator: number | null; + contentEnd: number, end: number; })[] { const splitUpNodes = []; - let currentNode, currentNodeStart, separator; - let nextNode = nodes[0]; - let nextNodeStart = start + findFirstLineBreakOutsideComment(code.original.slice(start, nextNode.start)) + 1; - nextNodeStart += code.original.slice(nextNodeStart, nextNode.start + 1).search(NON_WHITESPACE); + let node, nextNode, nextNodeStart, contentEnd, char; + let separator = start - 1; - for (let nextIndex = 1; nextIndex <= nodes.length; nextIndex++) { - currentNode = nextNode; - currentNodeStart = nextNodeStart; + for (let nextIndex = 0; nextIndex < nodes.length; nextIndex++) { nextNode = nodes[nextIndex]; - - if (nextNode === undefined) { - splitUpNodes.push({ - node: currentNode, start: currentNodeStart, end, separator: null - }); - } else { - separator = currentNode.end + findFirstOccurrenceOutsideComment( - code.original.slice(currentNode.end, nextNode.start), ',' + if (node !== undefined) { + separator = node.end + findFirstOccurrenceOutsideComment( + code.original.slice(node.end, nextNode.start), ',' ); - nextNodeStart = separator + 1 + findFirstLineBreakOutsideComment( - code.original.slice(separator + 1, nextNode.start) - ) + 1; - nextNodeStart += code.original.slice(nextNodeStart, nextNode.start + 1).search(NON_WHITESPACE); + } + nextNodeStart = contentEnd = separator + 2 + findFirstLineBreakOutsideComment( + code.original.slice(separator + 1, nextNode.start) + ); + while (char = code.original.charCodeAt(nextNodeStart), + char === 32 /*" "*/ || char === 9 /*"\t"*/ || char === 10 /*"\n"*/ || char === 13/*"\r"*/) nextNodeStart++; + if (node !== undefined) { splitUpNodes.push({ - node: currentNode, start: currentNodeStart, end: nextNodeStart, separator + node, start, contentEnd, separator, end: nextNodeStart }); } + node = nextNode; + start = nextNodeStart; } + splitUpNodes.push({ + node, start, separator: null, contentEnd: end, end + }); return splitUpNodes; } diff --git a/test/form/samples/render-removed-declarations/_expected/amd.js b/test/form/samples/render-removed-declarations/_expected/amd.js index 903379b1cb5..b18e5bff6cd 100644 --- a/test/form/samples/render-removed-declarations/_expected/amd.js +++ b/test/form/samples/render-removed-declarations/_expected/amd.js @@ -52,7 +52,7 @@ define(function () { 'use strict'; // -> No line-break after declaration var kept1 = 1; // retained - console.log(1); + console.log(1); console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/cjs.js b/test/form/samples/render-removed-declarations/_expected/cjs.js index 3a97d57b2a7..a86721c9aff 100644 --- a/test/form/samples/render-removed-declarations/_expected/cjs.js +++ b/test/form/samples/render-removed-declarations/_expected/cjs.js @@ -52,6 +52,6 @@ var kept1 = 1; // retained // -> No line-break after declaration var kept1 = 1; // retained - console.log(1); +console.log(1); console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/es.js b/test/form/samples/render-removed-declarations/_expected/es.js index 4dcddb25723..3c3af3e03b7 100644 --- a/test/form/samples/render-removed-declarations/_expected/es.js +++ b/test/form/samples/render-removed-declarations/_expected/es.js @@ -50,6 +50,6 @@ var kept1 = 1; // retained // -> No line-break after declaration var kept1 = 1; // retained - console.log(1); +console.log(1); console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/iife.js b/test/form/samples/render-removed-declarations/_expected/iife.js index e99fc5c258c..0efd66aa43c 100644 --- a/test/form/samples/render-removed-declarations/_expected/iife.js +++ b/test/form/samples/render-removed-declarations/_expected/iife.js @@ -53,7 +53,7 @@ // -> No line-break after declaration var kept1 = 1; // retained - console.log(1); + console.log(1); console.log( kept1, kept2 ); diff --git a/test/form/samples/render-removed-declarations/_expected/umd.js b/test/form/samples/render-removed-declarations/_expected/umd.js index 02e98a1a6a0..2875c40099e 100644 --- a/test/form/samples/render-removed-declarations/_expected/umd.js +++ b/test/form/samples/render-removed-declarations/_expected/umd.js @@ -56,7 +56,7 @@ // -> No line-break after declaration var kept1 = 1; // retained - console.log(1); + console.log(1); console.log( kept1, kept2 ); From 22aa1fb7541deb3d3a6b305898902ccb06b7d0c2 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Wed, 14 Feb 2018 10:10:09 +0100 Subject: [PATCH 26/27] * Use charCodeAt where possible to improve performance * Properly handle \r\n line-breaks --- src/ast/nodes/VariableDeclaration.ts | 14 ++++++++++---- src/utils/renderHelpers.ts | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/ast/nodes/VariableDeclaration.ts b/src/ast/nodes/VariableDeclaration.ts index bd4a0efafce..9d20646f534 100644 --- a/src/ast/nodes/VariableDeclaration.ts +++ b/src/ast/nodes/VariableDeclaration.ts @@ -68,7 +68,7 @@ export default class VariableDeclaration extends NodeBase { ) { for (const declarator of this.declarations) { declarator.render(code, options); - if (!nodeRenderOptions.isNoStatement && code.original[this.end - 1] !== ';') { + if (!nodeRenderOptions.isNoStatement && code.original.charCodeAt(this.end - 1) !== 59 /*";"*/) { code.appendLeft(this.end, ';'); } } @@ -83,7 +83,7 @@ export default class VariableDeclaration extends NodeBase { this.declarations, code, this.start + this.kind.length, - this.end - (code.original[this.end - 1] === ';' ? 1 : 0) + this.end - (code.original.charCodeAt(this.end - 1) === 59 /*";"*/ ? 1 : 0) ); let actualContentEnd, renderedContentEnd; if (/\n\s*$/.test(code.slice(this.start, separatedNodes[0].start))) { @@ -151,15 +151,21 @@ export default class VariableDeclaration extends NodeBase { renderedContentEnd: number, addSemicolon: boolean ) { - if (code.original[this.end - 1] === ';') { + if (code.original.charCodeAt(this.end - 1) === 59 /*";"*/) { code.remove(this.end - 1, this.end); } if (addSemicolon) { separatorString += ';'; } if (lastSeparatorPos !== null) { - if (code.original[this.end] === '\n' && code.original[actualContentEnd - 1] === '\n') { + if ( + code.original.charCodeAt(actualContentEnd - 1) === 10 /*"\n"*/ + && (code.original.charCodeAt(this.end) === 10 /*"\n"*/ || code.original.charCodeAt(this.end) === 13 /*"\r"*/) + ) { actualContentEnd--; + if (code.original.charCodeAt(actualContentEnd) === 13 /*"\r"*/) { + actualContentEnd--; + } } if (actualContentEnd === lastSeparatorPos + 1) { code.overwrite(lastSeparatorPos, renderedContentEnd, separatorString); diff --git a/src/utils/renderHelpers.ts b/src/utils/renderHelpers.ts index 1c20dc998da..463c9afc219 100644 --- a/src/utils/renderHelpers.ts +++ b/src/utils/renderHelpers.ts @@ -12,9 +12,9 @@ export function findFirstOccurrenceOutsideComment (code: string, searchString: s searchPos = -1; } else if (searchPos !== -1) break; start = commentStart + 1; - if (code[start] === '*') { + if (code.charCodeAt(start) === 42 /*"*"*/) { start = code.indexOf('*/', start) + 2; - } else if (code[start] === '/') { + } else if (code.charCodeAt(start) === 47 /*"/"*/) { start = code.indexOf('\n', start) + 1; } } From bb8b81d2a9970517cf119b38acb26d18e6fb27f6 Mon Sep 17 00:00:00 2001 From: Lukas Taegert Date: Thu, 15 Feb 2018 06:23:55 +0100 Subject: [PATCH 27/27] Slightly clean up source map removal --- src/Module.ts | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/Module.ts b/src/Module.ts index 4aa1136fae3..d843ad69f37 100644 --- a/src/Module.ts +++ b/src/Module.ts @@ -235,17 +235,7 @@ export default class Module { filename: this.excludeFromSourcemap ? null : this.id, // don't include plugin helpers in sourcemap indentExclusionRanges: [] }); - - // remove existing sourceMappingURL comments - this.comments = this.comments.filter(comment => { - //only one line comment can contain source maps - const isSourceMapComment = - !comment.block && SOURCEMAPPING_URL_RE.test(comment.text); - if (isSourceMapComment) { - this.magicString.remove(comment.start, comment.end); - } - return !isSourceMapComment; - }); + this.removeExistingSourceMap(); timeStart('analyse'); @@ -254,6 +244,14 @@ export default class Module { timeEnd('analyse'); } + private removeExistingSourceMap(){ + this.comments.forEach(comment => { + if (!comment.block && SOURCEMAPPING_URL_RE.test(comment.text)) { + this.magicString.remove(comment.start, comment.end); + } + }); + } + private addExport (node: ExportAllDeclaration | ExportNamedDeclaration | ExportDefaultDeclaration) { const source = (node).source && (node).source.value;