UNPKG

ts-simple-ast

Version:

TypeScript compiler wrapper for AST navigation and code generation.

200 lines (198 loc) 8.53 kB
"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