ts-simple-ast
Version:
TypeScript compiler wrapper for AST navigation and code generation.
200 lines (198 loc) • 8.53 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const ts = require("typescript");
const compiler = require("./../compiler");
const errors = require("./../errors");
const utils_1 = require("./../utils");
const nodeToWrapperMappings_1 = require("./nodeToWrapperMappings");
/**
* Factory for creating compiler wrappers.
* @internal
*/
class CompilerFactory {
/**
* Initializes a new instance of CompilerFactory.
* @param global - Global container.
*/
constructor(global) {
this.global = global;
this.sourceFileCacheByFilePath = new utils_1.KeyValueCache();
this.normalizedDirectories = new Set();
this.nodeCache = new utils_1.KeyValueCache();
this.sourceFileAddedEventContainer = new utils_1.EventContainer();
}
/**
* Occurs when a source file is added to the cache.
* @param subscription - Subscripton.
*/
onSourceFileAdded(subscription) {
this.sourceFileAddedEventContainer.subscribe(subscription);
}
/**
* 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.
*/
addSourceFileFromText(filePath, sourceText) {
const absoluteFilePath = utils_1.FileUtils.getStandardizedAbsolutePath(filePath);
if (this.containsSourceFileAtPath(absoluteFilePath))
throw new errors.InvalidOperationError(`A source file already exists at the provided file path: ${absoluteFilePath}`);
const compilerSourceFile = ts.createSourceFile(absoluteFilePath, sourceText, this.global.manipulationSettings.getScriptTarget(), true);
return this.getSourceFile(compilerSourceFile);
}
/**
* 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.
*/
createTempSourceFileFromText(sourceText, filePath = "tsSimpleAstTempFile.ts") {
const compilerSourceFile = ts.createSourceFile(filePath, sourceText, this.global.manipulationSettings.getScriptTarget(), true);
const sourceFile = new compiler.SourceFile(this.global, compilerSourceFile);
this.nodeCache.set(compilerSourceFile, sourceFile);
return sourceFile;
}
/**
* 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.
*/
getSourceFileFromFilePath(filePath) {
const absoluteFilePath = utils_1.FileUtils.getStandardizedAbsolutePath(filePath);
let sourceFile = this.sourceFileCacheByFilePath.get(absoluteFilePath);
if (sourceFile == null) {
if (this.global.fileSystem.fileExistsSync(absoluteFilePath)) {
utils_1.Logger.log(`Loading file: ${absoluteFilePath}`);
sourceFile = this.addSourceFileFromText(absoluteFilePath, this.global.fileSystem.readFile(absoluteFilePath));
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.
*/
containsSourceFileAtPath(filePath) {
const absoluteFilePath = utils_1.FileUtils.getStandardizedAbsolutePath(filePath);
return this.sourceFileCacheByFilePath.get(absoluteFilePath) != null;
}
/**
* Gets if the internal cache contains a source file with the specified directory path.
* @param dirPath - Directory path to check.
*/
containsFileInDirectory(dirPath) {
const normalizedDirPath = utils_1.FileUtils.getStandardizedAbsolutePath(dirPath);
return this.normalizedDirectories.has(normalizedDirPath);
}
/**
* Gets the source file for a node.
* @param compilerNode - Compiler node to get the source file of.
*/
getSourceFileForNode(compilerNode) {
let currentNode = compilerNode;
while (currentNode.kind !== ts.SyntaxKind.SourceFile) {
if (currentNode.parent == null)
throw new errors.NotImplementedError("Could not find node source file.");
currentNode = currentNode.parent;
}
return this.getSourceFile(currentNode);
}
/**
* Gets a wrapped compiler type based on the node's kind.
* @param node - Node to get the wrapped object from.
*/
getNodeFromCompilerNode(compilerNode, sourceFile) {
if (compilerNode.kind === ts.SyntaxKind.SourceFile)
return this.getSourceFile(compilerNode);
else if (nodeToWrapperMappings_1.nodeToWrapperMappings[compilerNode.kind] != null)
return this.nodeCache.getOrCreate(compilerNode, () => new nodeToWrapperMappings_1.nodeToWrapperMappings[compilerNode.kind](this.global, compilerNode, sourceFile));
else
return this.nodeCache.getOrCreate(compilerNode, () => new compiler.Node(this.global, compilerNode, sourceFile));
}
/**
* Gets a wrapped source file from a compiler source file.
* @param sourceFile - Compiler source file.
*/
getSourceFile(compilerSourceFile) {
return this.nodeCache.getOrCreate(compilerSourceFile, () => {
const sourceFile = new compiler.SourceFile(this.global, compilerSourceFile);
this.sourceFileCacheByFilePath.set(sourceFile.getFilePath(), sourceFile);
// add to list of directories
const normalizedDir = utils_1.FileUtils.getStandardizedAbsolutePath(utils_1.FileUtils.getDirPath(sourceFile.getFilePath()));
if (!this.normalizedDirectories.has(normalizedDir))
this.normalizedDirectories.add(normalizedDir);
// fire the event
this.sourceFileAddedEventContainer.fire({
addedSourceFile: sourceFile
});
return sourceFile;
});
}
/**
* Gets a wrapped type from a compiler type.
* @param type - Compiler type.
*/
getType(type) {
return new compiler.Type(this.global, type);
}
/**
* Gets a wrapped signature from a compiler signature.
* @param signature - Compiler signature.
*/
getSignature(signature) {
return new compiler.Signature(this.global, signature);
}
/**
* Gets a wrapped symbol from a compiler symbol.
* @param symbol - Compiler symbol.
*/
getSymbol(symbol) {
return new compiler.Symbol(this.global, symbol);
}
/**
* Gets a wrapped diagnostic from a compiler diagnostic.
* @param diagnostic - Compiler diagnostic.
*/
getDiagnostic(diagnostic) {
return new compiler.Diagnostic(this.global, diagnostic);
}
/**
* Gets a wrapped diagnostic message chain from a compiler diagnostic message chain.
* @param diagnostic - Compiler diagnostic message chain.
*/
getDiagnosticMessageChain(diagnosticMessageChain) {
return new compiler.DiagnosticMessageChain(this.global, diagnosticMessageChain);
}
/**
* Replaces a compiler node in the cache.
* @param oldNode - Old node to remove.
* @param newNode - New node to use.
*/
replaceCompilerNode(oldNode, newNode) {
const nodeToReplace = oldNode instanceof compiler.Node ? oldNode.compilerNode : oldNode;
const node = oldNode instanceof compiler.Node ? oldNode : this.nodeCache.get(oldNode);
this.nodeCache.replaceKey(nodeToReplace, newNode);
if (node != null)
node.replaceCompilerNode(newNode);
}
/**
* Removes a node from the cache.
* @param node - Node to remove.
*/
removeNodeFromCache(node) {
const compilerNode = node.compilerNode;
this.nodeCache.removeByKey(compilerNode);
if (compilerNode.kind === ts.SyntaxKind.SourceFile) {
const sourceFile = compilerNode;
this.sourceFileCacheByFilePath.removeByKey(sourceFile.fileName);
}
}
}
exports.CompilerFactory = CompilerFactory;
//# sourceMappingURL=CompilerFactory.js.map