mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-21 05:52:41 +08:00
Those 2 packages were still using the wrong scope (@angular-cli) and were not used by anyone outside the CLI. Just moving the code in the main package is enough.
111 lines
4.5 KiB
TypeScript
111 lines
4.5 KiB
TypeScript
'use strict';
|
|
|
|
import * as path from 'path';
|
|
import * as ts from 'typescript';
|
|
import * as dependentFilesUtils from './get-dependent-files';
|
|
|
|
|
|
import {Change, ReplaceChange} from './change';
|
|
import {NodeHost, Host} from '../lib/ast-tools';
|
|
|
|
/**
|
|
* 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, public rootPath: string) {}
|
|
|
|
/**
|
|
* Changes are applied from the bottom of a file to the top.
|
|
* An array of Change instances are sorted based upon the order,
|
|
* then apply() method is called sequentially.
|
|
*
|
|
* @param changes {Change []}
|
|
* @param host {Host}
|
|
* @return Promise after all apply() method of Change class is called
|
|
* to all Change instances sequentially.
|
|
*/
|
|
applySortedChangePromise(changes: Change[], host: Host = NodeHost): Promise<void> {
|
|
return changes
|
|
.sort((currentChange, nextChange) => nextChange.order - currentChange.order)
|
|
.reduce((newChange, change) => newChange.then(() => change.apply(host)), Promise.resolve());
|
|
}
|
|
|
|
/**
|
|
* Assesses the import specifier and determines if it is a relative import.
|
|
*
|
|
* @return {boolean} boolean value if the import specifier is a relative import.
|
|
*/
|
|
isRelativeImport(importClause: dependentFilesUtils.ModuleImport): boolean {
|
|
let singleSlash = importClause.specifierText.charAt(0) === '/';
|
|
let currentDirSyntax = importClause.specifierText.slice(0, 2) === './';
|
|
let parentDirSyntax = importClause.specifierText.slice(0, 3) === '../';
|
|
return singleSlash || currentDirSyntax || parentDirSyntax;
|
|
}
|
|
|
|
/**
|
|
* Rewrites the import specifiers of all the dependent files (cases for no index file).
|
|
*
|
|
* @todo Implement the logic for rewriting imports of the dependent files when the file
|
|
* being moved has index file in its old path and/or in its new path.
|
|
*
|
|
* @return {Promise<Change[]>}
|
|
*/
|
|
resolveDependentFiles(): Promise<Change[]> {
|
|
return dependentFilesUtils.getDependentFiles(this.oldFilePath, this.rootPath)
|
|
.then((files: dependentFilesUtils.ModuleMap) => {
|
|
let changes: Change[] = [];
|
|
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');
|
|
let fileDir = path.dirname(file);
|
|
let changeText = path.relative(fileDir, path.join(this.newFilePath, componentName));
|
|
if (changeText.length > 0 && changeText.charAt(0) !== '.') {
|
|
changeText = `.${path.sep}${changeText}`;
|
|
};
|
|
let position = specifier.end - specifier.specifierText.length;
|
|
return new ReplaceChange(file, position - 1, specifier.specifierText, changeText);
|
|
});
|
|
changes = changes.concat(tempChanges);
|
|
});
|
|
return changes;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Rewrites the file's own relative imports after it has been moved to new path.
|
|
*
|
|
* @return {Promise<Change[]>}
|
|
*/
|
|
resolveOwnImports(): Promise<Change[]> {
|
|
return dependentFilesUtils.createTsSourceFile(this.oldFilePath)
|
|
.then((tsFile: ts.SourceFile) => dependentFilesUtils.getImportClauses(tsFile))
|
|
.then(moduleSpecifiers => {
|
|
let changes: Change[] = moduleSpecifiers
|
|
.filter(importClause => this.isRelativeImport(importClause))
|
|
.map(specifier => {
|
|
let specifierText = specifier.specifierText;
|
|
let moduleAbsolutePath = path.resolve(path.dirname(this.oldFilePath), specifierText);
|
|
let changeText = path.relative(this.newFilePath, moduleAbsolutePath);
|
|
if (changeText.length > 0 && changeText.charAt(0) !== '.') {
|
|
changeText = `.${path.sep}${changeText}`;
|
|
}
|
|
let position = specifier.end - specifier.specifierText.length;
|
|
return new ReplaceChange(this.oldFilePath, position - 1, specifierText, changeText);
|
|
});
|
|
return changes;
|
|
});
|
|
}
|
|
}
|