Merge pull request #30 from kawwong/generate-ng-module
Add function for generateNgModule
This commit is contained in:
Коммит
8b7f315350
|
@ -0,0 +1,19 @@
|
|||
// This file is being ignored by typescript because it is only used in tests.
|
||||
|
||||
// @ts-ignore
|
||||
import { AngularPerfModule, RoutingService } from '@microsoft/mezzurite-angular';
|
||||
|
||||
// @ts-ignore
|
||||
@NgModule({
|
||||
imports: [
|
||||
AngularPerfModule.forRoot()
|
||||
]
|
||||
})
|
||||
// @ts-ignore
|
||||
export class InstrumentedModule {
|
||||
// @ts-ignore
|
||||
constructor (@Inject(RoutingService) private router: typeof RoutingService) {
|
||||
// @ts-ignore
|
||||
router.start();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// This file is being ignored by typescript because it is only used in tests.
|
||||
|
||||
// @ts-ignore
|
||||
import { RoutingService } from 'not-Mezzurite';
|
||||
|
||||
// @ts-ignore
|
||||
@NgModule({
|
||||
imports: [
|
||||
// @ts-ignore
|
||||
nothing.forRoot()
|
||||
]
|
||||
})
|
||||
// @ts-ignore
|
||||
export class NotInstrumentedModule {
|
||||
constructor () {
|
||||
// @ts-ignore
|
||||
dummy.blah();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
import { join } from 'path';
|
||||
import Project from 'ts-morph';
|
||||
|
||||
import generateNgModule from './generateNgModule';
|
||||
|
||||
describe('generateNgModule.ts', () => {
|
||||
const project = new Project({
|
||||
addFilesFromTsConfig: false
|
||||
});
|
||||
|
||||
it('should return null when filePath is null', () => {
|
||||
expect(generateNgModule(null, null)).toBeNull();
|
||||
});
|
||||
|
||||
it('should return null when sourceFile is null', () => {
|
||||
expect(generateNgModule('filePath', null)).toBeNull();
|
||||
});
|
||||
|
||||
it('should generate a Mezzurite component from an ngModule file passing all the checks', () => {
|
||||
const filePath = join('.', 'server', 'src', 'utilities', 'generateComponent', 'helpers', '__mocks__', 'ngModuleInstrumented.ts');
|
||||
const sourceFile = project.addExistingSourceFile(filePath);
|
||||
expect(generateNgModule(filePath, sourceFile))
|
||||
.toMatchObject({
|
||||
checks: {
|
||||
hasAngularPerfModule: true,
|
||||
hasImport: true,
|
||||
hasRoutingServiceStart: true
|
||||
},
|
||||
filePath,
|
||||
name: 'InstrumentedModule',
|
||||
type: 'ngModule'
|
||||
});
|
||||
project.removeSourceFile(sourceFile);
|
||||
});
|
||||
|
||||
it('should generate a Mezzurite component from an ngModule file passing none of the checks', () => {
|
||||
const filePath = join('.', 'server', 'src', 'utilities', 'generateComponent', 'helpers', '__mocks__', 'ngModuleNotInstrumented.ts');
|
||||
const sourceFile = project.addExistingSourceFile(filePath);
|
||||
expect(generateNgModule(filePath, sourceFile))
|
||||
.toMatchObject({
|
||||
checks: {
|
||||
hasAngularPerfModule: false,
|
||||
hasImport: false,
|
||||
hasRoutingServiceStart: false
|
||||
},
|
||||
filePath,
|
||||
name: 'NotInstrumentedModule',
|
||||
type: 'ngModule'
|
||||
});
|
||||
project.removeSourceFile(sourceFile);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,91 @@
|
|||
import { ClassDeclaration, Node, SyntaxKind, SourceFile } from 'ts-morph';
|
||||
|
||||
import MezzuriteComponent from '../../../models/MezzuriteComponent';
|
||||
|
||||
function generateNgModule (filePath: string, sourceFile: SourceFile): MezzuriteComponent {
|
||||
let component = null;
|
||||
|
||||
if (filePath != null && sourceFile != null) {
|
||||
// TODO: Handle multiple classes in a file.
|
||||
const sourceClass = sourceFile.getClasses()[0];
|
||||
|
||||
const hasAngularPerfModule = containsAngularPerfImport(sourceClass);
|
||||
const hasImport = sourceFile.getImportDeclaration('@microsoft/mezzurite-angular') != null;
|
||||
const hasRoutingServiceStart = containsRoutingServiceStart(sourceClass);
|
||||
|
||||
const name = sourceClass.getName();
|
||||
|
||||
component = {
|
||||
checks: {
|
||||
hasAngularPerfModule,
|
||||
hasImport,
|
||||
hasRoutingServiceStart
|
||||
},
|
||||
filePath,
|
||||
name,
|
||||
type: 'ngModule'
|
||||
};
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
function containsAngularPerfImport (sourceClass: ClassDeclaration): boolean {
|
||||
const ngModuleDecorator = sourceClass.getDecorator('NgModule');
|
||||
let containsAngularPerfImport = false;
|
||||
|
||||
if (ngModuleDecorator != null) {
|
||||
const decoratorArgument = ngModuleDecorator.getArguments().find((child: Node) => {
|
||||
return child.getKind() === SyntaxKind.ObjectLiteralExpression;
|
||||
});
|
||||
|
||||
if (decoratorArgument != null) {
|
||||
const decoratorArgumentParameters = decoratorArgument.getFirstChildByKind(SyntaxKind.SyntaxList).getChildren();
|
||||
const importNode = decoratorArgumentParameters.find((argument: Node) => {
|
||||
const isPropertyAssignment = argument.getKind() === SyntaxKind.PropertyAssignment;
|
||||
let hasImports = false;
|
||||
if (isPropertyAssignment) {
|
||||
const identifier = argument.getFirstChildByKind(SyntaxKind.Identifier);
|
||||
if (identifier.getText() === 'imports') {
|
||||
hasImports = true;
|
||||
}
|
||||
}
|
||||
return hasImports;
|
||||
});
|
||||
|
||||
if (importNode != null) {
|
||||
const imports = importNode.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression);
|
||||
containsAngularPerfImport = imports.getText().indexOf('AngularPerfModule.forRoot()') > -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return containsAngularPerfImport;
|
||||
}
|
||||
|
||||
function containsRoutingServiceStart (sourceClass: ClassDeclaration): boolean {
|
||||
let containsRoutingServiceStart = false;
|
||||
const constructors = sourceClass.getConstructors();
|
||||
|
||||
if (constructors.length > 0) {
|
||||
// TODO: How do you handle multiple constructors?
|
||||
const constructorParameters = constructors[0].getFirstChildByKind(SyntaxKind.Parameter);
|
||||
|
||||
if (constructorParameters != null) {
|
||||
const routingServiceType = constructorParameters.getFirstChildByKind(SyntaxKind.TypeQuery);
|
||||
if (constructorParameters != null) {
|
||||
if (routingServiceType.getText().indexOf('RoutingService') > -1) {
|
||||
const constructorBlock = constructors[0].getFirstChildByKind(SyntaxKind.Block);
|
||||
// TODO: Make this checking more robust.
|
||||
containsRoutingServiceStart = constructorBlock.getChildren().find((child: Node) => {
|
||||
return child.getText().indexOf('start()') > -1;
|
||||
}) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return containsRoutingServiceStart;
|
||||
}
|
||||
|
||||
export default generateNgModule;
|
|
@ -1,5 +1,7 @@
|
|||
import generateNgComponent from './generateNgComponent';
|
||||
import generateNgModule from './generateNgModule';
|
||||
|
||||
export default {
|
||||
generateNgComponent
|
||||
generateNgComponent,
|
||||
generateNgModule
|
||||
};
|
||||
|
|
|
@ -42,4 +42,10 @@ describe('index.ts', () => {
|
|||
helpers.generateNgComponent = jest.fn(() => component);
|
||||
expect(generateComponent('ngComponent', 'filePath', sourceFile)).toMatchObject(component);
|
||||
});
|
||||
|
||||
it('should return the component when generateNgModule is not null', () => {
|
||||
helpers.generateNgModule = jest.fn(() => component);
|
||||
expect(generateComponent('ngModule', 'filePath', sourceFile)).toMatchObject(component);
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -9,6 +9,8 @@ function generateComponent (componentType: string, filePath: string, sourceFile:
|
|||
if (componentType != null && filePath != null && sourceFile != null) {
|
||||
if (componentType === 'ngComponent') {
|
||||
component = helpers.generateNgComponent(filePath, sourceFile);
|
||||
} else if (componentType === 'ngModule') {
|
||||
component = helpers.generateNgModule(filePath, sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче