Include a new module in the declarations NgModule utilizing ts-morph

Currently, I am utilizing the ts-morph library and my objective is to add a new component to the declarations:

This is my initial setup:
@NgModule({
declarations: [],
imports: [],
providers: [],
})

Here is what I am aiming for:

@NgModule({
declarations: [ExampleComponent],
imports: [],
providers: [],
})

I have attempted the following without success:

 const decorator = classDeclaration.getDecorator("NgModule"); 
 const arg = decorator.getArguments()[0];
 
 const declarationsProp = arg.getDescendants()
    .find(d => d.getKind() === SyntaxKind.PropertyAssignment &&
    (d.compilerNode as ts.PropertyAssignment).name === "declarations");

const array = declarationsProp.getFirstChildByKindOrThrow(SyntaxKind.ArrayLiteralExpression);
const closeBracketToken = array.getLastChildByKindOrThrow(SyntaxKind.CloseBracketToken);
 
sourceFile.insertText(closeBracketToken.getPos(), `, "something new!"`);

I also explored another solution but faced challenges with adding the new component:

 const classDeclaration = sourceFile
      .getClasses()
      .find(
        (classDeclaration) =>
          classDeclaration.getName() === 'ExampleModule'
      );

    (classDeclaration.getDecorator('NgModule').getStructure()
      .arguments as any[]).forEach((element) => {
      addLog(LogType.Info, LogMode.Always, element);
    });

Answer №1

If you're seeking an updated syntax, here is a solution:

const ngModuleClass = editCodeBlockInput.sourceFile.getClass(c => c.getText().includes('@NgModule'));
  const ngModuleDecorator = ngModuleClass.getDecorator('NgModule');
  const moduleArguments = ngModuleDecorator.getArguments()[0];

  const declarationsProp = moduleArguments.getDescendants()
    .find(d => d.getKind() === SyntaxKind.PropertyAssignment &&
        (d.compilerNode as ts.PropertyAssignment).name.getText() === "imports");

  const array = declarationsProp.getFirstChildByKindOrThrow(SyntaxKind.ArrayLiteralExpression);
  array.addElement("newImportGoesHere");

Answer №2

Dealing with the same issue, I came up with a solution that worked for me.

const classDeclaration = sourceFile
    .getClasses()
    .find(
      (classDeclaration) =>
        classDeclaration.getName() === 'ExampleModule'
    )!;

  const moduleArguments = classDeclaration!.getDecorator('NgModule')!.getArguments()!;
  const imports = moduleArguments[0];
  const fullText = imports.getFullText();

  const sliceIndex = fullText.indexOf('declarations: [');
  let text = '';
  text = fullText.slice(0, fullText.indexOf(']', sliceIndex));
  text += `, "something new!"],`;
  text += fullText.slice(fullText.indexOf('],', sliceIndex) + 2);

  imports.replaceWithText((writer) => {
    writer.writeLine(text);
  });

There may be a more elegant approach out there, but this is what got the job done for me...

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When attempting to install an npm package using npm link, you may encounter the error TS2307: Module not found

I'm in the process of developing an Angular library called clan-auth that will contain shared components for multiple Angular projects. When I install the library from our private npm Repository, everything works as expected. However, when I try to li ...

Changing a d3 event from JavaScript to Typescript in an Angular2 environment

I am a beginner in Typescript and Angular 2. My goal is to create an Angular2 component that incorporates a d3js tool click here. However, I am facing challenges when it comes to converting it to Typescript. For instance, I am unsure if this code rewrite ...

Having trouble getting Angular's ngClass directive to work correctly when applying multiple conditions

Struggling to make multiple conditions work with [ngClass] Check out a.component.html <div class="version-content" *ngFor="let version of versions; let lastVersion = last" [ngClass]="(version.isComingSoon === true) ? 'dashed': 'solid"> ...

What are some ways to utilize tuples in TypeScript along with generics?

My mission is to create a type safe mapping object where I can define key/value pairs just once. I've managed to achieve this with the code below: const myPropTuple = [ [0, "cat"], [1, "dog"], [2, "bird"] ] a ...

typescript push in react native is a crucial step to enhance performance and optimize

I've been diving into TypeScript within the realm of React Native. Oddly, when I translated a certain snippet to vanilla JavaScript, the application worked flawlessly. However, upon converting it back to TypeScript, an error message popped up stating ...

