ts-simple-ast
Version:
TypeScript compiler wrapper for static analysis and code manipulation.
556 lines (555 loc) • 26.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var compiler_1 = require("../compiler");
var errors = require("../errors");
var typescript_1 = require("../typescript");
var utils_1 = require("../utils");
var createTempSourceFile_1 = require("./createTempSourceFile");
var DirectoryCache_1 = require("./DirectoryCache");
var ForgetfulNodeCache_1 = require("./ForgetfulNodeCache");
var kindToWrapperMappings_1 = require("./kindToWrapperMappings");
/**
* Factory for creating compiler wrappers.
* @internal
*/
var CompilerFactory = /** @class */ (function () {
/**
* Initializes a new instance of CompilerFactory.
* @param global - Global container.
*/
function CompilerFactory(global) {
this.global = global;
this.sourceFileCacheByFilePath = new utils_1.KeyValueCache();
this.diagnosticCache = new utils_1.WeakCache();
this.definitionInfoCache = new utils_1.WeakCache();
this.documentSpanCache = new utils_1.WeakCache();
this.diagnosticMessageChainCache = new utils_1.WeakCache();
this.jsDocTagInfoCache = new utils_1.WeakCache();
this.signatureCache = new utils_1.WeakCache();
this.symbolCache = new utils_1.WeakCache();
this.symbolDisplayPartCache = new utils_1.WeakCache();
this.referenceEntryCache = new utils_1.WeakCache();
this.referencedSymbolCache = new utils_1.WeakCache();
this.referencedSymbolDefinitionInfoCache = new utils_1.WeakCache();
this.typeCache = new utils_1.WeakCache();
this.typeParameterCache = new utils_1.WeakCache();
this.nodeCache = new ForgetfulNodeCache_1.ForgetfulNodeCache();
this.sourceFileAddedEventContainer = new utils_1.EventContainer();
this.sourceFileMovedEventContainer = new utils_1.EventContainer();
this.sourceFileRemovedEventContainer = new utils_1.EventContainer();
this.directoryCache = new DirectoryCache_1.DirectoryCache(global);
}
/**
* Gets all the source files sorted by their directory depth.
*/
CompilerFactory.prototype.getSourceFilesByDirectoryDepth = function () {
var e_1, _a, _b, _c, dir, e_1_1;
return tslib_1.__generator(this, function (_d) {
switch (_d.label) {
case 0:
_d.trys.push([0, 5, 6, 7]);
_b = tslib_1.__values(this.getDirectoriesByDepth()), _c = _b.next();
_d.label = 1;
case 1:
if (!!_c.done) return [3 /*break*/, 4];
dir = _c.value;
return [5 /*yield**/, tslib_1.__values(dir.getSourceFiles())];
case 2:
_d.sent();
_d.label = 3;
case 3:
_c = _b.next();
return [3 /*break*/, 1];
case 4: return [3 /*break*/, 7];
case 5:
e_1_1 = _d.sent();
e_1 = { error: e_1_1 };
return [3 /*break*/, 7];
case 6:
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
return [7 /*endfinally*/];
case 7: return [2 /*return*/];
}
});
};
/**
* Gets the source file paths from the internal cache.
*/
CompilerFactory.prototype.getSourceFilePaths = function () {
return utils_1.ArrayUtils.from(this.sourceFileCacheByFilePath.getKeys());
};
/**
* Gets the child directories of a directory.
* @param dirPath - Directory path.
*/
CompilerFactory.prototype.getChildDirectoriesOfDirectory = function (dirPath) {
return this.directoryCache.getChildDirectoriesOfDirectory(dirPath);
};
/**
* Gets the child source files of a directory.
* @param dirPath - Directory path.
*/
CompilerFactory.prototype.getChildSourceFilesOfDirectory = function (dirPath) {
return this.directoryCache.getChildSourceFilesOfDirectory(dirPath);
};
/**
* Occurs when a source file is added to the cache.
* @param subscription - Subscripton.
* @param subscribe - Whether to subscribe or unsubscribe (default to true).
*/
CompilerFactory.prototype.onSourceFileAdded = function (subscription, subscribe) {
if (subscribe === void 0) { subscribe = true; }
if (subscribe)
this.sourceFileAddedEventContainer.subscribe(subscription);
else
this.sourceFileAddedEventContainer.unsubscribe(subscription);
};
/**
* Occurs when a source file is removed from the cache.
* @param subscription - Subscripton.
*/
CompilerFactory.prototype.onSourceFileRemoved = function (subscription) {
this.sourceFileRemovedEventContainer.subscribe(subscription);
};
/**
* Adds a source file by structure or text.
* @param filePath - File path.
* @param structureOrText - Structure or text.
* @param options - Options.
*/
CompilerFactory.prototype.createSourceFile = function (filePath, structureOrText, options) {
if (structureOrText == null || typeof structureOrText === "string")
return this.createSourceFileFromText(filePath, structureOrText || "", options);
var writer = this.global.createWriter();
var structurePrinter = this.global.structurePrinterFactory.forSourceFile({
isAmbient: utils_1.FileUtils.getExtension(filePath) === ".d.ts"
});
structurePrinter.printText(writer, structureOrText);
return this.createSourceFileFromText(filePath, writer.toString(), options);
};
/**
* Creates a source file from a file path and text.
* Adds it to the cache.
* @param filePath - File path for the source file.
* @param sourceText - Text to create the source file with.
* @param options - Options.
* @throws InvalidOperationError if the file exists.
*/
CompilerFactory.prototype.createSourceFileFromText = function (filePath, sourceText, options) {
filePath = this.global.fileSystemWrapper.getStandardizedAbsolutePath(filePath);
if (options != null && options.overwrite === true)
return this.createOrOverwriteSourceFileFromText(filePath, sourceText, options);
this.throwIfFileExists(filePath);
return this.getSourceFileFromText(filePath, sourceText, options);
};
/**
* Throws an error if the file exists in the cache or file system.
* @param filePath - File path.
* @param prefixMessage - Message to attach on as a prefix.
*/
CompilerFactory.prototype.throwIfFileExists = function (filePath, prefixMessage) {
if (!this.containsSourceFileAtPath(filePath) && !this.global.fileSystemWrapper.fileExistsSync(filePath))
return;
prefixMessage = prefixMessage == null ? "" : prefixMessage + " ";
throw new errors.InvalidOperationError(prefixMessage + "A source file already exists at the provided file path: " + filePath);
};
CompilerFactory.prototype.createOrOverwriteSourceFileFromText = function (filePath, sourceText, options) {
filePath = this.global.fileSystemWrapper.getStandardizedAbsolutePath(filePath);
var existingSourceFile = this.addOrGetSourceFileFromFilePath(filePath, options);
if (existingSourceFile != null) {
existingSourceFile.replaceWithText(sourceText);
return existingSourceFile;
}
return this.getSourceFileFromText(filePath, sourceText, options);
};
/**
* Creates a temporary source file that won't be added to the language service.
* @param sourceText - Text to create the source file with.
* @param filePath - File path to use.
* @returns Wrapped source file.
*/
CompilerFactory.prototype.createTempSourceFileFromText = function (sourceText, opts) {
if (opts === void 0) { opts = {}; }
var _a = opts.filePath, filePath = _a === void 0 ? "tsSimpleAstTempFile.ts" : _a, _b = opts.createLanguageService, createLanguageService = _b === void 0 ? false : _b;
return createTempSourceFile_1.createTempSourceFile(filePath, sourceText, {
createLanguageService: createLanguageService,
compilerOptions: this.global.compilerOptions.get(),
manipulationSettings: this.global.manipulationSettings.get()
});
};
/**
* Gets the source file from the cache by a file path.
* @param filePath - File path.
*/
CompilerFactory.prototype.getSourceFileFromCacheFromFilePath = function (filePath) {
filePath = this.global.fileSystemWrapper.getStandardizedAbsolutePath(filePath);
return this.sourceFileCacheByFilePath.get(filePath);
};
/**
* Gets a source file from a file path. Will use the file path cache if the file exists.
* @param filePath - File path to get the file from.
*/
CompilerFactory.prototype.addOrGetSourceFileFromFilePath = function (filePath, options) {
filePath = this.global.fileSystemWrapper.getStandardizedAbsolutePath(filePath);
var sourceFile = this.sourceFileCacheByFilePath.get(filePath);
if (sourceFile == null) {
if (this.global.fileSystemWrapper.fileExistsSync(filePath)) {
this.global.logger.log("Loading file: " + filePath);
sourceFile = this.getSourceFileFromText(filePath, this.global.fileSystemWrapper.readFileSync(filePath, this.global.getEncoding()), options);
sourceFile.setIsSaved(true); // source files loaded from the disk are saved to start with
}
if (sourceFile != null) {
// ensure these are added to the ast
sourceFile.getReferencedFiles();
sourceFile.getTypeReferenceDirectives();
}
}
return sourceFile;
};
/**
* Gets if the internal cache contains a source file at a specific file path.
* @param filePath - File path to check.
*/
CompilerFactory.prototype.containsSourceFileAtPath = function (filePath) {
var absoluteFilePath = this.global.fileSystemWrapper.getStandardizedAbsolutePath(filePath);
return this.sourceFileCacheByFilePath.has(absoluteFilePath);
};
/**
* Gets if the internal cache contains a source file with the specified directory path.
* @param dirPath - Directory path to check.
*/
CompilerFactory.prototype.containsDirectoryAtPath = function (dirPath) {
var normalizedDirPath = this.global.fileSystemWrapper.getStandardizedAbsolutePath(dirPath);
return this.directoryCache.has(normalizedDirPath);
};
/**
* Gets the source file for a node.
* @param compilerNode - Compiler node to get the source file of.
*/
CompilerFactory.prototype.getSourceFileForNode = function (compilerNode) {
var currentNode = compilerNode;
while (currentNode.kind !== typescript_1.SyntaxKind.SourceFile) {
if (currentNode.parent == null)
throw new errors.NotImplementedError("Could not find node source file.");
currentNode = currentNode.parent;
}
return this.getSourceFile(currentNode);
};
/**
* Gets if the factory contains the compiler node in its internal cache.
* @param compilerNode - Compiler node.
*/
CompilerFactory.prototype.hasCompilerNode = function (compilerNode) {
return this.nodeCache.has(compilerNode);
};
/**
* Gets an existing node from the cache.
* @param compilerNode - Compiler node.
*/
CompilerFactory.prototype.getExistingCompilerNode = function (compilerNode) {
return this.nodeCache.get(compilerNode);
};
/**
* Gets a wrapped compiler type based on the node's kind.
* @param node - Node to get the wrapped object from.
*/
CompilerFactory.prototype.getNodeFromCompilerNode = function (compilerNode, sourceFile) {
var _this = this;
if (compilerNode.kind === typescript_1.SyntaxKind.SourceFile)
return this.getSourceFile(compilerNode);
var createNode = function (ctor) {
// ensure the parent is created
if (compilerNode.parent != null && !_this.nodeCache.has(compilerNode.parent))
_this.getNodeFromCompilerNode(compilerNode.parent, sourceFile);
return new ctor(_this.global, compilerNode, sourceFile);
};
if (kindToWrapperMappings_1.kindToWrapperMappings[compilerNode.kind] != null)
return this.nodeCache.getOrCreate(compilerNode, function () { return createNode(kindToWrapperMappings_1.kindToWrapperMappings[compilerNode.kind]); });
else
return this.nodeCache.getOrCreate(compilerNode, function () { return createNode(compiler_1.Node); });
};
CompilerFactory.prototype.getSourceFileFromText = function (filePath, sourceText, options) {
var compilerSourceFile = utils_1.createCompilerSourceFile(filePath, sourceText, options.languageVersion != null ? options.languageVersion : this.global.compilerOptions.get().target);
return this.getSourceFile(compilerSourceFile);
};
/**
* Gets a wrapped source file from a compiler source file.
* @param sourceFile - Compiler source file.
*/
CompilerFactory.prototype.getSourceFile = function (compilerSourceFile) {
var _this = this;
var wasAdded = false;
var sourceFile = this.nodeCache.getOrCreate(compilerSourceFile, function () {
var createdSourceFile = new compiler_1.SourceFile(_this.global, compilerSourceFile);
_this.addSourceFileToCache(createdSourceFile);
wasAdded = true;
return createdSourceFile;
});
if (wasAdded)
this.sourceFileAddedEventContainer.fire(sourceFile);
return sourceFile;
};
CompilerFactory.prototype.addSourceFileToCache = function (sourceFile) {
this.sourceFileCacheByFilePath.set(sourceFile.getFilePath(), sourceFile);
this.global.fileSystemWrapper.removeFileDelete(sourceFile.getFilePath());
this.directoryCache.addSourceFile(sourceFile);
};
/**
* Gets a directory from a path.
* @param dirPath - Directory path.
*/
CompilerFactory.prototype.getDirectoryFromPath = function (dirPath) {
dirPath = this.global.fileSystemWrapper.getStandardizedAbsolutePath(dirPath);
var directory = this.directoryCache.get(dirPath);
if (directory == null && this.global.fileSystemWrapper.directoryExistsSync(dirPath))
directory = this.directoryCache.createOrAddIfExists(dirPath);
return directory;
};
/**
* Creates or adds a directory if it doesn't exist.
* @param dirPath - Directory path.
*/
CompilerFactory.prototype.createDirectoryOrAddIfExists = function (dirPath) {
return this.directoryCache.createOrAddIfExists(dirPath);
};
/**
* Gets a directory.
* @param dirPath - Directory path.
*/
CompilerFactory.prototype.getDirectoryFromCache = function (dirPath) {
return this.directoryCache.get(dirPath);
};
/**
* Gets all the directories iterated by depth.
*/
CompilerFactory.prototype.getDirectoriesByDepth = function () {
return this.directoryCache.getAllByDepth();
};
/**
* Gets the directories without a parent.
*/
CompilerFactory.prototype.getOrphanDirectories = function () {
return this.directoryCache.getOrphans();
};
/**
* Gets a warpped symbol display part form a compiler symbol display part.
* @param compilerObject - Compiler symbol display part.
*/
CompilerFactory.prototype.getSymbolDisplayPart = function (compilerObject) {
return this.symbolDisplayPartCache.getOrCreate(compilerObject, function () { return new compiler_1.SymbolDisplayPart(compilerObject); });
};
/**
* Gets a wrapped type from a compiler type.
* @param type - Compiler type.
*/
CompilerFactory.prototype.getType = function (type) {
var _this = this;
if ((type.flags & typescript_1.TypeFlags.TypeParameter) === typescript_1.TypeFlags.TypeParameter)
return this.getTypeParameter(type);
return this.typeCache.getOrCreate(type, function () { return new compiler_1.Type(_this.global, type); });
};
/**
* Gets a wrapped type parameter from a compiler type parameter.
* @param typeParameter - Compiler type parameter
*/
CompilerFactory.prototype.getTypeParameter = function (typeParameter) {
var _this = this;
return this.typeParameterCache.getOrCreate(typeParameter, function () { return new compiler_1.TypeParameter(_this.global, typeParameter); });
};
/**
* Gets a wrapped signature from a compiler signature.
* @param signature - Compiler signature.
*/
CompilerFactory.prototype.getSignature = function (signature) {
var _this = this;
return this.signatureCache.getOrCreate(signature, function () { return new compiler_1.Signature(_this.global, signature); });
};
/**
* Gets a wrapped symbol from a compiler symbol.
* @param symbol - Compiler symbol.
*/
CompilerFactory.prototype.getSymbol = function (symbol) {
var _this = this;
return this.symbolCache.getOrCreate(symbol, function () { return new compiler_1.Symbol(_this.global, symbol); });
};
/**
* Gets a wrapped definition info from a compiler object.
* @param compilerObject - Compiler definition info.
*/
CompilerFactory.prototype.getDefinitionInfo = function (compilerObject) {
var _this = this;
return this.definitionInfoCache.getOrCreate(compilerObject, function () { return new compiler_1.DefinitionInfo(_this.global, compilerObject); });
};
/**
* Gets a wrapped document span from a compiler object.
* @param compilerObject - Compiler document span.
*/
CompilerFactory.prototype.getDocumentSpan = function (compilerObject) {
var _this = this;
return this.documentSpanCache.getOrCreate(compilerObject, function () { return new compiler_1.DocumentSpan(_this.global, compilerObject); });
};
/**
* Gets a wrapped referenced entry from a compiler object.
* @param compilerObject - Compiler referenced entry.
*/
CompilerFactory.prototype.getReferenceEntry = function (compilerObject) {
var _this = this;
return this.referenceEntryCache.getOrCreate(compilerObject, function () { return new compiler_1.ReferenceEntry(_this.global, compilerObject); });
};
/**
* Gets a wrapped referenced symbol from a compiler object.
* @param compilerObject - Compiler referenced symbol.
*/
CompilerFactory.prototype.getReferencedSymbol = function (compilerObject) {
var _this = this;
return this.referencedSymbolCache.getOrCreate(compilerObject, function () { return new compiler_1.ReferencedSymbol(_this.global, compilerObject); });
};
/**
* Gets a wrapped referenced symbol definition info from a compiler object.
* @param compilerObject - Compiler referenced symbol definition info.
*/
CompilerFactory.prototype.getReferencedSymbolDefinitionInfo = function (compilerObject) {
var _this = this;
return this.referencedSymbolDefinitionInfoCache.getOrCreate(compilerObject, function () { return new compiler_1.ReferencedSymbolDefinitionInfo(_this.global, compilerObject); });
};
/**
* Gets a wrapped diagnostic from a compiler diagnostic.
* @param diagnostic - Compiler diagnostic.
*/
CompilerFactory.prototype.getDiagnostic = function (diagnostic) {
var _this = this;
return this.diagnosticCache.getOrCreate(diagnostic, function () {
if (diagnostic.start != null)
return new compiler_1.DiagnosticWithLocation(_this.global, diagnostic);
return new compiler_1.Diagnostic(_this.global, diagnostic);
});
};
/**
* Gets a wrapped diagnostic with location from a compiler diagnostic.
* @param diagnostic - Compiler diagnostic.
*/
CompilerFactory.prototype.getDiagnosticWithLocation = function (diagnostic) {
var _this = this;
return this.diagnosticCache.getOrCreate(diagnostic, function () { return new compiler_1.DiagnosticWithLocation(_this.global, diagnostic); });
};
/**
* Gets a wrapped diagnostic message chain from a compiler diagnostic message chain.
* @param diagnosticMessageChain - Compiler diagnostic message chain.
*/
CompilerFactory.prototype.getDiagnosticMessageChain = function (compilerObject) {
return this.diagnosticMessageChainCache.getOrCreate(compilerObject, function () { return new compiler_1.DiagnosticMessageChain(compilerObject); });
};
/**
* Gets a warpped JS doc tag info from a compiler object.
* @param jsDocTagInfo - Compiler object.
*/
CompilerFactory.prototype.getJSDocTagInfo = function (jsDocTagInfo) {
return this.jsDocTagInfoCache.getOrCreate(jsDocTagInfo, function () { return new compiler_1.JSDocTagInfo(jsDocTagInfo); });
};
/**
* Replaces a compiler node in the cache.
* @param oldNode - Old node to remove.
* @param newNode - New node to use.
*/
CompilerFactory.prototype.replaceCompilerNode = function (oldNode, newNode) {
var nodeToReplace = oldNode instanceof compiler_1.Node ? oldNode.compilerNode : oldNode;
var node = oldNode instanceof compiler_1.Node ? oldNode : this.nodeCache.get(oldNode);
if (nodeToReplace.kind === typescript_1.SyntaxKind.SourceFile && nodeToReplace.fileName !== newNode.fileName) {
var oldFilePath = nodeToReplace.fileName;
var sourceFile = node;
this.removeCompilerNodeFromCache(nodeToReplace);
sourceFile.replaceCompilerNodeFromFactory(newNode);
this.nodeCache.set(newNode, sourceFile);
this.addSourceFileToCache(sourceFile);
this.sourceFileAddedEventContainer.fire(sourceFile);
}
else {
this.nodeCache.replaceKey(nodeToReplace, newNode);
if (node != null)
node.replaceCompilerNodeFromFactory(newNode);
}
};
/**
* Removes a node from the cache.
* @param node - Node to remove.
*/
CompilerFactory.prototype.removeNodeFromCache = function (node) {
this.removeCompilerNodeFromCache(node.compilerNode);
};
/**
* Removes a compiler node from the cache.
* @param compilerNode - Compiler node to remove.
*/
CompilerFactory.prototype.removeCompilerNodeFromCache = function (compilerNode) {
this.nodeCache.removeByKey(compilerNode);
if (compilerNode.kind === typescript_1.SyntaxKind.SourceFile) {
var sourceFile = compilerNode;
this.directoryCache.removeSourceFile(sourceFile.fileName);
var tsSourceFile = this.sourceFileCacheByFilePath.get(sourceFile.fileName);
this.sourceFileCacheByFilePath.removeByKey(sourceFile.fileName);
if (tsSourceFile != null)
this.sourceFileRemovedEventContainer.fire(tsSourceFile);
}
};
/**
* Adds the specified directory to the cache.
* @param directory - Directory
*/
CompilerFactory.prototype.addDirectoryToCache = function (directory) {
this.directoryCache.addDirectory(directory);
};
/**
* Removes the directory from the cache.
* @param dirPath - Directory path.
*/
CompilerFactory.prototype.removeDirectoryFromCache = function (dirPath) {
this.directoryCache.remove(dirPath);
};
/**
* Forgets the nodes created in the block.
* @param block - Block of code to run.
*/
CompilerFactory.prototype.forgetNodesCreatedInBlock = function (block) {
var _this = this;
// can't use the async keyword here because exceptions that happen when doing this synchronously need to be thrown
this.nodeCache.setForgetPoint();
var wasPromise = false;
try {
var result = block(function () {
var e_2, _a;
var nodes = [];
for (var _i = 0; _i < arguments.length; _i++) {
nodes[_i] = arguments[_i];
}
try {
for (var nodes_1 = tslib_1.__values(nodes), nodes_1_1 = nodes_1.next(); !nodes_1_1.done; nodes_1_1 = nodes_1.next()) {
var node = nodes_1_1.value;
_this.nodeCache.rememberNode(node);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (nodes_1_1 && !nodes_1_1.done && (_a = nodes_1.return)) _a.call(nodes_1);
}
finally { if (e_2) throw e_2.error; }
}
});
if (result != null && typeof result.then === "function") {
wasPromise = true;
return result.then(function () { return _this.nodeCache.forgetLastPoint(); });
}
}
finally {
if (!wasPromise)
this.nodeCache.forgetLastPoint();
}
return Promise.resolve();
};
return CompilerFactory;
}());
exports.CompilerFactory = CompilerFactory;