UNPKG

ts-simple-ast

Version:

TypeScript compiler wrapper for AST navigation and code generation.

472 lines (471 loc) 21.8 kB
"use strict"; var __awaiter = (this && this.__awaiter)/* istanbul ignore next */ || function (thisArg, _arguments, P, generator) { return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator)/* istanbul ignore next */ || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = y[op[0] & 2 ? "return" : op[0] ? "throw" : "next"]) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [0, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __values = (this && this.__values)/* istanbul ignore next */ || function (o) { var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; if (m) return m.call(o); return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; }; Object.defineProperty(exports, "__esModule", { value: true }); var ts = require("typescript"); var compiler = require("./../compiler"); var errors = require("./../errors"); var utils_1 = require("./../utils"); var createTempSourceFile_1 = require("./createTempSourceFile"); var nodeToWrapperMappings_1 = require("./nodeToWrapperMappings"); var ForgetfulNodeCache_1 = require("./ForgetfulNodeCache"); var DirectoryCache_1 = require("./DirectoryCache"); /** * 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.nodeCache = new ForgetfulNodeCache_1.ForgetfulNodeCache(); this.sourceFileAddedEventContainer = 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 _a, _b, dir, e_1_1, e_1, _c; return __generator(this, function (_d) { switch (_d.label) { case 0: _d.trys.push([0, 5, 6, 7]); _a = __values(this.getDirectoriesByDepth()), _b = _a.next(); _d.label = 1; case 1: if (!!_b.done) return [3 /*break*/, 4]; dir = _b.value; return [5 /*yield**/, __values(dir.getSourceFiles())]; case 2: _d.sent(); _d.label = 3; case 3: _b = _a.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 (_b && !_b.done && (_c = _a.return)) _c.call(_a); } 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()); }; /** * Occurs when a source file is added to the cache. * @param subscription - Subscripton. */ CompilerFactory.prototype.onSourceFileAdded = function (subscription) { this.sourceFileAddedEventContainer.subscribe(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. */ CompilerFactory.prototype.createSourceFile = function (filePath, structureOrText) { if (structureOrText == null || typeof structureOrText === "string") return this.createSourceFileFromText(filePath, structureOrText || ""); var sourceFile = this.createSourceFileFromText(filePath, ""); sourceFile.fill(structureOrText); return sourceFile; }; /** * 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. * @throws InvalidOperationError if the file exists. */ CompilerFactory.prototype.createSourceFileFromText = function (filePath, sourceText) { filePath = utils_1.FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, filePath); if (this.containsSourceFileAtPath(filePath) || this.global.fileSystem.fileExistsSync(filePath)) throw new errors.InvalidOperationError("A source file already exists at the provided file path: " + filePath); return this.getSourceFileFromText(filePath, sourceText); }; /** * Creates or overwrites a source file and text. * Adds it to the cache. * @param filePath - File path for the source file. * @param sourceText - Text to create the source file with. */ CompilerFactory.prototype.createOrOverwriteSourceFileFromText = function (filePath, sourceText) { filePath = utils_1.FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, filePath); var existingSourceFile = this.getSourceFileFromFilePath(filePath); if (existingSourceFile != null) { existingSourceFile.replaceWithText(sourceText); return existingSourceFile; } return this.getSourceFileFromText(filePath, sourceText); }; /** * 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 }); }; /** * 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.getSourceFileFromFilePath = function (filePath) { filePath = utils_1.FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, filePath); var sourceFile = this.sourceFileCacheByFilePath.get(filePath); if (sourceFile == null) { if (this.global.fileSystem.fileExistsSync(filePath)) { utils_1.Logger.log("Loading file: " + filePath); sourceFile = this.getSourceFileFromText(filePath, this.global.fileSystem.readFileSync(filePath)); 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 = utils_1.FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, 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 = utils_1.FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, 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 !== 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 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 === ts.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 (nodeToWrapperMappings_1.nodeToWrapperMappings[compilerNode.kind] != null) return this.nodeCache.getOrCreate(compilerNode, function () { return createNode(nodeToWrapperMappings_1.nodeToWrapperMappings[compilerNode.kind]); }); else return this.nodeCache.getOrCreate(compilerNode, function () { return createNode(compiler.Node); }); }; CompilerFactory.prototype.getSourceFileFromText = function (filePath, sourceText) { var compilerSourceFile = ts.createSourceFile(filePath, sourceText, this.global.manipulationSettings.getScriptTarget(), true); 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; return this.nodeCache.getOrCreate(compilerSourceFile, function () { var sourceFile = new compiler.SourceFile(_this.global, compilerSourceFile); _this.sourceFileCacheByFilePath.set(sourceFile.getFilePath(), sourceFile); // add to list of directories var dirPath = sourceFile.getDirectoryPath(); _this.directoryCache.createOrAddIfNotExists(dirPath); _this.directoryCache.get(dirPath)._addSourceFile(sourceFile); // fire the event _this.sourceFileAddedEventContainer.fire(undefined); return sourceFile; }); }; /** * Gets a directory from a path. * @param dirPath - Directory path. */ CompilerFactory.prototype.getDirectoryFromPath = function (dirPath) { dirPath = utils_1.FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, dirPath); var directory = this.directoryCache.get(dirPath); if (directory == null && this.global.fileSystem.directoryExistsSync(dirPath)) directory = this.directoryCache.createOrAddIfNotExists(dirPath); return directory; }; /** * Creates or adds a directory if it doesn't exist. * @param dirPath - Directory path. */ CompilerFactory.prototype.createOrAddDirectoryIfNotExists = function (dirPath) { return this.directoryCache.createOrAddIfNotExists(dirPath); }; /** * Creates a directory. * @param dirPath - Directory path. */ CompilerFactory.prototype.createDirectory = function (dirPath) { if (this.containsDirectoryAtPath(dirPath) || this.global.fileSystem.directoryExistsSync(dirPath)) throw new errors.InvalidOperationError("A directory already exists at the provided path: " + dirPath); return this.directoryCache.createOrAddIfNotExists(dirPath); }; /** * Gets a directory. * @param dirPath - Directory path. */ CompilerFactory.prototype.getDirectory = 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 new compiler.SymbolDisplayPart(compilerObject); }; /** * Gets a wrapped type from a compiler type. * @param type - Compiler type. */ CompilerFactory.prototype.getType = function (type) { return new compiler.Type(this.global, type); }; /** * Gets a warpped type parameter from a compiler type parameter. * @param typeParameter - Compiler type parameter */ CompilerFactory.prototype.getTypeParameter = function (typeParameter) { return new compiler.TypeParameter(this.global, typeParameter); }; /** * Gets a wrapped signature from a compiler signature. * @param signature - Compiler signature. */ CompilerFactory.prototype.getSignature = function (signature) { return new compiler.Signature(this.global, signature); }; /** * Gets a wrapped symbol from a compiler symbol. * @param symbol - Compiler symbol. */ CompilerFactory.prototype.getSymbol = function (symbol) { return new compiler.Symbol(this.global, symbol); }; /** * Gets a wrapped diagnostic from a compiler diagnostic. * @param diagnostic - Compiler diagnostic. */ CompilerFactory.prototype.getDiagnostic = function (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. */ CompilerFactory.prototype.getDiagnosticMessageChain = function (diagnosticMessageChain) { return new compiler.DiagnosticMessageChain(this.global, diagnosticMessageChain); }; /** * Gets a warpped JS doc tag info from a compiler object. * @param jsDocTagInfo - Compiler object. */ CompilerFactory.prototype.getJSDocTagInfo = function (jsDocTagInfo) { return new compiler.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.Node ? oldNode.compilerNode : oldNode; var node = oldNode instanceof compiler.Node ? oldNode : this.nodeCache.get(oldNode); 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) { var compilerNode = node.compilerNode; this.nodeCache.removeByKey(compilerNode); if (compilerNode.kind === ts.SyntaxKind.SourceFile) { var sourceFile = compilerNode; this.directoryCache.get(utils_1.FileUtils.getDirPath(sourceFile.fileName))._removeSourceFile(sourceFile.fileName); this.sourceFileCacheByFilePath.removeByKey(sourceFile.fileName); this.sourceFileRemovedEventContainer.fire(undefined); } }; /** * Removes the directory from the cache. * @param directory - Directory. */ CompilerFactory.prototype.removeDirectoryFromCache = function (directory) { this.directoryCache.remove(directory.getPath()); }; /** * Forgets the nodes created in the block. * @param block - Block of code to run. */ CompilerFactory.prototype.forgetNodesCreatedInBlock = function (block) { return __awaiter(this, void 0, void 0, function () { var _this = this; var result; return __generator(this, function (_a) { switch (_a.label) { case 0: this.nodeCache.setForgetPoint(); _a.label = 1; case 1: _a.trys.push([1, , 4, 5]); result = block(function () { var nodes = []; for (var _i = 0; _i < arguments.length; _i++) { nodes[_i] = arguments[_i]; } try { for (var nodes_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; } } var e_2, _a; }); if (!(result != null && typeof result.then === "function")) return [3 /*break*/, 3]; return [4 /*yield*/, result]; case 2: _a.sent(); _a.label = 3; case 3: return [3 /*break*/, 5]; case 4: this.nodeCache.forgetLastPoint(); return [7 /*endfinally*/]; case 5: return [2 /*return*/]; } }); }); }; return CompilerFactory; }()); exports.CompilerFactory = CompilerFactory;