Skip to content

Commit

Permalink
Detect side-effects in tagged template expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
lukastaegert committed Jul 29, 2017
1 parent b7a4edf commit 8071790
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 0 deletions.
43 changes: 43 additions & 0 deletions src/ast/nodes/TaggedTemplateExpression.js
@@ -0,0 +1,43 @@
import Node from '../Node.js';
import isProgramLevel from '../utils/isProgramLevel.js';
import callHasEffects from './shared/callHasEffects.js';

export default class TaggedTemplateExpression extends Node {
bind ( scope ) {
if ( this.tag.type === 'Identifier' ) {
const declaration = scope.findDeclaration( this.tag.name );

if ( declaration.isNamespace ) {
this.module.error({
code: 'CANNOT_CALL_NAMESPACE',
message: `Cannot call a namespace ('${this.tag.name}')`
}, this.start );
}

if ( this.tag.name === 'eval' && declaration.isGlobal ) {
this.module.warn({
code: 'EVAL',
message: `Use of eval is strongly discouraged, as it poses security risks and may cause issues with minification`,
url: 'https://github.com/rollup/rollup/wiki/Troubleshooting#avoiding-eval'
}, this.start );
}
}

super.bind( scope );
}

hasEffects ( scope ) {
return this.quasi.hasEffects(scope) || callHasEffects( scope, this.tag, false );
}

initialise ( scope ) {
if ( isProgramLevel( this ) ) {
this.module.bundle.dependentExpressions.push( this );
}
super.initialise( scope );
}

isUsedByBundle () {
return this.hasEffects( this.findScope() );
}
}
2 changes: 2 additions & 0 deletions src/ast/nodes/index.js
Expand Up @@ -28,6 +28,7 @@ import NewExpression from './NewExpression.js';
import ObjectExpression from './ObjectExpression.js';
import ReturnStatement from './ReturnStatement.js';
import Statement from './shared/Statement.js';
import TaggedTemplateExpression from './TaggedTemplateExpression.js';
import TemplateLiteral from './TemplateLiteral.js';
import ThisExpression from './ThisExpression.js';
import ThrowStatement from './ThrowStatement.js';
Expand Down Expand Up @@ -68,6 +69,7 @@ export default {
ObjectExpression,
ReturnStatement,
SwitchStatement: Statement,
TaggedTemplateExpression,
TemplateLiteral,
ThisExpression,
ThrowStatement,
Expand Down
6 changes: 6 additions & 0 deletions test/form/side-effects-in-template-literals/_config.js
@@ -0,0 +1,6 @@
module.exports = {
description: 'detects side-effects in template literals and tagged template expressions',
options: {
moduleName: 'myBundle'
}
};
27 changes: 27 additions & 0 deletions test/form/side-effects-in-template-literals/_expected/amd.js
@@ -0,0 +1,27 @@
define(['exports'], function (exports) { 'use strict';

exports.x = 0;

function noEffects() {}

function modifyX() {
return exports.x++;
}

const b = `${globalFunction()}has effects`;

const c = `${modifyX()}has effects`;

const e = noEffects`${globalFunction()}has effects`;

const f = noEffects`${modifyX()}has effects`;

const g = globalFunction`has effects`;

const h = globalFunction()`has effects`;

const i = modifyX`has effects`;

Object.defineProperty(exports, '__esModule', { value: true });

});
25 changes: 25 additions & 0 deletions test/form/side-effects-in-template-literals/_expected/cjs.js
@@ -0,0 +1,25 @@
'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

exports.x = 0;

function noEffects() {}

function modifyX() {
return exports.x++;
}

const b = `${globalFunction()}has effects`;

const c = `${modifyX()}has effects`;

const e = noEffects`${globalFunction()}has effects`;

const f = noEffects`${modifyX()}has effects`;

const g = globalFunction`has effects`;

const h = globalFunction()`has effects`;

const i = modifyX`has effects`;
23 changes: 23 additions & 0 deletions test/form/side-effects-in-template-literals/_expected/es.js
@@ -0,0 +1,23 @@
let x = 0;

function noEffects() {}

function modifyX() {
return x++;
}

const b = `${globalFunction()}has effects`;

const c = `${modifyX()}has effects`;

const e = noEffects`${globalFunction()}has effects`;

const f = noEffects`${modifyX()}has effects`;

const g = globalFunction`has effects`;

const h = globalFunction()`has effects`;

const i = modifyX`has effects`;

export { x };
28 changes: 28 additions & 0 deletions test/form/side-effects-in-template-literals/_expected/iife.js
@@ -0,0 +1,28 @@
var myBundle = (function (exports) {
'use strict';

exports.x = 0;

function noEffects() {}

function modifyX() {
return exports.x++;
}

const b = `${globalFunction()}has effects`;

const c = `${modifyX()}has effects`;

const e = noEffects`${globalFunction()}has effects`;

const f = noEffects`${modifyX()}has effects`;

const g = globalFunction`has effects`;

const h = globalFunction()`has effects`;

const i = modifyX`has effects`;

return exports;

}({}));
31 changes: 31 additions & 0 deletions test/form/side-effects-in-template-literals/_expected/umd.js
@@ -0,0 +1,31 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.myBundle = {})));
}(this, (function (exports) { 'use strict';

exports.x = 0;

function noEffects() {}

function modifyX() {
return exports.x++;
}

const b = `${globalFunction()}has effects`;

const c = `${modifyX()}has effects`;

const e = noEffects`${globalFunction()}has effects`;

const f = noEffects`${modifyX()}has effects`;

const g = globalFunction`has effects`;

const h = globalFunction()`has effects`;

const i = modifyX`has effects`;

Object.defineProperty(exports, '__esModule', { value: true });

})));
27 changes: 27 additions & 0 deletions test/form/side-effects-in-template-literals/main.js
@@ -0,0 +1,27 @@
let x = 0;

function noEffects() {}

function modifyX() {
return x++;
}

const a = `${noEffects()}is removed`;

const b = `${globalFunction()}has effects`;

const c = `${modifyX()}has effects`;

const d = noEffects`is removed`;

const e = noEffects`${globalFunction()}has effects`;

const f = noEffects`${modifyX()}has effects`;

const g = globalFunction`has effects`;

const h = globalFunction()`has effects`;

const i = modifyX`has effects`;

export {x};

0 comments on commit 8071790

Please sign in to comment.