@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,1281 @@
1
+ // Modificado de microsoft/TypeScript v3.9.10, src/services/refactors/extractSymbol.ts: o namespace virou módulo ES, com os imports explícitos.
2
+ // A extração para uma função escreve a forma da Linguagem: um `const` com uma arrow, e não a `function` declarada (CK-69).
3
+ // Como o `const` não é içado, ele entra antes do statement que o usa, onde a extração para uma constante o põe. Saem a
4
+ // classe como escopo, com o método, a propriedade `readonly` e o que é estático; o `this` e o `super`; o generator; o
5
+ // statement com label; o enum; e a function expression (CK-02). Saem também o arquivo JavaScript e o JSDoc (CK-03).
6
+ import { Debug, DiagnosticCategory, Diagnostics, EmitFlags, ModifierFlags, NodeBuilderFlags, NodeFlags, SymbolFlags, SyntaxKind, ScriptTarget, TypeFlags, arrayFrom, codefix, compareProperties, compareStringsCaseSensitive, compareValues, createArrowFunction, createAssignment, createAwait, createBindingElement, createBlock, createCall, createDiagnosticForNode, createFileDiagnostic, createIdentifier, createKeywordTypeNode, createMap, createNodeArray, createObjectBindingPattern, createObjectLiteral, createParameter, createPropertyAccess, createPropertyAssignment, createPropertySignature, createQualifiedName, createReturn, createShorthandPropertyAssignment, createStatement, createToken, createTypeLiteralNode, createTypeReferenceNode, createUnionTypeNode, createVariableDeclaration, createVariableDeclarationList, createVariableStatement, emptyArray, find, findAncestor, findTokenOnLeftOfPosition, first, forEachChild, formatStringFromArgs, getEffectiveTypeParameterDeclarations, getEnclosingBlockScopeContainer, getLocaleSpecificMessage, getNodeId, getParentNodeInSpan, getRefactorContextSpan, getRenameLocation, getSymbolId, getSynthesizedDeepClone, getTokenAtPosition, getUniqueName, hasModifier, isArray, isArrowFunction, isAssignmentExpression, isBlock, isBlockScope, isCaseClause, isDeclaration, isDeclarationWithTypeParameters, isElementAccessExpression, isExpression, isExpressionNode, isExpressionStatement, isFunctionLikeDeclaration, isIdentifier, isIterationStatement, isModuleBlock, isParenthesizedTypeNode, isPartOfTypeNode, isPropertyAccessExpression, isQualifiedName, isReturnStatement, isShorthandPropertyAssignment, isSourceFile, isStatement, isSwitchStatement, isUnaryExpressionWithWrite, isUnionTypeNode, isVariableDeclaration, isVariableDeclarationList, isVariableStatement, last, map, nullTransformationContext, positionIsSynthesized, rangeContainsStartEnd, setEmitFlags, singleOrUndefined, suppressLeadingAndTrailingTrivia, textChanges, textSpanEnd, updateArrowFunction, updateParameter, visitEachChild, visitNode, visitNodes, } from "../_namespaces/edit.js";
7
+ import { registerRefactor, } from "../_namespaces/ts.refactor.js";
8
+ const refactorName = "Extract Symbol";
9
+ registerRefactor(refactorName, { getAvailableActions, getEditsForAction });
10
+ /**
11
+ * Compute the associated code actions
12
+ * Exported for tests.
13
+ */
14
+ export function getAvailableActions(context) {
15
+ const rangeToExtract = getRangeToExtract(context.file, getRefactorContextSpan(context));
16
+ const targetRange = rangeToExtract.targetRange;
17
+ if (targetRange === undefined) {
18
+ return emptyArray;
19
+ }
20
+ const extractions = getPossibleExtractions(targetRange, context);
21
+ if (extractions === undefined) {
22
+ // No extractions possible
23
+ return emptyArray;
24
+ }
25
+ const functionActions = [];
26
+ const usedFunctionNames = createMap();
27
+ const constantActions = [];
28
+ const usedConstantNames = createMap();
29
+ let i = 0;
30
+ for (const { functionExtraction, constantExtraction } of extractions) {
31
+ // Skip these since we don't have a way to report errors yet
32
+ if (functionExtraction.errors.length === 0) {
33
+ // Don't issue refactorings with duplicated names.
34
+ // Scopes come back in "innermost first" order, so extractions will
35
+ // preferentially go into nearer scopes
36
+ const description = functionExtraction.description;
37
+ if (!usedFunctionNames.has(description)) {
38
+ usedFunctionNames.set(description, true);
39
+ functionActions.push({
40
+ description,
41
+ name: `function_scope_${i}`
42
+ });
43
+ }
44
+ }
45
+ // Skip these since we don't have a way to report errors yet
46
+ if (constantExtraction.errors.length === 0) {
47
+ // Don't issue refactorings with duplicated names.
48
+ // Scopes come back in "innermost first" order, so extractions will
49
+ // preferentially go into nearer scopes
50
+ const description = constantExtraction.description;
51
+ if (!usedConstantNames.has(description)) {
52
+ usedConstantNames.set(description, true);
53
+ constantActions.push({
54
+ description,
55
+ name: `constant_scope_${i}`
56
+ });
57
+ }
58
+ }
59
+ // *do* increment i anyway because we'll look for the i-th scope
60
+ // later when actually doing the refactoring if the user requests it
61
+ i++;
62
+ }
63
+ const infos = [];
64
+ if (constantActions.length) {
65
+ infos.push({
66
+ name: refactorName,
67
+ description: getLocaleSpecificMessage(Diagnostics.Extract_constant),
68
+ actions: constantActions
69
+ });
70
+ }
71
+ if (functionActions.length) {
72
+ infos.push({
73
+ name: refactorName,
74
+ description: getLocaleSpecificMessage(Diagnostics.Extract_function),
75
+ actions: functionActions
76
+ });
77
+ }
78
+ return infos.length ? infos : emptyArray;
79
+ }
80
+ /* Exported for tests */
81
+ export function getEditsForAction(context, actionName) {
82
+ const rangeToExtract = getRangeToExtract(context.file, getRefactorContextSpan(context));
83
+ const targetRange = rangeToExtract.targetRange; // TODO:GH#18217
84
+ const parsedFunctionIndexMatch = /^function_scope_(\d+)$/.exec(actionName);
85
+ if (parsedFunctionIndexMatch) {
86
+ const index = +parsedFunctionIndexMatch[1];
87
+ Debug.assert(isFinite(index), "Expected to parse a finite number from the function scope index");
88
+ return getFunctionExtractionAtIndex(targetRange, context, index);
89
+ }
90
+ const parsedConstantIndexMatch = /^constant_scope_(\d+)$/.exec(actionName);
91
+ if (parsedConstantIndexMatch) {
92
+ const index = +parsedConstantIndexMatch[1];
93
+ Debug.assert(isFinite(index), "Expected to parse a finite number from the constant scope index");
94
+ return getConstantExtractionAtIndex(targetRange, context, index);
95
+ }
96
+ Debug.fail("Unrecognized action name");
97
+ }
98
+ // Move these into diagnostic messages if they become user-facing. Na tag, também as do `super`, do JSDoc, do label, do
99
+ // generator, da propriedade `readonly` de uma classe, da classe de um arquivo JavaScript e da `function` global que a
100
+ // extração deixaria fora do alcance, que saem com o que as dispara (CK-02, CK-03).
101
+ export var Messages;
102
+ (function (Messages) {
103
+ function createMessage(message) {
104
+ return { message, code: 0, category: DiagnosticCategory.Message, key: message };
105
+ }
106
+ Messages.cannotExtractRange = createMessage("Cannot extract range.");
107
+ Messages.cannotExtractImport = createMessage("Cannot extract import statement.");
108
+ Messages.cannotExtractEmpty = createMessage("Cannot extract empty range.");
109
+ Messages.expressionExpected = createMessage("expression expected.");
110
+ Messages.uselessConstantType = createMessage("No reason to extract constant of type.");
111
+ Messages.statementOrExpressionExpected = createMessage("Statement or expression expected.");
112
+ Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements = createMessage("Cannot extract range containing conditional break or continue statements.");
113
+ Messages.cannotExtractRangeContainingConditionalReturnStatement = createMessage("Cannot extract range containing conditional return statement.");
114
+ Messages.typeWillNotBeVisibleInTheNewScope = createMessage("Type will not visible in the new scope.");
115
+ Messages.cannotExtractIdentifier = createMessage("Select more than a single identifier.");
116
+ Messages.cannotExtractExportedEntity = createMessage("Cannot extract exported declaration");
117
+ Messages.cannotWriteInExpression = createMessage("Cannot write back side-effects when extracting an expression");
118
+ Messages.cannotExtractAmbientBlock = createMessage("Cannot extract code from ambient contexts");
119
+ Messages.cannotAccessVariablesFromNestedScopes = createMessage("Cannot access variables from nested scopes");
120
+ Messages.cannotExtractToOtherFunctionLike = createMessage("Cannot extract method to a function-like scope that is not a function");
121
+ Messages.cannotExtractToExpressionArrowFunction = createMessage("Cannot extract constant to an arrow function without a block");
122
+ })(Messages || (Messages = {}));
123
+ // Na tag, também o generator, o uso do `this` e a região estática de uma classe (CK-02).
124
+ var RangeFacts;
125
+ (function (RangeFacts) {
126
+ RangeFacts[RangeFacts["None"] = 0] = "None";
127
+ RangeFacts[RangeFacts["HasReturn"] = 1] = "HasReturn";
128
+ RangeFacts[RangeFacts["IsAsyncFunction"] = 4] = "IsAsyncFunction";
129
+ })(RangeFacts || (RangeFacts = {}));
130
+ /**
131
+ * getRangeToExtract takes a span inside a text file and returns either an expression or an array
132
+ * of statements representing the minimum set of nodes needed to extract the entire span. This
133
+ * process may fail, in which case a set of errors is returned instead (these are currently
134
+ * not shown to the user, but can be used by us diagnostically)
135
+ */
136
+ // exported only for tests
137
+ export function getRangeToExtract(sourceFile, span) {
138
+ const { length } = span;
139
+ if (length === 0) {
140
+ return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractEmpty)] };
141
+ }
142
+ // Walk up starting from the the start position until we find a non-SourceFile node that subsumes the selected span.
143
+ // This may fail (e.g. you select two statements in the root of a source file)
144
+ const start = getParentNodeInSpan(getTokenAtPosition(sourceFile, span.start), sourceFile, span);
145
+ // Do the same for the ending position
146
+ const end = getParentNodeInSpan(findTokenOnLeftOfPosition(sourceFile, textSpanEnd(span)), sourceFile, span);
147
+ const declarations = [];
148
+ // We'll modify these flags as we walk the tree to collect data
149
+ // about what things need to be done as part of the extraction.
150
+ let rangeFacts = RangeFacts.None;
151
+ if (!start || !end) {
152
+ // cannot find either start or end node
153
+ return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] };
154
+ }
155
+ if (start.parent !== end.parent) {
156
+ // start and end nodes belong to different subtrees
157
+ return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] };
158
+ }
159
+ if (start !== end) {
160
+ // start and end should be statements and parent should be either block or a source file
161
+ if (!isBlockLike(start.parent)) {
162
+ return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] };
163
+ }
164
+ const statements = [];
165
+ const start2 = start; // TODO: GH#18217 Need to alias `start` to get this to compile. See https://github.com/Microsoft/TypeScript/issues/19955#issuecomment-344118248
166
+ for (const statement of start2.parent.statements) {
167
+ if (statement === start || statements.length) {
168
+ const errors = checkNode(statement);
169
+ if (errors) {
170
+ return { errors };
171
+ }
172
+ statements.push(statement);
173
+ }
174
+ if (statement === end) {
175
+ break;
176
+ }
177
+ }
178
+ if (!statements.length) {
179
+ // https://github.com/Microsoft/TypeScript/issues/20559
180
+ // Ranges like [|case 1: break;|] will fail to populate `statements` because
181
+ // they will never find `start` in `start.parent.statements`.
182
+ // Consider: We could support ranges like [|case 1:|] by refining them to just
183
+ // the expression.
184
+ return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] };
185
+ }
186
+ return { targetRange: { range: statements, facts: rangeFacts, declarations } };
187
+ }
188
+ // Na tag, a seleção de um JSDoc dava o erro dele (CK-03).
189
+ if (isReturnStatement(start) && !start.expression) {
190
+ // Makes no sense to extract an expression-less return statement.
191
+ return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] };
192
+ }
193
+ // We have a single node (start)
194
+ const node = refineNode(start);
195
+ const errors = checkRootNode(node) || checkNode(node);
196
+ if (errors) {
197
+ return { errors };
198
+ }
199
+ return { targetRange: { range: getStatementOrExpressionRange(node), facts: rangeFacts, declarations } }; // TODO: GH#18217
200
+ /**
201
+ * Attempt to refine the extraction node (generally, by shrinking it) to produce better results.
202
+ * @param node The unrefined extraction node.
203
+ */
204
+ function refineNode(node) {
205
+ if (isReturnStatement(node)) {
206
+ if (node.expression) {
207
+ return node.expression;
208
+ }
209
+ }
210
+ else if (isVariableStatement(node)) {
211
+ let numInitializers = 0;
212
+ let lastInitializer;
213
+ for (const declaration of node.declarationList.declarations) {
214
+ if (declaration.initializer) {
215
+ numInitializers++;
216
+ lastInitializer = declaration.initializer;
217
+ }
218
+ }
219
+ if (numInitializers === 1) {
220
+ return lastInitializer;
221
+ }
222
+ // No special handling if there are multiple initializers.
223
+ }
224
+ else if (isVariableDeclaration(node)) {
225
+ if (node.initializer) {
226
+ return node.initializer;
227
+ }
228
+ }
229
+ return node;
230
+ }
231
+ function checkRootNode(node) {
232
+ if (isIdentifier(isExpressionStatement(node) ? node.expression : node)) {
233
+ return [createDiagnosticForNode(node, Messages.cannotExtractIdentifier)];
234
+ }
235
+ return undefined;
236
+ }
237
+ // Na tag, o `checkForStaticContext` marcava a região estática de uma classe (CK-02).
238
+ // Verifies whether we can actually extract this node or not.
239
+ function checkNode(nodeToCheck) {
240
+ let PermittedJumps;
241
+ (function (PermittedJumps) {
242
+ PermittedJumps[PermittedJumps["None"] = 0] = "None";
243
+ PermittedJumps[PermittedJumps["Break"] = 1] = "Break";
244
+ PermittedJumps[PermittedJumps["Continue"] = 2] = "Continue";
245
+ PermittedJumps[PermittedJumps["Return"] = 4] = "Return";
246
+ })(PermittedJumps || (PermittedJumps = {}));
247
+ // We believe it's true because the node is from the (unmodified) tree.
248
+ Debug.assert(nodeToCheck.pos <= nodeToCheck.end, "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (1)");
249
+ // For understanding how skipTrivia functioned:
250
+ Debug.assert(!positionIsSynthesized(nodeToCheck.pos), "This failure could trigger https://github.com/Microsoft/TypeScript/issues/20809 (2)");
251
+ if (!isStatement(nodeToCheck) && !(isExpressionNode(nodeToCheck) && isExtractableExpression(nodeToCheck))) {
252
+ return [createDiagnosticForNode(nodeToCheck, Messages.statementOrExpressionExpected)];
253
+ }
254
+ if (nodeToCheck.flags & NodeFlags.Ambient) {
255
+ return [createDiagnosticForNode(nodeToCheck, Messages.cannotExtractAmbientBlock)];
256
+ }
257
+ let errors;
258
+ let permittedJumps = 4 /* PermittedJumps.Return */;
259
+ visit(nodeToCheck);
260
+ return errors;
261
+ function visit(node) {
262
+ if (errors) {
263
+ // already found an error - can stop now
264
+ return true;
265
+ }
266
+ if (isDeclaration(node)) {
267
+ const declaringNode = (node.kind === SyntaxKind.VariableDeclaration) ? node.parent.parent : node;
268
+ if (hasModifier(declaringNode, ModifierFlags.Export)) {
269
+ // TODO: GH#18217 Silly to use `errors ||` since it's definitely not defined (see top of `visit`)
270
+ // Also, if we're only pushing one error, just use `let error: Diagnostic | undefined`!
271
+ // Also TODO: GH#19956
272
+ (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractExportedEntity));
273
+ return true;
274
+ }
275
+ declarations.push(node.symbol);
276
+ }
277
+ // Some things can't be extracted in certain situations. Na tag, também o `super` (CK-02).
278
+ switch (node.kind) {
279
+ case SyntaxKind.ImportDeclaration:
280
+ (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractImport));
281
+ return true;
282
+ }
283
+ // Na tag, também a classe, e a `function` e a classe globais, que a extração tiraria do alcance (CK-02).
284
+ if (isFunctionLikeDeclaration(node)) {
285
+ // do not dive into functions
286
+ return false;
287
+ }
288
+ const savedPermittedJumps = permittedJumps;
289
+ switch (node.kind) {
290
+ case SyntaxKind.IfStatement:
291
+ permittedJumps = 0 /* PermittedJumps.None */;
292
+ break;
293
+ case SyntaxKind.TryStatement:
294
+ // forbid all jumps inside try blocks
295
+ permittedJumps = 0 /* PermittedJumps.None */;
296
+ break;
297
+ case SyntaxKind.Block:
298
+ if (node.parent && node.parent.kind === SyntaxKind.TryStatement && node.parent.finallyBlock === node) {
299
+ // allow unconditional returns from finally blocks
300
+ permittedJumps = 4 /* PermittedJumps.Return */;
301
+ }
302
+ break;
303
+ case SyntaxKind.DefaultClause:
304
+ case SyntaxKind.CaseClause:
305
+ // allow unlabeled break inside case clauses
306
+ permittedJumps |= 1 /* PermittedJumps.Break */;
307
+ break;
308
+ default:
309
+ if (isIterationStatement(node)) {
310
+ // allow unlabeled break/continue inside loops
311
+ permittedJumps |= 1 /* PermittedJumps.Break */ | 2 /* PermittedJumps.Continue */;
312
+ }
313
+ break;
314
+ }
315
+ // Na tag, também o `this` e o tipo `this`, o statement com label com o salto para ele, e o `yield` (CK-02).
316
+ switch (node.kind) {
317
+ case SyntaxKind.BreakStatement:
318
+ case SyntaxKind.ContinueStatement: {
319
+ if (!(permittedJumps & (node.kind === SyntaxKind.BreakStatement ? 1 /* PermittedJumps.Break */ : 2 /* PermittedJumps.Continue */))) {
320
+ // attempt to break or continue in a forbidden context
321
+ (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalBreakOrContinueStatements));
322
+ }
323
+ break;
324
+ }
325
+ case SyntaxKind.AwaitExpression:
326
+ rangeFacts |= RangeFacts.IsAsyncFunction;
327
+ break;
328
+ case SyntaxKind.ReturnStatement:
329
+ if (permittedJumps & 4 /* PermittedJumps.Return */) {
330
+ rangeFacts |= RangeFacts.HasReturn;
331
+ }
332
+ else {
333
+ (errors || (errors = [])).push(createDiagnosticForNode(node, Messages.cannotExtractRangeContainingConditionalReturnStatement));
334
+ }
335
+ break;
336
+ default:
337
+ forEachChild(node, visit);
338
+ break;
339
+ }
340
+ permittedJumps = savedPermittedJumps;
341
+ }
342
+ }
343
+ }
344
+ function getStatementOrExpressionRange(node) {
345
+ if (isStatement(node)) {
346
+ return [node];
347
+ }
348
+ else if (isExpressionNode(node)) {
349
+ // If our selection is the expression in an ExpressionStatement, expand
350
+ // the selection to include the enclosing Statement (this stops us
351
+ // from trying to care about the return value of the extracted function
352
+ // and eliminates double semicolon insertion in certain scenarios)
353
+ return isExpressionStatement(node.parent) ? [node.parent] : node;
354
+ }
355
+ return undefined;
356
+ }
357
+ function isScope(node) {
358
+ return isFunctionLikeDeclaration(node) || isSourceFile(node) || isModuleBlock(node);
359
+ }
360
+ /**
361
+ * Computes possible places we could extract the function into. For example,
362
+ * you may be able to extract into a class method *or* local closure *or* namespace function,
363
+ * depending on what's in the extracted body.
364
+ */
365
+ function collectEnclosingScopes(range) {
366
+ let current = isReadonlyArray(range.range) ? first(range.range) : range.range;
367
+ // Na tag, o trecho que usava o `this` numa classe só ia para um método dela (CK-02).
368
+ const scopes = [];
369
+ while (true) {
370
+ current = current.parent;
371
+ // A function parameter's initializer is actually in the outer scope, not the function declaration
372
+ if (current.kind === SyntaxKind.Parameter) {
373
+ // Skip all the way to the outer scope of the function that declared this parameter
374
+ current = findAncestor(current, parent => isFunctionLikeDeclaration(parent)).parent;
375
+ }
376
+ // We want to find the nearest parent where we can place an "equivalent" sibling to the node we're extracting out of.
377
+ // Walk up to the closest parent of a place where we can logically put a sibling:
378
+ // * Function declaration
379
+ // * Class declaration or expression
380
+ // * Module/namespace or source file
381
+ if (isScope(current)) {
382
+ scopes.push(current);
383
+ if (current.kind === SyntaxKind.SourceFile) {
384
+ return scopes;
385
+ }
386
+ }
387
+ }
388
+ }
389
+ function getFunctionExtractionAtIndex(targetRange, context, requestedChangesIndex) {
390
+ const { scopes, readsAndWrites: { target, usagesPerScope, functionErrorsPerScope, exposedVariableDeclarations } } = getPossibleExtractionsWorker(targetRange, context);
391
+ Debug.assert(!functionErrorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?");
392
+ context.cancellationToken.throwIfCancellationRequested(); // TODO: GH#18217
393
+ return extractFunctionInScope(target, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], exposedVariableDeclarations, targetRange, context);
394
+ }
395
+ function getConstantExtractionAtIndex(targetRange, context, requestedChangesIndex) {
396
+ const { scopes, readsAndWrites: { target, usagesPerScope, constantErrorsPerScope, exposedVariableDeclarations } } = getPossibleExtractionsWorker(targetRange, context);
397
+ Debug.assert(!constantErrorsPerScope[requestedChangesIndex].length, "The extraction went missing? How?");
398
+ Debug.assert(exposedVariableDeclarations.length === 0, "Extract constant accepted a range containing a variable declaration?");
399
+ context.cancellationToken.throwIfCancellationRequested();
400
+ const expression = isExpression(target)
401
+ ? target
402
+ : target.statements[0].expression;
403
+ return extractConstantInScope(expression, scopes[requestedChangesIndex], usagesPerScope[requestedChangesIndex], context);
404
+ }
405
+ /**
406
+ * Given a piece of text to extract ('targetRange'), computes a list of possible extractions.
407
+ * Each returned ExtractResultForScope corresponds to a possible target scope and is either a set of changes
408
+ * or an error explaining why we can't extract into that scope.
409
+ */
410
+ function getPossibleExtractions(targetRange, context) {
411
+ const { scopes, readsAndWrites: { functionErrorsPerScope, constantErrorsPerScope } } = getPossibleExtractionsWorker(targetRange, context);
412
+ // Need the inner type annotation to avoid https://github.com/Microsoft/TypeScript/issues/7547
413
+ const extractions = scopes.map((scope, i) => {
414
+ const functionDescriptionPart = getDescriptionForFunctionInScope(scope);
415
+ const constantDescriptionPart = getDescriptionForConstantInScope(scope);
416
+ const scopeDescription = isFunctionLikeDeclaration(scope)
417
+ ? getDescriptionForFunctionLikeDeclaration(scope)
418
+ : getDescriptionForModuleLikeDeclaration(scope);
419
+ let functionDescription;
420
+ let constantDescription;
421
+ if (scopeDescription === 1 /* SpecialScope.Global */) {
422
+ functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [functionDescriptionPart, "global"]);
423
+ constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [constantDescriptionPart, "global"]);
424
+ }
425
+ else if (scopeDescription === 0 /* SpecialScope.Module */) {
426
+ functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [functionDescriptionPart, "module"]);
427
+ constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1_scope), [constantDescriptionPart, "module"]);
428
+ }
429
+ else {
430
+ functionDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [functionDescriptionPart, scopeDescription]);
431
+ constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_1), [constantDescriptionPart, scopeDescription]);
432
+ }
433
+ // Customize the phrasing for the innermost scope to increase clarity.
434
+ if (i === 0) {
435
+ constantDescription = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Extract_to_0_in_enclosing_scope), [constantDescriptionPart]);
436
+ }
437
+ return {
438
+ functionExtraction: {
439
+ description: functionDescription,
440
+ errors: functionErrorsPerScope[i],
441
+ },
442
+ constantExtraction: {
443
+ description: constantDescription,
444
+ errors: constantErrorsPerScope[i],
445
+ },
446
+ };
447
+ });
448
+ return extractions;
449
+ }
450
+ function getPossibleExtractionsWorker(targetRange, context) {
451
+ const { file: sourceFile } = context;
452
+ const scopes = collectEnclosingScopes(targetRange);
453
+ const enclosingTextRange = getEnclosingTextRange(targetRange, sourceFile);
454
+ const readsAndWrites = collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, context.program.getTypeChecker(), context.cancellationToken);
455
+ return { scopes, readsAndWrites };
456
+ }
457
+ // Na tag, o método e o campo `readonly` de uma classe (CK-02).
458
+ function getDescriptionForFunctionInScope(scope) {
459
+ return isFunctionLikeDeclaration(scope)
460
+ ? "inner function"
461
+ : "function";
462
+ }
463
+ function getDescriptionForConstantInScope(_scope) {
464
+ return "constant";
465
+ }
466
+ // Na tag, também o construtor, a `function` e a function expression, o método e os acessores, e a classe (CK-02).
467
+ function getDescriptionForFunctionLikeDeclaration(_scope) {
468
+ return "arrow function";
469
+ }
470
+ function getDescriptionForModuleLikeDeclaration(scope) {
471
+ return scope.kind === SyntaxKind.ModuleBlock
472
+ ? `namespace '${scope.parent.name.getText()}'`
473
+ : scope.externalModuleIndicator ? 0 /* SpecialScope.Module */ : 1 /* SpecialScope.Global */;
474
+ }
475
+ var SpecialScope;
476
+ (function (SpecialScope) {
477
+ SpecialScope[SpecialScope["Module"] = 0] = "Module";
478
+ SpecialScope[SpecialScope["Global"] = 1] = "Global";
479
+ })(SpecialScope || (SpecialScope = {}));
480
+ /**
481
+ * Result of 'extractRange' operation for a specific scope.
482
+ * Stores either a list of changes that should be applied to extract a range or a list of errors
483
+ */
484
+ function extractFunctionInScope(node, scope, { usages: usagesInScope, typeParameterUsages, substitutions }, exposedVariableDeclarations, range, context) {
485
+ const checker = context.program.getTypeChecker();
486
+ // O alvo da configuração fixa (CK-24).
487
+ const scriptTarget = ScriptTarget.ES2020;
488
+ const importAdder = codefix.createImportAdder(context.file, context.program, context.preferences, context.host);
489
+ // Make a unique name for the extracted function. Na tag, o nome era outro para um método (CK-02).
490
+ const file = scope.getSourceFile();
491
+ const functionNameText = getUniqueName("newFunction", file);
492
+ const functionName = createIdentifier(functionNameText);
493
+ let returnType;
494
+ const parameters = [];
495
+ const callArguments = [];
496
+ let writes;
497
+ // Na tag, o arquivo JavaScript não anotava os tipos (CK-03).
498
+ usagesInScope.forEach((usage, name) => {
499
+ let type = checker.getTypeOfSymbolAtLocation(usage.symbol, usage.node);
500
+ // Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {"
501
+ type = checker.getBaseTypeOfLiteralType(type);
502
+ const typeNode = codefix.typeToAutoImportableTypeNode(checker, importAdder, type, scope, scriptTarget, NodeBuilderFlags.NoTruncation);
503
+ const paramDecl = createParameter(
504
+ /*modifiers*/ undefined,
505
+ /*dotDotDotToken*/ undefined,
506
+ /*name*/ name,
507
+ /*questionToken*/ undefined, typeNode);
508
+ parameters.push(paramDecl);
509
+ if (usage.usage === 2 /* Usage.Write */) {
510
+ (writes || (writes = [])).push(usage);
511
+ }
512
+ callArguments.push(createIdentifier(name));
513
+ });
514
+ const typeParametersAndDeclarations = arrayFrom(typeParameterUsages.values()).map(type => ({ type, declaration: getFirstDeclaration(type) }));
515
+ const sortedTypeParametersAndDeclarations = typeParametersAndDeclarations.sort(compareTypesByDeclarationOrder);
516
+ const typeParameters = sortedTypeParametersAndDeclarations.length === 0
517
+ ? undefined
518
+ : sortedTypeParametersAndDeclarations.map(t => t.declaration);
519
+ // Strictly speaking, we should check whether each name actually binds to the appropriate type
520
+ // parameter. In cases of shadowing, they may not.
521
+ const callTypeArguments = typeParameters !== undefined
522
+ ? typeParameters.map(decl => createTypeReferenceNode(decl.name, /*typeArguments*/ undefined))
523
+ : undefined;
524
+ // Provide explicit return types for contextually-typed functions
525
+ // to avoid problems when there are literal types present
526
+ if (isExpression(node)) {
527
+ const contextualType = checker.getContextualType(node);
528
+ returnType = checker.typeToTypeNode(contextualType, scope, NodeBuilderFlags.NoTruncation);
529
+ }
530
+ const { body, returnValueProperty } = transformFunctionBody(node, exposedVariableDeclarations, writes, substitutions, !!(range.facts & RangeFacts.HasReturn));
531
+ suppressLeadingAndTrailingTrivia(body);
532
+ // A função da Linguagem é um `const` com uma arrow (CK-69). Na tag, uma `function` declarada, ou, numa classe, um
533
+ // método privado, estático na região estática (CK-02); e a estrela do generator (CK-02).
534
+ const newFunction = createVariableStatement(
535
+ /*modifiers*/ undefined, createVariableDeclarationList([createVariableDeclaration(functionName,
536
+ /*type*/ undefined, createArrowFunction(range.facts & RangeFacts.IsAsyncFunction ? [createToken(SyntaxKind.AsyncKeyword)] : undefined, typeParameters, parameters, returnType,
537
+ /*equalsGreaterThanToken*/ undefined, body))], NodeFlags.Const));
538
+ // O `const` não é içado como a `function`: ele entra antes do statement que o usa, onde a extração para uma constante
539
+ // o põe, e não depois do trecho, no fim do escopo, como a `function` da tag (CK-69).
540
+ const changeTracker = textChanges.ChangeTracker.fromContext(context);
541
+ const nodeToInsertBefore = getNodeToInsertConstantBefore(isReadonlyArray(range.range) ? first(range.range) : range.range, scope);
542
+ if (nodeToInsertBefore.pos === 0) {
543
+ changeTracker.insertNodeAtTopOfFile(context.file, newFunction, /*blankLineBetween*/ true);
544
+ }
545
+ else {
546
+ changeTracker.insertNodeBefore(context.file, nodeToInsertBefore, newFunction, /*blankLineBetween*/ true);
547
+ }
548
+ importAdder.writeFixes(changeTracker);
549
+ const newNodes = [];
550
+ // replace range with function call. Na tag, o método de uma classe se chamava pelo `this` ou pelo nome dela (CK-02).
551
+ const called = createIdentifier(functionNameText);
552
+ let call = createCall(called, callTypeArguments, // Note that no attempt is made to take advantage of type argument inference
553
+ callArguments);
554
+ if (range.facts & RangeFacts.IsAsyncFunction) {
555
+ call = createAwait(call);
556
+ }
557
+ if (exposedVariableDeclarations.length && !writes) {
558
+ // No need to mix declarations and writes.
559
+ // How could any variables be exposed if there's a return statement?
560
+ Debug.assert(!returnValueProperty, "Expected no returnValueProperty");
561
+ Debug.assert(!(range.facts & RangeFacts.HasReturn), "Expected RangeFacts.HasReturn flag to be unset");
562
+ if (exposedVariableDeclarations.length === 1) {
563
+ // Declaring exactly one variable: let x = newFunction();
564
+ const variableDeclaration = exposedVariableDeclarations[0];
565
+ newNodes.push(createVariableStatement(
566
+ /*modifiers*/ undefined, createVariableDeclarationList([createVariableDeclaration(getSynthesizedDeepClone(variableDeclaration.name), /*type*/ getSynthesizedDeepClone(variableDeclaration.type), /*initializer*/ call)], // TODO (acasey): test binding patterns
567
+ variableDeclaration.parent.flags)));
568
+ }
569
+ else {
570
+ // Declaring multiple variables / return properties:
571
+ // let {x, y} = newFunction();
572
+ const bindingElements = [];
573
+ const typeElements = [];
574
+ let commonNodeFlags = exposedVariableDeclarations[0].parent.flags;
575
+ let sawExplicitType = false;
576
+ for (const variableDeclaration of exposedVariableDeclarations) {
577
+ bindingElements.push(createBindingElement(
578
+ /*dotDotDotToken*/ undefined,
579
+ /*propertyName*/ undefined,
580
+ /*name*/ getSynthesizedDeepClone(variableDeclaration.name)));
581
+ // Being returned through an object literal will have widened the type.
582
+ const variableType = checker.typeToTypeNode(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(variableDeclaration)), scope, NodeBuilderFlags.NoTruncation);
583
+ typeElements.push(createPropertySignature(
584
+ /*modifiers*/ undefined,
585
+ /*name*/ variableDeclaration.symbol.name,
586
+ /*questionToken*/ undefined,
587
+ /*type*/ variableType,
588
+ /*initializer*/ undefined));
589
+ sawExplicitType = sawExplicitType || variableDeclaration.type !== undefined;
590
+ commonNodeFlags = commonNodeFlags & variableDeclaration.parent.flags;
591
+ }
592
+ const typeLiteral = sawExplicitType ? createTypeLiteralNode(typeElements) : undefined;
593
+ if (typeLiteral) {
594
+ setEmitFlags(typeLiteral, EmitFlags.SingleLine);
595
+ }
596
+ newNodes.push(createVariableStatement(
597
+ /*modifiers*/ undefined, createVariableDeclarationList([createVariableDeclaration(createObjectBindingPattern(bindingElements),
598
+ /*type*/ typeLiteral,
599
+ /*initializer*/ call)], commonNodeFlags)));
600
+ }
601
+ }
602
+ else if (exposedVariableDeclarations.length || writes) {
603
+ if (exposedVariableDeclarations.length) {
604
+ // CONSIDER: we're going to create one statement per variable, but we could actually preserve their original grouping.
605
+ for (const variableDeclaration of exposedVariableDeclarations) {
606
+ let flags = variableDeclaration.parent.flags;
607
+ if (flags & NodeFlags.Const) {
608
+ flags = (flags & ~NodeFlags.Const) | NodeFlags.Let;
609
+ }
610
+ newNodes.push(createVariableStatement(
611
+ /*modifiers*/ undefined, createVariableDeclarationList([createVariableDeclaration(variableDeclaration.symbol.name, getTypeDeepCloneUnionUndefined(variableDeclaration.type))], flags)));
612
+ }
613
+ }
614
+ if (returnValueProperty) {
615
+ // has both writes and return, need to create variable declaration to hold return value;
616
+ newNodes.push(createVariableStatement(
617
+ /*modifiers*/ undefined, createVariableDeclarationList([createVariableDeclaration(returnValueProperty, getTypeDeepCloneUnionUndefined(returnType))], NodeFlags.Let)));
618
+ }
619
+ const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes);
620
+ if (returnValueProperty) {
621
+ assignments.unshift(createShorthandPropertyAssignment(returnValueProperty));
622
+ }
623
+ // propagate writes back
624
+ if (assignments.length === 1) {
625
+ // We would only have introduced a return value property if there had been
626
+ // other assignments to make.
627
+ Debug.assert(!returnValueProperty, "Shouldn't have returnValueProperty here");
628
+ newNodes.push(createStatement(createAssignment(assignments[0].name, call)));
629
+ if (range.facts & RangeFacts.HasReturn) {
630
+ newNodes.push(createReturn());
631
+ }
632
+ }
633
+ else {
634
+ // emit e.g.
635
+ // { a, b, __return } = newFunction(a, b);
636
+ // return __return;
637
+ newNodes.push(createStatement(createAssignment(createObjectLiteral(assignments), call)));
638
+ if (returnValueProperty) {
639
+ newNodes.push(createReturn(createIdentifier(returnValueProperty)));
640
+ }
641
+ }
642
+ }
643
+ else {
644
+ if (range.facts & RangeFacts.HasReturn) {
645
+ newNodes.push(createReturn(call));
646
+ }
647
+ else if (isReadonlyArray(range.range)) {
648
+ newNodes.push(createStatement(call));
649
+ }
650
+ else {
651
+ newNodes.push(call);
652
+ }
653
+ }
654
+ if (isReadonlyArray(range.range)) {
655
+ changeTracker.replaceNodeRangeWithNodes(context.file, first(range.range), last(range.range), newNodes);
656
+ }
657
+ else {
658
+ changeTracker.replaceNodeWithNodes(context.file, range.range, newNodes);
659
+ }
660
+ const edits = changeTracker.getChanges();
661
+ const renameRange = isReadonlyArray(range.range) ? first(range.range) : range.range;
662
+ // A declaração vem antes do uso, como a da constante (CK-69): o rename começa na última ocorrência, que é a chamada.
663
+ const renameFilename = renameRange.getSourceFile().fileName;
664
+ const renameLocation = getRenameLocation(edits, renameFilename, functionNameText, /*isDeclaredBeforeUse*/ true);
665
+ return { renameFilename, renameLocation, edits };
666
+ function getTypeDeepCloneUnionUndefined(typeNode) {
667
+ if (typeNode === undefined) {
668
+ return undefined;
669
+ }
670
+ const clone = getSynthesizedDeepClone(typeNode);
671
+ let withoutParens = clone;
672
+ while (isParenthesizedTypeNode(withoutParens)) {
673
+ withoutParens = withoutParens.type;
674
+ }
675
+ return isUnionTypeNode(withoutParens) && find(withoutParens.types, t => t.kind === SyntaxKind.UndefinedKeyword)
676
+ ? clone
677
+ : createUnionTypeNode([clone, createKeywordTypeNode(SyntaxKind.UndefinedKeyword)]);
678
+ }
679
+ }
680
+ /**
681
+ * Result of 'extractRange' operation for a specific scope.
682
+ * Stores either a list of changes that should be applied to extract a range or a list of errors
683
+ */
684
+ function extractConstantInScope(node, scope, { substitutions }, context) {
685
+ const checker = context.program.getTypeChecker();
686
+ // Make a unique name for the extracted variable. Na tag, o nome era outro para uma propriedade de classe (CK-02).
687
+ const file = scope.getSourceFile();
688
+ const localNameText = getUniqueName("newLocal", file);
689
+ // Na tag, o arquivo JavaScript não anotava o tipo (CK-03).
690
+ let variableType = !checker.isContextSensitive(node)
691
+ ? undefined
692
+ : checker.typeToTypeNode(checker.getContextualType(node), scope, NodeBuilderFlags.NoTruncation);
693
+ let initializer = transformConstantInitializer(node, substitutions);
694
+ ({ variableType, initializer } = transformFunctionInitializerAndType(variableType, initializer));
695
+ suppressLeadingAndTrailingTrivia(initializer);
696
+ const changeTracker = textChanges.ChangeTracker.fromContext(context);
697
+ // Na tag, numa classe, a constante era uma propriedade `readonly` privada, estática na região estática (CK-02).
698
+ const newVariableDeclaration = createVariableDeclaration(localNameText, variableType, initializer);
699
+ // If the node is part of an initializer in a list of variable declarations, insert a new
700
+ // variable declaration into the list (in case it depends on earlier ones).
701
+ // CONSIDER: If the declaration list isn't const, we might want to split it into multiple
702
+ // lists so that the newly extracted one can be const.
703
+ const oldVariableDeclaration = getContainingVariableDeclarationIfInList(node, scope);
704
+ if (oldVariableDeclaration) {
705
+ // Declare
706
+ // CONSIDER: could detect that each is on a separate line (See `extractConstant_VariableList_MultipleLines` in `extractConstants.ts`)
707
+ changeTracker.insertNodeBefore(context.file, oldVariableDeclaration, newVariableDeclaration);
708
+ // Consume
709
+ const localReference = createIdentifier(localNameText);
710
+ changeTracker.replaceNode(context.file, node, localReference);
711
+ }
712
+ else if (node.parent.kind === SyntaxKind.ExpressionStatement && scope === findAncestor(node, isScope)) {
713
+ // If the parent is an expression statement and the target scope is the immediately enclosing one,
714
+ // replace the statement with the declaration.
715
+ const newVariableStatement = createVariableStatement(
716
+ /*modifiers*/ undefined, createVariableDeclarationList([newVariableDeclaration], NodeFlags.Const));
717
+ changeTracker.replaceNode(context.file, node.parent, newVariableStatement);
718
+ }
719
+ else {
720
+ const newVariableStatement = createVariableStatement(
721
+ /*modifiers*/ undefined, createVariableDeclarationList([newVariableDeclaration], NodeFlags.Const));
722
+ // Declare
723
+ const nodeToInsertBefore = getNodeToInsertConstantBefore(node, scope);
724
+ if (nodeToInsertBefore.pos === 0) {
725
+ changeTracker.insertNodeAtTopOfFile(context.file, newVariableStatement, /*blankLineBetween*/ false);
726
+ }
727
+ else {
728
+ changeTracker.insertNodeBefore(context.file, nodeToInsertBefore, newVariableStatement, /*blankLineBetween*/ false);
729
+ }
730
+ // Consume
731
+ if (node.parent.kind === SyntaxKind.ExpressionStatement) {
732
+ // If the parent is an expression statement, delete it.
733
+ changeTracker.delete(context.file, node.parent);
734
+ }
735
+ else {
736
+ const localReference = createIdentifier(localNameText);
737
+ changeTracker.replaceNode(context.file, node, localReference);
738
+ }
739
+ }
740
+ const edits = changeTracker.getChanges();
741
+ const renameFilename = node.getSourceFile().fileName;
742
+ const renameLocation = getRenameLocation(edits, renameFilename, localNameText, /*isDeclaredBeforeUse*/ true);
743
+ return { renameFilename, renameLocation, edits };
744
+ function transformFunctionInitializerAndType(variableType, initializer) {
745
+ // If no contextual type exists there is nothing to transfer to the function signature
746
+ if (variableType === undefined)
747
+ return { variableType, initializer };
748
+ // Only do this for arrow functions that are not generic. Na tag, também a function expression (CK-02).
749
+ if (!isArrowFunction(initializer) || !!initializer.typeParameters)
750
+ return { variableType, initializer };
751
+ const functionType = checker.getTypeAtLocation(node);
752
+ const functionSignature = singleOrUndefined(checker.getSignaturesOfType(functionType));
753
+ // If no function signature, maybe there was an error, do nothing
754
+ if (!functionSignature)
755
+ return { variableType, initializer };
756
+ // If the function signature has generic type parameters we don't attempt to move the parameters
757
+ if (!!functionSignature.getTypeParameters())
758
+ return { variableType, initializer };
759
+ // We add parameter types if needed
760
+ const parameters = [];
761
+ let hasAny = false;
762
+ for (const p of initializer.parameters) {
763
+ if (p.type) {
764
+ parameters.push(p);
765
+ }
766
+ else {
767
+ const paramType = checker.getTypeAtLocation(p);
768
+ if (paramType === checker.getAnyType())
769
+ hasAny = true;
770
+ parameters.push(updateParameter(p, p.modifiers, p.dotDotDotToken, p.name, p.questionToken, p.type || checker.typeToTypeNode(paramType, scope, NodeBuilderFlags.NoTruncation), p.initializer));
771
+ }
772
+ }
773
+ // If a parameter was inferred as any we skip adding function parameters at all.
774
+ // Turning an implicit any (which under common settings is a error) to an explicit
775
+ // is probably actually a worse refactor outcome.
776
+ if (hasAny)
777
+ return { variableType, initializer };
778
+ variableType = undefined;
779
+ // Na tag, a function expression ganhava também o parâmetro `this` da assinatura (CK-02).
780
+ initializer = updateArrowFunction(initializer, node.modifiers, initializer.typeParameters, parameters, initializer.type || checker.typeToTypeNode(functionSignature.getReturnType(), scope, NodeBuilderFlags.NoTruncation), initializer.equalsGreaterThanToken, initializer.body);
781
+ return { variableType, initializer };
782
+ }
783
+ }
784
+ function getContainingVariableDeclarationIfInList(node, scope) {
785
+ let prevNode;
786
+ while (node !== undefined && node !== scope) {
787
+ if (isVariableDeclaration(node) &&
788
+ node.initializer === prevNode &&
789
+ isVariableDeclarationList(node.parent) &&
790
+ node.parent.declarations.length > 1) {
791
+ return node;
792
+ }
793
+ prevNode = node;
794
+ node = node.parent;
795
+ }
796
+ }
797
+ function getFirstDeclaration(type) {
798
+ let firstDeclaration;
799
+ const symbol = type.symbol;
800
+ if (symbol && symbol.declarations) {
801
+ for (const declaration of symbol.declarations) {
802
+ if (firstDeclaration === undefined || declaration.pos < firstDeclaration.pos) {
803
+ firstDeclaration = declaration;
804
+ }
805
+ }
806
+ }
807
+ return firstDeclaration;
808
+ }
809
+ function compareTypesByDeclarationOrder({ type: type1, declaration: declaration1 }, { type: type2, declaration: declaration2 }) {
810
+ return compareProperties(declaration1, declaration2, "pos", compareValues)
811
+ || compareStringsCaseSensitive(type1.symbol ? type1.symbol.getName() : "", type2.symbol ? type2.symbol.getName() : "")
812
+ || compareValues(type1.id, type2.id);
813
+ }
814
+ function transformFunctionBody(body, exposedVariableDeclarations, writes, substitutions, hasReturn) {
815
+ const hasWritesOrVariableDeclarations = writes !== undefined || exposedVariableDeclarations.length > 0;
816
+ if (isBlock(body) && !hasWritesOrVariableDeclarations && substitutions.size === 0) {
817
+ // already block, no declarations or writes to propagate back, no substitutions - can use node as is
818
+ return { body: createBlock(body.statements, /*multLine*/ true), returnValueProperty: undefined };
819
+ }
820
+ let returnValueProperty;
821
+ let ignoreReturns = false;
822
+ const statements = createNodeArray(isBlock(body) ? body.statements.slice(0) : [isStatement(body) ? body : createReturn(body)]);
823
+ // rewrite body if either there are writes that should be propagated back via return statements or there are substitutions
824
+ if (hasWritesOrVariableDeclarations || substitutions.size) {
825
+ const rewrittenStatements = visitNodes(statements, visitor).slice();
826
+ if (hasWritesOrVariableDeclarations && !hasReturn && isStatement(body)) {
827
+ // add return at the end to propagate writes back in case if control flow falls out of the function body
828
+ // it is ok to know that range has at least one return since it we only allow unconditional returns
829
+ const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes);
830
+ if (assignments.length === 1) {
831
+ rewrittenStatements.push(createReturn(assignments[0].name));
832
+ }
833
+ else {
834
+ rewrittenStatements.push(createReturn(createObjectLiteral(assignments)));
835
+ }
836
+ }
837
+ return { body: createBlock(rewrittenStatements, /*multiLine*/ true), returnValueProperty };
838
+ }
839
+ else {
840
+ return { body: createBlock(statements, /*multiLine*/ true), returnValueProperty: undefined };
841
+ }
842
+ function visitor(node) {
843
+ if (!ignoreReturns && node.kind === SyntaxKind.ReturnStatement && hasWritesOrVariableDeclarations) {
844
+ const assignments = getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes);
845
+ if (node.expression) {
846
+ if (!returnValueProperty) {
847
+ returnValueProperty = "__return";
848
+ }
849
+ assignments.unshift(createPropertyAssignment(returnValueProperty, visitNode(node.expression, visitor)));
850
+ }
851
+ if (assignments.length === 1) {
852
+ return createReturn(assignments[0].name);
853
+ }
854
+ else {
855
+ return createReturn(createObjectLiteral(assignments));
856
+ }
857
+ }
858
+ else {
859
+ const oldIgnoreReturns = ignoreReturns;
860
+ ignoreReturns = ignoreReturns || isFunctionLikeDeclaration(node);
861
+ const substitution = substitutions.get(getNodeId(node).toString());
862
+ const result = substitution ? getSynthesizedDeepClone(substitution) : visitEachChild(node, visitor, nullTransformationContext);
863
+ ignoreReturns = oldIgnoreReturns;
864
+ return result;
865
+ }
866
+ }
867
+ }
868
+ function transformConstantInitializer(initializer, substitutions) {
869
+ return substitutions.size
870
+ ? visitor(initializer)
871
+ : initializer;
872
+ function visitor(node) {
873
+ const substitution = substitutions.get(getNodeId(node).toString());
874
+ return substitution ? getSynthesizedDeepClone(substitution) : visitEachChild(node, visitor, nullTransformationContext);
875
+ }
876
+ }
877
+ // Na tag, também onde entrava a `function` extraída (o `getNodeToInsertFunctionBefore`, depois do trecho, antes da
878
+ // função seguinte do escopo, com o `getStatementsOrClassElements`), que agora entra como a constante (CK-69), e onde
879
+ // entrava a propriedade de uma classe (CK-02).
880
+ function getNodeToInsertConstantBefore(node, scope) {
881
+ let prevScope;
882
+ for (let curr = node; curr !== scope; curr = curr.parent) {
883
+ if (isScope(curr)) {
884
+ prevScope = curr;
885
+ }
886
+ }
887
+ for (let curr = (prevScope || node).parent;; curr = curr.parent) {
888
+ if (isBlockLike(curr)) {
889
+ let prevStatement;
890
+ for (const statement of curr.statements) {
891
+ if (statement.pos > node.pos) {
892
+ break;
893
+ }
894
+ prevStatement = statement;
895
+ }
896
+ if (!prevStatement && isCaseClause(curr)) {
897
+ // We must have been in the expression of the case clause.
898
+ Debug.assert(isSwitchStatement(curr.parent.parent), "Grandparent isn't a switch statement");
899
+ return curr.parent.parent;
900
+ }
901
+ // There must be at least one statement since we started in one.
902
+ return Debug.checkDefined(prevStatement, "prevStatement failed to get set");
903
+ }
904
+ Debug.assert(curr !== scope, "Didn't encounter a block-like before encountering scope");
905
+ }
906
+ }
907
+ function getPropertyAssignmentsForWritesAndVariableDeclarations(exposedVariableDeclarations, writes) {
908
+ const variableAssignments = map(exposedVariableDeclarations, v => createShorthandPropertyAssignment(v.symbol.name));
909
+ const writeAssignments = map(writes, w => createShorthandPropertyAssignment(w.symbol.name));
910
+ // TODO: GH#18217 `variableAssignments` not possibly undefined!
911
+ return variableAssignments === undefined
912
+ ? writeAssignments
913
+ : writeAssignments === undefined
914
+ ? variableAssignments
915
+ : variableAssignments.concat(writeAssignments);
916
+ }
917
+ function isReadonlyArray(v) {
918
+ return isArray(v);
919
+ }
920
+ /**
921
+ * Produces a range that spans the entirety of nodes, given a selection
922
+ * that might start/end in the middle of nodes.
923
+ *
924
+ * For example, when the user makes a selection like this
925
+ * v---v
926
+ * var someThing = foo + bar;
927
+ * this returns ^-------^
928
+ */
929
+ function getEnclosingTextRange(targetRange, sourceFile) {
930
+ return isReadonlyArray(targetRange.range)
931
+ ? { pos: first(targetRange.range).getStart(sourceFile), end: last(targetRange.range).getEnd() }
932
+ : targetRange.range;
933
+ }
934
+ var Usage;
935
+ (function (Usage) {
936
+ // value should be passed to extracted method
937
+ Usage[Usage["Read"] = 1] = "Read";
938
+ // value should be passed to extracted method and propagated back
939
+ Usage[Usage["Write"] = 2] = "Write";
940
+ })(Usage || (Usage = {}));
941
+ function collectReadsAndWrites(targetRange, scopes, enclosingTextRange, sourceFile, checker, cancellationToken) {
942
+ const allTypeParameterUsages = createMap(); // Key is type ID
943
+ const usagesPerScope = [];
944
+ const substitutionsPerScope = [];
945
+ const functionErrorsPerScope = [];
946
+ const constantErrorsPerScope = [];
947
+ const visibleDeclarationsInExtractedRange = [];
948
+ const exposedVariableSymbolSet = createMap(); // Key is symbol ID
949
+ const exposedVariableDeclarations = [];
950
+ let firstExposedNonVariableDeclaration;
951
+ const expression = !isReadonlyArray(targetRange.range)
952
+ ? targetRange.range
953
+ : targetRange.range.length === 1 && isExpressionStatement(targetRange.range[0])
954
+ ? targetRange.range[0].expression
955
+ : undefined;
956
+ let expressionDiagnostic;
957
+ if (expression === undefined) {
958
+ const statements = targetRange.range;
959
+ const start = first(statements).getStart();
960
+ const end = last(statements).end;
961
+ expressionDiagnostic = createFileDiagnostic(sourceFile, start, end - start, Messages.expressionExpected);
962
+ }
963
+ else if (checker.getTypeAtLocation(expression).flags & (TypeFlags.Void | TypeFlags.Never)) {
964
+ expressionDiagnostic = createDiagnosticForNode(expression, Messages.uselessConstantType);
965
+ }
966
+ // initialize results
967
+ for (const scope of scopes) {
968
+ usagesPerScope.push({ usages: createMap(), typeParameterUsages: createMap(), substitutions: createMap() });
969
+ substitutionsPerScope.push(createMap());
970
+ // Na tag, a função se extraía para dentro de uma `function` declarada, e não de outra função; a arrow é a função
971
+ // que fica, e a extração para dentro dela continua recusada (CK-02).
972
+ functionErrorsPerScope.push(isFunctionLikeDeclaration(scope)
973
+ ? [createDiagnosticForNode(scope, Messages.cannotExtractToOtherFunctionLike)]
974
+ : []);
975
+ // Na tag, também a classe de um arquivo JavaScript (CK-02, CK-03).
976
+ const constantErrors = [];
977
+ if (expressionDiagnostic) {
978
+ constantErrors.push(expressionDiagnostic);
979
+ }
980
+ if (isArrowFunction(scope) && !isBlock(scope.body)) {
981
+ constantErrors.push(createDiagnosticForNode(scope, Messages.cannotExtractToExpressionArrowFunction));
982
+ }
983
+ constantErrorsPerScope.push(constantErrors);
984
+ }
985
+ const seenUsages = createMap();
986
+ const target = isReadonlyArray(targetRange.range) ? createBlock(targetRange.range) : targetRange.range;
987
+ const unmodifiedNode = isReadonlyArray(targetRange.range) ? first(targetRange.range) : targetRange.range;
988
+ const inGenericContext = isInGenericContext(unmodifiedNode);
989
+ collectUsages(target);
990
+ // Unfortunately, this code takes advantage of the knowledge that the generated method
991
+ // will use the contextual type of an expression as the return type of the extracted
992
+ // method (and will therefore "use" all the types involved).
993
+ if (inGenericContext && !isReadonlyArray(targetRange.range)) {
994
+ const contextualType = checker.getContextualType(targetRange.range); // TODO: GH#18217
995
+ recordTypeParameterUsages(contextualType);
996
+ }
997
+ if (allTypeParameterUsages.size > 0) {
998
+ const seenTypeParameterUsages = createMap(); // Key is type ID
999
+ let i = 0;
1000
+ for (let curr = unmodifiedNode; curr !== undefined && i < scopes.length; curr = curr.parent) {
1001
+ if (curr === scopes[i]) {
1002
+ // Copy current contents of seenTypeParameterUsages into scope.
1003
+ seenTypeParameterUsages.forEach((typeParameter, id) => {
1004
+ usagesPerScope[i].typeParameterUsages.set(id, typeParameter);
1005
+ });
1006
+ i++;
1007
+ }
1008
+ // Note that we add the current node's type parameters *after* updating the corresponding scope.
1009
+ if (isDeclarationWithTypeParameters(curr)) {
1010
+ for (const typeParameterDecl of getEffectiveTypeParameterDeclarations(curr)) {
1011
+ const typeParameter = checker.getTypeAtLocation(typeParameterDecl);
1012
+ if (allTypeParameterUsages.has(typeParameter.id.toString())) {
1013
+ seenTypeParameterUsages.set(typeParameter.id.toString(), typeParameter);
1014
+ }
1015
+ }
1016
+ }
1017
+ }
1018
+ // If we didn't get through all the scopes, then there were some that weren't in our
1019
+ // parent chain (impossible at time of writing). A conservative solution would be to
1020
+ // copy allTypeParameterUsages into all remaining scopes.
1021
+ Debug.assert(i === scopes.length, "Should have iterated all scopes");
1022
+ }
1023
+ // If there are any declarations in the extracted block that are used in the same enclosing
1024
+ // lexical scope, we can't move the extraction "up" as those declarations will become unreachable
1025
+ if (visibleDeclarationsInExtractedRange.length) {
1026
+ const containingLexicalScopeOfExtraction = isBlockScope(scopes[0], scopes[0].parent)
1027
+ ? scopes[0]
1028
+ : getEnclosingBlockScopeContainer(scopes[0]);
1029
+ forEachChild(containingLexicalScopeOfExtraction, checkForUsedDeclarations);
1030
+ }
1031
+ for (let i = 0; i < scopes.length; i++) {
1032
+ const scopeUsages = usagesPerScope[i];
1033
+ // Special case: in the innermost scope, all usages are available.
1034
+ // (The computed value reflects the value at the top-level of the scope, but the
1035
+ // local will actually be declared at the same level as the extracted expression).
1036
+ if (i > 0 && (scopeUsages.usages.size > 0 || scopeUsages.typeParameterUsages.size > 0)) {
1037
+ const errorNode = isReadonlyArray(targetRange.range) ? targetRange.range[0] : targetRange.range;
1038
+ constantErrorsPerScope[i].push(createDiagnosticForNode(errorNode, Messages.cannotAccessVariablesFromNestedScopes));
1039
+ }
1040
+ // Na tag, também a escrita numa propriedade `readonly` de uma classe, que só o construtor inicializa (CK-02).
1041
+ let hasWrite = false;
1042
+ usagesPerScope[i].usages.forEach(value => {
1043
+ if (value.usage === 2 /* Usage.Write */) {
1044
+ hasWrite = true;
1045
+ }
1046
+ });
1047
+ // If an expression was extracted, then there shouldn't have been any variable declarations.
1048
+ Debug.assert(isReadonlyArray(targetRange.range) || exposedVariableDeclarations.length === 0, "No variable declarations expected if something was extracted");
1049
+ if (hasWrite && !isReadonlyArray(targetRange.range)) {
1050
+ const diag = createDiagnosticForNode(targetRange.range, Messages.cannotWriteInExpression);
1051
+ functionErrorsPerScope[i].push(diag);
1052
+ constantErrorsPerScope[i].push(diag);
1053
+ }
1054
+ else if (firstExposedNonVariableDeclaration) {
1055
+ const diag = createDiagnosticForNode(firstExposedNonVariableDeclaration, Messages.cannotExtractExportedEntity);
1056
+ functionErrorsPerScope[i].push(diag);
1057
+ constantErrorsPerScope[i].push(diag);
1058
+ }
1059
+ }
1060
+ return { target, usagesPerScope, functionErrorsPerScope, constantErrorsPerScope, exposedVariableDeclarations };
1061
+ function isInGenericContext(node) {
1062
+ return !!findAncestor(node, n => isDeclarationWithTypeParameters(n) && getEffectiveTypeParameterDeclarations(n).length !== 0);
1063
+ }
1064
+ function recordTypeParameterUsages(type) {
1065
+ // PERF: This is potentially very expensive. `type` could be a library type with
1066
+ // a lot of properties, each of which the walker will visit. Unfortunately, the
1067
+ // solution isn't as trivial as filtering to user types because of (e.g.) Array.
1068
+ const symbolWalker = checker.getSymbolWalker(() => (cancellationToken.throwIfCancellationRequested(), true));
1069
+ const { visitedTypes } = symbolWalker.walkType(type);
1070
+ for (const visitedType of visitedTypes) {
1071
+ if (visitedType.isTypeParameter()) {
1072
+ allTypeParameterUsages.set(visitedType.id.toString(), visitedType);
1073
+ }
1074
+ }
1075
+ }
1076
+ function collectUsages(node, valueUsage = 1 /* Usage.Read */) {
1077
+ if (inGenericContext) {
1078
+ const type = checker.getTypeAtLocation(node);
1079
+ recordTypeParameterUsages(type);
1080
+ }
1081
+ if (isDeclaration(node) && node.symbol) {
1082
+ visibleDeclarationsInExtractedRange.push(node);
1083
+ }
1084
+ if (isAssignmentExpression(node)) {
1085
+ // use 'write' as default usage for values
1086
+ collectUsages(node.left, 2 /* Usage.Write */);
1087
+ collectUsages(node.right);
1088
+ }
1089
+ else if (isUnaryExpressionWithWrite(node)) {
1090
+ collectUsages(node.operand, 2 /* Usage.Write */);
1091
+ }
1092
+ else if (isPropertyAccessExpression(node) || isElementAccessExpression(node)) {
1093
+ // use 'write' as default usage for values
1094
+ forEachChild(node, collectUsages);
1095
+ }
1096
+ else if (isIdentifier(node)) {
1097
+ if (!node.parent) {
1098
+ return;
1099
+ }
1100
+ if (isQualifiedName(node.parent) && node !== node.parent.left) {
1101
+ return;
1102
+ }
1103
+ if (isPropertyAccessExpression(node.parent) && node !== node.parent.expression) {
1104
+ return;
1105
+ }
1106
+ recordUsage(node, valueUsage, /*isTypeNode*/ isPartOfTypeNode(node));
1107
+ }
1108
+ else {
1109
+ forEachChild(node, collectUsages);
1110
+ }
1111
+ }
1112
+ function recordUsage(n, usage, isTypeNode) {
1113
+ const symbolId = recordUsagebySymbol(n, usage, isTypeNode);
1114
+ if (symbolId) {
1115
+ for (let i = 0; i < scopes.length; i++) {
1116
+ // push substitution from map<symbolId, subst> to map<nodeId, subst> to simplify rewriting
1117
+ const substitution = substitutionsPerScope[i].get(symbolId);
1118
+ if (substitution) {
1119
+ usagesPerScope[i].substitutions.set(getNodeId(n).toString(), substitution);
1120
+ }
1121
+ }
1122
+ }
1123
+ }
1124
+ function recordUsagebySymbol(identifier, usage, isTypeName) {
1125
+ const symbol = getSymbolReferencedByIdentifier(identifier);
1126
+ if (!symbol) {
1127
+ // cannot find symbol - do nothing
1128
+ return undefined;
1129
+ }
1130
+ const symbolId = getSymbolId(symbol).toString();
1131
+ const lastUsage = seenUsages.get(symbolId);
1132
+ // there are two kinds of value usages
1133
+ // - reads - if range contains a read from the value located outside of the range then value should be passed as a parameter
1134
+ // - writes - if range contains a write to a value located outside the range the value should be passed as a parameter and
1135
+ // returned as a return value
1136
+ // 'write' case is a superset of 'read' so if we already have processed 'write' of some symbol there is not need to handle 'read'
1137
+ // since all information is already recorded
1138
+ if (lastUsage && lastUsage >= usage) {
1139
+ return symbolId;
1140
+ }
1141
+ seenUsages.set(symbolId, usage);
1142
+ if (lastUsage) {
1143
+ // if we get here this means that we are trying to handle 'write' and 'read' was already processed
1144
+ // walk scopes and update existing records.
1145
+ for (const perScope of usagesPerScope) {
1146
+ const prevEntry = perScope.usages.get(identifier.text);
1147
+ if (prevEntry) {
1148
+ perScope.usages.set(identifier.text, { usage, symbol, node: identifier });
1149
+ }
1150
+ }
1151
+ return symbolId;
1152
+ }
1153
+ // find first declaration in this file
1154
+ const decls = symbol.getDeclarations();
1155
+ const declInFile = decls && find(decls, d => d.getSourceFile() === sourceFile);
1156
+ if (!declInFile) {
1157
+ return undefined;
1158
+ }
1159
+ if (rangeContainsStartEnd(enclosingTextRange, declInFile.getStart(), declInFile.end)) {
1160
+ // declaration is located in range to be extracted - do nothing
1161
+ return undefined;
1162
+ }
1163
+ // Na tag, a escrita numa referência de fora, num trecho extraído para um generator, era recusada (CK-02).
1164
+ for (let i = 0; i < scopes.length; i++) {
1165
+ const scope = scopes[i];
1166
+ const resolvedSymbol = checker.resolveName(symbol.name, scope, symbol.flags, /*excludeGlobals*/ false);
1167
+ if (resolvedSymbol === symbol) {
1168
+ continue;
1169
+ }
1170
+ if (!substitutionsPerScope[i].has(symbolId)) {
1171
+ const substitution = tryReplaceWithQualifiedNameOrPropertyAccess(symbol.exportSymbol || symbol, scope, isTypeName);
1172
+ if (substitution) {
1173
+ substitutionsPerScope[i].set(symbolId, substitution);
1174
+ }
1175
+ else if (isTypeName) {
1176
+ // If the symbol is a type parameter that won't be in scope, we'll pass it as a type argument
1177
+ // so there's no problem.
1178
+ if (!(symbol.flags & SymbolFlags.TypeParameter)) {
1179
+ const diag = createDiagnosticForNode(identifier, Messages.typeWillNotBeVisibleInTheNewScope);
1180
+ functionErrorsPerScope[i].push(diag);
1181
+ constantErrorsPerScope[i].push(diag);
1182
+ }
1183
+ }
1184
+ else {
1185
+ usagesPerScope[i].usages.set(identifier.text, { usage, symbol, node: identifier });
1186
+ }
1187
+ }
1188
+ }
1189
+ return symbolId;
1190
+ }
1191
+ function checkForUsedDeclarations(node) {
1192
+ // If this node is entirely within the original extraction range, we don't need to do anything.
1193
+ if (node === targetRange.range || (isReadonlyArray(targetRange.range) && targetRange.range.indexOf(node) >= 0)) {
1194
+ return;
1195
+ }
1196
+ // Otherwise check and recurse.
1197
+ const sym = isIdentifier(node)
1198
+ ? getSymbolReferencedByIdentifier(node)
1199
+ : checker.getSymbolAtLocation(node);
1200
+ if (sym) {
1201
+ const decl = find(visibleDeclarationsInExtractedRange, d => d.symbol === sym);
1202
+ if (decl) {
1203
+ if (isVariableDeclaration(decl)) {
1204
+ const idString = decl.symbol.id.toString();
1205
+ if (!exposedVariableSymbolSet.has(idString)) {
1206
+ exposedVariableDeclarations.push(decl);
1207
+ exposedVariableSymbolSet.set(idString, true);
1208
+ }
1209
+ }
1210
+ else {
1211
+ // CONSIDER: this includes binding elements, which we could
1212
+ // expose in the same way as variables.
1213
+ firstExposedNonVariableDeclaration = firstExposedNonVariableDeclaration || decl;
1214
+ }
1215
+ }
1216
+ }
1217
+ forEachChild(node, checkForUsedDeclarations);
1218
+ }
1219
+ /**
1220
+ * Return the symbol referenced by an identifier (even if it declares a different symbol).
1221
+ */
1222
+ function getSymbolReferencedByIdentifier(identifier) {
1223
+ // If the identifier is both a property name and its value, we're only interested in its value
1224
+ // (since the name is a declaration and will be included in the extracted range).
1225
+ return identifier.parent && isShorthandPropertyAssignment(identifier.parent) && identifier.parent.name === identifier
1226
+ ? checker.getShorthandAssignmentValueSymbol(identifier.parent)
1227
+ : checker.getSymbolAtLocation(identifier);
1228
+ }
1229
+ function tryReplaceWithQualifiedNameOrPropertyAccess(symbol, scopeDecl, isTypeNode) {
1230
+ if (!symbol) {
1231
+ return undefined;
1232
+ }
1233
+ const decls = symbol.getDeclarations();
1234
+ if (decls && decls.some(d => d.parent === scopeDecl)) {
1235
+ return createIdentifier(symbol.name);
1236
+ }
1237
+ const prefix = tryReplaceWithQualifiedNameOrPropertyAccess(symbol.parent, scopeDecl, isTypeNode);
1238
+ if (prefix === undefined) {
1239
+ return undefined;
1240
+ }
1241
+ return isTypeNode
1242
+ ? createQualifiedName(prefix, createIdentifier(symbol.name))
1243
+ : createPropertyAccess(prefix, symbol.name);
1244
+ }
1245
+ }
1246
+ /**
1247
+ * Computes whether or not a node represents an expression in a position where it could
1248
+ * be extracted.
1249
+ * The isExpression() in utilities.ts returns some false positives we need to handle,
1250
+ * such as `import x from 'y'` -- the 'y' is a StringLiteral but is *not* an expression
1251
+ * in the sense of something that you could extract on
1252
+ */
1253
+ function isExtractableExpression(node) {
1254
+ const { parent } = node;
1255
+ // Na tag, o valor de um membro de enum não se extraía (CK-02).
1256
+ switch (node.kind) {
1257
+ case SyntaxKind.StringLiteral:
1258
+ return parent.kind !== SyntaxKind.ImportDeclaration &&
1259
+ parent.kind !== SyntaxKind.ImportSpecifier;
1260
+ case SyntaxKind.SpreadElement:
1261
+ case SyntaxKind.ObjectBindingPattern:
1262
+ case SyntaxKind.BindingElement:
1263
+ return false;
1264
+ case SyntaxKind.Identifier:
1265
+ return parent.kind !== SyntaxKind.BindingElement &&
1266
+ parent.kind !== SyntaxKind.ImportSpecifier &&
1267
+ parent.kind !== SyntaxKind.ExportSpecifier;
1268
+ }
1269
+ return true;
1270
+ }
1271
+ function isBlockLike(node) {
1272
+ switch (node.kind) {
1273
+ case SyntaxKind.Block:
1274
+ case SyntaxKind.SourceFile:
1275
+ case SyntaxKind.ModuleBlock:
1276
+ case SyntaxKind.CaseClause:
1277
+ return true;
1278
+ default:
1279
+ return false;
1280
+ }
1281
+ }