@@ -125,7 +125,7 @@ export function convertNgModuleDeclarationToStandalone(
125125 const directiveMeta = typeChecker . getDirectiveMetadata ( decl ) ;
126126
127127 if ( directiveMeta && directiveMeta . decorator && ! directiveMeta . isStandalone ) {
128- let decorator = addStandaloneToDecorator ( directiveMeta . decorator ) ;
128+ let decorator = removeStandaloneFalseFromDecorator ( directiveMeta . decorator ) ;
129129
130130 if ( directiveMeta . isComponent ) {
131131 const importsToAdd = getComponentImportExpressions (
@@ -157,7 +157,10 @@ export function convertNgModuleDeclarationToStandalone(
157157 const pipeMeta = typeChecker . getPipeMetadata ( decl ) ;
158158
159159 if ( pipeMeta && pipeMeta . decorator && ! pipeMeta . isStandalone ) {
160- tracker . replaceNode ( pipeMeta . decorator , addStandaloneToDecorator ( pipeMeta . decorator ) ) ;
160+ tracker . replaceNode (
161+ pipeMeta . decorator ,
162+ removeStandaloneFalseFromDecorator ( pipeMeta . decorator ) ,
163+ ) ;
161164 }
162165 }
163166}
@@ -427,11 +430,31 @@ function moveDeclarationsToImports(
427430}
428431
429432/** Adds `standalone: true` to a decorator node. */
430- function addStandaloneToDecorator ( node : ts . Decorator ) : ts . Decorator {
431- return setPropertyOnAngularDecorator (
432- node ,
433- 'standalone' ,
434- ts . factory . createToken ( ts . SyntaxKind . TrueKeyword ) ,
433+ function removeStandaloneFalseFromDecorator ( node : ts . Decorator ) : ts . Decorator {
434+ // Invalid decorator.
435+ if ( ! ts . isCallExpression ( node . expression ) || node . expression . arguments . length !== 1 ) {
436+ return node ;
437+ }
438+
439+ if ( ! ts . isObjectLiteralExpression ( node . expression . arguments [ 0 ] ) ) {
440+ // Unsupported case (e.g. `@Component(SOME_CONST)`). Return the original node.
441+ return node ;
442+ }
443+
444+ const hasTrailingComma = node . expression . arguments [ 0 ] . properties . hasTrailingComma ;
445+
446+ const properties = node . expression . arguments [ 0 ] . properties ;
447+ const literalProperties = properties . filter ( ( element ) => ! isStandaloneProperty ( element ) ) ;
448+
449+ // Use `createDecorator` instead of `updateDecorator`, because
450+ // the latter ends up duplicating the node's leading comment.
451+ return ts . factory . createDecorator (
452+ ts . factory . createCallExpression ( node . expression . expression , node . expression . typeArguments , [
453+ ts . factory . createObjectLiteralExpression (
454+ ts . factory . createNodeArray ( literalProperties , hasTrailingComma ) ,
455+ literalProperties . length > 1 ,
456+ ) ,
457+ ] ) ,
435458 ) ;
436459}
437460
@@ -489,6 +512,11 @@ function setPropertyOnAngularDecorator(
489512 ) ;
490513}
491514
515+ function isStandaloneProperty ( prop : ts . Node ) : prop is ts . PropertyAssignment {
516+ return (
517+ ts . isPropertyAssignment ( prop ) && ts . isIdentifier ( prop . name ) && prop . name . text === 'standalone'
518+ ) ;
519+ }
492520/** Checks if a node is a `PropertyAssignment` with a name. */
493521function isNamedPropertyAssignment (
494522 node : ts . Node ,
@@ -746,13 +774,13 @@ export function migrateTestDeclarations(
746774 const closestClass = closestNode ( decorator . node , ts . isClassDeclaration ) ;
747775
748776 if ( decorator . name === 'Pipe' || decorator . name === 'Directive' ) {
749- tracker . replaceNode ( decorator . node , addStandaloneToDecorator ( decorator . node ) ) ;
777+ tracker . replaceNode ( decorator . node , removeStandaloneFalseFromDecorator ( decorator . node ) ) ;
750778
751779 if ( closestClass ) {
752780 allDeclarations . add ( closestClass ) ;
753781 }
754782 } else if ( decorator . name === 'Component' ) {
755- const newDecorator = addStandaloneToDecorator ( decorator . node ) ;
783+ const newDecorator = removeStandaloneFalseFromDecorator ( decorator . node ) ;
756784 const importsToAdd = componentImports . get ( decorator . node ) ;
757785
758786 if ( closestClass ) {
0 commit comments