Skip to content

Commit cee4954

Browse files
committed
Added more control over sourcemap/comment emit and fixed a number of source map emit issues.
1 parent 3ef9ab4 commit cee4954

10 files changed

Lines changed: 297 additions & 149 deletions

File tree

src/compiler/comments.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,15 @@ namespace ts {
7777
emitTrailingDetachedComments
7878
};
7979

80-
function getLeadingComments(range: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[];
8180
function getLeadingComments(range: TextRange): CommentRange[];
82-
function getLeadingComments(range: TextRange | Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange) {
83-
if (shouldSkipCommentsForNodeCallback && shouldSkipCommentsForNodeCallback(<Node>range)) {
81+
function getLeadingComments(node: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[];
82+
function getLeadingComments(nodeOrRange: TextRange | Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange) {
83+
let range = nodeOrRange;
84+
if (getCustomCommentRangeForNodeCallback) {
85+
range = getCustomCommentRangeForNodeCallback(<Node>nodeOrRange) || range;
86+
}
87+
88+
if (shouldSkipCommentsForNodeCallback && shouldSkipCommentsForNodeCallback(<Node>nodeOrRange)) {
8489
// If the node will not be emitted in JS, remove all the comments (normal,
8590
// pinned and `///`) associated with the node, unless it is a triple slash
8691
// comment at the top of the file.
@@ -100,10 +105,6 @@ namespace ts {
100105
return undefined;
101106
}
102107

103-
if (getCustomCommentRangeForNodeCallback) {
104-
range = getCustomCommentRangeForNodeCallback(<Node>range) || range;
105-
}
106-
107108
return getLeadingCommentsOfPosition(range.pos);
108109
}
109110

@@ -123,15 +124,16 @@ namespace ts {
123124
return false;
124125
}
125126

126-
function getTrailingComments(range: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[];
127127
function getTrailingComments(range: TextRange): CommentRange[];
128-
function getTrailingComments(range: TextRange | Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange) {
129-
if (shouldSkipCommentsForNodeCallback && shouldSkipCommentsForNodeCallback(<Node>range)) {
128+
function getTrailingComments(node: Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange): CommentRange[];
129+
function getTrailingComments(nodeOrRange: TextRange | Node, shouldSkipCommentsForNodeCallback?: (node: Node) => boolean, getCustomCommentRangeForNodeCallback?: (node: Node) => TextRange) {
130+
let range = <TextRange>nodeOrRange;
131+
if (shouldSkipCommentsForNodeCallback && shouldSkipCommentsForNodeCallback(<Node>nodeOrRange)) {
130132
return undefined;
131133
}
132134

133135
if (getCustomCommentRangeForNodeCallback) {
134-
range = getCustomCommentRangeForNodeCallback(<Node>range) || range;
136+
range = getCustomCommentRangeForNodeCallback(<Node>nodeOrRange) || range;
135137
}
136138

137139
return getTrailingCommentsOfPosition(range.end);

src/compiler/factory.ts

Lines changed: 39 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ namespace ts {
88
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
99
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
1010

11-
function createNode(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags): Node {
11+
function createNode(kind: SyntaxKind, location?: TextRange, flags?: NodeFlags, emitOptions?: NodeEmitOptions): Node {
1212
const ConstructorForKind = kind === SyntaxKind.SourceFile
1313
? (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))
1414
: (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()));
@@ -21,6 +21,10 @@ namespace ts {
2121
node.flags = flags;
2222
}
2323

24+
if (emitOptions) {
25+
node.emitOptions = emitOptions;
26+
}
27+
2428
return node;
2529
}
2630

@@ -64,11 +68,11 @@ namespace ts {
6468
/**
6569
* Creates a shallow, memberwise clone of a node with no source map location.
6670
*/
67-
export function getSynthesizedClone<T extends Node>(node: T): T {
71+
export function getSynthesizedClone<T extends Node>(node: T, emitOptions?: NodeEmitOptions): T {
6872
// We don't use "clone" from core.ts here, as we need to preserve the prototype chain of
6973
// the original node. We also need to exclude specific properties and only include own-
7074
// properties (to skip members already defined on the shared prototype).
71-
const clone = <T>createNode(node.kind, /*location*/ undefined);
75+
const clone = <T>createNode(node.kind, /*location*/ undefined, /*flags*/ undefined, emitOptions);
7276
clone.flags = node.flags;
7377
clone.original = node;
7478

@@ -86,56 +90,46 @@ namespace ts {
8690
/**
8791
* Creates a shallow, memberwise clone of a node for mutation.
8892
*/
89-
export function getMutableClone<T extends Node>(node: T): T {
90-
const clone = getSynthesizedClone(node);
93+
export function getMutableClone<T extends Node>(node: T, emitOptions?: NodeEmitOptions): T {
94+
const clone = getSynthesizedClone(node, emitOptions);
9195
clone.pos = node.pos;
9296
clone.end = node.end;
9397
clone.parent = node.parent;
9498
return clone;
9599
}
96100

97-
/**
98-
* Creates a shallow, memberwise clone of a node at the specified source map location.
99-
*/
100-
export function getRelocatedClone<T extends Node>(node: T, location: TextRange): T {
101-
const clone = getSynthesizedClone(node);
102-
clone.pos = location.pos;
103-
clone.end = location.end;
104-
return clone;
105-
}
106-
107101
/**
108102
* Gets a clone of a node with a unique node ID.
109103
*/
110-
export function getUniqueClone<T extends Node>(node: T): T {
111-
const clone = getMutableClone(node);
104+
export function getUniqueClone<T extends Node>(node: T, emitOptions?: NodeEmitOptions): T {
105+
const clone = getMutableClone(node, emitOptions);
112106
clone.id = undefined;
113107
getNodeId(clone);
114108
return clone;
115109
}
116110

117111
// Literals
118112

119-
export function createLiteral(textSource: StringLiteral | Identifier, location?: TextRange): StringLiteral;
120-
export function createLiteral(value: string, location?: TextRange): StringLiteral;
121-
export function createLiteral(value: number, location?: TextRange): LiteralExpression;
122-
export function createLiteral(value: string | number | boolean, location?: TextRange): PrimaryExpression;
123-
export function createLiteral(value: string | number | boolean | StringLiteral | Identifier, location?: TextRange): PrimaryExpression {
113+
export function createLiteral(textSource: StringLiteral | Identifier, location?: TextRange, emitOptions?: NodeEmitOptions): StringLiteral;
114+
export function createLiteral(value: string, location?: TextRange, emitOptions?: NodeEmitOptions): StringLiteral;
115+
export function createLiteral(value: number, location?: TextRange, emitOptions?: NodeEmitOptions): LiteralExpression;
116+
export function createLiteral(value: string | number | boolean, location?: TextRange, emitOptions?: NodeEmitOptions): PrimaryExpression;
117+
export function createLiteral(value: string | number | boolean | StringLiteral | Identifier, location?: TextRange, emitOptions?: NodeEmitOptions): PrimaryExpression {
124118
if (typeof value === "number") {
125-
const node = <LiteralExpression>createNode(SyntaxKind.NumericLiteral, location);
119+
const node = <LiteralExpression>createNode(SyntaxKind.NumericLiteral, location, /*flags*/ undefined, emitOptions);
126120
node.text = value.toString();
127121
return node;
128122
}
129123
else if (typeof value === "boolean") {
130-
return <PrimaryExpression>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword, location);
124+
return <PrimaryExpression>createNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword, location, /*flags*/ undefined, emitOptions);
131125
}
132126
else if (typeof value === "string") {
133-
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location);
127+
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined, emitOptions);
134128
node.text = value;
135129
return node;
136130
}
137131
else {
138-
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location);
132+
const node = <StringLiteral>createNode(SyntaxKind.StringLiteral, location, /*flags*/ undefined, emitOptions);
139133
node.textSourceNode = value;
140134
node.text = value.text;
141135
return node;
@@ -256,10 +250,14 @@ namespace ts {
256250
}
257251

258252
export function createParameter(name: string | Identifier | BindingPattern, initializer?: Expression, location?: TextRange) {
253+
return createParameterWithDotDotDotToken(/*dotDotDotToken*/ undefined, name, initializer, location);
254+
}
255+
256+
export function createParameterWithDotDotDotToken(dotDotDotToken: Node, name: string | Identifier | BindingPattern, initializer?: Expression, location?: TextRange) {
259257
const node = <ParameterDeclaration>createNode(SyntaxKind.Parameter, location);
260258
node.decorators = undefined;
261259
node.modifiers = undefined;
262-
node.dotDotDotToken = undefined;
260+
node.dotDotDotToken = dotDotDotToken;
263261
node.name = typeof name === "string" ? createIdentifier(name) : name;
264262
node.questionToken = undefined;
265263
node.type = undefined;
@@ -287,8 +285,8 @@ namespace ts {
287285
return node;
288286
}
289287

290-
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange) {
291-
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, location);
288+
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange, emitOptions?: NodeEmitOptions) {
289+
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, location, /*flags*/ undefined, emitOptions);
292290
node.expression = parenthesizeForAccess(expression);
293291
node.dotToken = createSynthesizedNode(SyntaxKind.DotToken);
294292
node.name = typeof name === "string" ? createIdentifier(name) : name;
@@ -738,7 +736,7 @@ namespace ts {
738736

739737
export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression {
740738
if (isIdentifier(memberName)) {
741-
return createPropertyAccess(target, getSynthesizedClone(memberName), location);
739+
return createPropertyAccess(target, memberName, location, { flags: NodeEmitFlags.NoNestedSourceMaps | NodeEmitFlags.Merge });
742740
}
743741
else if (isComputedPropertyName(memberName)) {
744742
return createElementAccess(target, memberName.expression, location);
@@ -749,8 +747,7 @@ namespace ts {
749747
}
750748

751749
export function createRestParameter(name: string | Identifier) {
752-
const node = createParameter(name, /*initializer*/ undefined);
753-
node.dotDotDotToken = createSynthesizedNode(SyntaxKind.DotDotDotToken);
750+
const node = createParameterWithDotDotDotToken(createSynthesizedNode(SyntaxKind.DotDotDotToken), name, /*initializer*/ undefined);
754751
return node;
755752
}
756753

@@ -1279,10 +1276,16 @@ namespace ts {
12791276
: getSynthesizedClone(node);
12801277
}
12811278

1282-
export function createExpressionForPropertyName(memberName: PropertyName, location?: TextRange): Expression {
1283-
return isIdentifier(memberName) ? createLiteral(memberName.text, location)
1284-
: isComputedPropertyName(memberName) ? getRelocatedClone(memberName.expression, location || synthesizedLocation)
1285-
: getRelocatedClone(memberName, location || synthesizedLocation);
1279+
export function createExpressionForPropertyName(memberName: PropertyName, emitOptions: NodeEmitOptions): Expression {
1280+
if (isIdentifier(memberName)) {
1281+
return createLiteral(memberName, /*location*/ undefined, emitOptions);
1282+
}
1283+
else if (isComputedPropertyName(memberName)) {
1284+
return getMutableClone(memberName.expression, emitOptions);
1285+
}
1286+
else {
1287+
return getMutableClone(memberName, emitOptions);
1288+
}
12861289
}
12871290

12881291
// Utilities

src/compiler/printer.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ const _super = (function (geti, seti) {
172172
let context: TransformationContext;
173173
let getNodeEmitFlags: (node: Node) => NodeEmitFlags;
174174
let setNodeEmitFlags: (node: Node, flags: NodeEmitFlags) => void;
175-
let getNodeCustomCommentRange: (node: Node) => TextRange;
175+
let getCommentRange: (node: Node) => TextRange;
176+
let getSourceMapRange: (node: Node) => TextRange;
176177
let isSubstitutionEnabled: (node: Node) => boolean;
177178
let isEmitNotificationEnabled: (node: Node) => boolean;
178179
let onSubstituteNode: (node: Node, isExpression: boolean) => Node;
@@ -233,7 +234,8 @@ const _super = (function (geti, seti) {
233234

234235
getNodeEmitFlags = undefined;
235236
setNodeEmitFlags = undefined;
236-
getNodeCustomCommentRange = undefined;
237+
getCommentRange = undefined;
238+
getSourceMapRange = undefined;
237239
isSubstitutionEnabled = undefined;
238240
isEmitNotificationEnabled = undefined;
239241
onSubstituteNode = undefined;
@@ -253,7 +255,8 @@ const _super = (function (geti, seti) {
253255
context = _context;
254256
getNodeEmitFlags = context.getNodeEmitFlags;
255257
setNodeEmitFlags = context.setNodeEmitFlags;
256-
getNodeCustomCommentRange = context.getNodeCustomCommentRange;
258+
getCommentRange = context.getCommentRange;
259+
getSourceMapRange = context.getSourceMapRange;
257260
isSubstitutionEnabled = context.isSubstitutionEnabled;
258261
isEmitNotificationEnabled = context.isEmitNotificationEnabled;
259262
onSubstituteNode = context.onSubstituteNode;
@@ -337,12 +340,12 @@ const _super = (function (geti, seti) {
337340

338341
function emitNodeWithWorker(node: Node, emitWorker: (node: Node) => void) {
339342
if (node) {
340-
const leadingComments = getLeadingComments(node, shouldSkipLeadingCommentsForNode, getNodeCustomCommentRange);
341-
const trailingComments = getTrailingComments(node, shouldSkipTrailingCommentsForNode, getNodeCustomCommentRange);
343+
const leadingComments = getLeadingComments(node, shouldSkipLeadingCommentsForNode, getCommentRange);
344+
const trailingComments = getTrailingComments(node, shouldSkipTrailingCommentsForNode, getCommentRange);
342345
emitLeadingComments(node, leadingComments);
343-
emitStart(node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren);
346+
emitStart(node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange);
344347
emitWorker(node);
345-
emitEnd(node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren);
348+
emitEnd(node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange);
346349
emitTrailingComments(node, trailingComments);
347350
}
348351
}
@@ -2429,9 +2432,9 @@ const _super = (function (geti, seti) {
24292432

24302433
function writeTokenNode(node: Node) {
24312434
if (node) {
2432-
emitStart(node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren);
2435+
emitStart(node, shouldSkipLeadingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange);
24332436
writeTokenText(node.kind);
2434-
emitEnd(node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren);
2437+
emitEnd(node, shouldSkipTrailingSourceMapForNode, shouldSkipSourceMapForChildren, getSourceMapRange);
24352438
}
24362439
}
24372440

0 commit comments

Comments
 (0)