UNPKG

ts-simple-ast

Version:

TypeScript compiler wrapper for AST navigation and code generation.

291 lines (290 loc) 14.6 kB
"use strict"; 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 }; } }; }; var __read = (this && this.__read)/* istanbul ignore next */ || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; Object.defineProperty(exports, "__esModule", { value: true }); var ts = require("typescript"); var manipulation_1 = require("./../../manipulation"); var errors = require("./../../errors"); var fileSystem_1 = require("./../../fileSystem"); var utils_1 = require("./../../utils"); var Program_1 = require("./Program"); var results_1 = require("./results"); var LanguageService = /** @class */ (function () { /** @internal */ function LanguageService(global) { var _this = this; this.global = global; // I don't know what I'm doing for some of this... var version = 0; var fileExistsSync = function (path) { return _this.global.compilerFactory.containsSourceFileAtPath(path) || global.fileSystem.fileExistsSync(path); }; var languageServiceHost = { getCompilationSettings: function () { return global.compilerOptions; }, getNewLine: function () { return global.manipulationSettings.getNewLineKind(); }, getScriptFileNames: function () { return _this.global.compilerFactory.getSourceFilePaths(); }, getScriptVersion: function (fileName) { return (version++).toString(); }, getScriptSnapshot: function (fileName) { if (!fileExistsSync(fileName)) return undefined; return ts.ScriptSnapshot.fromString(_this.global.compilerFactory.getSourceFileFromFilePath(fileName).getFullText()); }, getCurrentDirectory: function () { return global.fileSystem.getCurrentDirectory(); }, getDefaultLibFileName: function (options) { if (_this.global.fileSystem instanceof fileSystem_1.DefaultFileSystemHost) return ts.getDefaultLibFilePath(global.compilerOptions); else return utils_1.FileUtils.pathJoin(global.fileSystem.getCurrentDirectory(), "node_modules/typescript/lib/" + ts.getDefaultLibFileName(global.compilerOptions)); }, useCaseSensitiveFileNames: function () { return true; }, readFile: function (path, encoding) { if (_this.global.compilerFactory.containsSourceFileAtPath(path)) return _this.global.compilerFactory.getSourceFileFromFilePath(path).getFullText(); return _this.global.fileSystem.readFileSync(path, encoding); }, fileExists: fileExistsSync, directoryExists: function (dirName) { return _this.global.compilerFactory.containsDirectoryAtPath(dirName) || _this.global.fileSystem.directoryExistsSync(dirName); } }; this.compilerHost = { getSourceFile: function (fileName, languageVersion, onError) { var sourceFile = _this.global.compilerFactory.getSourceFileFromFilePath(fileName); return sourceFile == null ? undefined : sourceFile.compilerNode; }, // getSourceFileByPath: (...) => {}, // not providing these will force it to use the file name as the file path // getDefaultLibLocation: (...) => {}, getDefaultLibFileName: function (options) { return languageServiceHost.getDefaultLibFileName(options); }, writeFile: function (filePath, data, writeByteOrderMark, onError, sourceFiles) { _this.global.fileSystem.writeFileSync(filePath, data); }, getCurrentDirectory: function () { return languageServiceHost.getCurrentDirectory(); }, getDirectories: function (path) { // todo: not sure where this is used... return []; }, fileExists: function (fileName) { return languageServiceHost.fileExists(fileName); }, readFile: function (fileName) { return languageServiceHost.readFile(fileName); }, getCanonicalFileName: function (fileName) { return utils_1.FileUtils.getStandardizedAbsolutePath(_this.global.fileSystem, fileName); }, useCaseSensitiveFileNames: function () { return languageServiceHost.useCaseSensitiveFileNames(); }, getNewLine: function () { return languageServiceHost.getNewLine(); }, getEnvironmentVariable: function (name) { return process.env[name]; } }; this._compilerObject = ts.createLanguageService(languageServiceHost); this.program = new Program_1.Program(this.global, this.global.compilerFactory.getSourceFilePaths(), this.compilerHost); this.global.compilerFactory.onSourceFileAdded(function () { return _this.resetProgram(); }); this.global.compilerFactory.onSourceFileRemoved(function () { return _this.resetProgram(); }); } Object.defineProperty(LanguageService.prototype, "compilerObject", { /** * Gets the compiler language service. */ get: function () { return this._compilerObject; }, enumerable: true, configurable: true }); /** * Resets the program. This should be done whenever any modifications happen. * @internal */ LanguageService.prototype.resetProgram = function () { this.program.reset(this.global.compilerFactory.getSourceFilePaths(), this.compilerHost); }; /** * Gets the language service's program. */ LanguageService.prototype.getProgram = function () { return this.program; }; /** * Rename the specified node. * @param node - Node to rename. * @param newName - New name for the node. */ LanguageService.prototype.renameNode = function (node, newName) { errors.throwIfNotStringOrWhitespace(newName, "newName"); if (node.getText() === newName) return; this.renameLocations(this.findRenameLocations(node), newName); }; /** * Rename the provided rename locations. * @param renameLocations - Rename locations. * @param newName - New name for the node. */ LanguageService.prototype.renameLocations = function (renameLocations, newName) { var renameLocationsBySourceFile = new utils_1.KeyValueCache(); try { for (var renameLocations_1 = __values(renameLocations), renameLocations_1_1 = renameLocations_1.next(); !renameLocations_1_1.done; renameLocations_1_1 = renameLocations_1.next()) { var renameLocation = renameLocations_1_1.value; var locations = renameLocationsBySourceFile.getOrCreate(renameLocation.getSourceFile(), function () { return []; }); locations.push(renameLocation); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (renameLocations_1_1 && !renameLocations_1_1.done && (_a = renameLocations_1.return)) _a.call(renameLocations_1); } finally { if (e_1) throw e_1.error; } } try { for (var _b = __values(renameLocationsBySourceFile.getEntries()), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = __read(_c.value, 2), sourceFile = _d[0], locations = _d[1]; manipulation_1.replaceSourceFileTextForRename({ sourceFile: sourceFile, renameLocations: locations, newName: newName }); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_c && !_c.done && (_e = _b.return)) _e.call(_b); } finally { if (e_2) throw e_2.error; } } var e_1, _a, e_2, _e; }; /** * Gets the definitions for the specified node. * @param node - Node. */ LanguageService.prototype.getDefinitions = function (node) { return this.getDefinitionsAtPosition(node.sourceFile, node.getStart()); }; /** * Gets the definitions at the specified position. * @param sourceFile - Source file. * @param pos - Position. */ LanguageService.prototype.getDefinitionsAtPosition = function (sourceFile, pos) { var _this = this; var results = this.compilerObject.getDefinitionAtPosition(sourceFile.getFilePath(), pos) || []; return results.map(function (info) { return new results_1.DefinitionInfo(_this.global, info); }); }; /** * Gets the implementations for the specified node. * @param node - Node. */ LanguageService.prototype.getImplementations = function (node) { return this.getImplementationsAtPosition(node.sourceFile, node.getStart()); }; /** * Gets the implementations at the specified position. * @param sourceFile - Source file. * @param pos - Position. */ LanguageService.prototype.getImplementationsAtPosition = function (sourceFile, pos) { var _this = this; var results = this.compilerObject.getImplementationAtPosition(sourceFile.getFilePath(), pos) || []; return results.map(function (location) { return new results_1.ImplementationLocation(_this.global, location); }); }; /** * Finds references based on the specified node. * @param node - Node to find references for. */ LanguageService.prototype.findReferences = function (node) { return this.findReferencesAtPosition(node.sourceFile, node.getStart()); }; /** * Finds references based on the specified position. * @param sourceFile - Source file. * @param pos - Position to find the reference at. */ LanguageService.prototype.findReferencesAtPosition = function (sourceFile, pos) { var _this = this; var results = this.compilerObject.findReferences(sourceFile.getFilePath(), pos) || []; return results.map(function (s) { return new results_1.ReferencedSymbol(_this.global, s); }); }; /** * Find the rename locations for the specified node. * @param node - Node to get the rename locations for. */ LanguageService.prototype.findRenameLocations = function (node) { var _this = this; var sourceFile = node.getSourceFile(); var renameLocations = this.compilerObject.findRenameLocations(sourceFile.getFilePath(), node.getStart(), false, false) || []; return renameLocations.map(function (l) { return new results_1.RenameLocation(_this.global, l); }); }; /** * Gets the formatting edits for a document. * @param filePath - File path of the source file. * @param settings - Format code settings. */ LanguageService.prototype.getFormattingEditsForDocument = function (filePath, settings) { utils_1.fillDefaultFormatCodeSettings(settings, this.global.manipulationSettings); var formattingEdits = this.compilerObject.getFormattingEditsForDocument(filePath, settings) || []; return formattingEdits.map(function (e) { return new results_1.TextChange(e); }); }; /** * Gets the formatted text for a document. * @param filePath - File path of the source file. * @param settings - Format code settings. */ LanguageService.prototype.getFormattedDocumentText = function (filePath, settings) { var sourceFile = this.global.compilerFactory.getSourceFileFromFilePath(filePath); if (sourceFile == null) throw new errors.FileNotFoundError(filePath); var newText = getCompilerFormattedText(this); if (settings.ensureNewLineAtEndOfFile && !utils_1.StringUtils.endsWith(newText, settings.newLineCharacter)) newText += settings.newLineCharacter; return newText.replace(/\r?\n/g, settings.newLineCharacter); function getCompilerFormattedText(languageService) { var formattingEditsInReverseOrder = languageService.getFormattingEditsForDocument(filePath, settings) .sort(function (a, b) { return b.getSpan().getStart() - a.getSpan().getStart(); }); var fullText = sourceFile.getFullText(); try { for (var formattingEditsInReverseOrder_1 = __values(formattingEditsInReverseOrder), formattingEditsInReverseOrder_1_1 = formattingEditsInReverseOrder_1.next(); !formattingEditsInReverseOrder_1_1.done; formattingEditsInReverseOrder_1_1 = formattingEditsInReverseOrder_1.next()) { var textChange = formattingEditsInReverseOrder_1_1.value; var span = textChange.getSpan(); fullText = fullText.slice(0, span.getStart()) + textChange.getNewText() + fullText.slice(span.getEnd()); } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (formattingEditsInReverseOrder_1_1 && !formattingEditsInReverseOrder_1_1.done && (_a = formattingEditsInReverseOrder_1.return)) _a.call(formattingEditsInReverseOrder_1); } finally { if (e_3) throw e_3.error; } } return fullText; var e_3, _a; } }; LanguageService.prototype.getEmitOutput = function (filePathOrSourceFile, emitOnlyDtsFiles) { var filePath = typeof filePathOrSourceFile === "string" ? utils_1.FileUtils.getStandardizedAbsolutePath(this.global.fileSystem, filePathOrSourceFile) : filePathOrSourceFile.getFilePath(); if (!this.global.compilerFactory.containsSourceFileAtPath(filePath)) throw new errors.FileNotFoundError(filePath); return new results_1.EmitOutput(this.global, filePath, this.compilerObject.getEmitOutput(filePath, emitOnlyDtsFiles)); }; return LanguageService; }()); exports.LanguageService = LanguageService;