Skip to content

Commit

Permalink
feat(mutates): add new functions
Browse files Browse the repository at this point in the history
  • Loading branch information
IKatsuba committed Jun 14, 2024
1 parent 6592ff8 commit ac25d76
Show file tree
Hide file tree
Showing 35 changed files with 616 additions and 33 deletions.
2 changes: 1 addition & 1 deletion packages/angular/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ export * from './lib/injectable';
export * from './lib/metadata';
export * from './lib/module';
export * from './lib/pipe';
export * from './lib/testing';
export * from './lib/types';
export * from './lib/create-angular-project';
export * from './lib/ng-tree-file-system';
1 change: 0 additions & 1 deletion packages/angular/src/lib/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
export * from './is-standalone';
export * from './match';
29 changes: 0 additions & 29 deletions packages/angular/src/lib/helpers/is-standalone.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`getMetadataProperty > should get metadata property 1`] = `"providers: []"`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`pushToMetadataProperty > should add providers to the app module 1`] = `
"
@Component({
providers: [AppService]
}) class AppComponent {}
"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`removeItemFromMetadataProperty > should add providers to the app module 1`] = `
"
@Component({providers: []}) class AppComponent {}
"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`setMetadataProperty > should set providers to the component 1`] = `
"
@Component({providers: []}) class AppComponent {}
"
`;
29 changes: 29 additions & 0 deletions packages/angular/src/lib/metadata/get-metadata-property.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Tree } from '@angular-devkit/schematics';

import { createSourceFile } from '@mutates/core';

import { createAngularProject } from '../create-angular-project';
import { getNgModule } from '../module';
import { createTestingTree } from '../testing';
import { getMetadataProperty } from './get-metadata-property';

describe('getMetadataProperty', () => {
let host: Tree;
beforeEach(() => {
host = createTestingTree();

createAngularProject(host);
});

it('should get metadata property', () => {
createSourceFile(
'src/main.ts',
`
@NgModule({providers: []}) class AppModule {}
`,
);
const metadataProperty = getMetadataProperty(getNgModule('src/main.ts').at(0)!, 'providers');

expect(metadataProperty?.getText()).matchSnapshot();
});
});
17 changes: 17 additions & 0 deletions packages/angular/src/lib/metadata/get-metadata-property.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ClassDeclaration, PropertyAssignment } from 'ts-morph';

import { getObjectProperties } from '@mutates/core';

import { MetadataProperty } from '../types/metadata-property';
import { getMetadata } from './get-metadata';

export function getMetadataProperty<T extends MetadataProperty>(
klass: ClassDeclaration,
property: T,
): PropertyAssignment | undefined {
const [metadata] = getMetadata(klass);

return getObjectProperties(metadata, {
name: property as string,
}).at(0);
}
8 changes: 7 additions & 1 deletion packages/angular/src/lib/metadata/get-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ export enum MetadataType {

export function getMetadata(
klass: ClassDeclaration | ClassDeclaration[],
metadataType: MetadataType | MetadataType[],
metadataType: MetadataType | MetadataType[] = [
MetadataType.NgModule,
MetadataType.Component,
MetadataType.Directive,
MetadataType.Pipe,
MetadataType.Injectable,
],
): ObjectLiteralExpression[] {
const decorators = getDecorators(klass, {
name: metadataType,
Expand Down
5 changes: 5 additions & 0 deletions packages/angular/src/lib/metadata/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
export * from './providers';
export * from './get-metadata';
export * from './get-metadata-property';
export * from './standalone';
export * from './push-to-metadata-property';
export * from './set-metadata-property';
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`addAppProviders > should add providers to the app module 1`] = `
"import {NgModule} from '@angular/core';
@NgModule({
providers: [AppService],
})
export class AppModule {}
"
`;

exports[`addAppProviders > should add providers to the bootstrapApplication function 1`] = `
"import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
import {environment} from './environments/environment';
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent, {providers: [AppService]})
"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`addProviders > should add providers to the app module 1`] = `
"
@Component({
providers: [AppService]
}) class AppComponent {}
"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`removeProviders > should add providers to the app module 1`] = `
"
@Component({
providers: [],
}) class AppComponent {}
"
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Tree } from '@angular-devkit/schematics';

import { createSourceFile, readFileSync, saveProject } from '@mutates/core';

import { createAngularProject } from '../../create-angular-project';
import { createTestingTree } from '../../testing';
import { addAppProviders } from './add-app-providers';

