Skip to content

Commit 50fa541

Browse files
committed
Move legacy decorators into separate transform
1 parent a1e77ed commit 50fa541

File tree

12 files changed

+1663
-1043
lines changed

12 files changed

+1663
-1043
lines changed

src/compiler/factory/nodeFactory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1252,7 +1252,8 @@ namespace ts {
12521252
node.transformFlags |=
12531253
propagateChildFlags(node.expression) |
12541254
TransformFlags.ContainsTypeScript |
1255-
TransformFlags.ContainsTypeScriptClassSyntax;
1255+
TransformFlags.ContainsTypeScriptClassSyntax |
1256+
TransformFlags.ContainsDecorators;
12561257
return node;
12571258
}
12581259

src/compiler/factory/utilities.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,4 +1215,16 @@ namespace ts {
12151215
return resultHolder.value;
12161216
}
12171217
}
1218+
1219+
/**
1220+
* If `nodes` is not undefined, creates an empty `NodeArray` that preserves the `pos` and `end` of `nodes`.
1221+
* @internal
1222+
*/
1223+
export function elideNodes<T extends Node>(factory: NodeFactory, nodes: NodeArray<T>): NodeArray<T>;
1224+
export function elideNodes<T extends Node>(factory: NodeFactory, nodes: NodeArray<T> | undefined): NodeArray<T> | undefined;
1225+
export function elideNodes<T extends Node>(factory: NodeFactory, nodes: NodeArray<T> | undefined): NodeArray<T> | undefined {
1226+
if (nodes === undefined) return undefined;
1227+
if (nodes.length === 0) return nodes;
1228+
return setTextRange(factory.createNodeArray([], nodes.hasTrailingComma), nodes);
1229+
}
12181230
}

