diff --git a/libs/plugin/src/generators/convert-outputs/__snapshots__/generator.spec.ts.snap b/libs/plugin/src/generators/convert-outputs/__snapshots__/generator.spec.ts.snap index 54c21104..330ad167 100644 --- a/libs/plugin/src/generators/convert-outputs/__snapshots__/generator.spec.ts.snap +++ b/libs/plugin/src/generators/convert-outputs/__snapshots__/generator.spec.ts.snap @@ -28,6 +28,13 @@ export class MyCmp { withObservable = outputFromObservable(this.someObservable$); aliasOutput = output({ alias: 'withAlias' }); + + noInitializer = output(); + + initializedInConstructor = output(); + + constructor() { + } ngOnInit() { let imABoolean = false; diff --git a/libs/plugin/src/generators/convert-outputs/generator.spec.ts b/libs/plugin/src/generators/convert-outputs/generator.spec.ts index 247c8da5..c6de5407 100644 --- a/libs/plugin/src/generators/convert-outputs/generator.spec.ts +++ b/libs/plugin/src/generators/convert-outputs/generator.spec.ts @@ -55,6 +55,14 @@ export class MyCmp { @Output() withObservable = this.someObservable$; @Output('withAlias') aliasOutput = new EventEmitter(); + + @Output() noInitializer: EventEmitter; + + @Output() initializedInConstructor; + + constructor() { + this.initializedInConstructor = new EventEmitter(); + } ngOnInit() { let imABoolean = false; diff --git a/libs/plugin/src/generators/convert-outputs/generator.ts b/libs/plugin/src/generators/convert-outputs/generator.ts index e68c751b..28430faa 100644 --- a/libs/plugin/src/generators/convert-outputs/generator.ts +++ b/libs/plugin/src/generators/convert-outputs/generator.ts @@ -62,8 +62,25 @@ function getOutputInitializer( alias = decoratorArg.getText(); } + const initializerOrType = + initializer ?? (typeof currentType === 'string' ? currentType : undefined); + + if (!initializerOrType) { + logger.error( + `[ngxtension] Unable to find initializer or type for "${propertyName}"`, + ); + return exit(1); + } + // check if the initializer is not an EventEmitter -> means its an observable - if (!initializer.includes('EventEmitter')) { + if (!initializerOrType.includes('EventEmitter')) { + if (!initializer) { + logger.error( + `[ngxtension] Unable to find initializer for "${propertyName}"`, + ); + return exit(1); + } + // if the initializer is a Subject or BehaviorSubject if ( initializer.includes('Subject') || @@ -96,10 +113,11 @@ function getOutputInitializer( } } else { let type = ''; - if (initializer.includes('EventEmitter()')) { + if (initializerOrType.includes('EventEmitter()')) { // there is no type } else { - const genericTypeOnEmitter = initializer.match(/EventEmitter<(.+)>/); + const genericTypeOnEmitter = + initializerOrType.match(/EventEmitter<(.+)>/); if (genericTypeOnEmitter?.length) { type = genericTypeOnEmitter[1]; } @@ -242,7 +260,7 @@ export async function convertOutputsGenerator( if (Node.isPropertyDeclaration(node)) { const outputDecorator = node.getDecorator('Output'); if (outputDecorator) { - const { + let { name, isReadonly, docs, @@ -252,6 +270,20 @@ export async function convertOutputsGenerator( initializer, } = node.getStructure(); + if (!initializer) { + // look for constructor initializer + const constructor = targetClass.getConstructors()[0]; + if (constructor) { + const constructorInitializer = constructor + .getStatements() + .find((stmt) => stmt.getText().includes(`${name} =`)); + if (constructorInitializer) { + initializer = constructorInitializer.getText(); + } + constructorInitializer?.remove(); + } + } + const { needsOutputFromObservableImport, removeOnlyDecorator,