Skip to content
This repository has been archived by the owner on May 1, 2020. It is now read-only.

Commit

Permalink
feat(deep-linking): upgrade script to generate NgModules for pages with
Browse files Browse the repository at this point in the history
@deeplink decorator
  • Loading branch information
danbucholtz authored Mar 17, 2017
1 parent 08534d7 commit 2943188
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 2 deletions.
4 changes: 2 additions & 2 deletions src/deep-linking/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,8 @@ export function addDeepLinkArgumentToAppNgModule(appNgModuleFileContent: string,
return updatedFileContent;
}

export function generateDefaultDeepLinkNgModuleContent(filePath: string, className: string) {
const importFrom = basename(filePath, '.ts');
export function generateDefaultDeepLinkNgModuleContent(pageFilePath: string, className: string) {
const importFrom = basename(pageFilePath, '.ts');

return `
import { NgModule } from '@angular/core';
Expand Down
137 changes: 137 additions & 0 deletions src/upgrade-scripts/add-default-ngmodules.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
import * as fs from 'fs';
import { join } from 'path';

import * as upgradeScript from './add-default-ngmodules';
import * as deeplinkUtils from '../deep-linking/util';
import { FileCache } from '../util/file-cache';
import * as globUtil from '../util/glob-util';
import * as helpers from '../util/helpers';

describe('add default ngmodules upgrade script', () => {
describe('getTsFilePaths', () => {
it('should return a list of absolute file paths', () => {
const srcDirectory = join('Users', 'noone', 'this', 'path', 'is', 'fake', 'src');
const context = {
srcDir: srcDirectory
};

const knownFileOne = join(srcDirectory, 'pages', 'page-one', 'page-one.ts');
const knownFileTwo = join(srcDirectory, 'pages', 'page-two', 'page-two.ts');
const knownFileThree = join(srcDirectory, 'pages', 'page-three', 'page-three.ts');
const knownFileFour = join(srcDirectory, 'util', 'some-util.ts');
const globResults = [
{ absolutePath: knownFileOne},
{ absolutePath: knownFileTwo},
{ absolutePath: knownFileThree},
{ absolutePath: knownFileFour},
];
spyOn(globUtil, globUtil.globAll.name).and.returnValue(Promise.resolve(globResults));
const promise = upgradeScript.getTsFilePaths(context);

return promise.then((filePaths: string[]) => {
expect(filePaths.length).toEqual(4);
expect(filePaths[0]).toEqual(knownFileOne);
expect(filePaths[1]).toEqual(knownFileTwo);
expect(filePaths[2]).toEqual(knownFileThree);
expect(filePaths[3]).toEqual(knownFileFour);
});
});
});

describe('readTsFiles', () => {
it('should read the ts files', () => {
const context = {
fileCache: new FileCache()
};
const srcDirectory = join('Users', 'noone', 'this', 'path', 'is', 'fake', 'src');
const knownFileOne = join(srcDirectory, 'pages', 'page-one', 'page-one.ts');
const knownFileTwo = join(srcDirectory, 'pages', 'page-two', 'page-two.ts');
const knownFileThree = join(srcDirectory, 'pages', 'page-three', 'page-three.ts');
const knownFileFour = join(srcDirectory, 'util', 'some-util.ts');

const fileList = [knownFileOne, knownFileTwo, knownFileThree, knownFileFour];

spyOn(helpers, helpers.readFileAsync.name).and.callFake((filePath: string) => {
// just set the file content to the path name + 'content' to keep things simple
return Promise.resolve(filePath + 'content');
});

const promise = upgradeScript.readTsFiles(context, fileList);

return promise.then(() => {
// the files should be cached now
const fileOne = context.fileCache.get(knownFileOne);
expect(fileOne.content).toEqual(knownFileOne + 'content');

const fileTwo = context.fileCache.get(knownFileTwo);
expect(fileTwo.content).toEqual(knownFileTwo + 'content');

const fileThree = context.fileCache.get(knownFileThree);
expect(fileThree.content).toEqual(knownFileThree + 'content');

const fileFour = context.fileCache.get(knownFileFour);
expect(fileFour.content).toEqual(knownFileFour + 'content');
});
});
});

describe('generateAndWriteNgModules', () => {
it('should generate NgModules for only the pages with deeplink decorator AND if the module.ts file doesnt exist', () => {
const srcDirectory = join('Users', 'noone', 'this', 'path', 'is', 'fake', 'src');
const knownFileOne = join(srcDirectory, 'pages', 'page-one', 'page-one.ts');
const knownFileTwo = join(srcDirectory, 'pages', 'page-two', 'page-two.ts');
const knownFileThree = join(srcDirectory, 'pages', 'page-three', 'page-three.ts');
const knownFileThreeModule = join(srcDirectory, 'pages', 'page-three', 'page-three.module.ts');
const knownFileFour = join(srcDirectory, 'util', 'some-util.ts');
const knownFileFive = join(srcDirectory, 'pages', 'page-three', 'provider.ts');
const knownFileSix = join(srcDirectory, 'modals', 'modal-one', 'modal-one.ts');

const context = {
fileCache: new FileCache()
};

context.fileCache.set(knownFileOne, { path: knownFileOne, content: getClassContent('PageOne', 'page-one')});
context.fileCache.set(knownFileTwo, { path: knownFileTwo, content: getClassContent('PageTwo', 'page-two')});
context.fileCache.set(knownFileThree, { path: knownFileThree, content: getClassContent('PageThree', 'page-three')});
context.fileCache.set(knownFileThreeModule, { path: knownFileThreeModule, content: deeplinkUtils.generateDefaultDeepLinkNgModuleContent(knownFileThree, 'PageThree')});
context.fileCache.set(knownFileFour, { path: knownFileFour, content: `${knownFileFour} content`});
context.fileCache.set(knownFileFive, { path: knownFileFive, content: `${knownFileFive} content`});
context.fileCache.set(knownFileSix, { path: knownFileSix, content: getClassContent('ModalOne', 'modal-one')});

const ngModuleFileExtension = '.module.ts';

spyOn(helpers, helpers.getStringPropertyValue.name).and.returnValue(ngModuleFileExtension);
const fsSpy = spyOn(fs, 'writeFileSync');

upgradeScript.generateAndWriteNgModules(context.fileCache);

expect(fsSpy.calls.count()).toEqual(3);
expect(fsSpy.calls.argsFor(0)[0]).toEqual(helpers.changeExtension(knownFileOne, ngModuleFileExtension));
expect(fsSpy.calls.argsFor(0)[1]).toEqual(deeplinkUtils.generateDefaultDeepLinkNgModuleContent(knownFileOne, 'PageOne'));

expect(fsSpy.calls.argsFor(1)[0]).toEqual(helpers.changeExtension(knownFileTwo, ngModuleFileExtension));
expect(fsSpy.calls.argsFor(1)[1]).toEqual(deeplinkUtils.generateDefaultDeepLinkNgModuleContent(knownFileTwo, 'PageTwo'));

expect(fsSpy.calls.argsFor(2)[0]).toEqual(helpers.changeExtension(knownFileSix, ngModuleFileExtension));
expect(fsSpy.calls.argsFor(2)[1]).toEqual(deeplinkUtils.generateDefaultDeepLinkNgModuleContent(knownFileSix, 'ModalOne'));
});
});
});

function getClassContent(className: string, folderName: string) {
return `
import { Component } from '@angular/core';
import { DeepLink, NavController } from 'ionic-angular';
@DeepLink()
@Component({
selector: '${folderName}',
templateUrl: './${folderName}.html'
})
export class ${className} {
constructor(public navCtrl: NavController) {}
}
`;
}
62 changes: 62 additions & 0 deletions src/upgrade-scripts/add-default-ngmodules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { writeFileSync } from 'fs';
import { join } from 'path';

import { generateDefaultDeepLinkNgModuleContent, getDeepLinkDecoratorContentForSourceFile, getNgModulePathFromCorrespondingPage } from '../deep-linking/util';
import { generateContext } from '../util/config';
import * as Constants from '../util/constants';
import { FileCache } from '../util/file-cache';
import { globAll, GlobResult } from '../util/glob-util';
import { changeExtension, getStringPropertyValue, readFileAsync } from '../util/helpers';
import { BuildContext, File } from '../util/interfaces';

import { getTypescriptSourceFile } from '../util/typescript-utils';

export function getTsFilePaths(context: BuildContext) {
const tsFileGlobString = join(context.srcDir, '**', '*.ts');
return globAll([tsFileGlobString]).then((results: GlobResult[]) => {
return results.map(result => result.absolutePath);
});
}

export function readTsFiles(context: BuildContext, tsFilePaths: string[]) {
const promises = tsFilePaths.map(tsFilePath => {
const promise = readFileAsync(tsFilePath);
promise.then((fileContent: string) => {
context.fileCache.set(tsFilePath, { path: tsFilePath, content: fileContent});
});
return promise;
});
return Promise.all(promises);
}

export function generateAndWriteNgModules(fileCache: FileCache) {
fileCache.getAll().forEach(file => {
const sourceFile = getTypescriptSourceFile(file.path, file.content);
const deepLinkDecoratorData = getDeepLinkDecoratorContentForSourceFile(sourceFile);
if (deepLinkDecoratorData) {
// we have a valid DeepLink decorator
const correspondingNgModulePath = getNgModulePathFromCorrespondingPage(file.path);
const ngModuleFile = fileCache.get(correspondingNgModulePath);
if (!ngModuleFile) {
// the ngModule file does not exist, so go ahead and create a default one
const defaultNgModuleContent = generateDefaultDeepLinkNgModuleContent(file.path, deepLinkDecoratorData.className);
const ngModuleFilePath = changeExtension(file.path, getStringPropertyValue(Constants.ENV_NG_MODULE_FILE_NAME_SUFFIX));
writeFileSync(ngModuleFilePath, defaultNgModuleContent);
}
}
});
}

function run() {
const context = generateContext();

// find out what files to read
return getTsFilePaths(context).then((filePaths: string[]) => {
// read the files
return readTsFiles(context, filePaths);
}).then(() => {
generateAndWriteNgModules(context.fileCache);
});
}

run();

0 comments on commit 2943188

Please sign in to comment.