@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.
- package/LICENSE +55 -0
- package/NOTICE +13 -0
- package/dist/_namespaces/edit.d.ts +8 -0
- package/dist/_namespaces/edit.js +11 -0
- package/dist/_namespaces/ts.Completions.StringCompletions.d.ts +1 -0
- package/dist/_namespaces/ts.Completions.StringCompletions.js +2 -0
- package/dist/_namespaces/ts.Completions.d.ts +2 -0
- package/dist/_namespaces/ts.Completions.js +3 -0
- package/dist/_namespaces/ts.FindAllReferences.d.ts +2 -0
- package/dist/_namespaces/ts.FindAllReferences.js +3 -0
- package/dist/_namespaces/ts.GoToDefinition.d.ts +1 -0
- package/dist/_namespaces/ts.GoToDefinition.js +2 -0
- package/dist/_namespaces/ts.NavigationBar.d.ts +1 -0
- package/dist/_namespaces/ts.NavigationBar.js +2 -0
- package/dist/_namespaces/ts.OrganizeImports.d.ts +1 -0
- package/dist/_namespaces/ts.OrganizeImports.js +2 -0
- package/dist/_namespaces/ts.OutliningElementsCollector.d.ts +1 -0
- package/dist/_namespaces/ts.OutliningElementsCollector.js +2 -0
- package/dist/_namespaces/ts.Rename.d.ts +1 -0
- package/dist/_namespaces/ts.Rename.js +2 -0
- package/dist/_namespaces/ts.SignatureHelp.d.ts +1 -0
- package/dist/_namespaces/ts.SignatureHelp.js +2 -0
- package/dist/_namespaces/ts.SmartSelectionRange.d.ts +1 -0
- package/dist/_namespaces/ts.SmartSelectionRange.js +2 -0
- package/dist/_namespaces/ts.SymbolDisplay.d.ts +1 -0
- package/dist/_namespaces/ts.SymbolDisplay.js +2 -0
- package/dist/_namespaces/ts.codefix.d.ts +26 -0
- package/dist/_namespaces/ts.codefix.js +27 -0
- package/dist/_namespaces/ts.d.ts +17 -0
- package/dist/_namespaces/ts.formatting.d.ts +7 -0
- package/dist/_namespaces/ts.formatting.js +8 -0
- package/dist/_namespaces/ts.js +20 -0
- package/dist/_namespaces/ts.refactor.addOrRemoveBracesToArrowFunction.d.ts +1 -0
- package/dist/_namespaces/ts.refactor.addOrRemoveBracesToArrowFunction.js +2 -0
- package/dist/_namespaces/ts.refactor.convertParamsToDestructuredObject.d.ts +1 -0
- package/dist/_namespaces/ts.refactor.convertParamsToDestructuredObject.js +2 -0
- package/dist/_namespaces/ts.refactor.convertStringOrTemplateLiteral.d.ts +1 -0
- package/dist/_namespaces/ts.refactor.convertStringOrTemplateLiteral.js +2 -0
- package/dist/_namespaces/ts.refactor.d.ts +9 -0
- package/dist/_namespaces/ts.refactor.extractSymbol.d.ts +1 -0
- package/dist/_namespaces/ts.refactor.extractSymbol.js +2 -0
- package/dist/_namespaces/ts.refactor.js +10 -0
- package/dist/_namespaces/ts.textChanges.d.ts +1 -0
- package/dist/_namespaces/ts.textChanges.js +2 -0
- package/dist/classifier.d.ts +5 -0
- package/dist/classifier.js +439 -0
- package/dist/codeFixProvider.d.ts +13 -0
- package/dist/codeFixProvider.js +84 -0
- package/dist/codefixes/addConvertToUnknownForNonOverlappingTypes.d.ts +1 -0
- package/dist/codefixes/addConvertToUnknownForNonOverlappingTypes.js +21 -0
- package/dist/codefixes/addEmptyExportDeclaration.d.ts +1 -0
- package/dist/codefixes/addEmptyExportDeclaration.js +17 -0
- package/dist/codefixes/addMissingAsync.d.ts +1 -0
- package/dist/codefixes/addMissingAsync.js +75 -0
- package/dist/codefixes/addMissingAwait.d.ts +1 -0
- package/dist/codefixes/addMissingAwait.js +236 -0
- package/dist/codefixes/addMissingConst.d.ts +1 -0
- package/dist/codefixes/addMissingConst.js +91 -0
- package/dist/codefixes/addNameToNamelessParameter.d.ts +1 -0
- package/dist/codefixes/addNameToNamelessParameter.js +29 -0
- package/dist/codefixes/convertConstToLet.d.ts +1 -0
- package/dist/codefixes/convertConstToLet.js +30 -0
- package/dist/codefixes/convertToAsyncFunction.d.ts +1 -0
- package/dist/codefixes/convertToAsyncFunction.js +495 -0
- package/dist/codefixes/convertToMappedObjectType.d.ts +1 -0
- package/dist/codefixes/convertToMappedObjectType.js +48 -0
- package/dist/codefixes/correctQualifiedNameToIndexedAccessType.d.ts +1 -0
- package/dist/codefixes/correctQualifiedNameToIndexedAccessType.js +33 -0
- package/dist/codefixes/fixAddModuleReferTypeMissingTypeof.d.ts +1 -0
- package/dist/codefixes/fixAddModuleReferTypeMissingTypeof.js +27 -0
- package/dist/codefixes/fixAwaitInSyncFunction.d.ts +1 -0
- package/dist/codefixes/fixAwaitInSyncFunction.js +69 -0
- package/dist/codefixes/fixExpectedComma.d.ts +1 -0
- package/dist/codefixes/fixExpectedComma.js +35 -0
- package/dist/codefixes/fixInvalidJsxCharacters.d.ts +1 -0
- package/dist/codefixes/fixInvalidJsxCharacters.js +41 -0
- package/dist/codefixes/fixMissingCallParentheses.d.ts +1 -0
- package/dist/codefixes/fixMissingCallParentheses.js +42 -0
- package/dist/codefixes/fixSpelling.d.ts +1 -0
- package/dist/codefixes/fixSpelling.js +94 -0
- package/dist/codefixes/fixUnreachableCode.d.ts +1 -0
- package/dist/codefixes/fixUnreachableCode.js +65 -0
- package/dist/codefixes/fixUnusedIdentifier.d.ts +1 -0
- package/dist/codefixes/fixUnusedIdentifier.js +224 -0
- package/dist/codefixes/helpers.d.ts +8 -0
- package/dist/codefixes/helpers.js +53 -0
- package/dist/codefixes/importFixes.d.ts +14 -0
- package/dist/codefixes/importFixes.js +441 -0
- package/dist/codefixes/inferFromUsage.d.ts +1 -0
- package/dist/codefixes/inferFromUsage.js +742 -0
- package/dist/codefixes/removeUnnecessaryAwait.d.ts +1 -0
- package/dist/codefixes/removeUnnecessaryAwait.js +41 -0
- package/dist/codefixes/returnValueCorrect.d.ts +1 -0
- package/dist/codefixes/returnValueCorrect.js +132 -0
- package/dist/codefixes/splitTypeOnlyImport.d.ts +1 -0
- package/dist/codefixes/splitTypeOnlyImport.js +32 -0
- package/dist/codefixes/useBigintLiteral.d.ts +1 -0
- package/dist/codefixes/useBigintLiteral.js +29 -0
- package/dist/completions.d.ts +83 -0
- package/dist/completions.js +1720 -0
- package/dist/documentHighlights.d.ts +8 -0
- package/dist/documentHighlights.js +367 -0
- package/dist/documentRegistry.d.ts +36 -0
- package/dist/documentRegistry.js +63 -0
- package/dist/editingServices.d.ts +1 -0
- package/dist/editingServices.js +4 -0
- package/dist/findAllReferences.d.ts +113 -0
- package/dist/findAllReferences.js +1366 -0
- package/dist/formatting/formatting.d.ts +26 -0
- package/dist/formatting/formatting.js +1021 -0
- package/dist/formatting/formattingContext.d.ts +34 -0
- package/dist/formatting/formattingContext.js +78 -0
- package/dist/formatting/formattingScanner.d.ts +14 -0
- package/dist/formatting/formattingScanner.js +228 -0
- package/dist/formatting/rule.d.ts +31 -0
- package/dist/formatting/rule.js +22 -0
- package/dist/formatting/rules.d.ts +7 -0
- package/dist/formatting/rules.js +610 -0
- package/dist/formatting/rulesMap.d.ts +5 -0
- package/dist/formatting/rulesMap.js +127 -0
- package/dist/formatting/smartIndenter.d.ts +44 -0
- package/dist/formatting/smartIndenter.js +518 -0
- package/dist/getEditsForFileRename.d.ts +6 -0
- package/dist/getEditsForFileRename.js +86 -0
- package/dist/goToDefinition.d.ts +8 -0
- package/dist/goToDefinition.js +246 -0
- package/dist/importTracker.d.ts +50 -0
- package/dist/importTracker.js +422 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/navigationBar.d.ts +3 -0
- package/dist/navigationBar.js +549 -0
- package/dist/organizeImports.d.ts +18 -0
- package/dist/organizeImports.js +290 -0
- package/dist/outliningElementsCollector.d.ts +2 -0
- package/dist/outliningElementsCollector.js +261 -0
- package/dist/refactorProvider.d.ts +5 -0
- package/dist/refactorProvider.js +16 -0
- package/dist/refactors/addOrRemoveBracesToArrowFunction.d.ts +1 -0
- package/dist/refactors/addOrRemoveBracesToArrowFunction.js +86 -0
- package/dist/refactors/convertExport.d.ts +1 -0
- package/dist/refactors/convertExport.js +126 -0
- package/dist/refactors/convertImport.d.ts +1 -0
- package/dist/refactors/convertImport.js +116 -0
- package/dist/refactors/convertParamsToDestructuredObject.d.ts +1 -0
- package/dist/refactors/convertParamsToDestructuredObject.js +282 -0
- package/dist/refactors/convertStringOrTemplateLiteral.d.ts +1 -0
- package/dist/refactors/convertStringOrTemplateLiteral.js +148 -0
- package/dist/refactors/extractSymbol.d.ts +60 -0
- package/dist/refactors/extractSymbol.js +1281 -0
- package/dist/refactors/extractType.d.ts +1 -0
- package/dist/refactors/extractType.js +102 -0
- package/dist/refactors/moveToNewFile.d.ts +1 -0
- package/dist/refactors/moveToNewFile.js +477 -0
- package/dist/rename.d.ts +2 -0
- package/dist/rename.js +100 -0
- package/dist/services.d.ts +48 -0
- package/dist/services.js +1480 -0
- package/dist/signatureHelp.d.ts +8 -0
- package/dist/signatureHelp.js +414 -0
- package/dist/smartSelection.d.ts +2 -0
- package/dist/smartSelection.js +243 -0
- package/dist/stringCompletions.d.ts +4 -0
- package/dist/stringCompletions.js +220 -0
- package/dist/suggestionDiagnostics.d.ts +6 -0
- package/dist/suggestionDiagnostics.js +92 -0
- package/dist/symbolDisplay.d.ts +16 -0
- package/dist/symbolDisplay.js +400 -0
- package/dist/textChanges.d.ts +161 -0
- package/dist/textChanges.js +1163 -0
- package/dist/types.d.ts +908 -0
- package/dist/types.js +263 -0
- package/dist/utilities.d.ts +283 -0
- package/dist/utilities.js +1981 -0
- package/package.json +45 -3
- package/README.md +0 -3
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
// Modificado de microsoft/TypeScript v3.9.10, src/services/organizeImports.ts: o namespace virou módulo ES, com os imports explícitos.
|
|
2
|
+
// Saem o import da fábrica do JSX, que a tag tinha por usado sempre que o arquivo tem JSX (a fábrica é do emit, CK-19), e
|
|
3
|
+
// o import que um `declare module "x"` aumenta, que a tag mantinha mesmo sem uso (o módulo ambiente de nome em string,
|
|
4
|
+
// CK-02, princípio 4).
|
|
5
|
+
import { FindAllReferences, compareBooleans, compareStringsCaseInsensitive, createIdentifier, createImportSpecifier, createNamedImports, emptyArray, flatMap, getNewLineOrDefaultFromHost, group, isAmbientModule, isExportDeclaration, isExternalModuleNameRelative, isImportDeclaration, isNamedExports, isNamespaceImport, isStringLiteralLike, length, stableSort, suppressLeadingTrivia, textChanges, updateExportDeclaration, updateImportClause, updateImportDeclaration, updateNamedExports, updateNamedImports, updateNamespaceExport, } from "./_namespaces/edit.js";
|
|
6
|
+
/**
|
|
7
|
+
* Organize imports by:
|
|
8
|
+
* 1) Removing unused imports
|
|
9
|
+
* 2) Coalescing imports from the same module
|
|
10
|
+
* 3) Sorting imports
|
|
11
|
+
*/
|
|
12
|
+
export function organizeImports(sourceFile, formatContext, host, program, preferences) {
|
|
13
|
+
const changeTracker = textChanges.ChangeTracker.fromContext({ host, formatContext, preferences });
|
|
14
|
+
const coalesceAndOrganizeImports = (importGroup) => coalesceImports(removeUnusedImports(importGroup, sourceFile, program));
|
|
15
|
+
// All of the old ImportDeclarations in the file, in syntactic order.
|
|
16
|
+
const topLevelImportDecls = sourceFile.statements.filter(isImportDeclaration);
|
|
17
|
+
organizeImportsWorker(topLevelImportDecls, coalesceAndOrganizeImports);
|
|
18
|
+
// All of the old ExportDeclarations in the file, in syntactic order.
|
|
19
|
+
const topLevelExportDecls = sourceFile.statements.filter(isExportDeclaration);
|
|
20
|
+
organizeImportsWorker(topLevelExportDecls, coalesceExports);
|
|
21
|
+
for (const ambientModule of sourceFile.statements.filter(isAmbientModule)) {
|
|
22
|
+
if (!ambientModule.body) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const ambientModuleImportDecls = ambientModule.body.statements.filter(isImportDeclaration);
|
|
26
|
+
organizeImportsWorker(ambientModuleImportDecls, coalesceAndOrganizeImports);
|
|
27
|
+
const ambientModuleExportDecls = ambientModule.body.statements.filter(isExportDeclaration);
|
|
28
|
+
organizeImportsWorker(ambientModuleExportDecls, coalesceExports);
|
|
29
|
+
}
|
|
30
|
+
return changeTracker.getChanges();
|
|
31
|
+
function organizeImportsWorker(oldImportDecls, coalesce) {
|
|
32
|
+
if (length(oldImportDecls) === 0) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Special case: normally, we'd expect leading and trailing trivia to follow each import
|
|
36
|
+
// around as it's sorted. However, we do not want this to happen for leading trivia
|
|
37
|
+
// on the first import because it is probably the header comment for the file.
|
|
38
|
+
// Consider: we could do a more careful check that this trivia is actually a header,
|
|
39
|
+
// but the consequences of being wrong are very minor.
|
|
40
|
+
suppressLeadingTrivia(oldImportDecls[0]);
|
|
41
|
+
const oldImportGroups = group(oldImportDecls, importDecl => getExternalModuleName(importDecl.moduleSpecifier));
|
|
42
|
+
const sortedImportGroups = stableSort(oldImportGroups, (group1, group2) => compareModuleSpecifiers(group1[0].moduleSpecifier, group2[0].moduleSpecifier));
|
|
43
|
+
const newImportDecls = flatMap(sortedImportGroups, importGroup => getExternalModuleName(importGroup[0].moduleSpecifier)
|
|
44
|
+
? coalesce(importGroup)
|
|
45
|
+
: importGroup);
|
|
46
|
+
// Delete or replace the first import.
|
|
47
|
+
if (newImportDecls.length === 0) {
|
|
48
|
+
changeTracker.delete(sourceFile, oldImportDecls[0]);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
// Note: Delete the surrounding trivia because it will have been retained in newImportDecls.
|
|
52
|
+
changeTracker.replaceNodeWithNodes(sourceFile, oldImportDecls[0], newImportDecls, {
|
|
53
|
+
leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, // Leave header comment in place
|
|
54
|
+
trailingTriviaOption: textChanges.TrailingTriviaOption.Include,
|
|
55
|
+
suffix: getNewLineOrDefaultFromHost(host, formatContext.options),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// Delete any subsequent imports.
|
|
59
|
+
for (let i = 1; i < oldImportDecls.length; i++) {
|
|
60
|
+
changeTracker.deleteNode(sourceFile, oldImportDecls[i]);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function removeUnusedImports(oldImports, sourceFile, program) {
|
|
65
|
+
const typeChecker = program.getTypeChecker();
|
|
66
|
+
const usedImports = [];
|
|
67
|
+
for (const importDecl of oldImports) {
|
|
68
|
+
const { importClause } = importDecl;
|
|
69
|
+
if (!importClause) {
|
|
70
|
+
// Imports without import clauses are assumed to be included for their side effects and are not removed.
|
|
71
|
+
usedImports.push(importDecl);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
let { name, namedBindings } = importClause;
|
|
75
|
+
// Default import
|
|
76
|
+
if (name && !isDeclarationUsed(name)) {
|
|
77
|
+
name = undefined;
|
|
78
|
+
}
|
|
79
|
+
if (namedBindings) {
|
|
80
|
+
if (isNamespaceImport(namedBindings)) {
|
|
81
|
+
// Namespace import
|
|
82
|
+
if (!isDeclarationUsed(namedBindings.name)) {
|
|
83
|
+
namedBindings = undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// List of named imports
|
|
88
|
+
const newElements = namedBindings.elements.filter(e => isDeclarationUsed(e.name));
|
|
89
|
+
if (newElements.length < namedBindings.elements.length) {
|
|
90
|
+
namedBindings = newElements.length
|
|
91
|
+
? updateNamedImports(namedBindings, newElements)
|
|
92
|
+
: undefined;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (name || namedBindings) {
|
|
97
|
+
usedImports.push(updateImportDeclarationAndClause(importDecl, name, namedBindings));
|
|
98
|
+
}
|
|
99
|
+
// Na tag, o import que um `declare module "x"` do arquivo aumentava ficava, mesmo sem uso (CK-02, princípio 4).
|
|
100
|
+
}
|
|
101
|
+
return usedImports;
|
|
102
|
+
// Na tag, também o nome da fábrica do JSX, que contava como usado quando o arquivo tinha JSX (CK-19).
|
|
103
|
+
function isDeclarationUsed(identifier) {
|
|
104
|
+
return FindAllReferences.Core.isSymbolReferencedInFile(identifier, typeChecker, sourceFile);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
function getExternalModuleName(specifier) {
|
|
108
|
+
return specifier !== undefined && isStringLiteralLike(specifier)
|
|
109
|
+
? specifier.text
|
|
110
|
+
: undefined;
|
|
111
|
+
}
|
|
112
|
+
// Internal for testing
|
|
113
|
+
/**
|
|
114
|
+
* @param importGroup a list of ImportDeclarations, all with the same module name.
|
|
115
|
+
*/
|
|
116
|
+
export function coalesceImports(importGroup) {
|
|
117
|
+
if (importGroup.length === 0) {
|
|
118
|
+
return importGroup;
|
|
119
|
+
}
|
|
120
|
+
const { importWithoutClause, typeOnlyImports, regularImports } = getCategorizedImports(importGroup);
|
|
121
|
+
const coalescedImports = [];
|
|
122
|
+
if (importWithoutClause) {
|
|
123
|
+
coalescedImports.push(importWithoutClause);
|
|
124
|
+
}
|
|
125
|
+
for (const group of [regularImports, typeOnlyImports]) {
|
|
126
|
+
const isTypeOnly = group === typeOnlyImports;
|
|
127
|
+
const { defaultImports, namespaceImports, namedImports } = group;
|
|
128
|
+
// Normally, we don't combine default and namespace imports, but it would be silly to
|
|
129
|
+
// produce two import declarations in this special case.
|
|
130
|
+
if (!isTypeOnly && defaultImports.length === 1 && namespaceImports.length === 1 && namedImports.length === 0) {
|
|
131
|
+
// Add the namespace import to the existing default ImportDeclaration.
|
|
132
|
+
const defaultImport = defaultImports[0];
|
|
133
|
+
coalescedImports.push(updateImportDeclarationAndClause(defaultImport, defaultImport.importClause.name, namespaceImports[0].importClause.namedBindings)); // TODO: GH#18217
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
const sortedNamespaceImports = stableSort(namespaceImports, (i1, i2) => compareIdentifiers(i1.importClause.namedBindings.name, i2.importClause.namedBindings.name)); // TODO: GH#18217
|
|
137
|
+
for (const namespaceImport of sortedNamespaceImports) {
|
|
138
|
+
// Drop the name, if any
|
|
139
|
+
coalescedImports.push(updateImportDeclarationAndClause(namespaceImport, /*name*/ undefined, namespaceImport.importClause.namedBindings)); // TODO: GH#18217
|
|
140
|
+
}
|
|
141
|
+
if (defaultImports.length === 0 && namedImports.length === 0) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
let newDefaultImport;
|
|
145
|
+
const newImportSpecifiers = [];
|
|
146
|
+
if (defaultImports.length === 1) {
|
|
147
|
+
newDefaultImport = defaultImports[0].importClause.name;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
for (const defaultImport of defaultImports) {
|
|
151
|
+
newImportSpecifiers.push(createImportSpecifier(createIdentifier("default"), defaultImport.importClause.name)); // TODO: GH#18217
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
newImportSpecifiers.push(...flatMap(namedImports, i => i.importClause.namedBindings.elements)); // TODO: GH#18217
|
|
155
|
+
const sortedImportSpecifiers = sortSpecifiers(newImportSpecifiers);
|
|
156
|
+
const importDecl = defaultImports.length > 0
|
|
157
|
+
? defaultImports[0]
|
|
158
|
+
: namedImports[0];
|
|
159
|
+
const newNamedImports = sortedImportSpecifiers.length === 0
|
|
160
|
+
? newDefaultImport
|
|
161
|
+
? undefined
|
|
162
|
+
: createNamedImports(emptyArray)
|
|
163
|
+
: namedImports.length === 0
|
|
164
|
+
? createNamedImports(sortedImportSpecifiers)
|
|
165
|
+
: updateNamedImports(namedImports[0].importClause.namedBindings, sortedImportSpecifiers); // TODO: GH#18217
|
|
166
|
+
// Type-only imports are not allowed to mix default, namespace, and named imports in any combination.
|
|
167
|
+
// We could rewrite a default import as a named import (`import { default as name }`), but we currently
|
|
168
|
+
// choose not to as a stylistic preference.
|
|
169
|
+
if (isTypeOnly && newDefaultImport && newNamedImports) {
|
|
170
|
+
coalescedImports.push(updateImportDeclarationAndClause(importDecl, newDefaultImport, /*namedBindings*/ undefined));
|
|
171
|
+
coalescedImports.push(updateImportDeclarationAndClause(namedImports[0] ?? importDecl, /*name*/ undefined, newNamedImports));
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
coalescedImports.push(updateImportDeclarationAndClause(importDecl, newDefaultImport, newNamedImports));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return coalescedImports;
|
|
178
|
+
}
|
|
179
|
+
/*
|
|
180
|
+
* Returns entire import declarations because they may already have been rewritten and
|
|
181
|
+
* may lack parent pointers. The desired parts can easily be recovered based on the
|
|
182
|
+
* categorization.
|
|
183
|
+
*
|
|
184
|
+
* NB: There may be overlap between `defaultImports` and `namespaceImports`/`namedImports`.
|
|
185
|
+
*/
|
|
186
|
+
function getCategorizedImports(importGroup) {
|
|
187
|
+
let importWithoutClause;
|
|
188
|
+
const typeOnlyImports = { defaultImports: [], namespaceImports: [], namedImports: [] };
|
|
189
|
+
const regularImports = { defaultImports: [], namespaceImports: [], namedImports: [] };
|
|
190
|
+
for (const importDeclaration of importGroup) {
|
|
191
|
+
if (importDeclaration.importClause === undefined) {
|
|
192
|
+
// Only the first such import is interesting - the others are redundant.
|
|
193
|
+
// Note: Unfortunately, we will lose trivia that was on this node.
|
|
194
|
+
importWithoutClause = importWithoutClause || importDeclaration;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
197
|
+
const group = importDeclaration.importClause.isTypeOnly ? typeOnlyImports : regularImports;
|
|
198
|
+
const { name, namedBindings } = importDeclaration.importClause;
|
|
199
|
+
if (name) {
|
|
200
|
+
group.defaultImports.push(importDeclaration);
|
|
201
|
+
}
|
|
202
|
+
if (namedBindings) {
|
|
203
|
+
if (isNamespaceImport(namedBindings)) {
|
|
204
|
+
group.namespaceImports.push(importDeclaration);
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
group.namedImports.push(importDeclaration);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
importWithoutClause,
|
|
213
|
+
typeOnlyImports,
|
|
214
|
+
regularImports,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
// Internal for testing
|
|
218
|
+
/**
|
|
219
|
+
* @param exportGroup a list of ExportDeclarations, all with the same module name.
|
|
220
|
+
*/
|
|
221
|
+
export function coalesceExports(exportGroup) {
|
|
222
|
+
if (exportGroup.length === 0) {
|
|
223
|
+
return exportGroup;
|
|
224
|
+
}
|
|
225
|
+
const { exportWithoutClause, namedExports, typeOnlyExports } = getCategorizedExports(exportGroup);
|
|
226
|
+
const coalescedExports = [];
|
|
227
|
+
if (exportWithoutClause) {
|
|
228
|
+
coalescedExports.push(exportWithoutClause);
|
|
229
|
+
}
|
|
230
|
+
for (const exportGroup of [namedExports, typeOnlyExports]) {
|
|
231
|
+
if (exportGroup.length === 0) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const newExportSpecifiers = [];
|
|
235
|
+
newExportSpecifiers.push(...flatMap(exportGroup, i => i.exportClause && isNamedExports(i.exportClause) ? i.exportClause.elements : emptyArray));
|
|
236
|
+
const sortedExportSpecifiers = sortSpecifiers(newExportSpecifiers);
|
|
237
|
+
const exportDecl = exportGroup[0];
|
|
238
|
+
coalescedExports.push(updateExportDeclaration(exportDecl, exportDecl.modifiers, exportDecl.exportClause && (isNamedExports(exportDecl.exportClause) ?
|
|
239
|
+
updateNamedExports(exportDecl.exportClause, sortedExportSpecifiers) :
|
|
240
|
+
updateNamespaceExport(exportDecl.exportClause, exportDecl.exportClause.name)), exportDecl.moduleSpecifier, exportDecl.isTypeOnly));
|
|
241
|
+
}
|
|
242
|
+
return coalescedExports;
|
|
243
|
+
/*
|
|
244
|
+
* Returns entire export declarations because they may already have been rewritten and
|
|
245
|
+
* may lack parent pointers. The desired parts can easily be recovered based on the
|
|
246
|
+
* categorization.
|
|
247
|
+
*/
|
|
248
|
+
function getCategorizedExports(exportGroup) {
|
|
249
|
+
let exportWithoutClause;
|
|
250
|
+
const namedExports = [];
|
|
251
|
+
const typeOnlyExports = [];
|
|
252
|
+
for (const exportDeclaration of exportGroup) {
|
|
253
|
+
if (exportDeclaration.exportClause === undefined) {
|
|
254
|
+
// Only the first such export is interesting - the others are redundant.
|
|
255
|
+
// Note: Unfortunately, we will lose trivia that was on this node.
|
|
256
|
+
exportWithoutClause = exportWithoutClause || exportDeclaration;
|
|
257
|
+
}
|
|
258
|
+
else if (exportDeclaration.isTypeOnly) {
|
|
259
|
+
typeOnlyExports.push(exportDeclaration);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
namedExports.push(exportDeclaration);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
exportWithoutClause,
|
|
267
|
+
namedExports,
|
|
268
|
+
typeOnlyExports,
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
function updateImportDeclarationAndClause(importDeclaration, name, namedBindings) {
|
|
273
|
+
return updateImportDeclaration(importDeclaration, importDeclaration.modifiers, updateImportClause(importDeclaration.importClause, name, namedBindings, importDeclaration.importClause.isTypeOnly), // TODO: GH#18217
|
|
274
|
+
importDeclaration.moduleSpecifier);
|
|
275
|
+
}
|
|
276
|
+
function sortSpecifiers(specifiers) {
|
|
277
|
+
return stableSort(specifiers, (s1, s2) => compareIdentifiers(s1.propertyName || s1.name, s2.propertyName || s2.name) ||
|
|
278
|
+
compareIdentifiers(s1.name, s2.name));
|
|
279
|
+
}
|
|
280
|
+
/* internal */ // Exported for testing
|
|
281
|
+
export function compareModuleSpecifiers(m1, m2) {
|
|
282
|
+
const name1 = getExternalModuleName(m1);
|
|
283
|
+
const name2 = getExternalModuleName(m2);
|
|
284
|
+
return compareBooleans(name1 === undefined, name2 === undefined) ||
|
|
285
|
+
compareBooleans(isExternalModuleNameRelative(name1), isExternalModuleNameRelative(name2)) ||
|
|
286
|
+
compareStringsCaseInsensitive(name1, name2);
|
|
287
|
+
}
|
|
288
|
+
function compareIdentifiers(s1, s2) {
|
|
289
|
+
return compareStringsCaseInsensitive(s1.text, s2.text);
|
|
290
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
// Modificado de microsoft/TypeScript v3.9.10, src/services/outliningElementsCollector.ts: o namespace virou módulo ES, com os imports explícitos.
|
|
2
|
+
import { Debug, SyntaxKind, createTextSpanFromBounds, createTextSpanFromNode, createTextSpanFromRange, findAncestor, findChildOfKind, getLeadingCommentRangesOfNode, getSingleInitializerOfVariableStatementOrPropertyDeclaration, isAnyImportSyntax, isArrayLiteralExpression, isArrowFunction, isCallExpression, isDeclaration, isFunctionLike, isIfStatement, isInComment, isNodeArrayMultiLine, isVariableStatement, } from "./_namespaces/ts.js";
|
|
3
|
+
export function collectElements(sourceFile, cancellationToken) {
|
|
4
|
+
const res = [];
|
|
5
|
+
addNodeOutliningSpans(sourceFile, cancellationToken, res);
|
|
6
|
+
addRegionOutliningSpans(sourceFile, res);
|
|
7
|
+
return res.sort((span1, span2) => span1.textSpan.start - span2.textSpan.start);
|
|
8
|
+
}
|
|
9
|
+
function addNodeOutliningSpans(sourceFile, cancellationToken, out) {
|
|
10
|
+
let depthRemaining = 40;
|
|
11
|
+
let current = 0;
|
|
12
|
+
// Includes the EOF Token so that comments which aren't attached to statements are included
|
|
13
|
+
const statements = [...sourceFile.statements, sourceFile.endOfFileToken];
|
|
14
|
+
const n = statements.length;
|
|
15
|
+
while (current < n) {
|
|
16
|
+
while (current < n && !isAnyImportSyntax(statements[current])) {
|
|
17
|
+
visitNonImportNode(statements[current]);
|
|
18
|
+
current++;
|
|
19
|
+
}
|
|
20
|
+
if (current === n)
|
|
21
|
+
break;
|
|
22
|
+
const firstImport = current;
|
|
23
|
+
while (current < n && isAnyImportSyntax(statements[current])) {
|
|
24
|
+
addOutliningForLeadingCommentsForNode(statements[current], sourceFile, cancellationToken, out);
|
|
25
|
+
current++;
|
|
26
|
+
}
|
|
27
|
+
const lastImport = current - 1;
|
|
28
|
+
if (lastImport !== firstImport) {
|
|
29
|
+
out.push(createOutliningSpanFromBounds(findChildOfKind(statements[firstImport], SyntaxKind.ImportKeyword, sourceFile).getStart(sourceFile), statements[lastImport].getEnd(), "imports" /* OutliningSpanKind.Imports */));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function visitNonImportNode(n) {
|
|
33
|
+
if (depthRemaining === 0)
|
|
34
|
+
return;
|
|
35
|
+
cancellationToken.throwIfCancellationRequested();
|
|
36
|
+
if (isDeclaration(n) || n.kind === SyntaxKind.EndOfFileToken) {
|
|
37
|
+
addOutliningForLeadingCommentsForNode(n, sourceFile, cancellationToken, out);
|
|
38
|
+
}
|
|
39
|
+
if (isFunctionExpressionAssignedToVariable(n)) {
|
|
40
|
+
addOutliningForLeadingCommentsForNode(n.parent.parent.parent, sourceFile, cancellationToken, out);
|
|
41
|
+
}
|
|
42
|
+
const span = getOutliningSpanForNode(n, sourceFile);
|
|
43
|
+
if (span)
|
|
44
|
+
out.push(span);
|
|
45
|
+
depthRemaining--;
|
|
46
|
+
if (isCallExpression(n)) {
|
|
47
|
+
depthRemaining++;
|
|
48
|
+
visitNonImportNode(n.expression);
|
|
49
|
+
depthRemaining--;
|
|
50
|
+
n.arguments.forEach(visitNonImportNode);
|
|
51
|
+
n.typeArguments?.forEach(visitNonImportNode);
|
|
52
|
+
}
|
|
53
|
+
else if (isIfStatement(n) && n.elseStatement && isIfStatement(n.elseStatement)) {
|
|
54
|
+
// Consider an 'else if' to be on the same depth as the 'if'.
|
|
55
|
+
visitNonImportNode(n.expression);
|
|
56
|
+
visitNonImportNode(n.thenStatement);
|
|
57
|
+
depthRemaining++;
|
|
58
|
+
visitNonImportNode(n.elseStatement);
|
|
59
|
+
depthRemaining--;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
n.forEachChild(visitNonImportNode);
|
|
63
|
+
}
|
|
64
|
+
depthRemaining++;
|
|
65
|
+
}
|
|
66
|
+
/** A arrow atribuída a uma variável. Na tag, também a function expression (CK-02). */
|
|
67
|
+
function isFunctionExpressionAssignedToVariable(n) {
|
|
68
|
+
if (!isArrowFunction(n)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
const ancestor = findAncestor(n, isVariableStatement);
|
|
72
|
+
return !!ancestor && getSingleInitializerOfVariableStatementOrPropertyDeclaration(ancestor) === n;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function addRegionOutliningSpans(sourceFile, out) {
|
|
76
|
+
const regions = [];
|
|
77
|
+
const lineStarts = sourceFile.getLineStarts();
|
|
78
|
+
for (const currentLineStart of lineStarts) {
|
|
79
|
+
const lineEnd = sourceFile.getLineEndOfPosition(currentLineStart);
|
|
80
|
+
const lineText = sourceFile.text.substring(currentLineStart, lineEnd);
|
|
81
|
+
const result = isRegionDelimiter(lineText);
|
|
82
|
+
if (!result || isInComment(sourceFile, currentLineStart)) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (!result[1]) {
|
|
86
|
+
const span = createTextSpanFromBounds(sourceFile.text.indexOf("//", currentLineStart), lineEnd);
|
|
87
|
+
regions.push(createOutliningSpan(span, "region" /* OutliningSpanKind.Region */, span, /*autoCollapse*/ false, result[2] || "#region"));
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
const region = regions.pop();
|
|
91
|
+
if (region) {
|
|
92
|
+
region.textSpan.length = lineEnd - region.textSpan.start;
|
|
93
|
+
region.hintSpan.length = lineEnd - region.textSpan.start;
|
|
94
|
+
out.push(region);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const regionDelimiterRegExp = /^\s*\/\/\s*#(end)?region(?:\s+(.*))?(?:\r)?$/;
|
|
100
|
+
function isRegionDelimiter(lineText) {
|
|
101
|
+
return regionDelimiterRegExp.exec(lineText);
|
|
102
|
+
}
|
|
103
|
+
function addOutliningForLeadingCommentsForNode(n, sourceFile, cancellationToken, out) {
|
|
104
|
+
const comments = getLeadingCommentRangesOfNode(n, sourceFile);
|
|
105
|
+
if (!comments)
|
|
106
|
+
return;
|
|
107
|
+
let firstSingleLineCommentStart = -1;
|
|
108
|
+
let lastSingleLineCommentEnd = -1;
|
|
109
|
+
let singleLineCommentCount = 0;
|
|
110
|
+
const sourceText = sourceFile.getFullText();
|
|
111
|
+
for (const { kind, pos, end } of comments) {
|
|
112
|
+
cancellationToken.throwIfCancellationRequested();
|
|
113
|
+
switch (kind) {
|
|
114
|
+
case SyntaxKind.SingleLineCommentTrivia:
|
|
115
|
+
// never fold region delimiters into single-line comment regions
|
|
116
|
+
const commentText = sourceText.slice(pos, end);
|
|
117
|
+
if (isRegionDelimiter(commentText)) {
|
|
118
|
+
combineAndAddMultipleSingleLineComments();
|
|
119
|
+
singleLineCommentCount = 0;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
// For single line comments, combine consecutive ones (2 or more) into
|
|
123
|
+
// a single span from the start of the first till the end of the last
|
|
124
|
+
if (singleLineCommentCount === 0) {
|
|
125
|
+
firstSingleLineCommentStart = pos;
|
|
126
|
+
}
|
|
127
|
+
lastSingleLineCommentEnd = end;
|
|
128
|
+
singleLineCommentCount++;
|
|
129
|
+
break;
|
|
130
|
+
case SyntaxKind.MultiLineCommentTrivia:
|
|
131
|
+
combineAndAddMultipleSingleLineComments();
|
|
132
|
+
out.push(createOutliningSpanFromBounds(pos, end, "comment" /* OutliningSpanKind.Comment */));
|
|
133
|
+
singleLineCommentCount = 0;
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
Debug.assertNever(kind);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
combineAndAddMultipleSingleLineComments();
|
|
140
|
+
function combineAndAddMultipleSingleLineComments() {
|
|
141
|
+
// Only outline spans of two or more consecutive single line comments
|
|
142
|
+
if (singleLineCommentCount > 1) {
|
|
143
|
+
out.push(createOutliningSpanFromBounds(firstSingleLineCommentStart, lastSingleLineCommentEnd, "comment" /* OutliningSpanKind.Comment */));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
function createOutliningSpanFromBounds(pos, end, kind) {
|
|
148
|
+
return createOutliningSpan(createTextSpanFromBounds(pos, end), kind);
|
|
149
|
+
}
|
|
150
|
+
function getOutliningSpanForNode(n, sourceFile) {
|
|
151
|
+
switch (n.kind) {
|
|
152
|
+
case SyntaxKind.Block:
|
|
153
|
+
if (isFunctionLike(n.parent)) {
|
|
154
|
+
return functionSpan(n.parent, n, sourceFile);
|
|
155
|
+
}
|
|
156
|
+
// Check if the block is standalone, or 'attached' to some parent statement.
|
|
157
|
+
// If the latter, we want to collapse the block, but consider its hint span
|
|
158
|
+
// to be the entire span of the parent.
|
|
159
|
+
switch (n.parent.kind) {
|
|
160
|
+
case SyntaxKind.DoStatement:
|
|
161
|
+
case SyntaxKind.ForInStatement:
|
|
162
|
+
case SyntaxKind.ForOfStatement:
|
|
163
|
+
case SyntaxKind.ForStatement:
|
|
164
|
+
case SyntaxKind.IfStatement:
|
|
165
|
+
case SyntaxKind.WhileStatement:
|
|
166
|
+
// Na tag, também o `with` (CK-02).
|
|
167
|
+
case SyntaxKind.CatchClause:
|
|
168
|
+
return spanForNode(n.parent);
|
|
169
|
+
case SyntaxKind.TryStatement:
|
|
170
|
+
// Could be the try-block, or the finally-block.
|
|
171
|
+
const tryStatement = n.parent;
|
|
172
|
+
if (tryStatement.tryBlock === n) {
|
|
173
|
+
return spanForNode(n.parent);
|
|
174
|
+
}
|
|
175
|
+
else if (tryStatement.finallyBlock === n) {
|
|
176
|
+
const node = findChildOfKind(tryStatement, SyntaxKind.FinallyKeyword, sourceFile);
|
|
177
|
+
if (node)
|
|
178
|
+
return spanForNode(node);
|
|
179
|
+
}
|
|
180
|
+
// falls through
|
|
181
|
+
default:
|
|
182
|
+
// Block was a standalone block. In this case we want to only collapse
|
|
183
|
+
// the span of the block, independent of any parent span.
|
|
184
|
+
return createOutliningSpan(createTextSpanFromNode(n, sourceFile), "code" /* OutliningSpanKind.Code */);
|
|
185
|
+
}
|
|
186
|
+
case SyntaxKind.ModuleBlock:
|
|
187
|
+
return spanForNode(n.parent);
|
|
188
|
+
// Na tag, também a classe, a class expression, a interface e o enum (CK-02).
|
|
189
|
+
case SyntaxKind.CaseBlock:
|
|
190
|
+
case SyntaxKind.TypeLiteral:
|
|
191
|
+
return spanForNode(n);
|
|
192
|
+
case SyntaxKind.CaseClause:
|
|
193
|
+
case SyntaxKind.DefaultClause:
|
|
194
|
+
return spanForNodeArray(n.statements);
|
|
195
|
+
case SyntaxKind.ObjectLiteralExpression:
|
|
196
|
+
return spanForObjectOrArrayLiteral(n);
|
|
197
|
+
case SyntaxKind.ArrayLiteralExpression:
|
|
198
|
+
return spanForObjectOrArrayLiteral(n, SyntaxKind.OpenBracketToken);
|
|
199
|
+
case SyntaxKind.JsxElement:
|
|
200
|
+
return spanForJSXElement(n);
|
|
201
|
+
case SyntaxKind.JsxFragment:
|
|
202
|
+
return spanForJSXFragment(n);
|
|
203
|
+
case SyntaxKind.JsxSelfClosingElement:
|
|
204
|
+
case SyntaxKind.JsxOpeningElement:
|
|
205
|
+
return spanForJSXAttributes(n.attributes);
|
|
206
|
+
case SyntaxKind.TemplateExpression:
|
|
207
|
+
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
|
208
|
+
return spanForTemplateLiteral(n);
|
|
209
|
+
}
|
|
210
|
+
function spanForJSXElement(node) {
|
|
211
|
+
const textSpan = createTextSpanFromBounds(node.openingElement.getStart(sourceFile), node.closingElement.getEnd());
|
|
212
|
+
const tagName = node.openingElement.tagName.getText(sourceFile);
|
|
213
|
+
const bannerText = "<" + tagName + ">...</" + tagName + ">";
|
|
214
|
+
return createOutliningSpan(textSpan, "code" /* OutliningSpanKind.Code */, textSpan, /*autoCollapse*/ false, bannerText);
|
|
215
|
+
}
|
|
216
|
+
function spanForJSXFragment(node) {
|
|
217
|
+
const textSpan = createTextSpanFromBounds(node.openingFragment.getStart(sourceFile), node.closingFragment.getEnd());
|
|
218
|
+
const bannerText = "<>...</>";
|
|
219
|
+
return createOutliningSpan(textSpan, "code" /* OutliningSpanKind.Code */, textSpan, /*autoCollapse*/ false, bannerText);
|
|
220
|
+
}
|
|
221
|
+
function spanForJSXAttributes(node) {
|
|
222
|
+
if (node.properties.length === 0) {
|
|
223
|
+
return undefined;
|
|
224
|
+
}
|
|
225
|
+
return createOutliningSpanFromBounds(node.getStart(sourceFile), node.getEnd(), "code" /* OutliningSpanKind.Code */);
|
|
226
|
+
}
|
|
227
|
+
function spanForTemplateLiteral(node) {
|
|
228
|
+
if (node.kind === SyntaxKind.NoSubstitutionTemplateLiteral && node.text.length === 0) {
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
return createOutliningSpanFromBounds(node.getStart(sourceFile), node.getEnd(), "code" /* OutliningSpanKind.Code */);
|
|
232
|
+
}
|
|
233
|
+
function spanForObjectOrArrayLiteral(node, open = SyntaxKind.OpenBraceToken) {
|
|
234
|
+
// If the block has no leading keywords and is inside an array literal or call expression,
|
|
235
|
+
// we only want to collapse the span of the block.
|
|
236
|
+
// Otherwise, the collapsed section will include the end of the previous line.
|
|
237
|
+
return spanForNode(node, /*autoCollapse*/ false, /*useFullStart*/ !isArrayLiteralExpression(node.parent) && !isCallExpression(node.parent), open);
|
|
238
|
+
}
|
|
239
|
+
function spanForNode(hintSpanNode, autoCollapse = false, useFullStart = true, open = SyntaxKind.OpenBraceToken, close = open === SyntaxKind.OpenBraceToken ? SyntaxKind.CloseBraceToken : SyntaxKind.CloseBracketToken) {
|
|
240
|
+
const openToken = findChildOfKind(n, open, sourceFile);
|
|
241
|
+
const closeToken = findChildOfKind(n, close, sourceFile);
|
|
242
|
+
return openToken && closeToken && spanBetweenTokens(openToken, closeToken, hintSpanNode, sourceFile, autoCollapse, useFullStart);
|
|
243
|
+
}
|
|
244
|
+
function spanForNodeArray(nodeArray) {
|
|
245
|
+
return nodeArray.length ? createOutliningSpan(createTextSpanFromRange(nodeArray), "code" /* OutliningSpanKind.Code */) : undefined;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
function functionSpan(node, body, sourceFile) {
|
|
249
|
+
const openToken = isNodeArrayMultiLine(node.parameters, sourceFile)
|
|
250
|
+
? findChildOfKind(node, SyntaxKind.OpenParenToken, sourceFile)
|
|
251
|
+
: findChildOfKind(body, SyntaxKind.OpenBraceToken, sourceFile);
|
|
252
|
+
const closeToken = findChildOfKind(body, SyntaxKind.CloseBraceToken, sourceFile);
|
|
253
|
+
return openToken && closeToken && spanBetweenTokens(openToken, closeToken, node, sourceFile, /*autoCollapse*/ node.kind !== SyntaxKind.ArrowFunction);
|
|
254
|
+
}
|
|
255
|
+
function spanBetweenTokens(openToken, closeToken, hintSpanNode, sourceFile, autoCollapse = false, useFullStart = true) {
|
|
256
|
+
const textSpan = createTextSpanFromBounds(useFullStart ? openToken.getFullStart() : openToken.getStart(sourceFile), closeToken.getEnd());
|
|
257
|
+
return createOutliningSpan(textSpan, "code" /* OutliningSpanKind.Code */, createTextSpanFromNode(hintSpanNode, sourceFile), autoCollapse);
|
|
258
|
+
}
|
|
259
|
+
function createOutliningSpan(textSpan, kind, hintSpan = textSpan, autoCollapse = false, bannerText = "...") {
|
|
260
|
+
return { textSpan, kind, hintSpan, bannerText, autoCollapse };
|
|
261
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ApplicableRefactorInfo, Refactor, RefactorContext, RefactorEditInfo } from "./_namespaces/edit.js";
|
|
2
|
+
/** @param name An unique code associated with each refactor. Does not have to be human-readable. */
|
|
3
|
+
export declare function registerRefactor(name: string, refactor: Refactor): void;
|
|
4
|
+
export declare function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[];
|
|
5
|
+
export declare function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string): RefactorEditInfo | undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Modificado de microsoft/TypeScript v3.9.10, src/services/refactorProvider.ts: o namespace virou módulo ES, com os imports explícitos.
|
|
2
|
+
import { arrayFrom, createMap, flatMapIterator, } from "./_namespaces/edit.js";
|
|
3
|
+
// A map with the refactor code as key, the refactor itself as value
|
|
4
|
+
// e.g. nonSuggestableRefactors[refactorCode] -> the refactor you want
|
|
5
|
+
const refactors = createMap();
|
|
6
|
+
/** @param name An unique code associated with each refactor. Does not have to be human-readable. */
|
|
7
|
+
export function registerRefactor(name, refactor) {
|
|
8
|
+
refactors.set(name, refactor);
|
|
9
|
+
}
|
|
10
|
+
export function getApplicableRefactors(context) {
|
|
11
|
+
return arrayFrom(flatMapIterator(refactors.values(), refactor => context.cancellationToken && context.cancellationToken.isCancellationRequested() ? undefined : refactor.getAvailableActions(context)));
|
|
12
|
+
}
|
|
13
|
+
export function getEditsForRefactor(context, refactorName, actionName) {
|
|
14
|
+
const refactor = refactors.get(refactorName);
|
|
15
|
+
return refactor && refactor.getEditsForAction(context, actionName);
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// Modificado de microsoft/TypeScript v3.9.10, src/services/refactors/addOrRemoveBracesToArrowFunction.ts: o namespace virou módulo ES, com os imports explícitos.
|
|
2
|
+
import { Debug, Diagnostics, SyntaxKind, copyLeadingComments, copyTrailingAsLeadingComments, copyTrailingComments, createBlock, createIdentifier, createParen, createReturn, emptyArray, first, getContainingFunction, getTokenAtPosition, isArrowFunction, isExpression, isReturnStatement, needsParentheses, rangeContainsRange, suppressLeadingAndTrailingTrivia, textChanges, } from "../_namespaces/edit.js";
|
|
3
|
+
import { registerRefactor, } from "../_namespaces/ts.refactor.js";
|
|
4
|
+
const refactorName = "Add or remove braces in an arrow function";
|
|
5
|
+
const refactorDescription = Diagnostics.Add_or_remove_braces_in_an_arrow_function.message;
|
|
6
|
+
const addBracesActionName = "Add braces to arrow function";
|
|
7
|
+
const removeBracesActionName = "Remove braces from arrow function";
|
|
8
|
+
const addBracesActionDescription = Diagnostics.Add_braces_to_arrow_function.message;
|
|
9
|
+
const removeBracesActionDescription = Diagnostics.Remove_braces_from_arrow_function.message;
|
|
10
|
+
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
|
|
11
|
+
function getAvailableActions(context) {
|
|
12
|
+
const { file, startPosition } = context;
|
|
13
|
+
const info = getConvertibleArrowFunctionAtPosition(file, startPosition);
|
|
14
|
+
if (!info)
|
|
15
|
+
return emptyArray;
|
|
16
|
+
return [{
|
|
17
|
+
name: refactorName,
|
|
18
|
+
description: refactorDescription,
|
|
19
|
+
actions: [
|
|
20
|
+
info.addBraces ?
|
|
21
|
+
{
|
|
22
|
+
name: addBracesActionName,
|
|
23
|
+
description: addBracesActionDescription
|
|
24
|
+
} : {
|
|
25
|
+
name: removeBracesActionName,
|
|
26
|
+
description: removeBracesActionDescription
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}];
|
|
30
|
+
}
|
|
31
|
+
function getEditsForAction(context, actionName) {
|
|
32
|
+
const { file, startPosition } = context;
|
|
33
|
+
const info = getConvertibleArrowFunctionAtPosition(file, startPosition);
|
|
34
|
+
if (!info)
|
|
35
|
+
return undefined;
|
|
36
|
+
const { expression, returnStatement, func } = info;
|
|
37
|
+
let body;
|
|
38
|
+
if (actionName === addBracesActionName) {
|
|
39
|
+
const returnStatement = createReturn(expression);
|
|
40
|
+
body = createBlock([returnStatement], /* multiLine */ true);
|
|
41
|
+
suppressLeadingAndTrailingTrivia(body);
|
|
42
|
+
copyLeadingComments(expression, returnStatement, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ true);
|
|
43
|
+
}
|
|
44
|
+
else if (actionName === removeBracesActionName && returnStatement) {
|
|
45
|
+
// O corpo `{ return; }` vira o `undefined`, e não o `void 0` da tag: o operador `void` saiu da Linguagem
|
|
46
|
+
// (CK-63, CK-69).
|
|
47
|
+
const actualExpression = expression || createIdentifier("undefined");
|
|
48
|
+
body = needsParentheses(actualExpression) ? createParen(actualExpression) : actualExpression;
|
|
49
|
+
suppressLeadingAndTrailingTrivia(body);
|
|
50
|
+
copyTrailingAsLeadingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false);
|
|
51
|
+
copyLeadingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false);
|
|
52
|
+
copyTrailingComments(returnStatement, body, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ false);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
Debug.fail("invalid action");
|
|
56
|
+
}
|
|
57
|
+
const edits = textChanges.ChangeTracker.with(context, t => {
|
|
58
|
+
t.replaceNode(file, func.body, body);
|
|
59
|
+
});
|
|
60
|
+
return { renameFilename: undefined, renameLocation: undefined, edits };
|
|
61
|
+
}
|
|
62
|
+
function getConvertibleArrowFunctionAtPosition(file, startPosition) {
|
|
63
|
+
const node = getTokenAtPosition(file, startPosition);
|
|
64
|
+
const func = getContainingFunction(node);
|
|
65
|
+
if (!func || !isArrowFunction(func) || (!rangeContainsRange(func, node) || rangeContainsRange(func.body, node)))
|
|
66
|
+
return undefined;
|
|
67
|
+
if (isExpression(func.body)) {
|
|
68
|
+
return {
|
|
69
|
+
func,
|
|
70
|
+
addBraces: true,
|
|
71
|
+
expression: func.body
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
else if (func.body.statements.length === 1) {
|
|
75
|
+
const firstStatement = first(func.body.statements);
|
|
76
|
+
if (isReturnStatement(firstStatement)) {
|
|
77
|
+
return {
|
|
78
|
+
func,
|
|
79
|
+
addBraces: false,
|
|
80
|
+
expression: firstStatement.expression,
|
|
81
|
+
returnStatement: firstStatement
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|