@tslite/services 0.0.0-stage → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/LICENSE +55 -0
  2. package/NOTICE +13 -0
  3. package/dist/_namespaces/edit.d.ts +8 -0
  4. package/dist/_namespaces/edit.js +11 -0
  5. package/dist/_namespaces/ts.Completions.StringCompletions.d.ts +1 -0
  6. package/dist/_namespaces/ts.Completions.StringCompletions.js +2 -0
  7. package/dist/_namespaces/ts.Completions.d.ts +2 -0
  8. package/dist/_namespaces/ts.Completions.js +3 -0
  9. package/dist/_namespaces/ts.FindAllReferences.d.ts +2 -0
  10. package/dist/_namespaces/ts.FindAllReferences.js +3 -0
  11. package/dist/_namespaces/ts.GoToDefinition.d.ts +1 -0
  12. package/dist/_namespaces/ts.GoToDefinition.js +2 -0
  13. package/dist/_namespaces/ts.NavigationBar.d.ts +1 -0
  14. package/dist/_namespaces/ts.NavigationBar.js +2 -0
  15. package/dist/_namespaces/ts.OrganizeImports.d.ts +1 -0
  16. package/dist/_namespaces/ts.OrganizeImports.js +2 -0
  17. package/dist/_namespaces/ts.OutliningElementsCollector.d.ts +1 -0
  18. package/dist/_namespaces/ts.OutliningElementsCollector.js +2 -0
  19. package/dist/_namespaces/ts.Rename.d.ts +1 -0
  20. package/dist/_namespaces/ts.Rename.js +2 -0
  21. package/dist/_namespaces/ts.SignatureHelp.d.ts +1 -0
  22. package/dist/_namespaces/ts.SignatureHelp.js +2 -0
  23. package/dist/_namespaces/ts.SmartSelectionRange.d.ts +1 -0
  24. package/dist/_namespaces/ts.SmartSelectionRange.js +2 -0
  25. package/dist/_namespaces/ts.SymbolDisplay.d.ts +1 -0
  26. package/dist/_namespaces/ts.SymbolDisplay.js +2 -0
  27. package/dist/_namespaces/ts.codefix.d.ts +26 -0
  28. package/dist/_namespaces/ts.codefix.js +27 -0
  29. package/dist/_namespaces/ts.d.ts +17 -0
  30. package/dist/_namespaces/ts.formatting.d.ts +7 -0
  31. package/dist/_namespaces/ts.formatting.js +8 -0
  32. package/dist/_namespaces/ts.js +20 -0
  33. package/dist/_namespaces/ts.refactor.addOrRemoveBracesToArrowFunction.d.ts +1 -0
  34. package/dist/_namespaces/ts.refactor.addOrRemoveBracesToArrowFunction.js +2 -0
  35. package/dist/_namespaces/ts.refactor.convertParamsToDestructuredObject.d.ts +1 -0
  36. package/dist/_namespaces/ts.refactor.convertParamsToDestructuredObject.js +2 -0
  37. package/dist/_namespaces/ts.refactor.convertStringOrTemplateLiteral.d.ts +1 -0
  38. package/dist/_namespaces/ts.refactor.convertStringOrTemplateLiteral.js +2 -0
  39. package/dist/_namespaces/ts.refactor.d.ts +9 -0
  40. package/dist/_namespaces/ts.refactor.extractSymbol.d.ts +1 -0
  41. package/dist/_namespaces/ts.refactor.extractSymbol.js +2 -0
  42. package/dist/_namespaces/ts.refactor.js +10 -0
  43. package/dist/_namespaces/ts.textChanges.d.ts +1 -0
  44. package/dist/_namespaces/ts.textChanges.js +2 -0
  45. package/dist/classifier.d.ts +5 -0
  46. package/dist/classifier.js +439 -0
  47. package/dist/codeFixProvider.d.ts +13 -0
  48. package/dist/codeFixProvider.js +84 -0
  49. package/dist/codefixes/addConvertToUnknownForNonOverlappingTypes.d.ts +1 -0
  50. package/dist/codefixes/addConvertToUnknownForNonOverlappingTypes.js +21 -0
  51. package/dist/codefixes/addEmptyExportDeclaration.d.ts +1 -0
  52. package/dist/codefixes/addEmptyExportDeclaration.js +17 -0
  53. package/dist/codefixes/addMissingAsync.d.ts +1 -0
  54. package/dist/codefixes/addMissingAsync.js +75 -0
  55. package/dist/codefixes/addMissingAwait.d.ts +1 -0
  56. package/dist/codefixes/addMissingAwait.js +236 -0
  57. package/dist/codefixes/addMissingConst.d.ts +1 -0
  58. package/dist/codefixes/addMissingConst.js +91 -0
  59. package/dist/codefixes/addNameToNamelessParameter.d.ts +1 -0
  60. package/dist/codefixes/addNameToNamelessParameter.js +29 -0
  61. package/dist/codefixes/convertConstToLet.d.ts +1 -0
  62. package/dist/codefixes/convertConstToLet.js +30 -0
  63. package/dist/codefixes/convertToAsyncFunction.d.ts +1 -0
  64. package/dist/codefixes/convertToAsyncFunction.js +495 -0
  65. package/dist/codefixes/convertToMappedObjectType.d.ts +1 -0
  66. package/dist/codefixes/convertToMappedObjectType.js +48 -0
  67. package/dist/codefixes/correctQualifiedNameToIndexedAccessType.d.ts +1 -0
  68. package/dist/codefixes/correctQualifiedNameToIndexedAccessType.js +33 -0
  69. package/dist/codefixes/fixAddModuleReferTypeMissingTypeof.d.ts +1 -0
  70. package/dist/codefixes/fixAddModuleReferTypeMissingTypeof.js +27 -0
  71. package/dist/codefixes/fixAwaitInSyncFunction.d.ts +1 -0
  72. package/dist/codefixes/fixAwaitInSyncFunction.js +69 -0
  73. package/dist/codefixes/fixExpectedComma.d.ts +1 -0
  74. package/dist/codefixes/fixExpectedComma.js +35 -0
  75. package/dist/codefixes/fixInvalidJsxCharacters.d.ts +1 -0
  76. package/dist/codefixes/fixInvalidJsxCharacters.js +41 -0
  77. package/dist/codefixes/fixMissingCallParentheses.d.ts +1 -0
  78. package/dist/codefixes/fixMissingCallParentheses.js +42 -0
  79. package/dist/codefixes/fixSpelling.d.ts +1 -0
  80. package/dist/codefixes/fixSpelling.js +94 -0
  81. package/dist/codefixes/fixUnreachableCode.d.ts +1 -0
  82. package/dist/codefixes/fixUnreachableCode.js +65 -0
  83. package/dist/codefixes/fixUnusedIdentifier.d.ts +1 -0
  84. package/dist/codefixes/fixUnusedIdentifier.js +224 -0
  85. package/dist/codefixes/helpers.d.ts +8 -0
  86. package/dist/codefixes/helpers.js +53 -0
  87. package/dist/codefixes/importFixes.d.ts +14 -0
  88. package/dist/codefixes/importFixes.js +441 -0
  89. package/dist/codefixes/inferFromUsage.d.ts +1 -0
  90. package/dist/codefixes/inferFromUsage.js +742 -0
  91. package/dist/codefixes/removeUnnecessaryAwait.d.ts +1 -0
  92. package/dist/codefixes/removeUnnecessaryAwait.js +41 -0
  93. package/dist/codefixes/returnValueCorrect.d.ts +1 -0
  94. package/dist/codefixes/returnValueCorrect.js +132 -0
  95. package/dist/codefixes/splitTypeOnlyImport.d.ts +1 -0
  96. package/dist/codefixes/splitTypeOnlyImport.js +32 -0
  97. package/dist/codefixes/useBigintLiteral.d.ts +1 -0
  98. package/dist/codefixes/useBigintLiteral.js +29 -0
  99. package/dist/completions.d.ts +83 -0
  100. package/dist/completions.js +1720 -0
  101. package/dist/documentHighlights.d.ts +8 -0
  102. package/dist/documentHighlights.js +367 -0
  103. package/dist/documentRegistry.d.ts +36 -0
  104. package/dist/documentRegistry.js +63 -0
  105. package/dist/editingServices.d.ts +1 -0
  106. package/dist/editingServices.js +4 -0
  107. package/dist/findAllReferences.d.ts +113 -0
  108. package/dist/findAllReferences.js +1366 -0
  109. package/dist/formatting/formatting.d.ts +26 -0
  110. package/dist/formatting/formatting.js +1021 -0
  111. package/dist/formatting/formattingContext.d.ts +34 -0
  112. package/dist/formatting/formattingContext.js +78 -0
  113. package/dist/formatting/formattingScanner.d.ts +14 -0
  114. package/dist/formatting/formattingScanner.js +228 -0
  115. package/dist/formatting/rule.d.ts +31 -0
  116. package/dist/formatting/rule.js +22 -0
  117. package/dist/formatting/rules.d.ts +7 -0
  118. package/dist/formatting/rules.js +610 -0
  119. package/dist/formatting/rulesMap.d.ts +5 -0
  120. package/dist/formatting/rulesMap.js +127 -0
  121. package/dist/formatting/smartIndenter.d.ts +44 -0
  122. package/dist/formatting/smartIndenter.js +518 -0
  123. package/dist/getEditsForFileRename.d.ts +6 -0
  124. package/dist/getEditsForFileRename.js +86 -0
  125. package/dist/goToDefinition.d.ts +8 -0
  126. package/dist/goToDefinition.js +246 -0
  127. package/dist/importTracker.d.ts +50 -0
  128. package/dist/importTracker.js +422 -0
  129. package/dist/index.d.ts +1 -0
  130. package/dist/index.js +3 -0
  131. package/dist/navigationBar.d.ts +3 -0
  132. package/dist/navigationBar.js +549 -0
  133. package/dist/organizeImports.d.ts +18 -0
  134. package/dist/organizeImports.js +290 -0
  135. package/dist/outliningElementsCollector.d.ts +2 -0
  136. package/dist/outliningElementsCollector.js +261 -0
  137. package/dist/refactorProvider.d.ts +5 -0
  138. package/dist/refactorProvider.js +16 -0
  139. package/dist/refactors/addOrRemoveBracesToArrowFunction.d.ts +1 -0
  140. package/dist/refactors/addOrRemoveBracesToArrowFunction.js +86 -0
  141. package/dist/refactors/convertExport.d.ts +1 -0
  142. package/dist/refactors/convertExport.js +126 -0
  143. package/dist/refactors/convertImport.d.ts +1 -0
  144. package/dist/refactors/convertImport.js +116 -0
  145. package/dist/refactors/convertParamsToDestructuredObject.d.ts +1 -0
  146. package/dist/refactors/convertParamsToDestructuredObject.js +282 -0
  147. package/dist/refactors/convertStringOrTemplateLiteral.d.ts +1 -0
  148. package/dist/refactors/convertStringOrTemplateLiteral.js +148 -0
  149. package/dist/refactors/extractSymbol.d.ts +60 -0
  150. package/dist/refactors/extractSymbol.js +1281 -0
  151. package/dist/refactors/extractType.d.ts +1 -0
  152. package/dist/refactors/extractType.js +102 -0
  153. package/dist/refactors/moveToNewFile.d.ts +1 -0
  154. package/dist/refactors/moveToNewFile.js +477 -0
  155. package/dist/rename.d.ts +2 -0
  156. package/dist/rename.js +100 -0
  157. package/dist/services.d.ts +48 -0
  158. package/dist/services.js +1480 -0
  159. package/dist/signatureHelp.d.ts +8 -0
  160. package/dist/signatureHelp.js +414 -0
  161. package/dist/smartSelection.d.ts +2 -0
  162. package/dist/smartSelection.js +243 -0
  163. package/dist/stringCompletions.d.ts +4 -0
  164. package/dist/stringCompletions.js +220 -0
  165. package/dist/suggestionDiagnostics.d.ts +6 -0
  166. package/dist/suggestionDiagnostics.js +92 -0
  167. package/dist/symbolDisplay.d.ts +16 -0
  168. package/dist/symbolDisplay.js +400 -0
  169. package/dist/textChanges.d.ts +161 -0
  170. package/dist/textChanges.js +1163 -0
  171. package/dist/types.d.ts +908 -0
  172. package/dist/types.js +263 -0
  173. package/dist/utilities.d.ts +283 -0
  174. package/dist/utilities.js +1981 -0
  175. package/package.json +45 -3
  176. package/README.md +0 -3
