Skip to content

Commit 74d92f0

Browse files
committed
Merge pull request #5724 from Microsoft/sourceMapAndBreakpointDecorators
Various fixes for sourcemap and breakpoints of decorators
2 parents aae6749 + a871698 commit 74d92f0

9 files changed

+649
-299
lines changed

src/compiler/emitter.ts

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5307,10 +5307,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
53075307
function emitDecoratorsOfConstructor(node: ClassLikeDeclaration) {
53085308
const decorators = node.decorators;
53095309
const constructor = getFirstConstructorWithBody(node);
5310-
const hasDecoratedParameters = constructor && forEach(constructor.parameters, nodeIsDecorated);
5310+
const firstParameterDecorator = constructor && forEach(constructor.parameters, parameter => parameter.decorators);
53115311

53125312
// skip decoration of the constructor if neither it nor its parameters are decorated
5313-
if (!decorators && !hasDecoratedParameters) {
5313+
if (!decorators && !firstParameterDecorator) {
53145314
return;
53155315
}
53165316

@@ -5326,28 +5326,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
53265326
//
53275327

53285328
writeLine();
5329-
emitStart(node);
5329+
emitStart(node.decorators || firstParameterDecorator);
53305330
emitDeclarationName(node);
53315331
write(" = __decorate([");
53325332
increaseIndent();
53335333
writeLine();
53345334

53355335
const decoratorCount = decorators ? decorators.length : 0;
5336-
let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => {
5337-
emitStart(decorator);
5338-
emit(decorator.expression);
5339-
emitEnd(decorator);
5340-
});
5341-
5342-
argumentsWritten += emitDecoratorsOfParameters(constructor, /*leadingComma*/ argumentsWritten > 0);
5336+
let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true,
5337+
decorator => emit(decorator.expression));
5338+
if (firstParameterDecorator) {
5339+
argumentsWritten += emitDecoratorsOfParameters(constructor, /*leadingComma*/ argumentsWritten > 0);
5340+
}
53435341
emitSerializedTypeMetadata(node, /*leadingComma*/ argumentsWritten >= 0);
53445342

53455343
decreaseIndent();
53465344
writeLine();
53475345
write("], ");
53485346
emitDeclarationName(node);
5349-
write(");");
5350-
emitEnd(node);
5347+
write(")");
5348+
emitEnd(node.decorators || firstParameterDecorator);
5349+
write(";");
53515350
writeLine();
53525351
}
53535352

@@ -5363,11 +5362,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
53635362
continue;
53645363
}
53655364

5366-
// skip a member if it or any of its parameters are not decorated
5367-
if (!nodeOrChildIsDecorated(member)) {
5368-
continue;
5369-
}
5370-
53715365
// skip an accessor declaration if it is not the first accessor
53725366
let decorators: NodeArray<Decorator>;
53735367
let functionLikeMember: FunctionLikeDeclaration;
@@ -5394,6 +5388,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
53945388
functionLikeMember = <MethodDeclaration>member;
53955389
}
53965390
}
5391+
const firstParameterDecorator = functionLikeMember && forEach(functionLikeMember.parameters, parameter => parameter.decorators);
5392+
5393+
// skip a member if it or any of its parameters are not decorated
5394+
if (!decorators && !firstParameterDecorator) {
5395+
continue;
5396+
}
53975397

53985398
// Emit the call to __decorate. Given the following:
53995399
//
@@ -5427,29 +5427,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
54275427
//
54285428

54295429
writeLine();
5430-
emitStart(member);
5430+
emitStart(decorators || firstParameterDecorator);
54315431
write("__decorate([");
54325432
increaseIndent();
54335433
writeLine();
54345434

54355435
const decoratorCount = decorators ? decorators.length : 0;
5436-
let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true, decorator => {
5437-
emitStart(decorator);
5438-
emit(decorator.expression);
5439-
emitEnd(decorator);
5440-
});
5436+
let argumentsWritten = emitList(decorators, 0, decoratorCount, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ false, /*noTrailingNewLine*/ true,
5437+
decorator => emit(decorator.expression));
54415438

5442-
argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0);
5439+
if (firstParameterDecorator) {
5440+
argumentsWritten += emitDecoratorsOfParameters(functionLikeMember, argumentsWritten > 0);
5441+
}
54435442
emitSerializedTypeMetadata(member, argumentsWritten > 0);
54445443

54455444
decreaseIndent();
54465445
writeLine();
54475446
write("], ");
5448-
emitStart(member.name);
54495447
emitClassMemberPrefix(node, member);
54505448
write(", ");
54515449
emitExpressionForPropertyName(member.name);
5452-
emitEnd(member.name);
54535450

54545451
if (languageVersion > ScriptTarget.ES3) {
54555452
if (member.kind !== SyntaxKind.PropertyDeclaration) {
@@ -5464,8 +5461,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
54645461
}
54655462
}
54665463

