From 77a7662c463bb2eb6082c6c1a9bc0b5f378b52b9 Mon Sep 17 00:00:00 2001 From: Ashok Tamang Date: Tue, 2 Aug 2016 13:52:19 -0700 Subject: [PATCH] feat: add features in get-dependent-files.ts add logic to filter out spec file associated with the given component unit and all index files while getting all dependent files add utlity function to get all the files (.html/stylesheets/.spec.ts) associated with the given component unit change the constructor method of the class ModuleResolver (add 'rootPath' as an additional parameter) --- addon/ng2/utilities/get-dependent-files.ts | 32 ++++++++- addon/ng2/utilities/module-resolver.ts | 18 +++-- tests/acceptance/get-dependent-files.spec.ts | 69 +++++++++++++++++++- tests/acceptance/module-resolver.spec.ts | 11 ++-- 4 files changed, 114 insertions(+), 16 deletions(-) diff --git a/addon/ng2/utilities/get-dependent-files.ts b/addon/ng2/utilities/get-dependent-files.ts index 6f38efd4dfcf..bcc978486d04 100644 --- a/addon/ng2/utilities/get-dependent-files.ts +++ b/addon/ng2/utilities/get-dependent-files.ts @@ -74,9 +74,37 @@ export function hasIndexFile(dirPath: string): Promise { }); } +/** + * Function to get all the templates, stylesheets, and spec files of a given component unit + * Assumption: When any component/service/pipe unit is generated, Angular CLI has a blueprint for + * creating associated files with the name of the generated unit. So, there are two + * assumptions made: + * a. the function only returns associated files that have names matching to the given unit. + * b. the function only looks for the associated files in the directory where the given unit + * exists. + * + * @todo read the metadata to look for the associated files of a given file. + * + * @param fileName + * + * @return absolute paths of '.html/.css/.sass/.spec.ts' files associated with the given file. + * + */ +export function getAllAssociatedFiles(fileName: string): Promise { + let fileDirName = path.dirname(fileName); + let componentName = path.basename(fileName, '.ts'); + const globSearch = denodeify(glob); + return globSearch(path.join(fileDirName, `${componentName}.*`), { nodir: true }) + .then((files: string[]) => { + return files.filter((file) => { + return (path.basename(file) !== 'index.ts'); + }); + }); +} + /** * Returns a map of all dependent file/s' path with their moduleSpecifier object - * (specifierText, pos, end) + * (specifierText, pos, end). * * @param fileName file upon which other files depend * @param rootPath root of the project @@ -86,7 +114,7 @@ export function hasIndexFile(dirPath: string): Promise { */ export function getDependentFiles(fileName: string, rootPath: string): Promise { const globSearch = denodeify(glob); - return globSearch(path.join(rootPath, '**/*.*.ts'), { nodir: true }) + return globSearch(path.join(rootPath, '**/*.ts'), { nodir: true }) .then((files: string[]) => Promise.all(files.map(file => createTsSourceFile(file))) .then((tsFiles: ts.SourceFile[]) => tsFiles.map(file => getImportClauses(file))) .then((moduleSpecifiers: ModuleImport[][]) => { diff --git a/addon/ng2/utilities/module-resolver.ts b/addon/ng2/utilities/module-resolver.ts index b20820cfb38d..d02c97d54404 100644 --- a/addon/ng2/utilities/module-resolver.ts +++ b/addon/ng2/utilities/module-resolver.ts @@ -7,16 +7,13 @@ import * as dependentFilesUtils from './get-dependent-files'; import { Promise } from 'es6-promise'; import { Change, ReplaceChange } from './change'; -// The root directory of Angular Project. -const ROOT_PATH = path.resolve('src/app'); - /** * Rewrites import module of dependent files when the file is moved. * Also, rewrites export module of related index file of the given file. */ export class ModuleResolver { - constructor(public oldFilePath: string, public newFilePath: string) {} + constructor(public oldFilePath: string, public newFilePath: string, public rootPath: string) {} /** * Changes are applied from the bottom of a file to the top. @@ -54,10 +51,19 @@ export class ModuleResolver { * @return {Promise} */ resolveDependentFiles(): Promise { - return dependentFilesUtils.getDependentFiles(this.oldFilePath, ROOT_PATH) + return dependentFilesUtils.getDependentFiles(this.oldFilePath, this.rootPath) .then((files: dependentFilesUtils.ModuleMap) => { let changes: Change[] = []; - Object.keys(files).forEach(file => { + let fileBaseName = path.basename(this.oldFilePath, '.ts'); + // Filter out the spec file associated with to-be-promoted component unit. + let relavantFiles = Object.keys(files).filter((file) => { + if (path.extname(path.basename(file, '.ts')) === '.spec') { + return path.basename(path.basename(file, '.ts'), '.spec') !== fileBaseName; + } else { + return true; + } + }); + relavantFiles.forEach(file => { let tempChanges: ReplaceChange[] = files[file] .map(specifier => { let componentName = path.basename(this.oldFilePath, '.ts'); diff --git a/tests/acceptance/get-dependent-files.spec.ts b/tests/acceptance/get-dependent-files.spec.ts index ff36244a0971..b2e9964ba9be 100644 --- a/tests/acceptance/get-dependent-files.spec.ts +++ b/tests/acceptance/get-dependent-files.spec.ts @@ -16,6 +16,10 @@ describe('Get Dependent Files: ', () => { 'foo': { 'foo.component.ts': `import * from '../bar/baz/baz.component' import * from '../bar/bar.component'`, + 'foo.component.html': '', + 'foo.component.css': '', + 'foo.component.spec.ts': '', + 'foo.ts': '', 'index.ts': `export * from './foo.component'` }, 'bar': { @@ -24,12 +28,23 @@ describe('Get Dependent Files: ', () => { 'baz.html': '

Hello

' }, 'bar.component.ts': `import * from './baz/baz.component' - import * from '../foo'` + import * from '../foo'`, + 'bar.component.spec.ts': '' }, 'foo-baz': { - 'no-module.component.ts': '' + 'no-module.component.ts': '', + 'no-module.component.spec.ts': 'import * from "../bar/bar.component";' }, - 'empty-dir': {} + 'quux': { + 'quux.ts': '', + 'quux.html': '', + 'quux.css': '', + 'quux.spec.ts': '' + }, + 'noAngular.tag.ts': '', + 'noAngular.tag.html': '', + 'noAngular.tag.sass': '', + 'noAngular.tag.spec.ts': '', } }; mockFs(mockDrive); @@ -102,6 +117,48 @@ describe('Get Dependent Files: ', () => { }); }); + describe('returns an array of all the associated files of a given component unit.', () => { + it('when the component name has a special Angular tag(component/pipe/service)', () => { + let sourceFile = path.join(rootPath, 'foo/foo.component.ts'); + return dependentFilesUtils.getAllAssociatedFiles(sourceFile) + .then((files: string[]) => { + let expectedContents = [ + 'src/app/foo/foo.component.css', + 'src/app/foo/foo.component.html', + 'src/app/foo/foo.component.spec.ts', + 'src/app/foo/foo.component.ts' + ]; + assert.deepEqual(files, expectedContents); + }); + }); + it('when the component name has non-Angular tag', () => { + let sourceFile = path.join(rootPath, 'noAngular.tag.ts'); + return dependentFilesUtils.getAllAssociatedFiles(sourceFile) + .then((files: string[]) => { + let expectedContents = [ + 'src/app/noAngular.tag.html', + 'src/app/noAngular.tag.sass', + 'src/app/noAngular.tag.spec.ts', + 'src/app/noAngular.tag.ts' + ]; + assert.deepEqual(files, expectedContents); + }); + }); + it('when the component name has no tag after the unique file name', () => { + let sourceFile = path.join(rootPath, 'quux/quux.ts'); + return dependentFilesUtils.getAllAssociatedFiles(sourceFile) + .then((files: string[]) => { + let expectedContents = [ + 'src/app/quux/quux.css', + 'src/app/quux/quux.html', + 'src/app/quux/quux.spec.ts', + 'src/app/quux/quux.ts' + ]; + assert.deepEqual(files, expectedContents); + }); + }); + }); + describe('returns a map of all files which depend on a given file ', () => { it('when the given component unit has no index file', () => { let sourceFile = path.join(rootPath, 'bar/bar.component.ts'); @@ -109,6 +166,7 @@ describe('Get Dependent Files: ', () => { .then((contents: dependentFilesUtils.ModuleMap) => { let bazFile = path.join(rootPath, 'bar/baz/baz.component.ts'); let fooFile = path.join(rootPath, 'foo/foo.component.ts'); + let noModuleSpecFile = path.join(rootPath, 'foo-baz/no-module.component.spec.ts'); let expectedContents: dependentFilesUtils.ModuleMap = {}; expectedContents[bazFile] = [{ specifierText: '../bar.component', @@ -120,6 +178,11 @@ describe('Get Dependent Files: ', () => { pos: 85, end: 108 }]; + expectedContents[noModuleSpecFile] = [{ + specifierText: '../bar/bar.component', + pos: 13, + end: 36 + }]; assert.deepEqual(contents, expectedContents); }); }); diff --git a/tests/acceptance/module-resolver.spec.ts b/tests/acceptance/module-resolver.spec.ts index bb154354adfe..cff22f2a2787 100644 --- a/tests/acceptance/module-resolver.spec.ts +++ b/tests/acceptance/module-resolver.spec.ts @@ -22,7 +22,8 @@ describe('ModuleResolver', () => { 'baz': { 'baz.component.ts': `import * from "../bar.component" import * from '../../foo-baz/qux/quux/foobar/foobar.component' - ` + `, + 'baz.component.spec.ts': 'import * from "./baz.component";' }, 'bar.component.ts': `import * from './baz/baz.component' import * from '../foo/foo.component'`, @@ -64,7 +65,7 @@ describe('ModuleResolver', () => { it('when there is no index.ts in oldPath', () => { let oldFilePath = path.join(rootPath, 'bar/baz/baz.component.ts'); let newFilePath = path.join(rootPath, 'foo'); - let resolver = new ModuleResolver(oldFilePath, newFilePath); + let resolver = new ModuleResolver(oldFilePath, newFilePath, rootPath); return resolver.resolveDependentFiles() .then((changes) => resolver.applySortedChangePromise(changes)) .then(() => dependentFilesUtils.createTsSourceFile(barFile)) @@ -93,7 +94,7 @@ describe('ModuleResolver', () => { it('when no files are importing the given file', () => { let oldFilePath = path.join(rootPath, 'foo-baz/foo-baz.component.ts'); let newFilePath = path.join(rootPath, 'bar'); - let resolver = new ModuleResolver(oldFilePath, newFilePath); + let resolver = new ModuleResolver(oldFilePath, newFilePath, rootPath); return resolver.resolveDependentFiles() .then((changes) => resolver.applySortedChangePromise(changes)) .then(() => resolver.resolveOwnImports()) @@ -108,7 +109,7 @@ describe('ModuleResolver', () => { it('when oldPath and newPath both do not have index.ts', () => { let oldFilePath = path.join(rootPath, 'bar/baz/baz.component.ts'); let newFilePath = path.join(rootPath, 'foo-baz'); - let resolver = new ModuleResolver(oldFilePath, newFilePath); + let resolver = new ModuleResolver(oldFilePath, newFilePath, rootPath); return resolver.resolveDependentFiles() .then((changes) => resolver.applySortedChangePromise(changes)) .then(() => dependentFilesUtils.createTsSourceFile(barFile)) @@ -137,7 +138,7 @@ describe('ModuleResolver', () => { it('when there are multiple spaces between symbols and specifier', () => { let oldFilePath = path.join(rootPath, 'foo-baz/qux/quux/foobar/foobar.component.ts'); let newFilePath = path.join(rootPath, 'foo'); - let resolver = new ModuleResolver(oldFilePath, newFilePath); + let resolver = new ModuleResolver(oldFilePath, newFilePath, rootPath); return resolver.resolveDependentFiles() .then((changes) => resolver.applySortedChangePromise(changes)) .then(() => dependentFilesUtils.createTsSourceFile(fooQuxFile))