src/compiler/transformer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ namespace ts {
4848
addRange(transformers, customTransformers && map(customTransformers.before, wrapScriptTransformerFactory));
4949

5050
transformers.push(transformTypeScript);
51+
transformers.push(transformLegacyDecorators);
5152
transformers.push(transformClassFields);
5253

5354
if (getJSXTransformEnabled(compilerOptions)) {

src/compiler/transformers/legacyDecorators.ts

Lines changed: 675 additions & 0 deletions
Large diffs are not rendered by default.

src/compiler/transformers/ts.ts

Lines changed: 225 additions & 1015 deletions
Large diffs are not rendered by default.

src/compiler/transformers/typeSerializer.ts

Lines changed: 569 additions & 0 deletions
Large diffs are not rendered by default.

src/compiler/transformers/utilities.ts

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,4 +384,140 @@ namespace ts {
384384
export function isNonStaticMethodOrAccessorWithPrivateName(member: ClassElement): member is PrivateIdentifierMethodDeclaration | PrivateIdentifierAccessorDeclaration {
385385
return !isStatic(member) && isMethodOrAccessor(member) && isPrivateIdentifier(member.name);
386386
}
387+
388+
/**
389+
* Gets an array of arrays of decorators for the parameters of a function-like node.
390+
* The offset into the result array should correspond to the offset of the parameter.
391+
*
392+
* @param node The function-like node.
393+
*/
394+
function getDecoratorsOfParameters(node: FunctionLikeDeclaration | undefined) {
395+
let decorators: (readonly Decorator[] | undefined)[] | undefined;
396+
if (node) {
397+
const parameters = node.parameters;
398+
const firstParameterIsThis = parameters.length > 0 && parameterIsThisKeyword(parameters[0]);
399+
const firstParameterOffset = firstParameterIsThis ? 1 : 0;
400+
const numParameters = firstParameterIsThis ? parameters.length - 1 : parameters.length;
401+
for (let i = 0; i < numParameters; i++) {
402+
const parameter = parameters[i + firstParameterOffset];
403+
if (decorators || parameter.decorators) {
404+
if (!decorators) {
405+
decorators = new Array(numParameters);
406+
}
407+
408+
decorators[i] = parameter.decorators;
409+
}
410+
}
411+
}
412+
413+
return decorators;
414+
}
415+
416+
/**
417+
* Gets an AllDecorators object containing the decorators for the class and the decorators for the
418+
* parameters of the constructor of the class.
419+
*
420+
* @param node The class node.
421+
*/
422+
export function getAllDecoratorsOfClass(node: ClassLikeDeclaration): AllDecorators | undefined {
423+
const decorators = node.decorators;
424+
const parameters = getDecoratorsOfParameters(getFirstConstructorWithBody(node));
425+
if (!decorators && !parameters) {
426+
return undefined;
427+
}
428+
429+
return {
430+
decorators,
431+
parameters
432+
};
433+
}
434+
435+
/**
436+
* Gets an AllDecorators object containing the decorators for the member and its parameters.
437+
*
438+
* @param parent The class node that contains the member.
439+
* @param member The class member.
440+
*/
441+
export function getAllDecoratorsOfClassElement(member: ClassElement, parent: ClassLikeDeclaration): AllDecorators | undefined {
442+
switch (member.kind) {
443+
case SyntaxKind.GetAccessor:
444+
case SyntaxKind.SetAccessor:
445+
return getAllDecoratorsOfAccessors(member as AccessorDeclaration, parent);
446+
447+
case SyntaxKind.MethodDeclaration:
448+
return getAllDecoratorsOfMethod(member as MethodDeclaration);
449+
450+
case SyntaxKind.PropertyDeclaration:
451+
return getAllDecoratorsOfProperty(member as PropertyDeclaration);
452+
453+
default:
454+
return undefined;
455+
}
456+
}
457+
458+
/**
459+
* Gets an AllDecorators object containing the decorators for the accessor and its parameters.
460+
*
461+
* @param parent The class node that contains the accessor.
462+
* @param accessor The class accessor member.
463+
*/
464+
function getAllDecoratorsOfAccessors(accessor: AccessorDeclaration, parent: ClassExpression | ClassDeclaration): AllDecorators | undefined {
465+
if (!accessor.body) {
466+
return undefined;
467+
}
468+
469+
const { firstAccessor, secondAccessor, getAccessor, setAccessor } = getAllAccessorDeclarations(parent.members, accessor);
470+
const firstAccessorWithDecorators = firstAccessor.decorators ? firstAccessor : secondAccessor && secondAccessor.decorators ? secondAccessor : undefined;
471+
if (!firstAccessorWithDecorators || accessor !== firstAccessorWithDecorators) {
472+
return undefined;
473+
}
474+
475+
const decorators = firstAccessorWithDecorators.decorators;
476+
const parameters = getDecoratorsOfParameters(setAccessor);
477+
if (!decorators && !parameters) {
478+
return undefined;
479+
}
480+
481+
return {
482+
decorators,
483+
parameters,
484+
getDecorators: getAccessor?.decorators,
485+
setDecorators: setAccessor?.decorators
486+
};
487+
}
488+
489+
/**
490+
* Gets an AllDecorators object containing the decorators for the method and its parameters.
491+
*
492+
* @param method The class method member.
493+
*/
494+
function getAllDecoratorsOfMethod(method: MethodDeclaration): AllDecorators | undefined {
495+
if (!method.body) {
496+
return undefined;
497+
}
498+
499+
const decorators = method.decorators;
500+
const parameters = getDecoratorsOfParameters(method);
501+
if (!decorators && !parameters) {
502+
return undefined;
503+
}
504+
505+
return { decorators, parameters };
506+
}
507+
508+
/**
509+
* Gets an AllDecorators object containing the decorators for the property.
510+
*
511+
* @param property The class property member.
512+
*/
513+
function getAllDecoratorsOfProperty(property: PropertyDeclaration): AllDecorators | undefined {
514+
const decorators = property.decorators;
515+
if (!decorators) {
516+
return undefined;
517+
518+
}
519+
520+
return { decorators };
521+
}
522+
387523
}

src/compiler/tsconfig.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
"transformers/taggedTemplate.ts",
5050
"transformers/ts.ts",
5151
"transformers/classFields.ts",
52+
"transformers/typeSerializer.ts",
53+
"transformers/legacyDecorators.ts",
5254
"transformers/es2017.ts",
5355
"transformers/es2018.ts",
5456
"transformers/es2019.ts",

src/compiler/types.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4736,6 +4736,14 @@ namespace ts {
47364736
setAccessor: SetAccessorDeclaration | undefined;
47374737
}
47384738

4739+
/* @internal */
4740+
export interface AllDecorators {
4741+
decorators: NodeArray<Decorator> | undefined;
4742+
parameters?: readonly (readonly Decorator[] | undefined)[];
4743+
getDecorators?: NodeArray<Decorator> | undefined;
4744+
setDecorators?: NodeArray<Decorator> | undefined;
4745+
}
4746+
47394747
/** Indicates how to serialize the name for a TypeReferenceNode when emitting decorator metadata */
47404748
/* @internal */
47414749
export enum TypeReferenceSerializationKind {
@@ -6812,21 +6820,22 @@ namespace ts {
68126820

68136821
// Markers
68146822
// - Flags used to indicate that a subtree contains a specific transformation.
6815-
ContainsTypeScriptClassSyntax = 1 << 12, // Decorators, Property Initializers, Parameter Property Initializers
6816-
ContainsLexicalThis = 1 << 13,
6817-
ContainsRestOrSpread = 1 << 14,
6818-
ContainsObjectRestOrSpread = 1 << 15,
6819-
ContainsComputedPropertyName = 1 << 16,
6820-
ContainsBlockScopedBinding = 1 << 17,
6821-
ContainsBindingPattern = 1 << 18,
6822-
ContainsYield = 1 << 19,
6823-
ContainsAwait = 1 << 20,
6824-
ContainsHoistedDeclarationOrCompletion = 1 << 21,
6825-
ContainsDynamicImport = 1 << 22,
6826-
ContainsClassFields = 1 << 23,
6827-
ContainsPossibleTopLevelAwait = 1 << 24,
6828-
ContainsLexicalSuper = 1 << 25,
6829-
ContainsUpdateExpressionForIdentifier = 1 << 26,
6823+
ContainsTypeScriptClassSyntax = 1 << 13, // Property Initializers, Parameter Property Initializers
6824+
ContainsLexicalThis = 1 << 14,
6825+
ContainsRestOrSpread = 1 << 15,
6826+
ContainsObjectRestOrSpread = 1 << 16,
6827+
ContainsComputedPropertyName = 1 << 17,
6828+
ContainsBlockScopedBinding = 1 << 18,
6829+
ContainsBindingPattern = 1 << 19,
6830+
ContainsYield = 1 << 20,
6831+
ContainsAwait = 1 << 21,
6832+
ContainsHoistedDeclarationOrCompletion = 1 << 22,
6833+
ContainsDynamicImport = 1 << 23,
6834+
ContainsClassFields = 1 << 24,
6835+
ContainsDecorators = 1 << 25,
6836+
ContainsPossibleTopLevelAwait = 1 << 26,
6837+
ContainsLexicalSuper = 1 << 27,
6838+
ContainsUpdateExpressionForIdentifier = 1 << 28,
68306839
// Please leave this as 1 << 29.
68316840
// It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system.
68326841
// It is a good reminder of how much room we have left

src/compiler/utilities.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3018,6 +3018,11 @@ namespace ts {
30183018
return [child, node];
30193019
}
30203020

3021+
export function skipTypeParentheses(node: TypeNode): TypeNode {
3022+
while (isParenthesizedTypeNode(node)) node = node.type;
3023+
return node;
3024+
}
3025+
30213026
export function skipParentheses(node: Expression, excludeJSDocTypeAssertions?: boolean): Expression;
30223027
export function skipParentheses(node: Node, excludeJSDocTypeAssertions?: boolean): Node;
30233028
export function skipParentheses(node: Node, excludeJSDocTypeAssertions?: boolean): Node {
@@ -5391,7 +5396,7 @@ namespace ts {
53915396
* Moves the start position of a range past any decorators.
53925397
*/
53935398
export function moveRangePastDecorators(node: Node): TextRange {
5394-
return node.decorators && node.decorators.length > 0
5399+
return node.decorators && !positionIsSynthesized(node.decorators.end)
53955400
? moveRangePos(node, node.decorators.end)
53965401
: node;
53975402
}
@@ -5400,7 +5405,7 @@ namespace ts {
54005405
* Moves the start position of a range past any decorators or modifiers.
54015406
*/
54025407
export function moveRangePastModifiers(node: Node): TextRange {
5403-
return node.modifiers && node.modifiers.length > 0
5408+
return node.modifiers && !positionIsSynthesized(node.modifiers.end)
54045409
? moveRangePos(node, node.modifiers.end)
54055410
: moveRangePastDecorators(node);
54065411
}

0 commit comments

Comments
 (0)