Skip to content

Commit 3c3e081

Browse files
committed
Fix source maps for rest params, class properties, parameter properties, and accessors.
1 parent 13fb37e commit 3c3e081

8 files changed

Lines changed: 130 additions & 77 deletions

File tree

src/compiler/factory.ts

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ namespace ts {
106106
* Gets a clone of a node with a unique node ID.
107107
*/
108108
export function getUniqueClone<T extends Node>(node: T): T {
109-
const clone = getSynthesizedClone(node);
109+
const clone = getMutableClone(node);
110110
clone.id = undefined;
111111
getNodeId(clone);
112112
return clone;
@@ -926,34 +926,8 @@ namespace ts {
926926
);
927927
}
928928

929-
function createPropertyDescriptor({ get, set, value, enumerable, configurable, writable }: PropertyDescriptorOptions, preferNewLine?: boolean, location?: TextRange, descriptorLocations?: PropertyDescriptorLocations) {
930-
const properties: ObjectLiteralElement[] = [];
931-
addPropertyAssignment(properties, "get", get, preferNewLine, descriptorLocations);
932-
addPropertyAssignment(properties, "set", set, preferNewLine, descriptorLocations);
933-
addPropertyAssignment(properties, "value", value, preferNewLine, descriptorLocations);
934-
addPropertyAssignment(properties, "enumerable", enumerable, preferNewLine, descriptorLocations);
935-
addPropertyAssignment(properties, "configurable", configurable, preferNewLine, descriptorLocations);
936-
addPropertyAssignment(properties, "writable", writable, preferNewLine, descriptorLocations);
937-
return createObjectLiteral(properties, location, preferNewLine);
938-
}
939-
940-
function addPropertyAssignment(properties: ObjectLiteralElement[], name: string, value: boolean | Expression, preferNewLine: boolean, descriptorLocations?: PropertyDescriptorLocations) {
941-
if (value !== undefined) {
942-
const property = createPropertyAssignment(
943-
name,
944-
typeof value === "boolean" ? createLiteral(value) : value,
945-
descriptorLocations ? descriptorLocations[name] : undefined
946-
);
947-
948-
if (preferNewLine) {
949-
startOnNewLine(property);
950-
}
951-
952-
properties.push(property);
953-
}
954-
}
955-
956929
export interface PropertyDescriptorOptions {
930+
[key: string]: boolean | Expression;
957931
get?: Expression;
958932
set?: Expression;
959933
value?: Expression;
@@ -962,17 +936,23 @@ namespace ts {
962936
writable?: boolean | Expression;
963937
}
964938

965-
export interface PropertyDescriptorLocations {
966-
[key: string]: TextRange;
967-
get?: TextRange;
968-
set?: TextRange;
969-
value?: TextRange;
970-
enumerable?: TextRange;
971-
configurable?: TextRange;
972-
writable?: TextRange;
939+
export interface PropertyDescriptorExtendedOptions {
940+
[key: string]: PropertyDescriptorExtendedOption;
941+
get?: PropertyDescriptorExtendedOption;
942+
set?: PropertyDescriptorExtendedOption;
943+
value?: PropertyDescriptorExtendedOption;
944+
enumerable?: PropertyDescriptorExtendedOption;
945+
configurable?: PropertyDescriptorExtendedOption;
946+
writable?: PropertyDescriptorExtendedOption;
947+
}
948+
949+
export interface PropertyDescriptorExtendedOption {
950+
location?: TextRange;
951+
emitFlags?: NodeEmitFlags;
952+
newLine?: boolean;
973953
}
974954

975-
export function createObjectDefineProperty(target: Expression, memberName: Expression, descriptor: PropertyDescriptorOptions, preferNewLine?: boolean, location?: TextRange, descriptorLocations?: PropertyDescriptorLocations) {
955+
export function createObjectDefineProperty(target: Expression, memberName: Expression, descriptor: PropertyDescriptorOptions, preferNewLine?: boolean, location?: TextRange, descriptorOptions?: PropertyDescriptorExtendedOptions, context?: TransformationContext) {
976956
return createCall(
977957
createPropertyAccess(
978958
createIdentifier("Object"),
@@ -981,12 +961,60 @@ namespace ts {
981961
[
982962
target,
983963
memberName,
984-
createPropertyDescriptor(descriptor, preferNewLine, /*location*/ undefined, descriptorLocations)
964+
createObjectLiteral(
965+
createPropertyDescriptorProperties(descriptor, descriptorOptions, preferNewLine, context),
966+
/*location*/ undefined,
967+
/*multiLine*/ preferNewLine
968+
)
985969
],
986970
location
987971
);
988972
}
989973

974+
function createPropertyDescriptorProperties(descriptor: PropertyDescriptorOptions, descriptorExtendedOptions: PropertyDescriptorExtendedOptions, preferNewLine: boolean, context: TransformationContext) {
975+
const properties: ObjectLiteralElement[] = [];
976+
addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "get", descriptor, descriptorExtendedOptions, preferNewLine, context);
977+
addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "set", descriptor, descriptorExtendedOptions, preferNewLine, context);
978+
addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "value", descriptor, descriptorExtendedOptions, preferNewLine, context);
979+
addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "enumerable", descriptor, descriptorExtendedOptions, preferNewLine, context);
980+
addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "configurable", descriptor, descriptorExtendedOptions, preferNewLine, context);
981+
addPropertyDescriptorPropertyAssignmentIfNeeded(properties, "writable", descriptor, descriptorExtendedOptions, preferNewLine, context);
982+
return properties;
983+
}
984+
985+
function addPropertyDescriptorPropertyAssignmentIfNeeded(properties: ObjectLiteralElement[], name: string, descriptor: PropertyDescriptorOptions, descriptorExtendedOptions: PropertyDescriptorExtendedOptions, preferNewLine: boolean, context: TransformationContext) {
986+
const value = getProperty(descriptor, name);
987+
if (value !== undefined) {
988+
const options = getProperty(descriptorExtendedOptions, name);
989+
let location: TextRange;
990+
let emitFlags: NodeEmitFlags;
991+
if (isDefined(options)) {
992+
location = options.location;
993+
emitFlags = options.emitFlags;
994+
if (isDefined(options.newLine)) {
995+
preferNewLine = options.newLine;
996+
}
997+
}
998+
999+
const property = createPropertyAssignment(
1000+
name,
1001+
typeof value === "boolean" ? createLiteral(value) : value,
1002+
location
1003+
);
1004+
1005+
if (isDefined(emitFlags)) {
1006+
Debug.assert(isDefined(context), "TransformationContext must be supplied when emitFlags are provided.");
1007+
context.setNodeEmitFlags(property, emitFlags);
1008+
}
1009+
1010+
if (preferNewLine) {
1011+
startOnNewLine(property);
1012+
}
1013+
1014+
properties.push(property);
1015+
}
1016+
}
1017+
9901018
function createObjectCreate(prototype: Expression) {
9911019
return createCall(
9921020
createPropertyAccess(createIdentifier("Object"), "create"),

src/compiler/printer.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,7 +1154,7 @@ const _super = (function (geti, seti) {
11541154

11551155
emitExpression(node.left);
11561156
increaseIndentIf(indentBeforeOperator, isCommaOperator ? " " : undefined);
1157-
writeTokenNode(node.operatorToken);
1157+
writeTokenText(node.operatorToken.kind);
11581158
increaseIndentIf(indentAfterOperator, " ");
11591159
emitExpression(node.right);
11601160
decreaseIndentIf(indentBeforeOperator, indentAfterOperator);
@@ -1353,7 +1353,7 @@ const _super = (function (geti, seti) {
13531353
}
13541354

13551355
function emitReturnStatement(node: ReturnStatement) {
1356-
write("return");
1356+
writeToken(SyntaxKind.ReturnKeyword, node.pos, node, shouldSkipSourceMapForToken);
13571357
emitExpressionWithPrefix(" ", node.expression);
13581358
write(";");
13591359
}
@@ -2301,14 +2301,20 @@ const _super = (function (geti, seti) {
23012301
}
23022302
}
23032303

2304-
function writeToken(token: SyntaxKind, tokenStartPos: number) {
2304+
function writeToken(token: SyntaxKind, tokenStartPos: number): number;
2305+
function writeToken(token: SyntaxKind, tokenStartPos: number, contextNode: Node, shouldIgnoreSourceMapForTokenCallback: (contextNode: Node) => boolean): number;
2306+
function writeToken(token: SyntaxKind, tokenStartPos: number, contextNode?: Node, shouldIgnoreSourceMapForTokenCallback?: (contextNode: Node) => boolean) {
23052307
tokenStartPos = skipTrivia(currentText, tokenStartPos);
2306-
emitPos(tokenStartPos);
2308+
emitPos(tokenStartPos, contextNode, shouldIgnoreSourceMapForTokenCallback);
23072309
const tokenEndPos = writeTokenText(token, tokenStartPos);
2308-
emitPos(tokenEndPos);
2310+
emitPos(tokenEndPos, contextNode, shouldIgnoreSourceMapForTokenCallback);
23092311
return tokenEndPos;
23102312
}
23112313

2314+
function shouldSkipSourceMapForToken(contextNode: Node) {
2315+
return (getNodeEmitFlags(contextNode) & NodeEmitFlags.NoTokenSourceMaps) !== 0;
2316+
}
2317+
23122318
function writeTokenText(token: SyntaxKind, pos?: number) {
23132319
const tokenString = tokenToString(token);
23142320
write(tokenString);

src/compiler/sourcemap.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace ts {
55
export interface SourceMapWriter {
66
getSourceMapData(): SourceMapData;
77
setSourceFile(sourceFile: SourceFile): void;
8+
emitPos(pos: number, contextNode: Node, shouldIgnorePosCallback: (node: Node) => boolean): void;
89
emitPos(pos: number): void;
910
emitStart(node: Node, shouldIgnoreNodeCallback?: (node: Node) => boolean, shouldIgnoreChildrenCallback?: (node: Node) => boolean): void;
1011
emitStart(range: TextRange): void;
@@ -271,11 +272,15 @@ namespace ts {
271272
sourceMapData.sourceMapDecodedMappings.push(lastEncodedSourceMapSpan);
272273
}
273274

274-
function emitPos(pos: number) {
275+
function emitPos(pos: number, contextNode?: Node, shouldIgnorePosCallback?: (node: Node) => boolean) {
275276
if (positionIsSynthesized(pos) || disableDepth > 0) {
276277
return;
277278
}
278279

280+
if (shouldIgnorePosCallback && shouldIgnorePosCallback(contextNode)) {
281+
return;
282+
}
283+
279284
const sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos);
280285

281286
// Convert the location to be one-based.

src/compiler/transformers/es6.ts

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ namespace ts {
674674
const statement = createReturn(outer);
675675
statement.pos = closingBraceLocation.pos;
676676
statements.push(statement);
677-
setNodeEmitFlags(statement, NodeEmitFlags.NoComments);
677+
setNodeEmitFlags(statement, NodeEmitFlags.NoComments | NodeEmitFlags.NoTokenSourceMaps);
678678

679679
addRange(statements, endLexicalEnvironment());
680680
const block = createBlock(createNodeArray(statements, /*location*/ node.members), /*location*/ undefined, /*multiLine*/ true);
@@ -1001,7 +1001,8 @@ namespace ts {
10011001
name,
10021002
createArrayLiteral([])
10031003
)
1004-
])
1004+
]),
1005+
/*location*/ parameter
10051006
)
10061007
);
10071008

@@ -1012,12 +1013,13 @@ namespace ts {
10121013
createFor(
10131014
createVariableDeclarationList([
10141015
createVariableDeclaration(temp, createLiteral(restIndex))
1015-
]),
1016+
], /*location*/ parameter),
10161017
createLessThan(
10171018
temp,
1018-
createPropertyAccess(createIdentifier("arguments"), "length")
1019+
createPropertyAccess(createIdentifier("arguments"), "length"),
1020+
/*location*/ parameter
10191021
),
1020-
createPostfixIncrement(temp),
1022+
createPostfixIncrement(temp, /*location*/ parameter),
10211023
createBlock([
10221024
startOnNewLine(
10231025
createStatement(
@@ -1027,7 +1029,8 @@ namespace ts {
10271029
createSubtract(temp, createLiteral(restIndex))
10281030
),
10291031
createElementAccess(createIdentifier("arguments"), temp)
1030-
)
1032+
),
1033+
/*location*/ parameter
10311034
)
10321035
)
10331036
])
@@ -1158,13 +1161,18 @@ namespace ts {
11581161
* @param receiver The receiver for the member.
11591162
*/
11601163
function transformAccessorsToExpression(receiver: LeftHandSideExpression, { firstAccessor, getAccessor, setAccessor }: AllAccessorDeclarations): Expression {
1164+
// To align with source maps in the old emitter, the receiver and property name
1165+
// arguments are both mapped contiguously to the accessor name.
1166+
const target = getSynthesizedClone(receiver);
1167+
target.pos = firstAccessor.name.pos;
1168+
1169+
const propertyName = createExpressionForPropertyName(visitNode(firstAccessor.name, visitor, isPropertyName));
1170+
propertyName.end = firstAccessor.name.end;
1171+
11611172
return setNodeEmitFlags(
11621173
createObjectDefineProperty(
1163-
receiver,
1164-
createExpressionForPropertyName(
1165-
visitNode(firstAccessor.name, visitor, isPropertyName),
1166-
/*location*/ firstAccessor.name
1167-
),
1174+
target,
1175+
propertyName,
11681176
/*descriptor*/ {
11691177
get: getAccessor && transformFunctionLikeToExpression(getAccessor, /*location*/ getAccessor, /*name*/ undefined),
11701178
set: setAccessor && transformFunctionLikeToExpression(setAccessor, /*location*/ setAccessor, /*name*/ undefined),
@@ -1174,9 +1182,10 @@ namespace ts {
11741182
/*preferNewLine*/ true,
11751183
/*location*/ undefined,
11761184
/*descriptorLocations*/ {
1177-
get: getAccessor,
1178-
set: setAccessor
1179-
}
1185+
get: { location: getAccessor, emitFlags: NodeEmitFlags.NoSourceMap },
1186+
set: { location: setAccessor, emitFlags: NodeEmitFlags.NoSourceMap }
1187+
},
1188+
context
11801189
),
11811190
NodeEmitFlags.NoComments
11821191
);

src/compiler/transformers/ts.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -898,13 +898,17 @@ namespace ts {
898898
function transformParameterWithPropertyAssignment(node: ParameterDeclaration) {
899899
Debug.assert(isIdentifier(node.name));
900900

901-
const name = getSynthesizedClone(<Identifier>node.name);
902901
return startOnNewLine(
903902
createStatement(
904903
createAssignment(
905-
createPropertyAccess(createThis(), name),
906-
name
907-
)
904+
createPropertyAccess(
905+
createThis(),
906+
getSynthesizedClone(<Identifier>node.name),
907+
/*location*/ node.name
908+
),
909+
getUniqueClone(<Identifier>node.name)
910+
),
911+
/*location*/ node
908912
)
909913
);
910914
}
@@ -994,7 +998,7 @@ namespace ts {
994998
const propertyName = visitPropertyNameOfClassElement(property);
995999
const initializer = visitNode(property.initializer, visitor, isExpression);
9961000
return createAssignment(
997-
createMemberAccessForPropertyName(receiver, propertyName),
1001+
createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName),
9981002
initializer,
9991003
location
10001004
);
@@ -1754,7 +1758,7 @@ namespace ts {
17541758
function getExpressionForPropertyName(member: ClassElement | EnumMember, generateNameForComputedPropertyName: boolean): Expression {
17551759
const name = member.name;
17561760
if (isComputedPropertyName(name)) {
1757-
return generateNameForComputedPropertyName
1761+
return generateNameForComputedPropertyName
17581762
? getGeneratedNameForNode(name)
17591763
: (<ComputedPropertyName>name).expression;
17601764
}

src/compiler/types.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2875,10 +2875,11 @@ namespace ts {
28752875
CapturesThis = 1 << 9, // The function captures a lexical `this`
28762876
NoSourceMap = 1 << 10, // Do not emit a source map location for this node.
28772877
NoNestedSourceMaps = 1 << 11, // Do not emit source map locations for children of this node.
2878-
NoComments = 1 << 12, // Do not emit comments for this node.
2879-
ExportName = 1 << 13, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal).
2880-
LocalName = 1 << 14, // Ensure an export prefix is not added for an identifier that points to an exported declaration.
2881-
Indented = 1 << 15, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter).
2878+
NoTokenSourceMaps = 1 << 12, // Do not emit source map locations for tokens of this node.
2879+
NoComments = 1 << 13, // Do not emit comments for this node.
2880+
ExportName = 1 << 14, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal).
2881+
LocalName = 1 << 15, // Ensure an export prefix is not added for an identifier that points to an exported declaration.
2882+
Indented = 1 << 16, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter).
28822883
}
28832884

28842885
/** Additional context provided to `visitEachChild` */

tests/baselines/reference/sourceMapValidationClass.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)