5467-
write(");");
5468-
emitEnd(member);
5464+
write(")");
5465+
emitEnd(decorators || firstParameterDecorator);
5466+
write(";");
54695467
writeLine();
54705468
}
54715469
}
@@ -5478,11 +5476,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, Promi
54785476
if (nodeIsDecorated(parameter)) {
54795477
const decorators = parameter.decorators;
54805478
argumentsWritten += emitList(decorators, 0, decorators.length, /*multiLine*/ true, /*trailingComma*/ false, /*leadingComma*/ leadingComma, /*noTrailingNewLine*/ true, decorator => {
5481-
emitStart(decorator);
54825479
write(`__param(${parameterIndex}, `);
54835480
emit(decorator.expression);
54845481
write(")");
5485-
emitEnd(decorator);
54865482
});
54875483
leadingComma = true;
54885484
}

src/compiler/parser.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4902,7 +4902,7 @@ namespace ts {
49024902

49034903
if (!decorators) {
49044904
decorators = <NodeArray<Decorator>>[];
4905-
decorators.pos = scanner.getStartPos();
4905+
decorators.pos = decoratorStart;
49064906
}
49074907

49084908
const decorator = <Decorator>createNode(SyntaxKind.Decorator, decoratorStart);

src/compiler/sourcemap.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,8 @@ namespace ts {
251251
}
252252

253253
function emitStart(range: TextRange) {
254-
emitPos(range.pos !== -1 ? skipTrivia(currentSourceFile.text, range.pos) : -1);
254+
const rangeHasDecorators = !!(range as Node).decorators;
255+
emitPos(range.pos !== -1 ? skipTrivia(currentSourceFile.text, rangeHasDecorators ? (range as Node).decorators.end : range.pos) : -1);
255256
}
256257

257258
function emitEnd(range: TextRange) {

src/compiler/utilities.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -906,23 +906,6 @@ namespace ts {
906906
return false;
907907
}
908908

909-
export function childIsDecorated(node: Node): boolean {
910-
switch (node.kind) {
911-
case SyntaxKind.ClassDeclaration:
912-
return forEach((<ClassDeclaration>node).members, nodeOrChildIsDecorated);
913-
914-
case SyntaxKind.MethodDeclaration:
915-
case SyntaxKind.SetAccessor:
916-
return forEach((<FunctionLikeDeclaration>node).parameters, nodeIsDecorated);
917-
}
918-
919-
return false;
920-
}
921-
922-
export function nodeOrChildIsDecorated(node: Node): boolean {
923-
return nodeIsDecorated(node) || childIsDecorated(node);
924-
}
925-
926909
export function isPropertyAccessExpression(node: Node): node is PropertyAccessExpression {
927910
return node.kind === SyntaxKind.PropertyAccessExpression;
928911
}

src/services/breakpoints.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ namespace ts.BreakpointResolver {
1616

1717
let tokenAtLocation = getTokenAtPosition(sourceFile, position);
1818
let lineOfPosition = sourceFile.getLineAndCharacterOfPosition(position).line;
19-
if (sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getStart()).line > lineOfPosition) {
19+
if (sourceFile.getLineAndCharacterOfPosition(tokenAtLocation.getStart(sourceFile)).line > lineOfPosition) {
2020
// Get previous token if the token is returned starts on new line
2121
// eg: let x =10; |--- cursor is here
2222
// let y = 10;
@@ -39,16 +39,23 @@ namespace ts.BreakpointResolver {
3939
return spanInNode(tokenAtLocation);
4040

4141
function textSpan(startNode: Node, endNode?: Node) {
42-
return createTextSpanFromBounds(startNode.getStart(), (endNode || startNode).getEnd());
42+
const start = startNode.decorators ?
43+
skipTrivia(sourceFile.text, startNode.decorators.end) :
44+
startNode.getStart(sourceFile);
45+
return createTextSpanFromBounds(start, (endNode || startNode).getEnd());
4346
}
4447

4548
function spanInNodeIfStartsOnSameLine(node: Node, otherwiseOnNode?: Node): TextSpan {
46-
if (node && lineOfPosition === sourceFile.getLineAndCharacterOfPosition(node.getStart()).line) {
49+
if (node && lineOfPosition === sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line) {
4750
return spanInNode(node);
4851
}
4952
return spanInNode(otherwiseOnNode);
5053
}
5154

55+
function spanInNodeArray<T>(nodeArray: NodeArray<T>) {
56+
return createTextSpanFromBounds(skipTrivia(sourceFile.text, nodeArray.pos), nodeArray.end);
57+
}
58+
5259
function spanInPreviousNode(node: Node): TextSpan {
5360
return spanInNode(findPrecedingToken(node.pos, sourceFile));
5461
}
@@ -65,6 +72,11 @@ namespace ts.BreakpointResolver {
6572
return spanInPreviousNode(node);
6673
}
6774

75+
if (node.parent.kind === SyntaxKind.Decorator) {
76+
// Set breakpoint on the decorator emit
77+
return spanInNode(node.parent);
78+
}
79+
6880
if (node.parent.kind === SyntaxKind.ForStatement) {
6981
// For now lets set the span on this expression, fix it later
7082
return textSpan(node);
@@ -207,6 +219,9 @@ namespace ts.BreakpointResolver {
207219
// span in statement
208220
return spanInNode((<WithStatement>node).statement);
209221

222+
case SyntaxKind.Decorator:
223+
return spanInNodeArray(node.parent.decorators);
224+
210225
// No breakpoint in interface, type alias
211226
case SyntaxKind.InterfaceDeclaration:
212227
case SyntaxKind.TypeAliasDeclaration:

0 commit comments

Comments
 (0)