Skip to content

Commit ce2592d

Browse files
authored
Correctly associate pure annotations and remove invalid ones (#4095)
* Simplify annotation handling * Remove invalid annotations and improve annotation association * Improve coverage and remove trailing annotations
1 parent 2febefa commit ce2592d

File tree

26 files changed

+250
-164
lines changed

26 files changed

+250
-164
lines changed

src/Graph.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { PluginDriver } from './utils/PluginDriver';
1717
import { BuildPhase } from './utils/buildPhase';
1818
import { errImplicitDependantIsNotIncluded, error } from './utils/error';
1919
import { analyseModuleExecution } from './utils/executionOrder';
20-
import { markPureCallExpressions } from './utils/pureComments';
20+
import { addAnnotations } from './utils/pureComments';
2121
import relativeId from './utils/relativeId';
2222
import { timeEnd, timeStart } from './utils/timers';
2323
import { markModuleAndImpureDependenciesAsExecuted } from './utils/traverseStaticDependencies';
@@ -137,7 +137,7 @@ export default class Graph {
137137

138138
options.onComment = onCommentOrig;
139139

140-
markPureCallExpressions(comments, ast, code);
140+
addAnnotations(comments, ast, code);
141141

142142
return ast;
143143
}

src/Module.ts

Lines changed: 1 addition & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import Program from './ast/nodes/Program';
1919
import TemplateLiteral from './ast/nodes/TemplateLiteral';
2020
import VariableDeclaration from './ast/nodes/VariableDeclaration';
2121
import { nodeConstructors } from './ast/nodes/index';
22-
import { ExpressionNode, GenericEsTreeNode, NodeBase } from './ast/nodes/shared/Node';
22+
import { ExpressionNode, NodeBase } from './ast/nodes/shared/Node';
2323
import ModuleScope from './ast/scopes/ModuleScope';
2424
import { PathTracker, UNKNOWN_PATH } from './ast/utils/PathTracker';
2525
import ExportDefaultVariable from './ast/variables/ExportDefaultVariable';
@@ -62,7 +62,6 @@ import { makeLegal } from './utils/identifierHelpers';
6262
import { basename, extname } from './utils/path';
6363
import relativeId from './utils/relativeId';
6464
import { RenderOptions } from './utils/renderHelpers';
65-
import { SOURCEMAPPING_URL_COMMENT_RE } from './utils/sourceMappingURL';
6665
import { timeEnd, timeStart } from './utils/timers';
6766
import { markModuleAndImpureDependenciesAsExecuted } from './utils/traverseStaticDependencies';
6867
import { MISSING_EXPORT_SHIM_VARIABLE } from './utils/variableNames';
@@ -121,34 +120,6 @@ const MISSING_EXPORT_SHIM_DESCRIPTION: ExportDescription = {
121120
localName: MISSING_EXPORT_SHIM_VARIABLE
122121
};
123122

124-
function findSourceMappingURLComments(ast: acorn.Node, code: string): [number, number][] {
125-
const ret: [number, number][] = [];
126-
127-
const addCommentsPos = (start: number, end: number): void => {
128-
if (start == end) {
129-
return;
130-
}
131-
132-
let sourcemappingUrlMatch;
133-
const interStatmentCode = code.slice(start, end);
134-
while ((sourcemappingUrlMatch = SOURCEMAPPING_URL_COMMENT_RE.exec(interStatmentCode))) {
135-
ret.push([
136-
start + sourcemappingUrlMatch.index,
137-
start + SOURCEMAPPING_URL_COMMENT_RE.lastIndex
138-
]);
139-
}
140-
};
141-
142-
let prevStmtEnd = 0;
143-
for (const stmt of (ast as GenericEsTreeNode).body) {
144-
addCommentsPos(prevStmtEnd, stmt.start);
145-
prevStmtEnd = stmt.end;
146-
}
147-
addCommentsPos(prevStmtEnd, code.length);
148-
149-
return ret;
150-
}
151-
152123
function getVariableForExportNameRecursive(
153124
target: Module | ExternalModule,
154125
name: string,
@@ -251,7 +222,6 @@ export default class Module {
251222
usesTopLevelAwait = false;
252223

253224
private allExportNames: Set<string> | null = null;
254-
private alwaysRemovedCode!: [number, number][];
255225
private astContext!: AstContext;
256226
private readonly context: string;
257227
private customTransformCache!: boolean;
@@ -688,7 +658,6 @@ export default class Module {
688658
}
689659

690660
setSource({
691-
alwaysRemovedCode,
692661
ast,
693662
code,
694663
customTransformCache,
@@ -700,7 +669,6 @@ export default class Module {
700669
transformFiles,
701670
...moduleOptions
702671
}: TransformModuleJSON & {
703-
alwaysRemovedCode?: [number, number][];
704672
transformFiles?: EmittedFile[] | undefined;
705673
}): void {
706674
this.info.code = code;
@@ -716,11 +684,9 @@ export default class Module {
716684

717685
timeStart('generate ast', 3);
718686

719-
this.alwaysRemovedCode = alwaysRemovedCode || [];
720687
if (!ast) {
721688
ast = this.tryParse();
722689
}
723-
this.alwaysRemovedCode.push(...findSourceMappingURLComments(ast, this.info.code));
724690

725691
timeEnd('generate ast', 3);
726692

@@ -734,9 +700,6 @@ export default class Module {
734700
filename: (this.excludeFromSourcemap ? null : fileName)!, // don't include plugin helpers in sourcemap
735701
indentExclusionRanges: []
736702
});
737-
for (const [start, end] of this.alwaysRemovedCode) {
738-
this.magicString.remove(start, end);
739-
}
740703

741704
timeStart('analyse ast', 3);
742705

@@ -778,7 +741,6 @@ export default class Module {
778741

779742
toJSON(): ModuleJSON {
780743
return {
781-
alwaysRemovedCode: this.alwaysRemovedCode,
782744
ast: this.ast!.esTreeNode,
783745
code: this.info.code!,
784746
customTransformCache: this.customTransformCache,

src/ast/keys.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const keys: {
99

1010
export function getAndCreateKeys(esTreeNode: GenericEsTreeNode): string[] {
1111
keys[esTreeNode.type] = Object.keys(esTreeNode).filter(
12-
key => typeof esTreeNode[key] === 'object' && key !== '_rollupAnnotations'
12+
key => typeof esTreeNode[key] === 'object' && key.charCodeAt(0) !== 95 /* _ */
1313
);
1414
return keys[esTreeNode.type];
1515
}

src/ast/nodes/CallExpression.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,7 @@ import {
2828
UNKNOWN_EXPRESSION,
2929
UnknownValue
3030
} from './shared/Expression';
31-
import {
32-
Annotation,
33-
ExpressionNode,
34-
INCLUDE_PARAMETERS,
35-
IncludeChildren,
36-
NodeBase
37-
} from './shared/Node';
31+
import { ExpressionNode, INCLUDE_PARAMETERS, IncludeChildren, NodeBase } from './shared/Node';
3832

3933
export default class CallExpression extends NodeBase implements DeoptimizableEntity {
4034
arguments!: (ExpressionNode | SpreadElement)[];
@@ -188,7 +182,7 @@ export default class CallExpression extends NodeBase implements DeoptimizableEnt
188182
}
189183
if (
190184
(this.context.options.treeshake as NormalizedTreeshakingOptions).annotations &&
191-
this.annotations?.some((a: Annotation) => a.pure)
185+
this.annotations
192186
)
193187
return false;
194188
return (

src/ast/nodes/IfStatement.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import MagicString from 'magic-string';
22
import { RenderOptions } from '../../utils/renderHelpers';
3-
import { removeAnnotations } from '../../utils/treeshakeNode';
43
import { DeoptimizableEntity } from '../DeoptimizableEntity';
54
import { BROKEN_FLOW_NONE, HasEffectsContext, InclusionContext } from '../ExecutionContext';
65
import TrackingScope from '../scopes/TrackingScope';
@@ -89,7 +88,6 @@ export default class IfStatement extends StatementBase implements DeoptimizableE
8988
if (includesIfElse) {
9089
this.test.render(code, options);
9190
} else {
92-
removeAnnotations(this, code);
9391
code.remove(this.start, this.consequent.start);
9492
}
9593
if (this.consequent.included && (noTreeshake || testValue === UnknownValue || testValue)) {

src/ast/nodes/NewExpression.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { CallOptions } from '../CallOptions';
33
import { HasEffectsContext } from '../ExecutionContext';
44
import { EMPTY_PATH, ObjectPath, UNKNOWN_PATH } from '../utils/PathTracker';
55
import * as NodeType from './NodeType';
6-
import { Annotation, ExpressionNode, NodeBase } from './shared/Node';
6+
import { ExpressionNode, NodeBase } from './shared/Node';
77

88
export default class NewExpression extends NodeBase {
99
arguments!: ExpressionNode[];
@@ -19,7 +19,7 @@ export default class NewExpression extends NodeBase {
1919
}
2020
if (
2121
(this.context.options.treeshake as NormalizedTreeshakingOptions).annotations &&
22-
this.annotations?.some((a: Annotation) => a.pure)
22+
this.annotations
2323
)
2424
return false;
2525
return (

src/ast/nodes/shared/Node.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as acorn from 'acorn';
22
import { locate, Location } from 'locate-character';
33
import MagicString from 'magic-string';
44
import { AstContext } from '../../../Module';
5+
import { ANNOTATION_KEY, INVALID_COMMENT_KEY } from '../../../utils/pureComments';
56
import { NodeRenderOptions, RenderOptions } from '../../../utils/renderHelpers';
67
import { Entity } from '../../Entity';
78
import {
@@ -21,13 +22,9 @@ export interface GenericEsTreeNode extends acorn.Node {
2122

2223
export const INCLUDE_PARAMETERS = 'variables' as const;
2324
export type IncludeChildren = boolean | typeof INCLUDE_PARAMETERS;
24-
export interface Annotation {
25-
comment?: acorn.Comment;
26-
pure?: boolean;
27-
}
2825

2926
export interface Node extends Entity {
30-
annotations?: Annotation[];
27+
annotations?: acorn.Comment[];
3128
context: AstContext;
3229
end: number;
3330
esTreeNode: GenericEsTreeNode;
@@ -87,7 +84,7 @@ export type StatementNode = Node;
8784
export interface ExpressionNode extends ExpressionEntity, Node {}
8885

8986
export class NodeBase extends ExpressionEntity implements ExpressionNode {
90-
annotations?: Annotation[];
87+
annotations?: acorn.Comment[];
9188
context: AstContext;
9289
end!: number;
9390
esTreeNode: acorn.Node;
@@ -201,8 +198,13 @@ export class NodeBase extends ExpressionEntity implements ExpressionNode {
201198
for (const [key, value] of Object.entries(esTreeNode)) {
202199
// That way, we can override this function to add custom initialisation and then call super.parseNode
203200
if (this.hasOwnProperty(key)) continue;
204-
if (key === '_rollupAnnotations') {
205-
this.annotations = value;
201+
if (key.charCodeAt(0) === 95 /* _ */) {
202+
if (key === ANNOTATION_KEY) {
203+
this.annotations = value;
204+
} else if (key === INVALID_COMMENT_KEY) {
205+
for (const { start, end } of value as acorn.Comment[])
206+
this.context.magicString.remove(start, end);
207+
}
206208
} else if (typeof value !== 'object' || value === null) {
207209
(this as GenericEsTreeNode)[key] = value;
208210
} else if (Array.isArray(value)) {

src/rollup/types.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ export interface TransformModuleJSON extends Partial<PartialNull<ModuleOptions>>
114114
}
115115

116116
export interface ModuleJSON extends TransformModuleJSON {
117-
alwaysRemovedCode: [number, number][];
118117
ast: AcornNode;
119118
dependencies: string[];
120119
id: string;

0 commit comments

Comments
 (0)