describe('addAppProviders', () => {
let host: Tree;
beforeEach(() => {
host = createTestingTree();

createAngularProject(host);
});

it('should add providers to the app module', () => {
createSourceFile(
'src/main.ts',
`import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app/app.module';
import {environment} from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic()
.bootstrapModule(AppModule)
.catch(err => console.log(err));
`,
);

createSourceFile(
'src/app/app.module.ts',
`import {NgModule} from '@angular/core';
@NgModule({
providers: [],
})
export class AppModule {}
`,
);

addAppProviders('src/main.ts', ['AppService']);

saveProject();

expect(readFileSync('src/app/app.module.ts')).matchSnapshot();
});

it('should add providers to the bootstrapApplication function', () => {
createSourceFile(
'src/main.ts',
`import {bootstrapApplication} from '@angular/platform-browser';
import {AppComponent} from './app/app.component';
import {environment} from './environments/environment';
if (environment.production) {
enableProdMode();
}
bootstrapApplication(AppComponent)
`,
);

addAppProviders('src/main.ts', ['AppService']);

saveProject();

expect(readFileSync('src/main.ts')).matchSnapshot();
});
});
39 changes: 39 additions & 0 deletions packages/angular/src/lib/metadata/providers/add-app-providers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ArrayLiteralExpression, ObjectLiteralExpression, SyntaxKind } from 'ts-morph';

import { getObjectProperties, pushToArrayIfNotExists } from '@mutates/core';

import { getBootstrapApplicationFn } from '../../bootstrap';
import { getAppModule } from '../../module';
import { getMetadataProperty } from '../index';

export function getAppProviders(mainFilePath: string): ArrayLiteralExpression | undefined {
const appModule = getAppModule(mainFilePath);

if (appModule) {
return getMetadataProperty(appModule, 'providers')?.getInitializerIfKind(
SyntaxKind.ArrayLiteralExpression,
);
}

const boostrapApplicationFn = getBootstrapApplicationFn(mainFilePath);

if (!boostrapApplicationFn) {
return;
}
const config = (boostrapApplicationFn.getArguments().at(1) ??
boostrapApplicationFn.addArgument(`{providers: []}`)) as ObjectLiteralExpression;

return getObjectProperties(config, { name: 'providers' })
.at(0)
?.getInitializerIfKind(SyntaxKind.ArrayLiteralExpression);
}

export function addAppProviders(mainFilePath: string, providers: string[]): void {
const appProviders = getAppProviders(mainFilePath);

if (!appProviders) {
return;
}

pushToArrayIfNotExists(appProviders, ...providers);
}
32 changes: 32 additions & 0 deletions packages/angular/src/lib/metadata/providers/add-providers.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Tree } from '@angular-devkit/schematics';

import { createSourceFile, readFileSync, saveProject } from '@mutates/core';

import { getComponents } from '../../component';
import { createAngularProject } from '../../create-angular-project';
import { createTestingTree } from '../../testing';
import { addProviders } from './add-providers';

describe('addProviders', () => {
let host: Tree;
beforeEach(() => {
host = createTestingTree();

createAngularProject(host);
});

it('should add providers to the app module', () => {
createSourceFile(
'src/main.ts',
`
@Component({}) class AppComponent {}
`,
);

addProviders(getComponents('src/main.ts').at(0)!, ['AppService']);

saveProject();

expect(readFileSync('src/main.ts')).matchSnapshot();
});
});
7 changes: 7 additions & 0 deletions packages/angular/src/lib/metadata/providers/add-providers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ClassDeclaration } from 'ts-morph';

import { pushToMetadataProperty } from '../push-to-metadata-property';

export function addProviders(ngEntity: ClassDeclaration, providers: string[]): void {
pushToMetadataProperty(ngEntity, 'providers', providers);
}
3 changes: 3 additions & 0 deletions packages/angular/src/lib/metadata/providers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './add-app-providers';
export * from './add-providers';
export * from './remove-providers';
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Tree } from '@angular-devkit/schematics';

import { createSourceFile, readFileSync, saveProject } from '@mutates/core';

import { getComponents } from '../../component';
import { createAngularProject } from '../../create-angular-project';
import { createTestingTree } from '../../testing';
import { removeProviders } from './remove-providers';

describe('removeProviders', () => {
let host: Tree;
beforeEach(() => {
host = createTestingTree();

createAngularProject(host);
});

it('should add providers to the app module', () => {
createSourceFile(
'src/main.ts',
`
@Component({
providers: [AppProvider],
}) class AppComponent {}
`,
);

removeProviders(getComponents('src/main.ts').at(0)!, ['AppProvider']);

saveProject();

expect(readFileSync('src/main.ts')).matchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { ClassDeclaration } from 'ts-morph';

import { removeItemFromMetadataProperty } from '../remove-item-from-metadata-property';

export function removeProviders(ngEntity: ClassDeclaration, providers: string[]): void {
removeItemFromMetadataProperty(ngEntity, 'providers', providers);
}
Loading

0 comments on commit ac25d76

Please sign in to comment.