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 generateNgComponent from './generateNgComponent';
|
||||||
|
import generateNgModule from './generateNgModule';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
generateNgComponent
|
generateNgComponent,
|
||||||
|
generateNgModule
|
||||||
};
|
};
|
||||||
|
|
|
@ -42,4 +42,10 @@ describe('index.ts', () => {
|
||||||
helpers.generateNgComponent = jest.fn(() => component);
|
helpers.generateNgComponent = jest.fn(() => component);
|
||||||
expect(generateComponent('ngComponent', 'filePath', sourceFile)).toMatchObject(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 != null && filePath != null && sourceFile != null) {
|
||||||
if (componentType === 'ngComponent') {
|
if (componentType === 'ngComponent') {
|
||||||
component = helpers.generateNgComponent(filePath, sourceFile);
|
component = helpers.generateNgComponent(filePath, sourceFile);
|
||||||
|
} else if (componentType === 'ngModule') {
|
||||||
|
component = helpers.generateNgModule(filePath, sourceFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче