@@ -228,6 +228,7 @@ interface ClassInfo {
228
228
classExtraInitializersName ?: Identifier ; // used in step 13
229
229
classThis ?: Identifier ; // `_classThis`, if needed.
230
230
classSuper ?: Identifier ; // `_classSuper`, if needed.
231
+ metadataReference : Identifier ;
231
232
232
233
memberInfos ?: Map < ClassElement , MemberInfo > ; // used in step 4.a, 12, and construction
233
234
@@ -563,6 +564,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
563
564
}
564
565
565
566
function createClassInfo ( node : ClassLikeDeclaration ) : ClassInfo {
567
+ const metadataReference = factory . createUniqueName ( "_metadata" , GeneratedIdentifierFlags . Optimistic | GeneratedIdentifierFlags . FileLevel ) ;
566
568
let instanceExtraInitializersName : Identifier | undefined ;
567
569
let staticExtraInitializersName : Identifier | undefined ;
568
570
let hasStaticInitializers = false ;
@@ -611,6 +613,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
611
613
612
614
return {
613
615
class : node ,
616
+ metadataReference,
614
617
instanceExtraInitializersName,
615
618
staticExtraInitializersName,
616
619
hasStaticInitializers,
@@ -619,18 +622,6 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
619
622
} ;
620
623
}
621
624
622
- function containsLexicalSuperInStaticInitializer ( node : ClassLikeDeclaration ) {
623
- for ( const member of node . members ) {
624
- if ( isClassStaticBlockDeclaration ( member ) ||
625
- isPropertyDeclaration ( member ) && hasStaticModifier ( member ) ) {
626
- if ( member . transformFlags & TransformFlags . ContainsLexicalSuper ) {
627
- return true ;
628
- }
629
- }
630
- }
631
- return false ;
632
- }
633
-
634
625
function transformClassLike ( node : ClassLikeDeclaration ) {
635
626
startLexicalEnvironment ( ) ;
636
627
@@ -681,31 +672,25 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
681
672
}
682
673
683
674
// Rewrite `super` in static initializers so that we can use the correct `this`.
684
- if ( classDecorators && containsLexicalSuperInStaticInitializer ( node ) ) {
685
- const extendsClause = getHeritageClause ( node . heritageClauses , SyntaxKind . ExtendsKeyword ) ;
686
- const extendsElement = extendsClause && firstOrUndefined ( extendsClause . types ) ;
687
- const extendsExpression = extendsElement && visitNode ( extendsElement . expression , visitor , isExpression ) ;
688
- if ( extendsExpression ) {
689
- classInfo . classSuper = factory . createUniqueName ( "_classSuper" , GeneratedIdentifierFlags . Optimistic | GeneratedIdentifierFlags . FileLevel ) ;
675
+ const extendsClause = getHeritageClause ( node . heritageClauses , SyntaxKind . ExtendsKeyword ) ;
676
+ const extendsElement = extendsClause && firstOrUndefined ( extendsClause . types ) ;
677
+ const extendsExpression = extendsElement && visitNode ( extendsElement . expression , visitor , isExpression ) ;
678
+ if ( extendsExpression ) {
679
+ classInfo . classSuper = factory . createUniqueName ( "_classSuper" , GeneratedIdentifierFlags . Optimistic | GeneratedIdentifierFlags . FileLevel ) ;
690
680
691
681
// Ensure we do not give the class or function an assigned name due to the variable by prefixing it
692
682
// with `0, `.
693
- const unwrapped = skipOuterExpressions ( extendsExpression ) ;
694
- const safeExtendsExpression =
695
- isClassExpression ( unwrapped ) && ! unwrapped . name ||
696
- isFunctionExpression ( unwrapped ) && ! unwrapped . name ||
697
- isArrowFunction ( unwrapped ) ?
698
- factory . createComma ( factory . createNumericLiteral ( 0 ) , extendsExpression ) :
699
- extendsExpression ;
700
- classDefinitionStatements . push ( createLet ( classInfo . classSuper , safeExtendsExpression ) ) ;
701
- const updatedExtendsElement = factory . updateExpressionWithTypeArguments ( extendsElement , classInfo . classSuper , /*typeArguments*/ undefined ) ;
702
- const updatedExtendsClause = factory . updateHeritageClause ( extendsClause , [ updatedExtendsElement ] ) ;
703
- heritageClauses = factory . createNodeArray ( [ updatedExtendsClause ] ) ;
704
- }
705
- }
706
- else {
707
- // 2. ClassHeritage clause is evaluated outside of the private name scope of the class.
708
- heritageClauses = visitNodes ( node . heritageClauses , visitor , isHeritageClause ) ;
683
+ const unwrapped = skipOuterExpressions ( extendsExpression ) ;
684
+ const safeExtendsExpression =
685
+ isClassExpression ( unwrapped ) && ! unwrapped . name ||
686
+ isFunctionExpression ( unwrapped ) && ! unwrapped . name ||
687
+ isArrowFunction ( unwrapped ) ?
688
+ factory . createComma ( factory . createNumericLiteral ( 0 ) , extendsExpression ) :
689
+ extendsExpression ;
690
+ classDefinitionStatements . push ( createLet ( classInfo . classSuper , safeExtendsExpression ) ) ;
691
+ const updatedExtendsElement = factory . updateExpressionWithTypeArguments ( extendsElement , classInfo . classSuper , /*typeArguments*/ undefined ) ;
692
+ const updatedExtendsClause = factory . updateHeritageClause ( extendsClause , [ updatedExtendsElement ] ) ;
693
+ heritageClauses = factory . createNodeArray ( [ updatedExtendsClause ] ) ;
709
694
}
710
695
711
696
const renamedClassThis = classInfo . classThis ?? factory . createThis ( ) ;
@@ -724,8 +709,10 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
724
709
// - The second pass visits the constructor to add instance initializers.
725
710
//
726
711
// NOTE: If there are no constructors, but there are instance initializers, a synthetic constructor is added.
727
-
728
712
enterClass ( classInfo ) ;
713
+
714
+ leadingBlockStatements = append ( leadingBlockStatements , createMetadata ( classInfo . metadataReference , classInfo . classSuper ) ) ;
715
+
729
716
let members = visitNodes ( node . members , classElementVisitor , isClassElement ) ;
730
717
if ( pendingExpressions ) {
731
718
let outerThis : Identifier | undefined ;
@@ -840,7 +827,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
840
827
leadingBlockStatements ??= [ ] ;
841
828
842
829
// produces:
843
- // __esDecorate(null, _classDescriptor = { value: this }, _classDecorators, { kind: "class", name: this.name }, _classExtraInitializers);
830
+ // __esDecorate(null, _classDescriptor = { value: this }, _classDecorators, { kind: "class", name: this.name, metadata }, _classExtraInitializers);
844
831
const valueProperty = factory . createPropertyAssignment ( "value" , renamedClassThis ) ;
845
832
const classDescriptor = factory . createObjectLiteralExpression ( [ valueProperty ] ) ;
846
833
const classDescriptorAssignment = factory . createAssignment ( classInfo . classDescriptorName , classDescriptor ) ;
@@ -849,7 +836,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
849
836
factory . createNull ( ) ,
850
837
classDescriptorAssignment ,
851
838
classInfo . classDecoratorsName ,
852
- { kind : "class" , name : classNameReference } ,
839
+ { kind : "class" , name : classNameReference , metadata : classInfo . metadataReference } ,
853
840
factory . createNull ( ) ,
854
841
classInfo . classExtraInitializersName
855
842
) ;
@@ -865,6 +852,9 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
865
852
leadingBlockStatements . push ( factory . createExpressionStatement ( classReferenceAssignment ) ) ;
866
853
}
867
854
855
+ // if (metadata) Object.defineProperty(C, Symbol.metadata, { configurable: true, writable: true, value: metadata });
856
+ leadingBlockStatements . push ( createSymbolMetadata ( renamedClassThis , classInfo . metadataReference ) ) ;
857
+
868
858
// 11. Static extra initializers are evaluated
869
859
if ( classInfo . staticExtraInitializersName ) {
870
860
const runStaticInitializersHelper = emitHelpers ( ) . createRunInitializersHelper ( renamedClassThis , classInfo . staticExtraInitializersName ) ;
@@ -1283,6 +1273,7 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
1283
1273
// 3. If _kind_ is ~field~, ~accessor~, or ~setter~, then ...
1284
1274
set : isPropertyDeclaration ( member ) || isSetAccessorDeclaration ( member )
1285
1275
} ,
1276
+ metadata : classInfo . metadataReference ,
1286
1277
} ;
1287
1278
1288
1279
const extraInitializers = isStatic ( member ) ?
@@ -2371,4 +2362,49 @@ export function transformESDecorators(context: TransformationContext): (x: Sourc
2371
2362
] )
2372
2363
) ;
2373
2364
}
2365
+ function createMetadata ( name : Identifier , classSuper : Identifier | undefined ) {
2366
+ const varDecl = factory . createVariableDeclaration (
2367
+ name ,
2368
+ /*exclamationToken*/ undefined ,
2369
+ /*type*/ undefined ,
2370
+ factory . createConditionalExpression (
2371
+ factory . createLogicalAnd (
2372
+ factory . createTypeCheck ( factory . createIdentifier ( "Symbol" ) , "function" ) ,
2373
+ factory . createPropertyAccessExpression ( factory . createIdentifier ( "Symbol" ) , "metadata" ) ,
2374
+ ) ,
2375
+ factory . createToken ( SyntaxKind . QuestionToken ) ,
2376
+ factory . createCallExpression (
2377
+ factory . createPropertyAccessExpression ( factory . createIdentifier ( "Object" ) , "create" ) ,
2378
+ /*typeArguments*/ undefined ,
2379
+ [ classSuper ? createSymbolMetadataReference ( classSuper ) : factory . createNull ( ) ]
2380
+ ) ,
2381
+ factory . createToken ( SyntaxKind . ColonToken ) ,
2382
+ factory . createVoidZero ( ) ,
2383
+ ) ,
2384
+ ) ;
2385
+ return factory . createVariableStatement ( /*modifiers*/ undefined , factory . createVariableDeclarationList ( [ varDecl ] , NodeFlags . Const ) ) ;
2386
+ }
2387
+
2388
+ function createSymbolMetadata ( target : Identifier | ThisExpression , value : Identifier ) {
2389
+ const defineProperty = factory . createObjectDefinePropertyCall (
2390
+ target ,
2391
+ factory . createPropertyAccessExpression ( factory . createIdentifier ( "Symbol" ) , "metadata" ) ,
2392
+ factory . createPropertyDescriptor ( { configurable : true , writable : true , enumerable : true , value } , /*singleLine*/ true )
2393
+ ) ;
2394
+ return setEmitFlags (
2395
+ factory . createIfStatement ( value , factory . createExpressionStatement ( defineProperty ) ) ,
2396
+ EmitFlags . SingleLine ,
2397
+ ) ;
2398
+ }
2399
+
2400
+ function createSymbolMetadataReference ( classSuper : Identifier ) {
2401
+ return factory . createBinaryExpression (
2402
+ factory . createElementAccessExpression (
2403
+ classSuper ,
2404
+ factory . createPropertyAccessExpression ( factory . createIdentifier ( "Symbol" ) , "metadata" ) ,
2405
+ ) ,
2406
+ SyntaxKind . QuestionQuestionToken ,
2407
+ factory . createNull ( )
2408
+ ) ;
2409
+ }
2374
2410
}
0 commit comments