Tips for incorporating the closeAutocomplete function into ng4-geoautocomplete

Hey there! I've incorporated the ng4-autocomplete component into my custom component and now I'm trying to figure out how to detect when the autocomplete dropdown closes. Can you help me out with implementing the "closeAutocomplete" method? Let& ...

Is there a way in NodeJS to preview the contents of a file in a browser before initiating the download process?

Is there a way to preview a file in the browser before downloading it in NodeJS? This would allow users to make sure they are choosing the correct file to download. Currently, I have this code for downloading a file: app.get("/download/file", (req, res) = ...

Issue with IE11 compatibility in Angular2 (AngularQuickStart version 2.4.0) due to syntax error

Encountering an error in the browser console when attempting to run my Angular2 app on IE11. The error "Недопустимый знак" translates to unacceptable symbol. https://i.stack.imgur.com/0mHBC.png Here is a snippet of my index.html: <!DO ...

Tips for adjusting the legend on a chart in chart.js when the text is being truncated

https://i.sstatic.net/5IzUO.png Is there a way to eliminate the extra space on the left and right side of the bar so that the legend can be fully displayed with the entire text? ...

The plugin by chartjs-plugin-crosshair is malfunctioning

Having some trouble with the chartjs-plugin-crosshair - it's not working as expected. Here are the packages I am using: "chart.js": "^3.9.1" "chartjs-plugin-crosshair": "^1.2.0" Seems like there might be an i ...

Steps for calculating the average of several columns within a table using Angular 10

Currently, I have a function that successfully calculates the sum of JSON data in all columns on my tables. However, my attempt to get the average of each column is resulting in NaN or infinity. What could be the issue here? Here is my current implementat ...

Distributing utility functions universally throughout the entire React application

Is there a way to create global functions in React that can be imported into one file and shared across all pages? Currently, I have to import helper.tsx into each individual file where I want to use them. For example, the helper.tsx file exports functio ...

What is the best way to invoke a function only once in typescript?

Struggling to implement TypeScript in React Native for fetching an API on screen load? I've been facing a tough time with it, especially when trying to call the function only once without using timeouts. Here's my current approach, but it's ...

Error: Module './App' not found in webpack module

I am encountering the error Uncaught Error: Module not found: Can't resolve ./App' and ./store in client/src. in the console of my local environment when I execute npm start from the client directory. The console is showing 2 errors: ERROR in ...

One way to change the cursor CSS property is by dynamically altering it based on scrolling behavior. This involves modifying the cursor property when scrolling

I'm attempting to adjust the cursor property within an Angular function. The issue I'm facing is that when I begin scrolling the webpage, the cursor changes to a pointer, but when I stop scrolling, it remains as a pointer. I've attempted to ...

Guide to removing selected value from a combobox in Angular

I am working on a simple HTML file that consists of one combobox and one clear button. I want the clear button to remove the selected value from the combobox when clicked. Below is my code: mat-card-content fxLayout="row wrap" fxLayoutAlign="left" fxLayou ...

Implementing centralized authentication through an IdentityServer application with the utilization of the resource owner password flow

I am currently developing two Angular 2 applications that will have a .NET Core 1.1 REST backend and be hosted on Azure App Service. My goal is to enable them to share authentication information in order to provide a seamless Single Sign-On experience. Add ...

Tips for utilizing generics to determine the data type of a property by its name

I am seeking a method to determine the type of any property within a class or a type. For instance, if I had the classes PersonClass and PersonType, and I wanted to retrieve the type of the nationalId property, I could achieve this using the following cod ...

Successfully upgraded Angular 7 to 8, however, encountering an issue with the core not being able to locate the rxjs module

After updating my Angular version from 7.X to 8.2.5, everything seemed fine until I started getting errors related to the rxjs module within the angular/core package. Despite having the latest version of rxjs (6.5.3), the errors persisted even after removi ...

Having trouble grasping the concept of Interfaces and dealing with FormGroup problems in Angular?

Apologies if my question is a duplicate, I have found several solutions for the same issue on Stack Overflow, but unfortunately, I struggle to understand them in technical terms. Problem 1 src/app/models/dataModel.ts:2:5 2 id: number; ~~ The exp ...