ts-simple-ast
Version:
TypeScript compiler wrapper for static analysis and code manipulation.
184 lines (183 loc) • 8.77 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var utils_1 = require("../utils");
/**
* Holds information about whether source files or directories are in the project.
*
* todo: Move this to a different folder.
*/
var InProjectCoordinator = /** @class */ (function () {
function InProjectCoordinator(compilerFactory) {
var _this = this;
this.compilerFactory = compilerFactory;
this.notInProjectFiles = utils_1.createHashSet();
compilerFactory.onSourceFileRemoved(function (sourceFile) {
_this.notInProjectFiles.delete(sourceFile);
});
}
/** Sets the source file as not being in the project. */
InProjectCoordinator.prototype.setSourceFileNotInProject = function (sourceFile) {
this.notInProjectFiles.add(sourceFile);
sourceFile._inProject = false;
};
/** Marks the specified source file being included in the project. */
InProjectCoordinator.prototype.markSourceFileAsInProject = function (sourceFile) {
if (this.isSourceFileInProject(sourceFile))
return;
this._internalMarkSourceFileAsInProject(sourceFile);
this.notInProjectFiles.delete(sourceFile);
};
/**
* Marks source files not in a not in project node_modules folder as being in the project.
* @returns Source files that were marked as being in the project.
*/
InProjectCoordinator.prototype.markSourceFilesAsInProjectForResolution = function () {
var e_1, _a;
var nodeModulesSearchName = "/node_modules/";
var compilerFactory = this.compilerFactory;
var changedSourceFiles = [];
var unchangedSourceFiles = [];
try {
for (var _b = tslib_1.__values(tslib_1.__spread(this.notInProjectFiles.values())), _c = _b.next(); !_c.done; _c = _b.next()) {
var sourceFile = _c.value;
if (shouldMarkInProject(sourceFile)) {
this._internalMarkSourceFileAsInProject(sourceFile);
this.notInProjectFiles.delete(sourceFile);
changedSourceFiles.push(sourceFile);
}
else {
unchangedSourceFiles.push(sourceFile);
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
return { changedSourceFiles: changedSourceFiles, unchangedSourceFiles: unchangedSourceFiles };
function shouldMarkInProject(sourceFile) {
// check if there's a node_modules directory (use the closest one)
var filePath = sourceFile.getFilePath();
var index = filePath.toLowerCase().lastIndexOf(nodeModulesSearchName);
if (index === -1)
return true;
// see if the node_modules directory is in the project
var nodeModulesPath = filePath.substring(0, index + nodeModulesSearchName.length - 1); // remove last slash
var nodeModulesDir = compilerFactory.getDirectoryFromCacheOnlyIfInCache(nodeModulesPath);
if (nodeModulesDir != null && nodeModulesDir._isInProject())
return true;
// see if there's a directory between this and the node_modules directory that's in the project
var directory = sourceFile.getDirectory();
while (directory != null && directory.getPath() !== nodeModulesPath) {
if (directory._isInProject())
return true;
directory = compilerFactory.getDirectoryFromCacheOnlyIfInCache(utils_1.FileUtils.getDirPath(directory.getPath()));
}
// otherwise, don't mark it as in the project
return false;
}
};
InProjectCoordinator.prototype._internalMarkSourceFileAsInProject = function (sourceFile) {
sourceFile._inProject = true;
this.markDirectoryAsInProject(sourceFile.getDirectory());
};
/** Checks if the specified source file is in the project. */
InProjectCoordinator.prototype.isSourceFileInProject = function (sourceFile) {
return sourceFile._inProject === true;
};
/** Sets the directory and files as not being in the project for testing. */
InProjectCoordinator.prototype.setDirectoryAndFilesAsNotInProjectForTesting = function (directory) {
var e_2, _a, e_3, _b;
try {
for (var _c = tslib_1.__values(directory.getDirectories()), _d = _c.next(); !_d.done; _d = _c.next()) {
var subDir = _d.value;
this.setDirectoryAndFilesAsNotInProjectForTesting(subDir);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_2) throw e_2.error; }
}
try {
for (var _e = tslib_1.__values(directory.getSourceFiles()), _f = _e.next(); !_f.done; _f = _e.next()) {
var file = _f.value;
delete file._inProject;
this.notInProjectFiles.add(file);
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
}
finally { if (e_3) throw e_3.error; }
}
delete directory._inProject;
};
/** Marks the specified directory as being in the project. */
InProjectCoordinator.prototype.markDirectoryAsInProject = function (directory) {
if (this.isDirectoryInProject(directory))
return;
var inProjectCoordinator = this;
var compilerFactory = this.compilerFactory;
directory._inProject = true;
markAncestorDirs(directory);
function markAncestorDirs(dir) {
var e_4, _a;
var ancestorDirs = utils_1.ArrayUtils.from(getAncestorsUpToOneInProject(dir));
// only mark the ancestor directories as being in the project if the top one is in the project
var topAncestor = ancestorDirs[ancestorDirs.length - 1];
if (topAncestor == null || !inProjectCoordinator.isDirectoryInProject(topAncestor))
return;
try {
for (var ancestorDirs_1 = tslib_1.__values(ancestorDirs), ancestorDirs_1_1 = ancestorDirs_1.next(); !ancestorDirs_1_1.done; ancestorDirs_1_1 = ancestorDirs_1.next()) {
var ancestorDir = ancestorDirs_1_1.value;
ancestorDir._inProject = true;
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (ancestorDirs_1_1 && !ancestorDirs_1_1.done && (_a = ancestorDirs_1.return)) _a.call(ancestorDirs_1);
}
finally { if (e_4) throw e_4.error; }
}
}
function getAncestorsUpToOneInProject(dir) {
var parentDirPath, parentDir;
return tslib_1.__generator(this, function (_a) {
switch (_a.label) {
case 0:
if (utils_1.FileUtils.isRootDirPath(dir.getPath()))
return [2 /*return*/];
parentDirPath = utils_1.FileUtils.getDirPath(dir.getPath());
parentDir = compilerFactory.getDirectoryFromCacheOnlyIfInCache(parentDirPath);
if (parentDir == null)
return [2 /*return*/];
return [4 /*yield*/, parentDir];
case 1:
_a.sent();
if (!!inProjectCoordinator.isDirectoryInProject(parentDir)) return [3 /*break*/, 3];
return [5 /*yield**/, tslib_1.__values(getAncestorsUpToOneInProject(parentDir))];
case 2:
_a.sent();
_a.label = 3;
case 3: return [2 /*return*/];
}
});
}
};
/** Checks if the specified directory is in the project. */
InProjectCoordinator.prototype.isDirectoryInProject = function (directory) {
return directory._inProject === true;
};
return InProjectCoordinator;
}());
exports.InProjectCoordinator = InProjectCoordinator;