@@ -12,11 +12,12 @@ import { generateError, isClassMethod, isGetterClassMethod, isSetterClassMethod
1212import api from './api' ;
1313import wire from './wire' ;
1414import track from './track' ;
15+ import privateDecorator from './private' ;
1516import type { BabelAPI , BabelTypes , LwcBabelPluginPass } from '../types' ;
1617import type { Node , types , Visitor , NodePath } from '@babel/core' ;
1718import type { ClassBodyItem , ImportSpecifier , LwcDecoratorName } from './types' ;
1819
19- const DECORATOR_TRANSFORMS = [ api , wire , track ] ;
20+ const DECORATOR_TRANSFORMS = [ api , wire , track , privateDecorator ] ;
2021const AVAILABLE_DECORATORS = DECORATOR_TRANSFORMS . map ( ( transform ) => transform . name ) . join ( ', ' ) ;
2122
2223export type DecoratorType = ( typeof DECORATOR_TYPES ) [ keyof typeof DECORATOR_TYPES ] ;
@@ -244,6 +245,7 @@ function getMetadataObjectPropertyList(
244245 ...api . transform ( t , decoratorMetas , classBodyItems ) ,
245246 ...track . transform ( t , decoratorMetas ) ,
246247 ...wire . transform ( t , decoratorMetas ) ,
248+ ...privateDecorator . transform ( t , decoratorMetas , classBodyItems ) ,
247249 ] ;
248250
249251 const fieldNames = classBodyItems
@@ -316,6 +318,71 @@ function decorators({ types: t }: BabelAPI): Visitor<LwcBabelPluginPass> {
316318
317319 decoratorPaths . forEach ( ( path ) => path . remove ( ) ) ;
318320
321+ // Lower instance class fields into constructor assignments BEFORE registerDecorators replacement
322+ const fieldProps = classBodyItems
323+ . filter ( ( f ) => f . isClassProperty ( { static : false , computed : false } ) )
324+ . filter ( ( f ) => ! ( f . node as types . ClassProperty ) . decorators ) ;
325+
326+ const assigns : types . Statement [ ] = [ ] ;
327+ for ( const fp of fieldProps ) {
328+ const id = ( fp . node . key as types . Identifier ) . name ;
329+ const init = fp . node . value ?? t . identifier ( 'undefined' ) ;
330+ assigns . push (
331+ t . expressionStatement (
332+ t . assignmentExpression (
333+ '=' ,
334+ t . memberExpression ( t . thisExpression ( ) , t . identifier ( id ) ) ,
335+ init
336+ )
337+ )
338+ ) ;
339+ fp . remove ( ) ; // remove native class field
340+ }
341+
342+ // Find or create constructor
343+ const ctorPath = classBodyItems . find ( ( p ) =>
344+ p . isClassMethod ( { kind : 'constructor' } )
345+ ) as NodePath < types . ClassMethod > | undefined ;
346+ if ( assigns . length ) {
347+ if ( ctorPath ) {
348+ // insert after super(...)
349+ const body = ctorPath . get ( 'body.body' ) as NodePath < types . Statement > [ ] ;
350+ const superIndex = body . findIndex (
351+ ( b ) =>
352+ b . isExpressionStatement ( ) &&
353+ b . node . expression . type === 'CallExpression' &&
354+ ( b . node . expression . callee as any ) . type === 'Super'
355+ ) ;
356+ const insertIndex = superIndex >= 0 ? superIndex + 1 : 0 ;
357+ if ( body [ insertIndex ] ) {
358+ body [ insertIndex ] . insertBefore ( assigns ) ;
359+ } else {
360+ ctorPath . get ( 'body' ) . pushContainer ( 'body' , assigns ) ;
361+ }
362+ } else {
363+ const needsSuper = node . superClass !== null ;
364+ const ctorBodyStmts : types . Statement [ ] = needsSuper
365+ ? [
366+ t . expressionStatement (
367+ t . callExpression ( t . super ( ) , [
368+ t . spreadElement ( t . identifier ( 'args' ) ) ,
369+ ] )
370+ ) ,
371+ ...assigns ,
372+ ]
373+ : assigns ;
374+ const params = needsSuper ? [ t . restElement ( t . identifier ( 'args' ) ) ] : [ ] ;
375+ const ctor = t . classMethod (
376+ 'constructor' ,
377+ t . identifier ( 'constructor' ) ,
378+ params ,
379+ t . blockStatement ( ctorBodyStmts )
380+ ) ;
381+ path . get ( 'body' ) . pushContainer ( 'body' , ctor ) ;
382+ }
383+ }
384+
385+ // Now perform registerDecorators transform
319386 const isAnonymousClassDeclaration =
320387 path . isClassDeclaration ( ) && ! path . get ( 'id' ) . isIdentifier ( ) ;
321388 const shouldTransformAsClassExpression =
0 commit comments