Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add features in get-dependent-files.ts #1525

Merged
merged 1 commit into from
Aug 10, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 30 additions & 2 deletions addon/ng2/utilities/get-dependent-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,37 @@ export function hasIndexFile(dirPath: string): Promise<Boolean> {
});
}

/**
* 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<string[]> {
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
Expand All @@ -86,7 +114,7 @@ export function hasIndexFile(dirPath: string): Promise<Boolean> {
*/
export function getDependentFiles(fileName: string, rootPath: string): Promise<ModuleMap> {
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[][]) => {
Expand Down
18 changes: 12 additions & 6 deletions addon/ng2/utilities/module-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -54,10 +51,19 @@ export class ModuleResolver {
* @return {Promise<Change[]>}
*/
resolveDependentFiles(): Promise<Change[]> {
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');
Expand Down
69 changes: 66 additions & 3 deletions tests/acceptance/get-dependent-files.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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': {
Expand All @@ -24,12 +28,23 @@ describe('Get Dependent Files: ', () => {
'baz.html': '<h1> Hello </h1>'
},
'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);
Expand Down Expand Up @@ -102,13 +117,56 @@ 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');
return dependentFilesUtils.getDependentFiles(sourceFile, rootPath)
.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',
Expand All @@ -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);
});
});
Expand Down
11 changes: 6 additions & 5 deletions tests/acceptance/module-resolver.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'`,
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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())
Expand All @@ -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))
Expand Down Expand Up @@ -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))
Expand Down