@@ -0,0 +1,1163 @@
1
+ // Modificado de microsoft/TypeScript v3.9.10, src/services/textChanges.ts: o namespace virou módulo ES, com os imports explícitos.
2
+ import { CharacterCodes, Debug, EmitHint, NewLineKind, NodeSet, ScriptTarget, SemicolonPreference, SyntaxKind, addToSeen, contains, createMap, createNodeArray, createObjectLiteral, createParen, createPrinter, createRange, createSourceFile, createTextChange, createTextRangeFromSpan, createTextSpan, createTextSpanFromRange, createTextWriter, createToken, endsWith, find, findChildOfKind, findLastIndex, findNextToken, findPrecedingToken, first, firstOrUndefined, formatting, getAncestor, getFirstNonSpaceCharacterPosition, getLeadingCommentRanges, getLineAndCharacterOfPosition, getLineOfLocalPosition, getLineStartPositionForPosition, getNewLineOrDefaultFromHost, getNodeId, getScriptKindFromFileName, getShebang, getStartPositionOfLine, getTokenAtPosition, getTouchingToken, group, indexOfNode, isAnyImportSyntax, isArray, isArrowFunction, isCallExpression, isExpression, isFunctionLike, isImportClause, isImportDeclaration, isInComment, isInJSXText, isInString, isInTemplateString, isJsonSourceFile, isLineBreak, isNamedImports, isObjectLiteralExpression, isParameter, isPinnedComment, isPrologueDirective, isPropertySignature, isRecognizedTripleSlashComment, isStatement, isStatementButNotDeclaration, isStringLiteral, isTypeElement, isVariableDeclaration, isWhiteSpaceLike, isWhiteSpaceSingleLine, last, mapDefined, nodeIsSynthesized, nullTransformationContext, positionsAreOnSameLine, probablyUsesSemicolons, rangeContainsRangeExclusive, rangeOfNode, rangeOfTypeParameters, rangeStartPositionsAreOnSameLine, removeSuffix, skipTrivia, stableSort, stringContainsAt, textSpanEnd, tokenToString, visitEachChild, visitNodes, } from "./_namespaces/edit.js";
3
+ /**
4
+ * Currently for simplicity we store recovered positions on the node itself.
5
+ * It can be changed to side-table later if we decide that current design is too invasive.
6
+ */
7
+ function getPos(n) {
8
+ const result = n.__pos;
9
+ Debug.assert(typeof result === "number");
10
+ return result;
11
+ }
12
+ function setPos(n, pos) {
13
+ Debug.assert(typeof pos === "number");
14
+ n.__pos = pos;
15
+ }
16
+ function getEnd(n) {
17
+ const result = n.__end;
18
+ Debug.assert(typeof result === "number");
19
+ return result;
20
+ }
21
+ function setEnd(n, end) {
22
+ Debug.assert(typeof end === "number");
23
+ n.__end = end;
24
+ }
25
+ export var LeadingTriviaOption;
26
+ (function (LeadingTriviaOption) {
27
+ /** Exclude all leading trivia (use getStart()) */
28
+ LeadingTriviaOption[LeadingTriviaOption["Exclude"] = 0] = "Exclude";
29
+ /** Include leading trivia and,
30
+ * if there are no line breaks between the node and the previous token,
31
+ * include all trivia between the node and the previous token
32
+ */
33
+ LeadingTriviaOption[LeadingTriviaOption["IncludeAll"] = 1] = "IncludeAll";
34
+ // Na tag, também o JSDoc preso ao nó; a cópia não tem o JSDoc, e o comentário `/** */` é um comentário como outro
35
+ // (CK-03).
36
+ /**
37
+ * Only delete trivia on the same line as getStart().
38
+ * Used to avoid deleting leading comments
39
+ */
40
+ LeadingTriviaOption[LeadingTriviaOption["StartLine"] = 2] = "StartLine";
41
+ })(LeadingTriviaOption || (LeadingTriviaOption = {}));
42
+ export var TrailingTriviaOption;
43
+ (function (TrailingTriviaOption) {
44
+ /** Exclude all trailing trivia (use getEnd()) */
45
+ TrailingTriviaOption[TrailingTriviaOption["Exclude"] = 0] = "Exclude";
46
+ /** Include trailing trivia */
47
+ TrailingTriviaOption[TrailingTriviaOption["Include"] = 1] = "Include";
48
+ })(TrailingTriviaOption || (TrailingTriviaOption = {}));
49
+ function skipWhitespacesAndLineBreaks(text, start) {
50
+ return skipTrivia(text, start, /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
51
+ }
52
+ function hasCommentsBeforeLineBreak(text, start) {
53
+ let i = start;
54
+ while (i < text.length) {
55
+ const ch = text.charCodeAt(i);
56
+ if (isWhiteSpaceSingleLine(ch)) {
57
+ i++;
58
+ continue;
59
+ }
60
+ return ch === CharacterCodes.slash;
61
+ }
62
+ return false;
63
+ }
64
+ const useNonAdjustedPositions = {
65
+ leadingTriviaOption: LeadingTriviaOption.Exclude,
66
+ trailingTriviaOption: TrailingTriviaOption.Exclude,
67
+ };
68
+ var ChangeKind;
69
+ (function (ChangeKind) {
70
+ ChangeKind[ChangeKind["Remove"] = 0] = "Remove";
71
+ ChangeKind[ChangeKind["ReplaceWithSingleNode"] = 1] = "ReplaceWithSingleNode";
72
+ ChangeKind[ChangeKind["ReplaceWithMultipleNodes"] = 2] = "ReplaceWithMultipleNodes";
73
+ ChangeKind[ChangeKind["Text"] = 3] = "Text";
74
+ })(ChangeKind || (ChangeKind = {}));
75
+ function getAdjustedRange(sourceFile, startNode, endNode, options) {
76
+ return { pos: getAdjustedStartPosition(sourceFile, startNode, options), end: getAdjustedEndPosition(sourceFile, endNode, options) };
77
+ }
78
+ function getAdjustedStartPosition(sourceFile, node, options) {
79
+ const { leadingTriviaOption } = options;
80
+ if (leadingTriviaOption === LeadingTriviaOption.Exclude) {
81
+ return node.getStart(sourceFile);
82
+ }
83
+ if (leadingTriviaOption === LeadingTriviaOption.StartLine) {
84
+ return getLineStartPositionForPosition(node.getStart(sourceFile), sourceFile);
85
+ }
86
+ // Na tag, também o começo do JSDoc preso ao nó (CK-03).
87
+ const fullStart = node.getFullStart();
88
+ const start = node.getStart(sourceFile);
89
+ if (fullStart === start) {
90
+ return start;
91
+ }
92
+ const fullStartLine = getLineStartPositionForPosition(fullStart, sourceFile);
93
+ const startLine = getLineStartPositionForPosition(start, sourceFile);
94
+ if (startLine === fullStartLine) {
95
+ // full start and start of the node are on the same line
96
+ // a, b;
97
+ // ^ ^
98
+ // | start
99
+ // fullstart
100
+ // when b is replaced - we usually want to keep the leading trvia
101
+ // when b is deleted - we delete it
102
+ return leadingTriviaOption === LeadingTriviaOption.IncludeAll ? fullStart : start;
103
+ }
104
+ // get start position of the line following the line that contains fullstart position
105
+ // (but only if the fullstart isn't the very beginning of the file)
106
+ const nextLineStart = fullStart > 0 ? 1 : 0;
107
+ let adjustedStartPosition = getStartPositionOfLine(getLineOfLocalPosition(sourceFile, fullStartLine) + nextLineStart, sourceFile);
108
+ // skip whitespaces/newlines
109
+ adjustedStartPosition = skipWhitespacesAndLineBreaks(sourceFile.text, adjustedStartPosition);
110
+ return getStartPositionOfLine(getLineOfLocalPosition(sourceFile, adjustedStartPosition), sourceFile);
111
+ }
112
+ function getAdjustedEndPosition(sourceFile, node, options) {
113
+ const { end } = node;
114
+ const { trailingTriviaOption } = options;
115
+ if (trailingTriviaOption === TrailingTriviaOption.Exclude || (isExpression(node) && trailingTriviaOption !== TrailingTriviaOption.Include)) {
116
+ return end;
117
+ }
118
+ const newEnd = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true);
119
+ return newEnd !== end && (trailingTriviaOption === TrailingTriviaOption.Include || isLineBreak(sourceFile.text.charCodeAt(newEnd - 1)))
120
+ ? newEnd
121
+ : end;
122
+ }
123
+ /**
124
+ * Checks if 'candidate' argument is a legal separator in the list that contains 'node' as an element
125
+ */
126
+ function isSeparator(node, candidate) {
127
+ return !!candidate && !!node.parent && (candidate.kind === SyntaxKind.CommaToken || (candidate.kind === SyntaxKind.SemicolonToken && node.parent.kind === SyntaxKind.ObjectLiteralExpression));
128
+ }
129
+ function spaces(count) {
130
+ let s = "";
131
+ for (let i = 0; i < count; i++) {
132
+ s += " ";
133
+ }
134
+ return s;
135
+ }
136
+ // Na tag, também o que recebe a anotação do `this` (a `function` e a function expression), com o
137
+ // `isThisTypeAnnotatable` (CK-02).
138
+ export class ChangeTracker {
139
+ static fromContext(context) {
140
+ return new ChangeTracker(getNewLineOrDefaultFromHost(context.host, context.formatContext.options), context.formatContext);
141
+ }
142
+ static with(context, cb) {
143
+ const tracker = ChangeTracker.fromContext(context);
144
+ cb(tracker);
145
+ return tracker.getChanges();
146
+ }
147
+ /** Public for tests only. Other callers should use `ChangeTracker.with`. */
148
+ constructor(newLineCharacter, formatContext) {
149
+ this.newLineCharacter = newLineCharacter;
150
+ this.formatContext = formatContext;
151
+ this.changes = [];
152
+ this.newFiles = [];
153
+ // Na tag, também a classe e a interface em que um membro se insere no começo (CK-02).
154
+ this.classesWithNodesInsertedAtStart = createMap(); // Set<ClassDeclaration> implemented as Map<node id, ClassDeclaration>
155
+ this.deletedNodes = [];
156
+ }
157
+ pushRaw(sourceFile, change) {
158
+ Debug.assertEqual(sourceFile.fileName, change.fileName);
159
+ for (const c of change.textChanges) {
160
+ this.changes.push({
161
+ kind: ChangeKind.Text,
162
+ sourceFile,
163
+ text: c.newText,
164
+ range: createTextRangeFromSpan(c.span),
165
+ });
166
+ }
167
+ }
168
+ deleteRange(sourceFile, range) {
169
+ this.changes.push({ kind: ChangeKind.Remove, sourceFile, range });
170
+ }
171
+ delete(sourceFile, node) {
172
+ this.deletedNodes.push({ sourceFile, node });
173
+ }
174
+ deleteNode(sourceFile, node, options = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }) {
175
+ this.deleteRange(sourceFile, getAdjustedRange(sourceFile, node, node, options));
176
+ }
177
+ deleteModifier(sourceFile, modifier) {
178
+ this.deleteRange(sourceFile, { pos: modifier.getStart(sourceFile), end: skipTrivia(sourceFile.text, modifier.end, /*stopAfterLineBreak*/ true) });
179
+ }
180
+ deleteNodeRange(sourceFile, startNode, endNode, options = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }) {
181
+ const startPosition = getAdjustedStartPosition(sourceFile, startNode, options);
182
+ const endPosition = getAdjustedEndPosition(sourceFile, endNode, options);
183
+ this.deleteRange(sourceFile, { pos: startPosition, end: endPosition });
184
+ }
185
+ deleteNodeRangeExcludingEnd(sourceFile, startNode, afterEndNode, options = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }) {
186
+ const startPosition = getAdjustedStartPosition(sourceFile, startNode, options);
187
+ const endPosition = afterEndNode === undefined ? sourceFile.text.length : getAdjustedStartPosition(sourceFile, afterEndNode, options);
188
+ this.deleteRange(sourceFile, { pos: startPosition, end: endPosition });
189
+ }
190
+ replaceRange(sourceFile, range, newNode, options = {}) {
191
+ this.changes.push({ kind: ChangeKind.ReplaceWithSingleNode, sourceFile, range, options, node: newNode });
192
+ }
193
+ replaceNode(sourceFile, oldNode, newNode, options = useNonAdjustedPositions) {
194
+ this.replaceRange(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, options), newNode, options);
195
+ }
196
+ replaceNodeRange(sourceFile, startNode, endNode, newNode, options = useNonAdjustedPositions) {
197
+ this.replaceRange(sourceFile, getAdjustedRange(sourceFile, startNode, endNode, options), newNode, options);
198
+ }
199
+ replaceRangeWithNodes(sourceFile, range, newNodes, options = {}) {
200
+ this.changes.push({ kind: ChangeKind.ReplaceWithMultipleNodes, sourceFile, range, options, nodes: newNodes });
201
+ }
202
+ replaceNodeWithNodes(sourceFile, oldNode, newNodes, options = useNonAdjustedPositions) {
203
+ this.replaceRangeWithNodes(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, options), newNodes, options);
204
+ }
205
+ replaceNodeWithText(sourceFile, oldNode, text) {
206
+ this.replaceRangeWithText(sourceFile, getAdjustedRange(sourceFile, oldNode, oldNode, useNonAdjustedPositions), text);
207
+ }
208
+ replaceNodeRangeWithNodes(sourceFile, startNode, endNode, newNodes, options = useNonAdjustedPositions) {
209
+ this.replaceRangeWithNodes(sourceFile, getAdjustedRange(sourceFile, startNode, endNode, options), newNodes, options);
210
+ }
211
+ nextCommaToken(sourceFile, node) {
212
+ const next = findNextToken(node, node.parent, sourceFile);
213
+ return next && next.kind === SyntaxKind.CommaToken ? next : undefined;
214
+ }
215
+ replacePropertyAssignment(sourceFile, oldNode, newNode) {
216
+ const suffix = this.nextCommaToken(sourceFile, oldNode) ? "" : ("," + this.newLineCharacter);
217
+ this.replaceNode(sourceFile, oldNode, newNode, { suffix });
218
+ }
219
+ insertNodeAt(sourceFile, pos, newNode, options = {}) {
220
+ this.replaceRange(sourceFile, createRange(pos), newNode, options);
221
+ }
222
+ insertNodesAt(sourceFile, pos, newNodes, options = {}) {
223
+ this.replaceRangeWithNodes(sourceFile, createRange(pos), newNodes, options);
224
+ }
225
+ insertNodeAtTopOfFile(sourceFile, newNode, blankLineBetween) {
226
+ this.insertAtTopOfFile(sourceFile, newNode, blankLineBetween);
227
+ }
228
+ insertNodesAtTopOfFile(sourceFile, newNodes, blankLineBetween) {
229
+ this.insertAtTopOfFile(sourceFile, newNodes, blankLineBetween);
230
+ }
231
+ insertAtTopOfFile(sourceFile, insert, blankLineBetween) {
232
+ const pos = getInsertionPositionAtSourceFileTop(sourceFile);
233
+ const options = {
234
+ prefix: pos === 0 ? undefined : this.newLineCharacter,
235
+ suffix: (isLineBreak(sourceFile.text.charCodeAt(pos)) ? "" : this.newLineCharacter) + (blankLineBetween ? this.newLineCharacter : ""),
236
+ };
237
+ if (isArray(insert)) {
238
+ this.insertNodesAt(sourceFile, pos, insert, options);
239
+ }
240
+ else {
241
+ this.insertNodeAt(sourceFile, pos, insert, options);
242
+ }
243
+ }
244
+ insertFirstParameter(sourceFile, parameters, newParam) {
245
+ const p0 = firstOrUndefined(parameters);
246
+ if (p0) {
247
+ this.insertNodeBefore(sourceFile, p0, newParam);
248
+ }
249
+ else {
250
+ this.insertNodeAt(sourceFile, parameters.pos, newParam);
251
+ }
252
+ }
253
+ insertNodeBefore(sourceFile, before, newNode, blankLineBetween = false) {
254
+ this.insertNodeAt(sourceFile, getAdjustedStartPosition(sourceFile, before, {}), newNode, this.getOptionsForInsertNodeBefore(before, newNode, blankLineBetween));
255
+ }
256
+ insertModifierBefore(sourceFile, modifier, before) {
257
+ const pos = before.getStart(sourceFile);
258
+ this.insertNodeAt(sourceFile, pos, createToken(modifier), { suffix: " " });
259
+ }
260
+ insertLastModifierBefore(sourceFile, modifier, before) {
261
+ if (!before.modifiers) {
262
+ this.insertModifierBefore(sourceFile, modifier, before);
263
+ return;
264
+ }
265
+ const pos = before.modifiers.end;
266
+ this.insertNodeAt(sourceFile, pos, createToken(modifier), { prefix: " " });
267
+ }
268
+ insertCommentBeforeLine(sourceFile, lineNumber, position, commentText) {
269
+ const lineStartPosition = getStartPositionOfLine(lineNumber, sourceFile);
270
+ const startPosition = getFirstNonSpaceCharacterPosition(sourceFile.text, lineStartPosition);
271
+ // First try to see if we can put the comment on the previous line.
272
+ // We need to make sure that we are not in the middle of a string literal or a comment.
273
+ // If so, we do not want to separate the node from its comment if we can.
274
+ // Otherwise, add an extra new line immediately before the error span.
275
+ const insertAtLineStart = isValidLocationToAddComment(sourceFile, startPosition);
276
+ const token = getTouchingToken(sourceFile, insertAtLineStart ? startPosition : position);
277
+ const indent = sourceFile.text.slice(lineStartPosition, startPosition);
278
+ const text = `${insertAtLineStart ? "" : this.newLineCharacter}//${commentText}${this.newLineCharacter}${indent}`;
279
+ this.insertText(sourceFile, token.getStart(sourceFile), text);
280
+ }
281
+ // Na tag, também a inserção de um comentário JSDoc antes de um nó (o `insertJsdocCommentBefore`, CK-03).
282
+ replaceRangeWithText(sourceFile, range, text) {
283
+ this.changes.push({ kind: ChangeKind.Text, sourceFile, range, text });
284
+ }
285
+ insertText(sourceFile, pos, text) {
286
+ this.replaceRangeWithText(sourceFile, createRange(pos), text);
287
+ }
288
+ /** Prefer this over replacing a node with another that has a type annotation, as it avoids reformatting the other parts of the node. */
289
+ tryInsertTypeAnnotation(sourceFile, node, type) {
290
+ let endNode;
291
+ if (isFunctionLike(node)) {
292
+ endNode = findChildOfKind(node, SyntaxKind.CloseParenToken, sourceFile);
293
+ if (!endNode) {
294
+ if (!isArrowFunction(node))
295
+ return false; // Function missing parentheses, give up
296
+ // If no `)`, is an arrow function `x => x`, so use the end of the first parameter
297
+ endNode = first(node.parameters);
298
+ }
299
+ }
300
+ else {
301
+ endNode = (node.kind === SyntaxKind.VariableDeclaration ? node.exclamationToken : node.questionToken) ?? node.name;
302
+ }
303
+ this.insertNodeAt(sourceFile, endNode.end, type, { prefix: ": " });
304
+ return true;
305
+ }
306
+ // Na tag, também a anotação do parâmetro `this` (o `tryInsertThisTypeAnnotation`, CK-02).
307
+ insertTypeParameters(sourceFile, node, typeParameters) {
308
+ // If no `(`, is an arrow function `x => x`, so use the pos of the first parameter
309
+ const start = (findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile) || first(node.parameters)).getStart(sourceFile);
310
+ this.insertNodesAt(sourceFile, start, typeParameters, { prefix: "<", suffix: ">" });
311
+ }
312
+ getOptionsForInsertNodeBefore(before, inserted, doubleNewlines) {
313
+ // Na tag, também antes de um membro de classe (CK-02).
314
+ if (isStatement(before)) {
315
+ return { suffix: doubleNewlines ? this.newLineCharacter + this.newLineCharacter : this.newLineCharacter };
316
+ }
317
+ else if (isVariableDeclaration(before)) { // insert `x = 1, ` into `const x = 1, y = 2;
318
+ return { suffix: ", " };
319
+ }
320
+ else if (isParameter(before)) {
321
+ return isParameter(inserted) ? { suffix: ", " } : {};
322
+ }
323
+ else if (isStringLiteral(before) && isImportDeclaration(before.parent) || isNamedImports(before)) {
324
+ return { suffix: ", " };
325
+ }
326
+ return Debug.failBadSyntaxKind(before); // We haven't handled this kind of node yet -- add it
327
+ }
328
+ // Na tag, também a inserção no começo e no fim do corpo de um construtor (o `insertNodeAtConstructorStart` e o
329
+ // `insertNodeAtConstructorEnd`, CK-02).
330
+ insertNodeAtEndOfScope(sourceFile, scope, newNode) {
331
+ const pos = getAdjustedStartPosition(sourceFile, scope.getLastToken(), {});
332
+ this.insertNodeAt(sourceFile, pos, newNode, {
333
+ prefix: isLineBreak(sourceFile.text.charCodeAt(scope.getLastToken().pos)) ? this.newLineCharacter : this.newLineCharacter + this.newLineCharacter,
334
+ suffix: this.newLineCharacter
335
+ });
336
+ }
337
+ // Na tag, também a inserção de um membro no começo de uma classe ou de uma interface (o `insertNodeAtClassStart`,
338
+ // CK-02); o worker e os auxiliares dele ficam com o object literal.
339
+ insertNodeAtObjectStart(sourceFile, obj, newElement) {
340
+ this.insertNodeAtStartWorker(sourceFile, obj, newElement);
341
+ }
342
+ insertNodeAtStartWorker(sourceFile, cls, newElement) {
343
+ const indentation = this.guessIndentationFromExistingMembers(sourceFile, cls) ?? this.computeIndentationForNewMember(sourceFile, cls);
344
+ this.insertNodeAt(sourceFile, getMembersOrProperties(cls).pos, newElement, this.getInsertNodeAtStartInsertOptions(sourceFile, cls, indentation));
345
+ }
346
+ /**
347
+ * Tries to guess the indentation from the existing members of a class/interface/object. All members must be on
348
+ * new lines and must share the same indentation.
349
+ */
350
+ guessIndentationFromExistingMembers(sourceFile, cls) {
351
+ let indentation;
352
+ let lastRange = cls;
353
+ for (const member of getMembersOrProperties(cls)) {
354
+ if (rangeStartPositionsAreOnSameLine(lastRange, member, sourceFile)) {
355
+ // each indented member must be on a new line
356
+ return undefined;
357
+ }
358
+ const memberStart = member.getStart(sourceFile);
359
+ const memberIndentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(memberStart, sourceFile), memberStart, sourceFile, this.formatContext.options);
360
+ if (indentation === undefined) {
361
+ indentation = memberIndentation;
362
+ }
363
+ else if (memberIndentation !== indentation) {
364
+ // indentation of multiple members is not consistent
365
+ return undefined;
366
+ }
367
+ lastRange = member;
368
+ }
369
+ return indentation;
370
+ }
371
+ computeIndentationForNewMember(sourceFile, cls) {
372
+ const clsStart = cls.getStart(sourceFile);
373
+ return formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(clsStart, sourceFile), clsStart, sourceFile, this.formatContext.options)
374
+ + (this.formatContext.options.indentSize ?? 4);
375
+ }
376
+ getInsertNodeAtStartInsertOptions(sourceFile, cls, indentation) {
377
+ // Rules:
378
+ // - Always insert leading newline.
379
+ // - For object literals:
380
+ // - Add a trailing comma if there are existing members in the node, or the source file is not a JSON file
381
+ // (because trailing commas are generally illegal in a JSON file).
382
+ // - Add a leading comma if the source file is not a JSON file, there are existing insertions,
383
+ // and the node is empty (because we didn't add a trailing comma per the previous rule).
384
+ // - Only insert a trailing newline if body is single-line and there are no other insertions for the node.
385
+ // NOTE: This is handled in `finishClassesWithNodesInsertedAtStart`.
386
+ const members = getMembersOrProperties(cls);
387
+ const isEmpty = members.length === 0;
388
+ const isFirstInsertion = addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(cls), { node: cls, sourceFile });
389
+ const insertTrailingComma = isObjectLiteralExpression(cls) && (!isJsonSourceFile(sourceFile) || !isEmpty);
390
+ const insertLeadingComma = isObjectLiteralExpression(cls) && isJsonSourceFile(sourceFile) && isEmpty && !isFirstInsertion;
391
+ return {
392
+ indentation,
393
+ prefix: (insertLeadingComma ? "," : "") + this.newLineCharacter,
394
+ suffix: insertTrailingComma ? "," : ""
395
+ };
396
+ }
397
+ insertNodeAfterComma(sourceFile, after, newNode) {
398
+ const endPosition = this.insertNodeAfterWorker(sourceFile, this.nextCommaToken(sourceFile, after) || after, newNode);
399
+ this.insertNodeAt(sourceFile, endPosition, newNode, this.getInsertNodeAfterOptions(sourceFile, after));
400
+ }
401
+ insertNodeAfter(sourceFile, after, newNode) {
402
+ const endPosition = this.insertNodeAfterWorker(sourceFile, after, newNode);
403
+ this.insertNodeAt(sourceFile, endPosition, newNode, this.getInsertNodeAfterOptions(sourceFile, after));
404
+ }
405
+ insertNodeAtEndOfList(sourceFile, list, newNode) {
406
+ this.insertNodeAt(sourceFile, list.end, newNode, { prefix: ", " });
407
+ }
408
+ insertNodesAfter(sourceFile, after, newNodes) {
409
+ const endPosition = this.insertNodeAfterWorker(sourceFile, after, first(newNodes));
410
+ this.insertNodesAt(sourceFile, endPosition, newNodes, this.getInsertNodeAfterOptions(sourceFile, after));
411
+ }
412
+ insertNodeAfterWorker(sourceFile, after, newNode) {
413
+ if (needSemicolonBetween(after, newNode)) {
414
+ // check if previous statement ends with semicolon
415
+ // if not - insert semicolon to preserve the code from changing the meaning due to ASI
416
+ if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) {
417
+ this.replaceRange(sourceFile, createRange(after.end), createToken(SyntaxKind.SemicolonToken));
418
+ }
419
+ }
420
+ const endPosition = getAdjustedEndPosition(sourceFile, after, {});
421
+ return endPosition;
422
+ }
423
+ getInsertNodeAfterOptions(sourceFile, after) {
424
+ const options = this.getInsertNodeAfterOptionsWorker(after);
425
+ return {
426
+ ...options,
427
+ prefix: after.end === sourceFile.end && isStatement(after) ? (options.prefix ? `\n${options.prefix}` : "\n") : options.prefix,
428
+ };
429
+ }
430
+ getInsertNodeAfterOptionsWorker(node) {
431
+ switch (node.kind) {
432
+ // Na tag, também a classe (CK-02).
433
+ case SyntaxKind.ModuleDeclaration:
434
+ return { prefix: this.newLineCharacter, suffix: this.newLineCharacter };
435
+ case SyntaxKind.VariableDeclaration:
436
+ case SyntaxKind.StringLiteral:
437
+ case SyntaxKind.Identifier:
438
+ return { prefix: ", " };
439
+ case SyntaxKind.PropertyAssignment:
440
+ return { suffix: "," + this.newLineCharacter };
441
+ case SyntaxKind.ExportKeyword:
442
+ return { prefix: " " };
443
+ case SyntaxKind.Parameter:
444
+ return {};
445
+ default:
446
+ // Na tag, também o membro de classe (CK-02).
447
+ Debug.assert(isStatement(node) || isTypeElement(node)); // Else we haven't handled this kind of node yet -- add it
448
+ return { suffix: this.newLineCharacter };
449
+ }
450
+ }
451
+ // Na tag, também o nome dado a uma function expression, a uma class expression ou a uma arrow, que virava uma
452
+ // `function` (o `insertName`): só o `convertToEs6Module` o chamava, e ele sai com o CommonJS (CK-03).
453
+ insertExportModifier(sourceFile, node) {
454
+ this.insertText(sourceFile, node.getStart(sourceFile), "export ");
455
+ }
456
+ /**
457
+ * This function should be used to insert nodes in lists when nodes don't carry separators as the part of the node range,
458
+ * i.e. arguments in arguments lists, parameters in parameter lists etc.
459
+ * Note that separators are part of the node in statements and class elements.
460
+ */
461
+ insertNodeInListAfter(sourceFile, after, newNode, containingList = formatting.SmartIndenter.getContainingList(after, sourceFile)) {
462
+ if (!containingList) {
463
+ Debug.fail("node is not a list element");
464
+ return;
465
+ }
466
+ const index = indexOfNode(containingList, after);
467
+ if (index < 0) {
468
+ return;
469
+ }
470
+ const end = after.getEnd();
471
+ if (index !== containingList.length - 1) {
472
+ // any element except the last one
473
+ // use next sibling as an anchor
474
+ const nextToken = getTokenAtPosition(sourceFile, after.end);
475
+ if (nextToken && isSeparator(after, nextToken)) {
476
+ // for list
477
+ // a, b, c
478
+ // create change for adding 'e' after 'a' as
479
+ // - find start of next element after a (it is b)
480
+ // - use this start as start and end position in final change
481
+ // - build text of change by formatting the text of node + separator + whitespace trivia of b
482
+ // in multiline case it will work as
483
+ // a,
484
+ // b,
485
+ // c,
486
+ // result - '*' denotes leading trivia that will be inserted after new text (displayed as '#')
487
+ // a,*
488
+ // ***insertedtext<separator>#
489
+ // ###b,
490
+ // c,
491
+ // find line and character of the next element
492
+ const lineAndCharOfNextElement = getLineAndCharacterOfPosition(sourceFile, skipWhitespacesAndLineBreaks(sourceFile.text, containingList[index + 1].getFullStart()));
493
+ // find line and character of the token that precedes next element (usually it is separator)
494
+ const lineAndCharOfNextToken = getLineAndCharacterOfPosition(sourceFile, nextToken.end);
495
+ let prefix;
496
+ let startPos;
497
+ if (lineAndCharOfNextToken.line === lineAndCharOfNextElement.line) {
498
+ // next element is located on the same line with separator:
499
+ // a,$$$$b
500
+ // ^ ^
501
+ // | |-next element
502
+ // |-separator
503
+ // where $$$ is some leading trivia
504
+ // for a newly inserted node we'll maintain the same relative position comparing to separator and replace leading trivia with spaces
505
+ // a, x,$$$$b
506
+ // ^ ^ ^
507
+ // | | |-next element
508
+ // | |-new inserted node padded with spaces
509
+ // |-separator
510
+ startPos = nextToken.end;
511
+ prefix = spaces(lineAndCharOfNextElement.character - lineAndCharOfNextToken.character);
512
+ }
513
+ else {
514
+ // next element is located on different line that separator
515
+ // let insert position be the beginning of the line that contains next element
516
+ startPos = getStartPositionOfLine(lineAndCharOfNextElement.line, sourceFile);
517
+ }
518
+ // write separator and leading trivia of the next element as suffix
519
+ const suffix = `${tokenToString(nextToken.kind)}${sourceFile.text.substring(nextToken.end, containingList[index + 1].getStart(sourceFile))}`;
520
+ this.replaceRange(sourceFile, createRange(startPos, containingList[index + 1].getStart(sourceFile)), newNode, { prefix, suffix });
521
+ }
522
+ }
523
+ else {
524
+ const afterStart = after.getStart(sourceFile);
525
+ const afterStartLinePosition = getLineStartPositionForPosition(afterStart, sourceFile);
526
+ let separator;
527
+ let multilineList = false;
528
+ // insert element after the last element in the list that has more than one item
529
+ // pick the element preceding the after element to:
530
+ // - pick the separator
531
+ // - determine if list is a multiline
532
+ if (containingList.length === 1) {
533
+ // if list has only one element then we'll format is as multiline if node has comment in trailing trivia, or as singleline otherwise
534
+ // i.e. var x = 1 // this is x
535
+ // | new element will be inserted at this position
536
+ separator = SyntaxKind.CommaToken;
537
+ }
538
+ else {
539
+ // element has more than one element, pick separator from the list
540
+ const tokenBeforeInsertPosition = findPrecedingToken(after.pos, sourceFile);
541
+ separator = isSeparator(after, tokenBeforeInsertPosition) ? tokenBeforeInsertPosition.kind : SyntaxKind.CommaToken;
542
+ // determine if list is multiline by checking lines of after element and element that precedes it.
543
+ const afterMinusOneStartLinePosition = getLineStartPositionForPosition(containingList[index - 1].getStart(sourceFile), sourceFile);
544
+ multilineList = afterMinusOneStartLinePosition !== afterStartLinePosition;
545
+ }
546
+ if (hasCommentsBeforeLineBreak(sourceFile.text, after.end)) {
547
+ // in this case we'll always treat containing list as multiline
548
+ multilineList = true;
549
+ }
550
+ if (multilineList) {
551
+ // insert separator immediately following the 'after' node to preserve comments in trailing trivia
552
+ this.replaceRange(sourceFile, createRange(end), createToken(separator));
553
+ // use the same indentation as 'after' item
554
+ const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(afterStartLinePosition, afterStart, sourceFile, this.formatContext.options);
555
+ // insert element before the line break on the line that contains 'after' element
556
+ let insertPos = skipTrivia(sourceFile.text, end, /*stopAfterLineBreak*/ true, /*stopAtComments*/ false);
557
+ if (insertPos !== end && isLineBreak(sourceFile.text.charCodeAt(insertPos - 1))) {
558
+ insertPos--;
559
+ }
560
+ this.replaceRange(sourceFile, createRange(insertPos), newNode, { indentation, prefix: this.newLineCharacter });
561
+ }
562
+ else {
563
+ this.replaceRange(sourceFile, createRange(end), newNode, { prefix: `${tokenToString(separator)} ` });
564
+ }
565
+ }
566
+ }
567
+ parenthesizeExpression(sourceFile, expression) {
568
+ this.replaceRange(sourceFile, rangeOfNode(expression), createParen(expression));
569
+ }
570
+ finishClassesWithNodesInsertedAtStart() {
571
+ this.classesWithNodesInsertedAtStart.forEach(({ node, sourceFile }) => {
572
+ const [openBraceEnd, closeBraceEnd] = getClassOrObjectBraceEnds(node, sourceFile);
573
+ if (openBraceEnd !== undefined && closeBraceEnd !== undefined) {
574
+ const isEmpty = getMembersOrProperties(node).length === 0;
575
+ const isSingleLine = positionsAreOnSameLine(openBraceEnd, closeBraceEnd, sourceFile);
576
+ if (isEmpty && isSingleLine && openBraceEnd !== closeBraceEnd - 1) {
577
+ // For `class C { }` remove the whitespace inside the braces.
578
+ this.deleteRange(sourceFile, createRange(openBraceEnd, closeBraceEnd - 1));
579
+ }
580
+ if (isSingleLine) {
581
+ this.insertText(sourceFile, closeBraceEnd - 1, this.newLineCharacter);
582
+ }
583
+ }
584
+ });
585
+ }
586
+ finishDeleteDeclarations() {
587
+ const deletedNodesInLists = new NodeSet(); // Stores nodes in lists that we already deleted. Used to avoid deleting `, ` twice in `a, b`.
588
+ for (const { sourceFile, node } of this.deletedNodes) {
589
+ if (!this.deletedNodes.some(d => d.sourceFile === sourceFile && rangeContainsRangeExclusive(d.node, node))) {
590
+ if (isArray(node)) {
591
+ this.deleteRange(sourceFile, rangeOfTypeParameters(node));
592
+ }
593
+ else {
594
+ deleteDeclaration.deleteDeclaration(this, deletedNodesInLists, sourceFile, node);
595
+ }
596
+ }
597
+ }
598
+ deletedNodesInLists.forEach(node => {
599
+ const sourceFile = node.getSourceFile();
600
+ const list = formatting.SmartIndenter.getContainingList(node, sourceFile);
601
+ if (node !== last(list))
602
+ return;
603
+ const lastNonDeletedIndex = findLastIndex(list, n => !deletedNodesInLists.has(n), list.length - 2);
604
+ if (lastNonDeletedIndex !== -1) {
605
+ this.deleteRange(sourceFile, { pos: list[lastNonDeletedIndex].end, end: startPositionToDeleteNodeInList(sourceFile, list[lastNonDeletedIndex + 1]) });
606
+ }
607
+ });
608
+ }
609
+ /**
610
+ * Note: after calling this, the TextChanges object must be discarded!
611
+ * @param validate only for tests
612
+ * The reason we must validate as part of this method is that `getNonFormattedText` changes the node's positions,
613
+ * so we can only call this once and can't get the non-formatted text separately.
614
+ */
615
+ getChanges(validate) {
616
+ this.finishDeleteDeclarations();
617
+ this.finishClassesWithNodesInsertedAtStart();
618
+ const changes = changesToText.getTextChangesFromChanges(this.changes, this.newLineCharacter, this.formatContext, validate);
619
+ for (const { oldFile, fileName, statements } of this.newFiles) {
620
+ changes.push(changesToText.newFileChanges(oldFile, fileName, statements, this.newLineCharacter, this.formatContext));
621
+ }
622
+ return changes;
623
+ }
624
+ createNewFile(oldFile, fileName, statements) {
625
+ this.newFiles.push({ oldFile, fileName, statements });
626
+ }
627
+ }
628
+ // find first non-whitespace position in the leading trivia of the node
629
+ function startPositionToDeleteNodeInList(sourceFile, node) {
630
+ return skipTrivia(sourceFile.text, getAdjustedStartPosition(sourceFile, node, { leadingTriviaOption: LeadingTriviaOption.IncludeAll }), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
631
+ }
632
+ // Os dois auxiliares abaixo: na tag, também a classe e a interface (CK-02).
633
+ function getClassOrObjectBraceEnds(cls, sourceFile) {
634
+ const open = findChildOfKind(cls, SyntaxKind.OpenBraceToken, sourceFile);
635
+ const close = findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile);
636
+ return [open?.end, close?.end];
637
+ }
638
+ function getMembersOrProperties(cls) {
639
+ return cls.properties;
640
+ }
641
+ export function getNewFileText(statements, scriptKind, newLineCharacter, formatContext) {
642
+ return changesToText.newFileChangesWorker(/*oldFile*/ undefined, scriptKind, statements, newLineCharacter, formatContext);
643
+ }
644
+ var changesToText;
645
+ (function (changesToText) {
646
+ function getTextChangesFromChanges(changes, newLineCharacter, formatContext, validate) {
647
+ return mapDefined(group(changes, c => c.sourceFile.path), changesInFile => {
648
+ const sourceFile = changesInFile[0].sourceFile;
649
+ // order changes by start position
650
+ // If the start position is the same, put the shorter range first, since an empty range (x, x) may precede (x, y) but not vice-versa.
651
+ const normalized = stableSort(changesInFile, (a, b) => (a.range.pos - b.range.pos) || (a.range.end - b.range.end));
652
+ // verify that change intervals do not overlap, except possibly at end points.
653
+ for (let i = 0; i < normalized.length - 1; i++) {
654
+ Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos, "Changes overlap", () => `${JSON.stringify(normalized[i].range)} and ${JSON.stringify(normalized[i + 1].range)}`);
655
+ }
656
+ const textChanges = mapDefined(normalized, c => {
657
+ const span = createTextSpanFromRange(c.range);
658
+ const newText = computeNewText(c, sourceFile, newLineCharacter, formatContext, validate);
659
+ // Filter out redundant changes.
660
+ if (span.length === newText.length && stringContainsAt(sourceFile.text, newText, span.start)) {
661
+ return undefined;
662
+ }
663
+ return createTextChange(span, newText);
664
+ });
665
+ return textChanges.length > 0 ? { fileName: sourceFile.fileName, textChanges } : undefined;
666
+ });
667
+ }
668
+ changesToText.getTextChangesFromChanges = getTextChangesFromChanges;
669
+ function newFileChanges(oldFile, fileName, statements, newLineCharacter, formatContext) {
670
+ const text = newFileChangesWorker(oldFile, getScriptKindFromFileName(fileName), statements, newLineCharacter, formatContext);
671
+ return { fileName, textChanges: [createTextChange(createTextSpan(0, 0), text)], isNewFile: true };
672
+ }
673
+ changesToText.newFileChanges = newFileChanges;
674
+ function newFileChangesWorker(oldFile, scriptKind, statements, newLineCharacter, formatContext) {
675
+ // TODO: this emits the file, parses it back, then formats it that -- may be a less roundabout way to do this
676
+ const nonFormattedText = statements.map(s => getNonformattedText(s, oldFile, newLineCharacter).text).join(newLineCharacter);
677
+ const sourceFile = createSourceFile("any file name", nonFormattedText, ScriptTarget.ESNext, /*setParentNodes*/ true, scriptKind);
678
+ const changes = formatting.formatDocument(sourceFile, formatContext);
679
+ return applyChanges(nonFormattedText, changes) + newLineCharacter;
680
+ }
681
+ changesToText.newFileChangesWorker = newFileChangesWorker;
682
+ function computeNewText(change, sourceFile, newLineCharacter, formatContext, validate) {
683
+ if (change.kind === ChangeKind.Remove) {
684
+ return "";
685
+ }
686
+ if (change.kind === ChangeKind.Text) {
687
+ return change.text;
688
+ }
689
+ const { options = {}, range: { pos } } = change;
690
+ const format = (n) => getFormattedTextOfNode(n, sourceFile, pos, options, newLineCharacter, formatContext, validate);
691
+ const text = change.kind === ChangeKind.ReplaceWithMultipleNodes
692
+ ? change.nodes.map(n => removeSuffix(format(n), newLineCharacter)).join(change.options.joiner || newLineCharacter) // TODO: GH#18217
693
+ : format(change.node);
694
+ // strip initial indentation (spaces or tabs) if text will be inserted in the middle of the line
695
+ const noIndent = (options.preserveLeadingWhitespace || options.indentation !== undefined || getLineStartPositionForPosition(pos, sourceFile) === pos) ? text : text.replace(/^\s+/, "");
696
+ return (options.prefix || "") + noIndent
697
+ + ((!options.suffix || endsWith(noIndent, options.suffix))
698
+ ? "" : options.suffix);
699
+ }
700
+ function getFormatCodeSettingsForWriting({ options }, sourceFile) {
701
+ const shouldAutoDetectSemicolonPreference = !options.semicolons || options.semicolons === SemicolonPreference.Ignore;
702
+ const shouldRemoveSemicolons = options.semicolons === SemicolonPreference.Remove || shouldAutoDetectSemicolonPreference && !probablyUsesSemicolons(sourceFile);
703
+ return {
704
+ ...options,
705
+ semicolons: shouldRemoveSemicolons ? SemicolonPreference.Remove : SemicolonPreference.Ignore,
706
+ };
707
+ }
708
+ /** Note: this may mutate `nodeIn`. */
709
+ function getFormattedTextOfNode(nodeIn, sourceFile, pos, { indentation, prefix, delta }, newLineCharacter, formatContext, validate) {
710
+ const { node, text } = getNonformattedText(nodeIn, sourceFile, newLineCharacter);
711
+ if (validate)
712
+ validate(node, text);
713
+ const formatOptions = getFormatCodeSettingsForWriting(formatContext, sourceFile);
714
+ const initialIndentation = indentation !== undefined
715
+ ? indentation
716
+ : formatting.SmartIndenter.getIndentation(pos, sourceFile, formatOptions, prefix === newLineCharacter || getLineStartPositionForPosition(pos, sourceFile) === pos);
717
+ if (delta === undefined) {
718
+ delta = formatting.SmartIndenter.shouldIndentChildNode(formatOptions, nodeIn) ? (formatOptions.indentSize || 0) : 0;
719
+ }
720
+ const file = { text, getLineAndCharacterOfPosition(pos) { return getLineAndCharacterOfPosition(this, pos); } };
721
+ const changes = formatting.formatNodeGivenIndentation(node, file, sourceFile.languageVariant, initialIndentation, delta, { ...formatContext, options: formatOptions });
722
+ return applyChanges(text, changes);
723
+ }
724
+ /** Note: output node may be mutated input node. */
725
+ function getNonformattedText(node, sourceFile, newLineCharacter) {
726
+ const writer = createWriter(newLineCharacter);
727
+ const newLine = newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed;
728
+ createPrinter({ newLine, neverAsciiEscape: true, preserveSourceNewlines: true }, writer).writeNode(EmitHint.Unspecified, node, sourceFile, writer);
729
+ return { text: writer.getText(), node: assignPositionsToNode(node) };
730
+ }
731
+ changesToText.getNonformattedText = getNonformattedText;
732
+ })(changesToText || (changesToText = {}));
733
+ export function applyChanges(text, changes) {
734
+ for (let i = changes.length - 1; i >= 0; i--) {
735
+ const { span, newText } = changes[i];
736
+ text = `${text.substring(0, span.start)}${newText}${text.substring(textSpanEnd(span))}`;
737
+ }
738
+ return text;
739
+ }
740
+ function isTrivia(s) {
741
+ return skipTrivia(s, 0) === s.length;
742
+ }
743
+ function assignPositionsToNode(node) {
744
+ // O `as`: as sobrecargas do `visitNodes` não aceitam o callback sob o `strict` do repo (o §5 da arquitetura do checker).
745
+ const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode); // TODO: GH#18217
746
+ // create proxy node for non synthesized nodes
747
+ const newNode = nodeIsSynthesized(visited) ? visited : Object.create(visited);
748
+ newNode.pos = getPos(node);
749
+ newNode.end = getEnd(node);
750
+ return newNode;
751
+ }
752
+ function assignPositionsToNodeArray(nodes, visitor, test, start, count) {
753
+ const visited = visitNodes(nodes, visitor, test, start, count);
754
+ if (!visited) {
755
+ return visited;
756
+ }
757
+ // clone nodearray if necessary
758
+ const nodeArray = visited === nodes ? createNodeArray(visited.slice(0)) : visited;
759
+ nodeArray.pos = getPos(nodes);
760
+ nodeArray.end = getEnd(nodes);
761
+ return nodeArray;
762
+ }
763
+ function createWriter(newLine) {
764
+ let lastNonTriviaPosition = 0;
765
+ const writer = createTextWriter(newLine);
766
+ const onEmitNode = (hint, node, printCallback) => {
767
+ if (node) {
768
+ setPos(node, lastNonTriviaPosition);
769
+ }
770
+ printCallback(hint, node);
771
+ if (node) {
772
+ setEnd(node, lastNonTriviaPosition);
773
+ }
774
+ };
775
+ const onBeforeEmitNodeArray = nodes => {
776
+ if (nodes) {
777
+ setPos(nodes, lastNonTriviaPosition);
778
+ }
779
+ };
780
+ const onAfterEmitNodeArray = nodes => {
781
+ if (nodes) {
782
+ setEnd(nodes, lastNonTriviaPosition);
783
+ }
784
+ };
785
+ const onBeforeEmitToken = node => {
786
+ if (node) {
787
+ setPos(node, lastNonTriviaPosition);
788
+ }
789
+ };
790
+ const onAfterEmitToken = node => {
791
+ if (node) {
792
+ setEnd(node, lastNonTriviaPosition);
793
+ }
794
+ };
795
+ function setLastNonTriviaPosition(s, force) {
796
+ if (force || !isTrivia(s)) {
797
+ lastNonTriviaPosition = writer.getTextPos();
798
+ let i = 0;
799
+ while (isWhiteSpaceLike(s.charCodeAt(s.length - i - 1))) {
800
+ i++;
801
+ }
802
+ // trim trailing whitespaces
803
+ lastNonTriviaPosition -= i;
804
+ }
805
+ }
806
+ function write(s) {
807
+ writer.write(s);
808
+ setLastNonTriviaPosition(s, /*force*/ false);
809
+ }
810
+ function writeComment(s) {
811
+ writer.writeComment(s);
812
+ }
813
+ function writeKeyword(s) {
814
+ writer.writeKeyword(s);
815
+ setLastNonTriviaPosition(s, /*force*/ false);
816
+ }
817
+ function writeOperator(s) {
818
+ writer.writeOperator(s);
819
+ setLastNonTriviaPosition(s, /*force*/ false);
820
+ }
821
+ function writePunctuation(s) {
822
+ writer.writePunctuation(s);
823
+ setLastNonTriviaPosition(s, /*force*/ false);
824
+ }
825
+ function writeTrailingSemicolon(s) {
826
+ writer.writeTrailingSemicolon(s);
827
+ setLastNonTriviaPosition(s, /*force*/ false);
828
+ }
829
+ function writeParameter(s) {
830
+ writer.writeParameter(s);
831
+ setLastNonTriviaPosition(s, /*force*/ false);
832
+ }
833
+ function writeProperty(s) {
834
+ writer.writeProperty(s);
835
+ setLastNonTriviaPosition(s, /*force*/ false);
836
+ }
837
+ function writeSpace(s) {
838
+ writer.writeSpace(s);
839
+ setLastNonTriviaPosition(s, /*force*/ false);
840
+ }
841
+ function writeStringLiteral(s) {
842
+ writer.writeStringLiteral(s);
843
+ setLastNonTriviaPosition(s, /*force*/ false);
844
+ }
845
+ function writeSymbol(s, sym) {
846
+ writer.writeSymbol(s, sym);
847
+ setLastNonTriviaPosition(s, /*force*/ false);
848
+ }
849
+ function writeLine(force) {
850
+ writer.writeLine(force);
851
+ }
852
+ function increaseIndent() {
853
+ writer.increaseIndent();
854
+ }
855
+ function decreaseIndent() {
856
+ writer.decreaseIndent();
857
+ }
858
+ function getText() {
859
+ return writer.getText();
860
+ }
861
+ function rawWrite(s) {
862
+ writer.rawWrite(s);
863
+ setLastNonTriviaPosition(s, /*force*/ false);
864
+ }
865
+ function writeLiteral(s) {
866
+ writer.writeLiteral(s);
867
+ setLastNonTriviaPosition(s, /*force*/ true);
868
+ }
869
+ function getTextPos() {
870
+ return writer.getTextPos();
871
+ }
872
+ function getLine() {
873
+ return writer.getLine();
874
+ }
875
+ function getColumn() {
876
+ return writer.getColumn();
877
+ }
878
+ function getIndent() {
879
+ return writer.getIndent();
880
+ }
881
+ function isAtStartOfLine() {
882
+ return writer.isAtStartOfLine();
883
+ }
884
+ function clear() {
885
+ writer.clear();
886
+ lastNonTriviaPosition = 0;
887
+ }
888
+ return {
889
+ onEmitNode,
890
+ onBeforeEmitNodeArray,
891
+ onAfterEmitNodeArray,
892
+ onBeforeEmitToken,
893
+ onAfterEmitToken,
894
+ write,
895
+ writeComment,
896
+ writeKeyword,
897
+ writeOperator,
898
+ writePunctuation,
899
+ writeTrailingSemicolon,
900
+ writeParameter,
901
+ writeProperty,
902
+ writeSpace,
903
+ writeStringLiteral,
904
+ writeSymbol,
905
+ writeLine,
906
+ increaseIndent,
907
+ decreaseIndent,
908
+ getText,
909
+ rawWrite,
910
+ writeLiteral,
911
+ getTextPos,
912
+ getLine,
913
+ getColumn,
914
+ getIndent,
915
+ isAtStartOfLine,
916
+ hasTrailingComment: () => writer.hasTrailingComment(),
917
+ hasTrailingWhitespace: () => writer.hasTrailingWhitespace(),
918
+ clear
919
+ };
920
+ }
921
+ function getInsertionPositionAtSourceFileTop(sourceFile) {
922
+ let lastPrologue;
923
+ for (const node of sourceFile.statements) {
924
+ if (isPrologueDirective(node)) {
925
+ lastPrologue = node;
926
+ }
927
+ else {
928
+ break;
929
+ }
930
+ }
931
+ let position = 0;
932
+ const text = sourceFile.text;
933
+ if (lastPrologue) {
934
+ position = lastPrologue.end;
935
+ advancePastLineBreak();
936
+ return position;
937
+ }
938
+ const shebang = getShebang(text);
939
+ if (shebang !== undefined) {
940
+ position = shebang.length;
941
+ advancePastLineBreak();
942
+ }
943
+ const ranges = getLeadingCommentRanges(text, position);
944
+ if (!ranges)
945
+ return position;
946
+ // Find the first attached comment to the first node and add before it
947
+ let lastComment;
948
+ let firstNodeLine;
949
+ for (const range of ranges) {
950
+ if (range.kind === SyntaxKind.MultiLineCommentTrivia) {
951
+ if (isPinnedComment(text, range.pos)) {
952
+ lastComment = { range, pinnedOrTripleSlash: true };
953
+ continue;
954
+ }
955
+ }
956
+ else if (isRecognizedTripleSlashComment(text, range.pos, range.end)) {
957
+ lastComment = { range, pinnedOrTripleSlash: true };
958
+ continue;
959
+ }
960
+ if (lastComment) {
961
+ // Always insert after pinned or triple slash comments
962
+ if (lastComment.pinnedOrTripleSlash)
963
+ break;
964
+ // There was a blank line between the last comment and this comment.
965
+ // This comment is not part of the copyright comments
966
+ const commentLine = sourceFile.getLineAndCharacterOfPosition(range.pos).line;
967
+ const lastCommentEndLine = sourceFile.getLineAndCharacterOfPosition(lastComment.range.end).line;
968
+ if (commentLine >= lastCommentEndLine + 2)
969
+ break;
970
+ }
971
+ if (sourceFile.statements.length) {
972
+ if (firstNodeLine === undefined)
973
+ firstNodeLine = sourceFile.getLineAndCharacterOfPosition(sourceFile.statements[0].getStart()).line;
974
+ const commentEndLine = sourceFile.getLineAndCharacterOfPosition(range.end).line;
975
+ if (firstNodeLine < commentEndLine + 2)
976
+ break;
977
+ }
978
+ lastComment = { range, pinnedOrTripleSlash: false };
979
+ }
980
+ if (lastComment) {
981
+ position = lastComment.range.end;
982
+ advancePastLineBreak();
983
+ }
984
+ return position;
985
+ function advancePastLineBreak() {
986
+ if (position < text.length) {
987
+ const charCode = text.charCodeAt(position);
988
+ if (isLineBreak(charCode)) {
989
+ position++;
990
+ if (position < text.length && charCode === CharacterCodes.carriageReturn && text.charCodeAt(position) === CharacterCodes.lineFeed) {
991
+ position++;
992
+ }
993
+ }
994
+ }
995
+ }
996
+ }
997
+ export function isValidLocationToAddComment(sourceFile, position) {
998
+ return !isInComment(sourceFile, position) && !isInString(sourceFile, position) && !isInTemplateString(sourceFile, position) && !isInJSXText(sourceFile, position);
999
+ }
1000
+ function needSemicolonBetween(a, b) {
1001
+ // Na tag, também a propriedade e o membro de classe (CK-02).
1002
+ return isPropertySignature(a) && isTypeElement(b) && b.name.kind === SyntaxKind.ComputedPropertyName
1003
+ || isStatementButNotDeclaration(a) && isStatementButNotDeclaration(b); // TODO: only if b would start with a `(` or `[`
1004
+ }
1005
+ var deleteDeclaration;
1006
+ (function (deleteDeclaration_1) {
1007
+ function deleteDeclaration(changes, deletedNodesInLists, sourceFile, node) {
1008
+ switch (node.kind) {
1009
+ case SyntaxKind.Parameter: {
1010
+ const oldFunction = node.parent;
1011
+ if (isArrowFunction(oldFunction) &&
1012
+ oldFunction.parameters.length === 1 &&
1013
+ !findChildOfKind(oldFunction, SyntaxKind.OpenParenToken, sourceFile)) {
1014
+ // Lambdas with exactly one parameter are special because, after removal, there
1015
+ // must be an empty parameter list (i.e. `()`) and this won't necessarily be the
1016
+ // case if the parameter is simply removed (e.g. in `x => 1`).
1017
+ changes.replaceNodeWithText(sourceFile, node, "()");
1018
+ }
1019
+ else {
1020
+ deleteNodeInList(changes, deletedNodesInLists, sourceFile, node);
1021
+ }
1022
+ break;
1023
+ }
1024
+ // Na tag, também o `import =` (CK-03).
1025
+ case SyntaxKind.ImportDeclaration:
1026
+ const isFirstImport = sourceFile.imports.length && node === first(sourceFile.imports).parent || node === find(sourceFile.statements, isAnyImportSyntax);
1027
+ // For first import, leave header comment in place, otherwise only delete JSDoc comments
1028
+ // Na tag, com o JSDoc preso ao import; a cópia não tem o JSDoc (CK-03).
1029
+ deleteNode(changes, sourceFile, node, { leadingTriviaOption: isFirstImport ? LeadingTriviaOption.Exclude : LeadingTriviaOption.StartLine });
1030
+ break;
1031
+ case SyntaxKind.BindingElement:
1032
+ const pattern = node.parent;
1033
+ const preserveComma = pattern.kind === SyntaxKind.ArrayBindingPattern && node !== last(pattern.elements);
1034
+ if (preserveComma) {
1035
+ deleteNode(changes, sourceFile, node);
1036
+ }
1037
+ else {
1038
+ deleteNodeInList(changes, deletedNodesInLists, sourceFile, node);
1039
+ }
1040
+ break;
1041
+ case SyntaxKind.VariableDeclaration:
1042
+ deleteVariableDeclaration(changes, deletedNodesInLists, sourceFile, node);
1043
+ break;
1044
+ case SyntaxKind.TypeParameter:
1045
+ deleteNodeInList(changes, deletedNodesInLists, sourceFile, node);
1046
+ break;
1047
+ case SyntaxKind.ImportSpecifier:
1048
+ const namedImports = node.parent;
1049
+ if (namedImports.elements.length === 1) {
1050
+ deleteImportBinding(changes, sourceFile, namedImports);
1051
+ }
1052
+ else {
1053
+ deleteNodeInList(changes, deletedNodesInLists, sourceFile, node);
1054
+ }
1055
+ break;
1056
+ case SyntaxKind.NamespaceImport:
1057
+ deleteImportBinding(changes, sourceFile, node);
1058
+ break;
1059
+ case SyntaxKind.SemicolonToken:
1060
+ deleteNode(changes, sourceFile, node, { trailingTriviaOption: TrailingTriviaOption.Exclude });
1061
+ break;
1062
+ // Na tag, também a palavra `function`, a classe e a `function` declarada (CK-02).
1063
+ default:
1064
+ if (isImportClause(node.parent) && node.parent.name === node) {
1065
+ deleteDefaultImport(changes, sourceFile, node.parent);
1066
+ }
1067
+ else if (isCallExpression(node.parent) && contains(node.parent.arguments, node)) {
1068
+ deleteNodeInList(changes, deletedNodesInLists, sourceFile, node);
1069
+ }
1070
+ else {
1071
+ deleteNode(changes, sourceFile, node);
1072
+ }
1073
+ }
1074
+ }
1075
+ deleteDeclaration_1.deleteDeclaration = deleteDeclaration;
1076
+ function deleteDefaultImport(changes, sourceFile, importClause) {
1077
+ if (!importClause.namedBindings) {
1078
+ // Delete the whole import
1079
+ deleteNode(changes, sourceFile, importClause.parent);
1080
+ }
1081
+ else {
1082
+ // import |d,| * as ns from './file'
1083
+ const start = importClause.name.getStart(sourceFile);
1084
+ const nextToken = getTokenAtPosition(sourceFile, importClause.name.end);
1085
+ if (nextToken && nextToken.kind === SyntaxKind.CommaToken) {
1086
+ // shift first non-whitespace position after comma to the start position of the node
1087
+ const end = skipTrivia(sourceFile.text, nextToken.end, /*stopAfterLineBreaks*/ false, /*stopAtComments*/ true);
1088
+ changes.deleteRange(sourceFile, { pos: start, end });
1089
+ }
1090
+ else {
1091
+ deleteNode(changes, sourceFile, importClause.name);
1092
+ }
1093
+ }
1094
+ }
1095
+ function deleteImportBinding(changes, sourceFile, node) {
1096
+ if (node.parent.name) {
1097
+ // Delete named imports while preserving the default import
1098
+ // import d|, * as ns| from './file'
1099
+ // import d|, { a }| from './file'
1100
+ const previousToken = Debug.checkDefined(getTokenAtPosition(sourceFile, node.pos - 1));
1101
+ changes.deleteRange(sourceFile, { pos: previousToken.getStart(sourceFile), end: node.end });
1102
+ }
1103
+ else {
1104
+ // Delete the entire import declaration
1105
+ // |import * as ns from './file'|
1106
+ // |import { a } from './file'|
1107
+ const importDecl = getAncestor(node, SyntaxKind.ImportDeclaration);
1108
+ deleteNode(changes, sourceFile, importDecl);
1109
+ }
1110
+ }
1111
+ function deleteVariableDeclaration(changes, deletedNodesInLists, sourceFile, node) {
1112
+ const { parent } = node;
1113
+ if (parent.kind === SyntaxKind.CatchClause) {
1114
+ // TODO: There's currently no unused diagnostic for this, could be a suggestion
1115
+ changes.deleteNodeRange(sourceFile, findChildOfKind(parent, SyntaxKind.OpenParenToken, sourceFile), findChildOfKind(parent, SyntaxKind.CloseParenToken, sourceFile));
1116
+ return;
1117
+ }
1118
+ if (parent.declarations.length !== 1) {
1119
+ deleteNodeInList(changes, deletedNodesInLists, sourceFile, node);
1120
+ return;
1121
+ }
1122
+ const gp = parent.parent;
1123
+ switch (gp.kind) {
1124
+ case SyntaxKind.ForOfStatement:
1125
+ case SyntaxKind.ForInStatement:
1126
+ changes.replaceNode(sourceFile, node, createObjectLiteral());
1127
+ break;
1128
+ case SyntaxKind.ForStatement:
1129
+ deleteNode(changes, sourceFile, parent);
1130
+ break;
1131
+ case SyntaxKind.VariableStatement:
1132
+ // Na tag, com o JSDoc preso à declaração; a cópia não tem o JSDoc (CK-03).
1133
+ deleteNode(changes, sourceFile, gp, { leadingTriviaOption: LeadingTriviaOption.StartLine });
1134
+ break;
1135
+ default:
1136
+ Debug.assertNever(gp);
1137
+ }
1138
+ }
1139
+ })(deleteDeclaration || (deleteDeclaration = {}));
1140
+ /** Warning: This deletes comments too. See `copyComments` in `convertFunctionToEs6Class`. */
1141
+ // Exported for tests only! (TODO: improve tests to not need this)
1142
+ export function deleteNode(changes, sourceFile, node, options = { leadingTriviaOption: LeadingTriviaOption.IncludeAll }) {
1143
+ const startPosition = getAdjustedStartPosition(sourceFile, node, options);
1144
+ const endPosition = getAdjustedEndPosition(sourceFile, node, options);
1145
+ changes.deleteRange(sourceFile, { pos: startPosition, end: endPosition });
1146
+ }
1147
+ function deleteNodeInList(changes, deletedNodesInLists, sourceFile, node) {
1148
+ const containingList = Debug.checkDefined(formatting.SmartIndenter.getContainingList(node, sourceFile));
1149
+ const index = indexOfNode(containingList, node);
1150
+ Debug.assert(index !== -1);
1151
+ if (containingList.length === 1) {
1152
+ deleteNode(changes, sourceFile, node);
1153
+ return;
1154
+ }
1155
+ // Note: We will only delete a comma *after* a node. This will leave a trailing comma if we delete the last node.
1156
+ // That's handled in the end by `finishTrailingCommaAfterDeletingNodesInList`.
1157
+ Debug.assert(!deletedNodesInLists.has(node), "Deleting a node twice");
1158
+ deletedNodesInLists.add(node);
1159
+ changes.deleteRange(sourceFile, {
1160
+ pos: startPositionToDeleteNodeInList(sourceFile, node),
1161
+ end: index === containingList.length - 1 ? getAdjustedEndPosition(sourceFile, node, {}) : startPositionToDeleteNodeInList(sourceFile, containingList[index + 1]),
1162
+ });
1163
+ }