UNPKG

ts-simple-ast

Version:

TypeScript compiler wrapper for static analysis and code manipulation.

803 lines (802 loc) 37.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var errors = require("../../../errors"); var manipulation_1 = require("../../../manipulation"); var textSeek_1 = require("../../../manipulation/textSeek"); var typescript_1 = require("../../../typescript"); var utils_1 = require("../../../utils"); var helpers_1 = require("../base/helpers"); var base_1 = require("../base"); var callBaseSet_1 = require("../callBaseSet"); var common_1 = require("../common"); var statement_1 = require("../statement"); var FileSystemRefreshResult_1 = require("./FileSystemRefreshResult"); var callBaseGetStructure_1 = require("../callBaseGetStructure"); // todo: not sure why I need to explicitly type this in order to get TS to not complain... (TS 2.4.1) exports.SourceFileBase = base_1.ModuledNode(base_1.TextInsertableNode(statement_1.StatementedNode(common_1.Node))); var SourceFile = /** @class */ (function (_super) { tslib_1.__extends(SourceFile, _super); /** * Initializes a new instance. * @private * @param context - Project context. * @param node - Underlying node. */ function SourceFile(context, node) { var _this = // start hack :( _super.call(this, context, node, undefined) || this; /** @internal */ _this._isSaved = false; /** @internal */ _this._modifiedEventContainer = new utils_1.EventContainer(); /** @internal */ _this._preModifiedEventContainer = new utils_1.EventContainer(); /** @internal */ _this._referenceContainer = new utils_1.SourceFileReferenceContainer(_this); _this._sourceFile = _this; // end hack // store this before a modification happens to the file var onPreModified = function () { _this.isFromExternalLibrary(); // memoize _this._preModifiedEventContainer.unsubscribe(onPreModified); }; _this._preModifiedEventContainer.subscribe(onPreModified); return _this; } /** * @internal * * WARNING: This should only be called by the compiler factory! */ SourceFile.prototype._replaceCompilerNodeFromFactory = function (compilerNode) { _super.prototype._replaceCompilerNodeFromFactory.call(this, compilerNode); this._context.resetProgram(); // make sure the program has the latest source file this._isSaved = false; this._modifiedEventContainer.fire(this); }; /** * Gets the file path. */ SourceFile.prototype.getFilePath = function () { return this.compilerNode.fileName; }; /** * Gets the file path's base name. */ SourceFile.prototype.getBaseName = function () { return utils_1.FileUtils.getBaseName(this.getFilePath()); }; /** * Gets the file path's base name without the extension. */ SourceFile.prototype.getBaseNameWithoutExtension = function () { var baseName = this.getBaseName(); var extension = this.getExtension(); return baseName.substring(0, baseName.length - extension.length); }; /** * Gets the file path's extension. */ SourceFile.prototype.getExtension = function () { return utils_1.FileUtils.getExtension(this.getFilePath()); }; /** * Gets the directory that the source file is contained in. */ SourceFile.prototype.getDirectory = function () { return this._context.compilerFactory.getDirectoryFromCache(this.getDirectoryPath()); }; /** * Gets the directory path that the source file is contained in. */ SourceFile.prototype.getDirectoryPath = function () { return utils_1.FileUtils.getDirPath(this.compilerNode.fileName); }; /** * Gets the full text with leading trivia. */ SourceFile.prototype.getFullText = function () { // return the string instead of letting Node.getFullText() do a substring to prevent an extra allocation return this.compilerNode.text; }; /** * Gets the line number at the provided position. * @param pos - Position */ SourceFile.prototype.getLineNumberAtPos = function (pos) { return utils_1.StringUtils.getLineNumberAtPos(this.getFullText(), pos); }; /** * Gets the character count from the start of the line to the provided position. * @param pos - Position. */ SourceFile.prototype.getLengthFromLineStartAtPos = function (pos) { return utils_1.StringUtils.getLengthFromLineStartAtPos(this.getFullText(), pos); }; /** * Copies this source file to the specified directory. * * This will modify the module specifiers in the new file, if necessary. * @param dirPathOrDirectory Directory path or directory object to copy the file to. * @param options Options for copying. * @returns The source file the copy was made to. */ SourceFile.prototype.copyToDirectory = function (dirPathOrDirectory, options) { var dirPath = typeof dirPathOrDirectory === "string" ? dirPathOrDirectory : dirPathOrDirectory.getPath(); return this.copy(utils_1.FileUtils.pathJoin(dirPath, this.getBaseName()), options); }; /** * Copy this source file to a new file. * * This will modify the module specifiers in the new file, if necessary. * @param filePath - New file path. Can be relative to the original file or an absolute path. * @param options - Options for copying. */ SourceFile.prototype.copy = function (filePath, options) { if (options === void 0) { options = {}; } var result = this._copyInternal(filePath, options); if (result === false) return this; var copiedSourceFile = result; if (copiedSourceFile.getDirectoryPath() !== this.getDirectoryPath()) copiedSourceFile._updateReferencesForCopyInternal(this._getReferencesForCopyInternal()); return copiedSourceFile; }; /** @internal */ SourceFile.prototype._copyInternal = function (filePath, options) { if (options === void 0) { options = {}; } var _a = options.overwrite, overwrite = _a === void 0 ? false : _a; var _b = this._context, compilerFactory = _b.compilerFactory, fileSystemWrapper = _b.fileSystemWrapper; filePath = fileSystemWrapper.getStandardizedAbsolutePath(filePath, this.getDirectoryPath()); if (filePath === this.getFilePath()) return false; return getCopiedSourceFile(this); function getCopiedSourceFile(currentFile) { try { return compilerFactory.createSourceFileFromText(filePath, currentFile.getFullText(), { overwrite: overwrite, markInProject: getShouldBeInProject() }); } catch (err) { if (err instanceof errors.InvalidOperationError) throw new errors.InvalidOperationError("Did you mean to provide the overwrite option? " + err.message); else throw err; } function getShouldBeInProject() { if (currentFile._isInProject()) return true; var destinationFile = compilerFactory.getSourceFileFromCacheFromFilePath(filePath); return destinationFile != null && destinationFile._isInProject(); } } }; /** @internal */ SourceFile.prototype._getReferencesForCopyInternal = function () { return utils_1.ArrayUtils.from(this._referenceContainer.getLiteralsReferencingOtherSourceFilesEntries()); }; /** @internal */ SourceFile.prototype._updateReferencesForCopyInternal = function (literalReferences) { var e_1, _a; try { // update the nodes in this list to point to the nodes in this copied source file for (var literalReferences_1 = tslib_1.__values(literalReferences), literalReferences_1_1 = literalReferences_1.next(); !literalReferences_1_1.done; literalReferences_1_1 = literalReferences_1.next()) { var reference = literalReferences_1_1.value; reference[0] = this.getChildSyntaxListOrThrow().getDescendantAtStartWithWidth(reference[0].getStart(), reference[0].getWidth()); } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (literalReferences_1_1 && !literalReferences_1_1.done && (_a = literalReferences_1.return)) _a.call(literalReferences_1); } finally { if (e_1) throw e_1.error; } } // update the string literals in the copied file updateStringLiteralReferences(literalReferences); }; /** * Copy this source file to a new file and immediately saves it to the file system asynchronously. * * This will modify the module specifiers in the new file, if necessary. * @param filePath - New file path. Can be relative to the original file or an absolute path. * @param options - Options for copying. */ SourceFile.prototype.copyImmediately = function (filePath, options) { return tslib_1.__awaiter(this, void 0, void 0, function () { var newSourceFile; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: newSourceFile = this.copy(filePath, options); return [4 /*yield*/, newSourceFile.save()]; case 1: _a.sent(); return [2 /*return*/, newSourceFile]; } }); }); }; /** * Copy this source file to a new file and immediately saves it to the file system synchronously. * * This will modify the module specifiers in the new file, if necessary. * @param filePath - New file path. Can be relative to the original file or an absolute path. * @param options - Options for copying. */ SourceFile.prototype.copyImmediatelySync = function (filePath, options) { var newSourceFile = this.copy(filePath, options); newSourceFile.saveSync(); return newSourceFile; }; /** * Moves this source file to the specified directory. * * This will modify the module specifiers in other files that specify this file and the module specifiers in the current file, if necessary. * @param dirPathOrDirectory Directory path or directory object to move the file to. * @param options Options for moving. */ SourceFile.prototype.moveToDirectory = function (dirPathOrDirectory, options) { var dirPath = typeof dirPathOrDirectory === "string" ? dirPathOrDirectory : dirPathOrDirectory.getPath(); return this.move(utils_1.FileUtils.pathJoin(dirPath, this.getBaseName()), options); }; /** * Moves this source file to a new file. * * This will modify the module specifiers in other files that specify this file and the module specifiers in the current file, if necessary. * @param filePath - New file path. Can be relative to the original file or an absolute path. * @param options - Options for moving. */ SourceFile.prototype.move = function (filePath, options) { if (options === void 0) { options = {}; } var oldDirPath = this.getDirectoryPath(); var sourceFileReferences = this._getReferencesForMoveInternal(); var oldFilePath = this.getFilePath(); if (!this._moveInternal(filePath, options)) return this; this._context.fileSystemWrapper.queueFileDelete(oldFilePath); this._updateReferencesForMoveInternal(sourceFileReferences, oldDirPath); // ignore any modifications in other source files this._context.lazyReferenceCoordinator.clearDirtySourceFiles(); // need to add the current source file as being dirty because it was removed and added to the cache in the move this._context.lazyReferenceCoordinator.addDirtySourceFile(this); return this; }; /** @internal */ SourceFile.prototype._moveInternal = function (filePath, options) { if (options === void 0) { options = {}; } var _a = options.overwrite, overwrite = _a === void 0 ? false : _a; filePath = this._context.fileSystemWrapper.getStandardizedAbsolutePath(filePath, this.getDirectoryPath()); if (filePath === this.getFilePath()) return false; var markAsInProject = false; if (overwrite) { // remove the past file if it exists var existingSourceFile = this._context.compilerFactory.getSourceFileFromCacheFromFilePath(filePath); if (existingSourceFile != null) { markAsInProject = existingSourceFile._isInProject(); existingSourceFile.forget(); } } else this._context.compilerFactory.throwIfFileExists(filePath, "Did you mean to provide the overwrite option?"); manipulation_1.replaceSourceFileForFilePathMove({ newFilePath: filePath, sourceFile: this }); if (markAsInProject) this._markAsInProject(); if (this._isInProject()) this.getDirectory()._markAsInProject(); return true; }; /** @internal */ SourceFile.prototype._getReferencesForMoveInternal = function () { return { literalReferences: utils_1.ArrayUtils.from(this._referenceContainer.getLiteralsReferencingOtherSourceFilesEntries()), referencingLiterals: utils_1.ArrayUtils.from(this._referenceContainer.getReferencingLiteralsInOtherSourceFiles()) }; }; /** @internal */ SourceFile.prototype._updateReferencesForMoveInternal = function (sourceFileReferences, oldDirPath) { var _this = this; var literalReferences = sourceFileReferences.literalReferences, referencingLiterals = sourceFileReferences.referencingLiterals; // update the literals in this file if the directory has changed if (oldDirPath !== this.getDirectoryPath()) updateStringLiteralReferences(literalReferences); // update the string literals in other files updateStringLiteralReferences(referencingLiterals.map(function (node) { return ([node, _this]); })); }; /** * Moves this source file to a new file and asynchronously updates the file system immediately. * * This will modify the module specifiers in other files that specify this file and the module specifiers in the current file, if necessary. * @param filePath - New file path. Can be relative to the original file or an absolute path. * @param options - Options for moving. */ SourceFile.prototype.moveImmediately = function (filePath, options) { return tslib_1.__awaiter(this, void 0, void 0, function () { var oldFilePath, newFilePath; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: oldFilePath = this.getFilePath(); newFilePath = this._context.fileSystemWrapper.getStandardizedAbsolutePath(filePath, this.getDirectoryPath()); this.move(filePath, options); if (!(oldFilePath !== newFilePath)) return [3 /*break*/, 2]; return [4 /*yield*/, this._context.fileSystemWrapper.moveFileImmediately(oldFilePath, newFilePath, this.getFullText())]; case 1: _a.sent(); this._isSaved = true; return [3 /*break*/, 4]; case 2: return [4 /*yield*/, this.save()]; case 3: _a.sent(); _a.label = 4; case 4: return [2 /*return*/, this]; } }); }); }; /** * Moves this source file to a new file and synchronously updates the file system immediately. * * This will modify the module specifiers in other files that specify this file and the module specifiers in the current file, if necessary. * @param filePath - New file path. Can be relative to the original file or an absolute path. * @param options - Options for moving. */ SourceFile.prototype.moveImmediatelySync = function (filePath, options) { var oldFilePath = this.getFilePath(); var newFilePath = this._context.fileSystemWrapper.getStandardizedAbsolutePath(filePath, this.getDirectoryPath()); this.move(filePath, options); if (oldFilePath !== newFilePath) { this._context.fileSystemWrapper.moveFileImmediatelySync(oldFilePath, newFilePath, this.getFullText()); this._isSaved = true; } else this.saveSync(); return this; }; /** * Queues a deletion of the file to the file system. * * The file will be deleted when you call ast.save(). If you wish to immediately delete the file, then use deleteImmediately(). */ SourceFile.prototype.delete = function () { var filePath = this.getFilePath(); this.forget(); this._context.fileSystemWrapper.queueFileDelete(filePath); }; /** * Asynchronously deletes the file from the file system. */ SourceFile.prototype.deleteImmediately = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var filePath; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: filePath = this.getFilePath(); this.forget(); return [4 /*yield*/, this._context.fileSystemWrapper.deleteFileImmediately(filePath)]; case 1: _a.sent(); return [2 /*return*/]; } }); }); }; /** * Synchronously deletes the file from the file system. */ SourceFile.prototype.deleteImmediatelySync = function () { var filePath = this.getFilePath(); this.forget(); this._context.fileSystemWrapper.deleteFileImmediatelySync(filePath); }; /** * Asynchronously saves this file with any changes. */ SourceFile.prototype.save = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._context.fileSystemWrapper.writeFile(this.getFilePath(), this._getTextForSave())]; case 1: _a.sent(); this._isSaved = true; return [2 /*return*/]; } }); }); }; /** * Synchronously saves this file with any changes. */ SourceFile.prototype.saveSync = function () { this._context.fileSystemWrapper.writeFileSync(this.getFilePath(), this._getTextForSave()); this._isSaved = true; }; /** @internal */ SourceFile.prototype._getTextForSave = function () { var text = this.getFullText(); return this._hasBom ? "\uFEFF" + text : text; }; /** * Gets any source files referenced via `/// <reference path="..." />` comments. */ SourceFile.prototype.getReferencedFiles = function () { var _this = this; var dirPath = this.getDirectoryPath(); return (this.compilerNode.referencedFiles || []) .map(function (f) { return _this._context.compilerFactory.addOrGetSourceFileFromFilePath(utils_1.FileUtils.pathJoin(dirPath, f.fileName), { markInProject: false }); }) .filter(function (f) { return f != null; }); }; /** * Gets any source files referenced via `/// <reference types="..." />` comments. */ SourceFile.prototype.getTypeReferenceDirectives = function () { var _this = this; var dirPath = this.getDirectoryPath(); return (this.compilerNode.typeReferenceDirectives || []) .map(function (f) { return _this._context.compilerFactory.addOrGetSourceFileFromFilePath(utils_1.FileUtils.pathJoin(dirPath, f.fileName), { markInProject: false }); }) .filter(function (f) { return f != null; }); }; /** * Get any source files that reference this source file. */ SourceFile.prototype.getReferencingSourceFiles = function () { return utils_1.ArrayUtils.from(this._referenceContainer.getDependentSourceFiles()); }; /** * Gets the import and exports in other source files that reference this source file. */ SourceFile.prototype.getReferencingNodesInOtherSourceFiles = function () { return utils_1.ArrayUtils.from(this._referenceContainer.getReferencingNodesInOtherSourceFiles()); }; /** * Gets the string literals in other source files that reference this source file. */ SourceFile.prototype.getReferencingLiteralsInOtherSourceFiles = function () { return utils_1.ArrayUtils.from(this._referenceContainer.getReferencingLiteralsInOtherSourceFiles()); }; /** * Gets all the descendant string literals that reference a source file. */ SourceFile.prototype.getImportStringLiterals = function () { var _this = this; this._ensureBound(); var literals = (this.compilerNode.imports || []); return literals.filter(function (l) { return (l.flags & typescript_1.ts.NodeFlags.Synthesized) === 0; }).map(function (l) { return _this._getNodeFromCompilerNode(l); }); }; /** * Gets the script target of the source file. */ SourceFile.prototype.getLanguageVersion = function () { return this.compilerNode.languageVersion; }; /** * Gets the language variant of the source file. */ SourceFile.prototype.getLanguageVariant = function () { return this.compilerNode.languageVariant; }; /** * Gets if this is a declaration file. */ SourceFile.prototype.isDeclarationFile = function () { return this.compilerNode.isDeclarationFile; }; /** * Gets if the source file was discovered while loading an external library. */ SourceFile.prototype.isFromExternalLibrary = function () { // This needs to be memoized and stored before modification because the TypeScript // compiler does the following code: // // function isSourceFileFromExternalLibrary(file: SourceFile): boolean { // return !!sourceFilesFoundSearchingNodeModules.get(file.path); // } // // So the compiler node will become out of date after a manipulation occurs and // this will return false. // do not create the program if not created before... if the program is // not created then we know this source file wasn't discovered by the program if (!this._context.program._isCompilerProgramCreated()) return false; var compilerProgram = this._context.program.compilerObject; return compilerProgram.isSourceFileFromExternalLibrary(this.compilerNode); }; /** * Gets if the source file is a descendant of a node_modules directory. */ SourceFile.prototype.isInNodeModules = function () { return this.getFilePath().indexOf("/node_modules/") >= 0; }; /** * Gets if this source file has been saved or if the latest changes have been saved. */ SourceFile.prototype.isSaved = function () { return this._isSaved; }; /** * Sets if this source file has been saved. * @internal */ SourceFile.prototype._setIsSaved = function (value) { this._isSaved = value; }; /** * Gets the pre-emit diagnostics of the specified source file. */ SourceFile.prototype.getPreEmitDiagnostics = function () { return this._context.getPreEmitDiagnostics(this); }; SourceFile.prototype.unindent = function (positionRangeOrPos, times) { if (times === void 0) { times = 1; } return this.indent(positionRangeOrPos, times * -1); }; SourceFile.prototype.indent = function (positionRangeOrPos, times) { var _this = this; if (times === void 0) { times = 1; } if (times === 0) return this; var sourceFileText = this.getFullText(); var positionRange = typeof positionRangeOrPos === "number" ? [positionRangeOrPos, positionRangeOrPos] : positionRangeOrPos; errors.throwIfRangeOutOfRange(positionRange, [0, sourceFileText.length], "positionRange"); var startLinePos = textSeek_1.getPreviousMatchingPos(sourceFileText, positionRange[0], function (char) { return char === "\n"; }); var endLinePos = textSeek_1.getNextMatchingPos(sourceFileText, positionRange[1], function (char) { return char === "\r" || char === "\n"; }); var indentText = this._context.manipulationSettings.getIndentationText(); var correctedText = utils_1.StringUtils.indent(sourceFileText.substring(startLinePos, endLinePos), times, indentText, function (pos) { return _this.isInStringAtPos(pos + startLinePos); }); manipulation_1.replaceSourceFileTextForFormatting({ sourceFile: this, newText: sourceFileText.substring(0, startLinePos) + correctedText + sourceFileText.substring(endLinePos) }); return this; }; /** * Emits the source file. */ SourceFile.prototype.emit = function (options) { return this._context.program.emit(tslib_1.__assign({ targetSourceFile: this }, options)); }; /** * Gets the emit output of this source file. * @param options - Emit options. */ SourceFile.prototype.getEmitOutput = function (options) { if (options === void 0) { options = {}; } return this._context.languageService.getEmitOutput(this, options.emitOnlyDtsFiles || false); }; /** * Formats the source file text using the internal TypeScript formatting API. * @param settings - Format code settings. */ SourceFile.prototype.formatText = function (settings) { if (settings === void 0) { settings = {}; } manipulation_1.replaceSourceFileTextForFormatting({ sourceFile: this, newText: this._context.languageService.getFormattedDocumentText(this.getFilePath(), settings) }); }; /** * Refresh the source file from the file system. * * WARNING: When updating from the file system, this will "forget" any previously navigated nodes. * @returns What action ended up taking place. */ SourceFile.prototype.refreshFromFileSystem = function () { return tslib_1.__awaiter(this, void 0, void 0, function () { var fileReadResult; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this._context.fileSystemWrapper.readFileOrNotExists(this.getFilePath(), this._context.getEncoding())]; case 1: fileReadResult = _a.sent(); return [2 /*return*/, this._refreshFromFileSystemInternal(fileReadResult)]; } }); }); }; /** * Synchronously refreshes the source file from the file system. * * WARNING: When updating from the file system, this will "forget" any previously navigated nodes. * @returns What action ended up taking place. */ SourceFile.prototype.refreshFromFileSystemSync = function () { var fileReadResult = this._context.fileSystemWrapper.readFileOrNotExistsSync(this.getFilePath(), this._context.getEncoding()); return this._refreshFromFileSystemInternal(fileReadResult); }; SourceFile.prototype.getRelativePathTo = function (sourceFileOrDir) { return this.getDirectory().getRelativePathTo(sourceFileOrDir); }; SourceFile.prototype.getRelativePathAsModuleSpecifierTo = function (sourceFileOrDir) { return this.getDirectory().getRelativePathAsModuleSpecifierTo(sourceFileOrDir); }; /** * Subscribe to when the source file is modified. * @param subscription - Subscription. * @param subscribe - Optional and defaults to true. Use an explicit false to unsubscribe. */ SourceFile.prototype.onModified = function (subscription, subscribe) { if (subscribe === void 0) { subscribe = true; } if (subscribe) this._modifiedEventContainer.subscribe(subscription); else this._modifiedEventContainer.unsubscribe(subscription); return this; }; /** * Do an action the next time the source file is modified. * @param action - Action to run. * @internal */ SourceFile.prototype._doActionPreNextModification = function (action) { var _this = this; var wrappedSubscription = function () { action(); _this._preModifiedEventContainer.unsubscribe(wrappedSubscription); }; this._preModifiedEventContainer.subscribe(wrappedSubscription); return this; }; /** @internal */ SourceFile.prototype._firePreModified = function () { this._preModifiedEventContainer.fire(this); }; /** * Organizes the imports in the file. * * WARNING! This will forget all the nodes in the file! It's best to do this after you're all done with the file. * @param formatSettings - Format code settings. * @param userPreferences - User preferences for refactoring. */ SourceFile.prototype.organizeImports = function (formatSettings, userPreferences) { if (formatSettings === void 0) { formatSettings = {}; } if (userPreferences === void 0) { userPreferences = {}; } this.applyTextChanges(utils_1.ArrayUtils.flatten(this._context.languageService.organizeImports(this, formatSettings, userPreferences).map(function (r) { return r.getTextChanges(); }))); return this; }; /** * Code fix to add import declarations for identifiers that are referenced, but not imported in the source file. * @param formatSettings - Format code settings. * @param userPreferences - User preferences for refactoring. */ SourceFile.prototype.fixMissingImports = function (formatSettings, userPreferences) { if (formatSettings === void 0) { formatSettings = {}; } if (userPreferences === void 0) { userPreferences = {}; } var e_2, _a; var combinedCodeFix = this._context.languageService.getCombinedCodeFix(this, "fixMissingImport", formatSettings, userPreferences); var sourceFile = this; try { for (var _b = tslib_1.__values(combinedCodeFix.getChanges()), _c = _b.next(); !_c.done; _c = _b.next()) { var fileTextChanges = _c.value; var changes = fileTextChanges.getTextChanges(); removeUnnecessaryDoubleBlankLines(changes); applyTextChanges(changes); } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_2) throw e_2.error; } } return this; function removeUnnecessaryDoubleBlankLines(changes) { changes.sort(function (a, b) { return a.getSpan().getStart() - b.getSpan().getStart(); }); // when a file has no imports, it will add a double newline to every change // so remove them except for the last change for (var i = 0; i < changes.length - 1; i++) { // skip last change var compilerObject = changes[i].compilerObject; compilerObject.newText = compilerObject.newText.replace(/(\r?)\n\r?\n$/, "$1\n"); } } function applyTextChanges(changes) { var e_3, _a; // group all the changes by their start position and insert them into the file var groups = utils_1.ArrayUtils.groupBy(changes, function (change) { return change.getSpan().getStart(); }); var addedLength = 0; try { for (var groups_1 = tslib_1.__values(groups), groups_1_1 = groups_1.next(); !groups_1_1.done; groups_1_1 = groups_1.next()) { var group = groups_1_1.value; // these should all be import declarations so it should be safe var insertPos = group[0].getSpan().getStart() + addedLength; var newText = group.map(function (item) { return item.getNewText(); }).join(""); manipulation_1.insertIntoTextRange({ sourceFile: sourceFile, insertPos: insertPos, newText: newText }); addedLength += newText.length; } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (groups_1_1 && !groups_1_1.done && (_a = groups_1.return)) _a.call(groups_1); } finally { if (e_3) throw e_3.error; } } } }; /** * Applies the text changes to the source file. * * WARNING! This will forget all the nodes in the file! It's best to do this after you're all done with the file. * @param textChanges - Text changes. */ SourceFile.prototype.applyTextChanges = function (textChanges) { // do nothing if no changes if (textChanges.length === 0) return this; this.forgetDescendants(); manipulation_1.replaceNodeText({ sourceFile: this._sourceFile, start: 0, replacingLength: this.getFullWidth(), newText: manipulation_1.getTextFromFormattingEdits(this, textChanges) }); return this; }; /** * Sets the node from a structure. * @param structure - Structure to set the node with. */ SourceFile.prototype.set = function (structure) { callBaseSet_1.callBaseSet(exports.SourceFileBase.prototype, this, structure); return this; }; /** * Gets the structure equivalent to this node. */ SourceFile.prototype.getStructure = function () { return callBaseGetStructure_1.callBaseGetStructure(exports.SourceFileBase.prototype, this, { bodyText: helpers_1.getBodyTextWithoutLeadingIndentation(this) }); }; SourceFile.prototype._refreshFromFileSystemInternal = function (fileReadResult) { if (fileReadResult === false) { this.forget(); return FileSystemRefreshResult_1.FileSystemRefreshResult.Deleted; } var fileText = fileReadResult; if (fileText === this.getFullText()) return FileSystemRefreshResult_1.FileSystemRefreshResult.NoChange; this.replaceText([0, this.getEnd()], fileText); this._setIsSaved(true); // saved when loaded from file system return FileSystemRefreshResult_1.FileSystemRefreshResult.Updated; }; /** @internal */ SourceFile.prototype._isInProject = function () { return this._context.inProjectCoordinator.isSourceFileInProject(this); }; /** @internal */ SourceFile.prototype._markAsInProject = function () { this._context.inProjectCoordinator.markSourceFileAsInProject(this); }; tslib_1.__decorate([ utils_1.Memoize ], SourceFile.prototype, "isFromExternalLibrary", null); return SourceFile; }(exports.SourceFileBase)); exports.SourceFile = SourceFile; function updateStringLiteralReferences(nodeReferences) { var e_4, _a; try { for (var nodeReferences_1 = tslib_1.__values(nodeReferences), nodeReferences_1_1 = nodeReferences_1.next(); !nodeReferences_1_1.done; nodeReferences_1_1 = nodeReferences_1.next()) { var _b = tslib_1.__read(nodeReferences_1_1.value, 2), stringLiteral = _b[0], sourceFile = _b[1]; if (utils_1.ModuleUtils.isModuleSpecifierRelative(stringLiteral.getLiteralText())) stringLiteral.setLiteralValue(stringLiteral._sourceFile.getRelativePathAsModuleSpecifierTo(sourceFile)); } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (nodeReferences_1_1 && !nodeReferences_1_1.done && (_a = nodeReferences_1.return)) _a.call(nodeReferences_1); } finally { if (e_4) throw e_4.error; } } }