Skip to content

Commit

Permalink
Add support for /*#__PURE__*/ comments.
Browse files Browse the repository at this point in the history
  • Loading branch information
conartist6 committed Aug 28, 2018
1 parent 162c0ac commit dab4060
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/Module.ts
@@ -1,4 +1,5 @@
import { IParse, Options as AcornOptions } from 'acorn';
import walk from 'acorn/dist/walk';
import * as ESTree from 'estree';
import { locate } from 'locate-character';
import MagicString from 'magic-string';
Expand Down Expand Up @@ -159,6 +160,38 @@ function handleMissingExport(
);
}

// Find syntax nodes following comments
function findNodesAfterComments(ast, commentNodes) {
const state = {
commentIdx: 0,
nodes: []
};

(function c(node, state, override) {
if (state.commentIdx === commentNodes.length) return;
const pos = commentNodes[state.commentIdx].end;
if (node.end < pos) return;
const type = override || node.type;
if (node.start >= pos) {
state.commentIdx++;
state.nodes.push(node);
}
walk.base[type](node, state, c);
})(ast, state);

return state.nodes;
}

function markNodePure(node) {
if (node.type === 'ExpressionStatement') {
markNodePure(node.expression);
} else if (node.type === 'CallExpression') {
node.markedPure = true;
}
}

const pureCommentRegex = /^ ?#__PURE__\s*$/;

export default class Module {
type: 'Module';
private graph: Graph;
Expand Down Expand Up @@ -258,6 +291,11 @@ export default class Module {

timeEnd('generate ast', 3);

const pureMarkerComments = this.comments.filter(comment => pureCommentRegex.test(comment.text));
const nodesAfterPureComments = findNodesAfterComments(this.esTreeAst, pureMarkerComments);

nodesAfterPureComments.forEach(node => markNodePure(node));

this.resolvedIds = resolvedIds || Object.create(null);

// By default, `id` is the filename. Custom resolvers and loaders
Expand Down
2 changes: 2 additions & 0 deletions src/ast/nodes/CallExpression.ts
Expand Up @@ -135,6 +135,8 @@ export default class CallExpression extends NodeBase implements DeoptimizableEnt
for (const argument of this.arguments) {
if (argument.hasEffects(options)) return true;
}
debugger;
if (this.markedPure) return false;
return (
this.callee.hasEffects(options) ||
this.callee.hasEffectsWhenCalledAtPath(
Expand Down
26 changes: 26 additions & 0 deletions test/function/samples/call-marked-pure/_config.js
@@ -0,0 +1,26 @@
const assert = require('assert');

module.exports = {
description: 'functions marked with pure comment do not have effects',
context: {
require(id) {
if (id === 'socks') {
return () => '🧦';
}
}
},
code(code) {
assert.ok(code.search(/socks\(\)/) === -1);
},
warnings: [
{
code: 'UNRESOLVED_IMPORT',
importer: 'main.js',
message:
"'socks' is imported by main.js, but could not be resolved – treating it as an external dependency",
source: 'socks',
url:
'https://github.com/rollup/rollup/wiki/Troubleshooting#treating-module-as-external-dependency'
}
]
};
8 changes: 8 additions & 0 deletions test/function/samples/call-marked-pure/main.js
@@ -0,0 +1,8 @@
import socks from 'socks';

/*#__PURE__*/ socks();
/* #__PURE__*/ socks();
/*#__PURE__ */ socks();
/* #__PURE__ */ socks();
// #__PURE__
socks();

0 comments on commit dab4060

Please sign in to comment.