@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,1981 @@
|
|
|
1
|
+
// Modificado de microsoft/TypeScript v3.9.10, src/services/utilities.ts: o namespace virou módulo ES, com os imports explícitos.
|
|
2
|
+
// O arquivo entra com o que os serviços que já vieram usam; o resto dele vem com o grupo que o usa (o docs/ARCHITECTURE.md
|
|
3
|
+
// do pacote). No fim, o que a leitura usa da edição e desceu para ela pela dependência (CK-67): o nome de um módulo como
|
|
4
|
+
// identificador, do `codefixes/importFixes.ts` da tag, e o comentário que cerca uma posição, do `formatting/formatting.ts`.
|
|
5
|
+
import { CharacterCodes, Debug, EmitFlags, InternalSymbolName, ModifierFlags, ModuleInstanceState, NodeFlags, ScriptTarget, SymbolAccessibility, SymbolDisplayPartKind, SymbolFlags, SymbolFormatFlags, SyntaxKind, TypeFormatFlags, addEmitFlags, addSyntheticLeadingComment, addSyntheticTrailingComment, cast, concatenate, contains, createBindingElement, createIdentifier, createImportClause, createImportDeclaration, createLiteral, createNamedImports, createRange, createScanner, createTextSpan, createTextSpanFromBounds, defaultMaximumTruncationLength, ensureScriptKind, find, findAncestor, findLast, firstDefined, forEachChild, forEachLeadingCommentRange, forEachTrailingCommentRange, getBaseFileName, getCombinedModifierFlags, getIndentString, getLeadingCommentRangesOfNode, getLastChild, getLineStarts, getModuleInstanceState, getNameOfDeclaration, getNodeId, getRootDeclaration, getSynthesizedClone, getSymbolId, getTextOfIdentifierOrLiteral, getTrailingCommentRanges, indexOfNode, isAmbientModule, isAnyImportSyntax, isArray, isArrayTypeNode, isAsExpression, isAwaitExpression, isBinaryExpression, isBindingElement, isCallExpression, isConditionalTypeNode, isDeclaration, isDeclarationName, isDeleteExpression, isElementAccessExpression, isExportAssignment, isExportDeclaration, isExportSpecifier, isExternalModule, isForInStatement, isForOfStatement, isFileLevelUniqueName, isFunctionLike, isIdentifier, isIdentifierPart, isIdentifierStart, isImportClause, isImportDeclaration, isImportOrExportSpecifier, isImportSpecifier, isInferTypeNode, isJsxElement, isJsxExpression, isJsxOpeningLikeElement, isJsxText, isKeyword, isLet, isLiteralTypeNode, isMappedTypeNode, isModifier, isModuleBlock, isModuleDeclaration, isNamedDeclaration, isNamedExports, isNamedImports, isNamespaceExport, isNamespaceImport, isNumericLiteral, isObjectLiteralExpression, isObjectBindingPattern, isOptionalChain, isOptionalChainRoot, isPartOfTypeNode, isPropertyAccessExpression, isPropertyNameLiteral, isRightSideOfQualifiedNameOrPropertyAccess, isSourceFile, isStringANonContextualKeyword, isStringDoubleQuoted, isStringLiteral, isStringOrNumericLiteralLike, isStringTextContainingNode, isSyntaxList, isTemplateLiteralKind, isToken, isTypeAliasDeclaration, isTypeNode, isTypeOfExpression, isTypeOperatorNode, isTypeParameterDeclaration, isTypeReferenceNode, isVarConst, isVariableDeclarationList, isWhiteSpaceLike, isWhiteSpaceSingleLine, last, lastOrUndefined, maybeBind, nodeIsMissing, nodeIsPresent, noop, notImplemented, nullTransformationContext, or, removeFileExtension, removeSuffix, setOriginalNode, setTextRange, singleOrUndefined, skipAlias, skipOuterExpressions, startsWith, stringToToken, stripQuotes, textSpanContainsPosition, textSpanEnd, tokenToString, tryCast, unescapeLeadingUnderscores, visitEachChild, } from "./_namespaces/ts.js";
|
|
6
|
+
// Os utilitários que mais de um serviço usa.
|
|
7
|
+
export const scanner = createScanner(ScriptTarget.Latest, /*skipTrivia*/ true);
|
|
8
|
+
export var SemanticMeaning;
|
|
9
|
+
(function (SemanticMeaning) {
|
|
10
|
+
SemanticMeaning[SemanticMeaning["None"] = 0] = "None";
|
|
11
|
+
SemanticMeaning[SemanticMeaning["Value"] = 1] = "Value";
|
|
12
|
+
SemanticMeaning[SemanticMeaning["Type"] = 2] = "Type";
|
|
13
|
+
SemanticMeaning[SemanticMeaning["Namespace"] = 4] = "Namespace";
|
|
14
|
+
SemanticMeaning[SemanticMeaning["All"] = 7] = "All";
|
|
15
|
+
})(SemanticMeaning || (SemanticMeaning = {}));
|
|
16
|
+
export function getMeaningFromDeclaration(node) {
|
|
17
|
+
switch (node.kind) {
|
|
18
|
+
case SyntaxKind.VariableDeclaration:
|
|
19
|
+
// Na tag, a variável de um arquivo JavaScript com a tag `@enum` do JSDoc era de todo significado (CK-03).
|
|
20
|
+
return 1 /* SemanticMeaning.Value */;
|
|
21
|
+
case SyntaxKind.Parameter:
|
|
22
|
+
case SyntaxKind.BindingElement:
|
|
23
|
+
case SyntaxKind.PropertySignature:
|
|
24
|
+
case SyntaxKind.PropertyAssignment:
|
|
25
|
+
case SyntaxKind.ShorthandPropertyAssignment:
|
|
26
|
+
case SyntaxKind.ArrowFunction:
|
|
27
|
+
case SyntaxKind.CatchClause:
|
|
28
|
+
case SyntaxKind.JsxAttribute:
|
|
29
|
+
return 1 /* SemanticMeaning.Value */;
|
|
30
|
+
case SyntaxKind.TypeParameter:
|
|
31
|
+
case SyntaxKind.TypeAliasDeclaration:
|
|
32
|
+
case SyntaxKind.TypeLiteral:
|
|
33
|
+
return 2 /* SemanticMeaning.Type */;
|
|
34
|
+
case SyntaxKind.ModuleDeclaration:
|
|
35
|
+
if (isAmbientModule(node)) {
|
|
36
|
+
return 4 /* SemanticMeaning.Namespace */ | 1 /* SemanticMeaning.Value */;
|
|
37
|
+
}
|
|
38
|
+
else if (getModuleInstanceState(node) === ModuleInstanceState.Instantiated) {
|
|
39
|
+
return 4 /* SemanticMeaning.Namespace */ | 1 /* SemanticMeaning.Value */;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
return 4 /* SemanticMeaning.Namespace */;
|
|
43
|
+
}
|
|
44
|
+
case SyntaxKind.NamedImports:
|
|
45
|
+
case SyntaxKind.ImportSpecifier:
|
|
46
|
+
case SyntaxKind.ImportDeclaration:
|
|
47
|
+
case SyntaxKind.ExportAssignment:
|
|
48
|
+
case SyntaxKind.ExportDeclaration:
|
|
49
|
+
return 7 /* SemanticMeaning.All */;
|
|
50
|
+
// An external module can be a Value
|
|
51
|
+
case SyntaxKind.SourceFile:
|
|
52
|
+
return 4 /* SemanticMeaning.Namespace */ | 1 /* SemanticMeaning.Value */;
|
|
53
|
+
}
|
|
54
|
+
return 7 /* SemanticMeaning.All */;
|
|
55
|
+
}
|
|
56
|
+
export function getMeaningFromLocation(node) {
|
|
57
|
+
node = getAdjustedReferenceLocation(node);
|
|
58
|
+
if (node.kind === SyntaxKind.SourceFile) {
|
|
59
|
+
return 1 /* SemanticMeaning.Value */;
|
|
60
|
+
}
|
|
61
|
+
else if (node.parent.kind === SyntaxKind.ExportAssignment
|
|
62
|
+
|| node.parent.kind === SyntaxKind.ImportSpecifier
|
|
63
|
+
|| node.parent.kind === SyntaxKind.ImportClause) {
|
|
64
|
+
return 7 /* SemanticMeaning.All */;
|
|
65
|
+
}
|
|
66
|
+
else if (isDeclarationName(node)) {
|
|
67
|
+
return getMeaningFromDeclaration(node.parent);
|
|
68
|
+
}
|
|
69
|
+
else if (isTypeReference(node)) {
|
|
70
|
+
return 2 /* SemanticMeaning.Type */;
|
|
71
|
+
}
|
|
72
|
+
else if (isNamespaceReference(node)) {
|
|
73
|
+
return 4 /* SemanticMeaning.Namespace */;
|
|
74
|
+
}
|
|
75
|
+
else if (isLiteralTypeNode(node.parent)) {
|
|
76
|
+
// This might be T["name"], which is actually referencing a property and not a type. So allow both meanings.
|
|
77
|
+
return 2 /* SemanticMeaning.Type */ | 1 /* SemanticMeaning.Value */;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return 1 /* SemanticMeaning.Value */;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Se o nome é a parte de fora de um nome qualificado num tipo (`A` em `A.B`). Na tag, também o de um acesso a propriedade
|
|
85
|
+
* no `implements` de uma classe ou no `extends` de uma interface (o `isPropertyAccessNamespaceReference`), que a Linguagem
|
|
86
|
+
* não tem (CK-02).
|
|
87
|
+
*/
|
|
88
|
+
function isNamespaceReference(node) {
|
|
89
|
+
return isQualifiedNameNamespaceReference(node);
|
|
90
|
+
}
|
|
91
|
+
function isQualifiedNameNamespaceReference(node) {
|
|
92
|
+
let root = node;
|
|
93
|
+
let isLastClause = true;
|
|
94
|
+
if (root.parent.kind === SyntaxKind.QualifiedName) {
|
|
95
|
+
while (root.parent && root.parent.kind === SyntaxKind.QualifiedName) {
|
|
96
|
+
root = root.parent;
|
|
97
|
+
}
|
|
98
|
+
isLastClause = root.right === node;
|
|
99
|
+
}
|
|
100
|
+
return root.parent.kind === SyntaxKind.TypeReference && !isLastClause;
|
|
101
|
+
}
|
|
102
|
+
function isTypeReference(node) {
|
|
103
|
+
if (isRightSideOfQualifiedNameOrPropertyAccess(node)) {
|
|
104
|
+
node = node.parent;
|
|
105
|
+
}
|
|
106
|
+
// Na tag, o `this` e o tipo `this` vinham antes (CK-02).
|
|
107
|
+
switch (node.parent.kind) {
|
|
108
|
+
case SyntaxKind.TypeReference:
|
|
109
|
+
return true;
|
|
110
|
+
case SyntaxKind.ImportType:
|
|
111
|
+
return !node.parent.isTypeOf;
|
|
112
|
+
}
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
export function isCallExpressionTarget(node, includeElementAccess = false, skipPastOuterExpressions = false) {
|
|
116
|
+
return isCalleeWorker(node, isCallExpression, selectExpressionOfCallOrNewExpressionOrDecorator, includeElementAccess, skipPastOuterExpressions);
|
|
117
|
+
}
|
|
118
|
+
function selectExpressionOfCallOrNewExpressionOrDecorator(node) {
|
|
119
|
+
return node.expression;
|
|
120
|
+
}
|
|
121
|
+
function isCalleeWorker(node, pred, calleeSelector, includeElementAccess, skipPastOuterExpressions) {
|
|
122
|
+
let target = includeElementAccess ? climbPastPropertyOrElementAccess(node) : climbPastPropertyAccess(node);
|
|
123
|
+
if (skipPastOuterExpressions) {
|
|
124
|
+
target = skipOuterExpressions(target);
|
|
125
|
+
}
|
|
126
|
+
return !!target && !!target.parent && pred(target.parent) && calleeSelector(target.parent) === target;
|
|
127
|
+
}
|
|
128
|
+
export function climbPastPropertyAccess(node) {
|
|
129
|
+
return isRightSideOfPropertyAccess(node) ? node.parent : node;
|
|
130
|
+
}
|
|
131
|
+
export function climbPastPropertyOrElementAccess(node) {
|
|
132
|
+
return isRightSideOfPropertyAccess(node) || isArgumentExpressionOfElementAccess(node) ? node.parent : node;
|
|
133
|
+
}
|
|
134
|
+
export function hasPropertyAccessExpressionWithName(node, funcName) {
|
|
135
|
+
if (!isPropertyAccessExpression(node.expression)) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
return node.expression.name.text === funcName;
|
|
139
|
+
}
|
|
140
|
+
export function isRightSideOfPropertyAccess(node) {
|
|
141
|
+
return tryCast(node.parent, isPropertyAccessExpression)?.name === node;
|
|
142
|
+
}
|
|
143
|
+
export function isArgumentExpressionOfElementAccess(node) {
|
|
144
|
+
return tryCast(node.parent, isElementAccessExpression)?.argumentExpression === node;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Se o literal é o nome de uma declaração ou a chave de um acesso. Na tag, também o de uma propriedade de classe, de um
|
|
148
|
+
* membro de enum, de um método e de um acessor (CK-02), o de uma method signature (CK-36), e o de um `declare module "x"`
|
|
149
|
+
* (CK-02).
|
|
150
|
+
*/
|
|
151
|
+
export function isLiteralNameOfPropertyDeclarationOrIndexAccess(node) {
|
|
152
|
+
switch (node.parent.kind) {
|
|
153
|
+
case SyntaxKind.PropertySignature:
|
|
154
|
+
case SyntaxKind.PropertyAssignment:
|
|
155
|
+
return getNameOfDeclaration(node.parent) === node;
|
|
156
|
+
case SyntaxKind.ElementAccessExpression:
|
|
157
|
+
return node.parent.argumentExpression === node;
|
|
158
|
+
case SyntaxKind.ComputedPropertyName:
|
|
159
|
+
return true;
|
|
160
|
+
case SyntaxKind.LiteralType:
|
|
161
|
+
return node.parent.parent.kind === SyntaxKind.IndexedAccessType;
|
|
162
|
+
default:
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* A declaração que contém o nó: o arquivo ou o namespace. Na tag, também o método, a `function`, o acessor, a classe, a
|
|
168
|
+
* interface e o enum (CK-02), a method signature (CK-36), e o escopo do typedef do JSDoc (CK-03).
|
|
169
|
+
*/
|
|
170
|
+
export function getContainerNode(node) {
|
|
171
|
+
while (true) {
|
|
172
|
+
node = node.parent;
|
|
173
|
+
if (!node) {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
switch (node.kind) {
|
|
177
|
+
case SyntaxKind.SourceFile:
|
|
178
|
+
case SyntaxKind.ModuleDeclaration:
|
|
179
|
+
return node;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* O tipo de elemento que o nó declara. Na tag, também a classe, a interface, o enum e o membro dele, a `function`, o
|
|
185
|
+
* acessor, o método, a construct signature, o construtor e a parameter property (CK-02), a method signature (CK-36), o
|
|
186
|
+
* typedef do JSDoc e o `import =` (CK-03), e a atribuição que declara: as do JavaScript (CK-03) e o expando (CK-38), que o
|
|
187
|
+
* binder da cópia não liga como declaração.
|
|
188
|
+
*/
|
|
189
|
+
export function getNodeKind(node) {
|
|
190
|
+
switch (node.kind) {
|
|
191
|
+
case SyntaxKind.SourceFile:
|
|
192
|
+
return isExternalModule(node) ? "module" /* ScriptElementKind.moduleElement */ : "script" /* ScriptElementKind.scriptElement */;
|
|
193
|
+
case SyntaxKind.ModuleDeclaration:
|
|
194
|
+
return "module" /* ScriptElementKind.moduleElement */;
|
|
195
|
+
case SyntaxKind.TypeAliasDeclaration:
|
|
196
|
+
return "type" /* ScriptElementKind.typeElement */;
|
|
197
|
+
case SyntaxKind.VariableDeclaration:
|
|
198
|
+
return getKindOfVariableDeclaration(node);
|
|
199
|
+
case SyntaxKind.BindingElement:
|
|
200
|
+
return getKindOfVariableDeclaration(getRootDeclaration(node));
|
|
201
|
+
case SyntaxKind.ArrowFunction:
|
|
202
|
+
return "function" /* ScriptElementKind.functionElement */;
|
|
203
|
+
case SyntaxKind.PropertyAssignment:
|
|
204
|
+
const { initializer } = node;
|
|
205
|
+
return isFunctionLike(initializer) ? "method" /* ScriptElementKind.memberFunctionElement */ : "property" /* ScriptElementKind.memberVariableElement */;
|
|
206
|
+
case SyntaxKind.PropertySignature:
|
|
207
|
+
case SyntaxKind.ShorthandPropertyAssignment:
|
|
208
|
+
case SyntaxKind.SpreadAssignment:
|
|
209
|
+
return "property" /* ScriptElementKind.memberVariableElement */;
|
|
210
|
+
case SyntaxKind.IndexSignature: return "index" /* ScriptElementKind.indexSignatureElement */;
|
|
211
|
+
case SyntaxKind.CallSignature: return "call" /* ScriptElementKind.callSignatureElement */;
|
|
212
|
+
case SyntaxKind.TypeParameter: return "type parameter" /* ScriptElementKind.typeParameterElement */;
|
|
213
|
+
case SyntaxKind.Parameter: return "parameter" /* ScriptElementKind.parameterElement */;
|
|
214
|
+
case SyntaxKind.ImportSpecifier:
|
|
215
|
+
case SyntaxKind.ExportSpecifier:
|
|
216
|
+
case SyntaxKind.NamespaceImport:
|
|
217
|
+
case SyntaxKind.NamespaceExport:
|
|
218
|
+
return "alias" /* ScriptElementKind.alias */;
|
|
219
|
+
case SyntaxKind.Identifier:
|
|
220
|
+
return isImportClause(node.parent) ? "alias" /* ScriptElementKind.alias */ : "" /* ScriptElementKind.unknown */;
|
|
221
|
+
case SyntaxKind.ExportAssignment:
|
|
222
|
+
const scriptKind = getNodeKind(node.expression);
|
|
223
|
+
// If the expression didn't come back with something (like it does for an identifiers)
|
|
224
|
+
return scriptKind === "" /* ScriptElementKind.unknown */ ? "const" /* ScriptElementKind.constElement */ : scriptKind;
|
|
225
|
+
default:
|
|
226
|
+
return "" /* ScriptElementKind.unknown */;
|
|
227
|
+
}
|
|
228
|
+
function getKindOfVariableDeclaration(v) {
|
|
229
|
+
return isVarConst(v)
|
|
230
|
+
? "const" /* ScriptElementKind.constElement */
|
|
231
|
+
: isLet(v)
|
|
232
|
+
? "let" /* ScriptElementKind.letElement */
|
|
233
|
+
: "var" /* ScriptElementKind.variableElement */;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Matches the beginning of a triple slash directive
|
|
237
|
+
const tripleSlashDirectivePrefixRegex = /^\/\/\/\s*</;
|
|
238
|
+
export function getLineStartPositionForPosition(position, sourceFile) {
|
|
239
|
+
const lineStarts = getLineStarts(sourceFile);
|
|
240
|
+
const line = sourceFile.getLineAndCharacterOfPosition(position).line;
|
|
241
|
+
return lineStarts[line];
|
|
242
|
+
}
|
|
243
|
+
export function rangeContainsRange(r1, r2) {
|
|
244
|
+
return startEndContainsRange(r1.pos, r1.end, r2);
|
|
245
|
+
}
|
|
246
|
+
export function rangeContainsRangeExclusive(r1, r2) {
|
|
247
|
+
return rangeContainsPositionExclusive(r1, r2.pos) && rangeContainsPositionExclusive(r1, r2.end);
|
|
248
|
+
}
|
|
249
|
+
export function rangeContainsPositionExclusive(r, pos) {
|
|
250
|
+
return r.pos < pos && pos < r.end;
|
|
251
|
+
}
|
|
252
|
+
export function startEndContainsRange(start, end, range) {
|
|
253
|
+
return start <= range.pos && end >= range.end;
|
|
254
|
+
}
|
|
255
|
+
export function rangeContainsStartEnd(range, start, end) {
|
|
256
|
+
return range.pos <= start && range.end >= end;
|
|
257
|
+
}
|
|
258
|
+
export function rangeOverlapsWithStartEnd(r1, start, end) {
|
|
259
|
+
return startEndOverlapsWithStartEnd(r1.pos, r1.end, start, end);
|
|
260
|
+
}
|
|
261
|
+
export function startEndOverlapsWithStartEnd(start1, end1, start2, end2) {
|
|
262
|
+
const start = Math.max(start1, start2);
|
|
263
|
+
const end = Math.min(end1, end2);
|
|
264
|
+
return start < end;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Assumes `candidate.start <= position` holds.
|
|
268
|
+
*/
|
|
269
|
+
export function positionBelongsToNode(candidate, position, sourceFile) {
|
|
270
|
+
Debug.assert(candidate.pos <= position);
|
|
271
|
+
return position < candidate.end || !isCompletedNode(candidate, sourceFile);
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Se o nó já está fechado no texto, para que a posição logo depois dele não pertença mais a ele. Na tag, também os nós
|
|
275
|
+
* que a parse tree não tem: a classe, a interface, o enum, o `new`, o construtor e o tipo construtor, o acessor, a
|
|
276
|
+
* `function`, o método, a construct signature, o `yield` e o template marcado (CK-02), a method signature (CK-36) e o
|
|
277
|
+
* operador `void` (CK-63).
|
|
278
|
+
*/
|
|
279
|
+
function isCompletedNode(n, sourceFile) {
|
|
280
|
+
if (n === undefined || nodeIsMissing(n)) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
switch (n.kind) {
|
|
284
|
+
case SyntaxKind.ObjectLiteralExpression:
|
|
285
|
+
case SyntaxKind.ObjectBindingPattern:
|
|
286
|
+
case SyntaxKind.TypeLiteral:
|
|
287
|
+
case SyntaxKind.Block:
|
|
288
|
+
case SyntaxKind.ModuleBlock:
|
|
289
|
+
case SyntaxKind.CaseBlock:
|
|
290
|
+
case SyntaxKind.NamedImports:
|
|
291
|
+
case SyntaxKind.NamedExports:
|
|
292
|
+
return nodeEndsWith(n, SyntaxKind.CloseBraceToken, sourceFile);
|
|
293
|
+
case SyntaxKind.CatchClause:
|
|
294
|
+
return isCompletedNode(n.block, sourceFile);
|
|
295
|
+
case SyntaxKind.CallExpression:
|
|
296
|
+
case SyntaxKind.ParenthesizedExpression:
|
|
297
|
+
case SyntaxKind.ParenthesizedType:
|
|
298
|
+
return nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile);
|
|
299
|
+
case SyntaxKind.FunctionType:
|
|
300
|
+
return isCompletedNode(n.type, sourceFile);
|
|
301
|
+
case SyntaxKind.CallSignature:
|
|
302
|
+
case SyntaxKind.ArrowFunction:
|
|
303
|
+
if (n.body) {
|
|
304
|
+
return isCompletedNode(n.body, sourceFile);
|
|
305
|
+
}
|
|
306
|
+
if (n.type) {
|
|
307
|
+
return isCompletedNode(n.type, sourceFile);
|
|
308
|
+
}
|
|
309
|
+
// Even though type parameters can be unclosed, we can get away with
|
|
310
|
+
// having at least a closing paren.
|
|
311
|
+
return hasChildOfKind(n, SyntaxKind.CloseParenToken, sourceFile);
|
|
312
|
+
case SyntaxKind.ModuleDeclaration:
|
|
313
|
+
return !!n.body && isCompletedNode(n.body, sourceFile);
|
|
314
|
+
case SyntaxKind.IfStatement:
|
|
315
|
+
if (n.elseStatement) {
|
|
316
|
+
return isCompletedNode(n.elseStatement, sourceFile);
|
|
317
|
+
}
|
|
318
|
+
return isCompletedNode(n.thenStatement, sourceFile);
|
|
319
|
+
case SyntaxKind.ExpressionStatement:
|
|
320
|
+
return isCompletedNode(n.expression, sourceFile) ||
|
|
321
|
+
hasChildOfKind(n, SyntaxKind.SemicolonToken, sourceFile);
|
|
322
|
+
case SyntaxKind.ArrayLiteralExpression:
|
|
323
|
+
case SyntaxKind.ArrayBindingPattern:
|
|
324
|
+
case SyntaxKind.ElementAccessExpression:
|
|
325
|
+
case SyntaxKind.ComputedPropertyName:
|
|
326
|
+
case SyntaxKind.TupleType:
|
|
327
|
+
return nodeEndsWith(n, SyntaxKind.CloseBracketToken, sourceFile);
|
|
328
|
+
case SyntaxKind.IndexSignature:
|
|
329
|
+
if (n.type) {
|
|
330
|
+
return isCompletedNode(n.type, sourceFile);
|
|
331
|
+
}
|
|
332
|
+
return hasChildOfKind(n, SyntaxKind.CloseBracketToken, sourceFile);
|
|
333
|
+
case SyntaxKind.CaseClause:
|
|
334
|
+
case SyntaxKind.DefaultClause:
|
|
335
|
+
// there is no such thing as terminator token for CaseClause/DefaultClause so for simplicity always consider them non-completed
|
|
336
|
+
return false;
|
|
337
|
+
case SyntaxKind.ForStatement:
|
|
338
|
+
case SyntaxKind.ForInStatement:
|
|
339
|
+
case SyntaxKind.ForOfStatement:
|
|
340
|
+
case SyntaxKind.WhileStatement:
|
|
341
|
+
return isCompletedNode(n.statement, sourceFile);
|
|
342
|
+
case SyntaxKind.DoStatement:
|
|
343
|
+
// rough approximation: if DoStatement has While keyword - then if node is completed is checking the presence of ')';
|
|
344
|
+
return hasChildOfKind(n, SyntaxKind.WhileKeyword, sourceFile)
|
|
345
|
+
? nodeEndsWith(n, SyntaxKind.CloseParenToken, sourceFile)
|
|
346
|
+
: isCompletedNode(n.statement, sourceFile);
|
|
347
|
+
case SyntaxKind.TypeQuery:
|
|
348
|
+
return isCompletedNode(n.exprName, sourceFile);
|
|
349
|
+
case SyntaxKind.TypeOfExpression:
|
|
350
|
+
case SyntaxKind.DeleteExpression:
|
|
351
|
+
case SyntaxKind.SpreadElement:
|
|
352
|
+
const unaryWordExpression = n;
|
|
353
|
+
return isCompletedNode(unaryWordExpression.expression, sourceFile);
|
|
354
|
+
case SyntaxKind.TemplateExpression:
|
|
355
|
+
const lastSpan = lastOrUndefined(n.templateSpans);
|
|
356
|
+
return isCompletedNode(lastSpan, sourceFile);
|
|
357
|
+
case SyntaxKind.TemplateSpan:
|
|
358
|
+
return nodeIsPresent(n.literal);
|
|
359
|
+
case SyntaxKind.ExportDeclaration:
|
|
360
|
+
case SyntaxKind.ImportDeclaration:
|
|
361
|
+
return nodeIsPresent(n.moduleSpecifier);
|
|
362
|
+
case SyntaxKind.PrefixUnaryExpression:
|
|
363
|
+
return isCompletedNode(n.operand, sourceFile);
|
|
364
|
+
case SyntaxKind.BinaryExpression:
|
|
365
|
+
return isCompletedNode(n.right, sourceFile);
|
|
366
|
+
case SyntaxKind.ConditionalExpression:
|
|
367
|
+
return isCompletedNode(n.whenFalse, sourceFile);
|
|
368
|
+
default:
|
|
369
|
+
return true;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
/*
|
|
373
|
+
* Checks if node ends with 'expectedLastToken'.
|
|
374
|
+
* If child at position 'length - 1' is 'SemicolonToken' it is skipped and 'expectedLastToken' is compared with child at position 'length - 2'.
|
|
375
|
+
*/
|
|
376
|
+
function nodeEndsWith(n, expectedLastToken, sourceFile) {
|
|
377
|
+
const children = n.getChildren(sourceFile);
|
|
378
|
+
if (children.length) {
|
|
379
|
+
const lastChild = last(children);
|
|
380
|
+
if (lastChild.kind === expectedLastToken) {
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
else if (lastChild.kind === SyntaxKind.SemicolonToken && children.length !== 1) {
|
|
384
|
+
return children[children.length - 2].kind === expectedLastToken;
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
return false;
|
|
388
|
+
}
|
|
389
|
+
export function findListItemInfo(node) {
|
|
390
|
+
const list = findContainingList(node);
|
|
391
|
+
// It is possible at this point for syntaxList to be undefined, either if
|
|
392
|
+
// node.parent had no list child, or if none of its list children contained
|
|
393
|
+
// the span of node. If this happens, return undefined. The caller should
|
|
394
|
+
// handle this case.
|
|
395
|
+
if (!list) {
|
|
396
|
+
return undefined;
|
|
397
|
+
}
|
|
398
|
+
const children = list.getChildren();
|
|
399
|
+
const listItemIndex = indexOfNode(children, node);
|
|
400
|
+
return {
|
|
401
|
+
listItemIndex,
|
|
402
|
+
list
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
export function hasChildOfKind(n, kind, sourceFile) {
|
|
406
|
+
return !!findChildOfKind(n, kind, sourceFile);
|
|
407
|
+
}
|
|
408
|
+
export function findChildOfKind(n, kind, sourceFile) {
|
|
409
|
+
return find(n.getChildren(sourceFile), (c) => c.kind === kind);
|
|
410
|
+
}
|
|
411
|
+
export function findContainingList(node) {
|
|
412
|
+
// The node might be a list element (nonsynthetic) or a comma (synthetic). Either way, it will
|
|
413
|
+
// be parented by the container of the SyntaxList, not the SyntaxList itself.
|
|
414
|
+
// In order to find the list item index, we first need to locate SyntaxList itself and then search
|
|
415
|
+
// for the position of the relevant node (or comma).
|
|
416
|
+
const syntaxList = find(node.parent.getChildren(), (c) => isSyntaxList(c) && rangeContainsRange(c, node));
|
|
417
|
+
// Either we didn't find an appropriate list, or the list must contain us.
|
|
418
|
+
Debug.assert(!syntaxList || contains(syntaxList.getChildren(), node));
|
|
419
|
+
return syntaxList;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* O nome de uma declaração. Na tag, fora do rename, a classe e a `function` sem nome davam o modificador `default` ou a
|
|
423
|
+
* palavra-chave delas (CK-02).
|
|
424
|
+
*/
|
|
425
|
+
function getAdjustedLocationForDeclaration(node) {
|
|
426
|
+
if (isNamedDeclaration(node)) {
|
|
427
|
+
return node.name;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function getAdjustedLocationForImportDeclaration(node, forRename) {
|
|
431
|
+
if (node.importClause) {
|
|
432
|
+
if (node.importClause.name && node.importClause.namedBindings) {
|
|
433
|
+
// do not adjust if we have both a name and named bindings
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
// /**/import [|name|] from ...;
|
|
437
|
+
// import /**/type [|name|] from ...;
|
|
438
|
+
if (node.importClause.name) {
|
|
439
|
+
return node.importClause.name;
|
|
440
|
+
}
|
|
441
|
+
// /**/import { [|name|] } from ...;
|
|
442
|
+
// /**/import { propertyName as [|name|] } from ...;
|
|
443
|
+
// /**/import * as [|name|] from ...;
|
|
444
|
+
// import /**/type { [|name|] } from ...;
|
|
445
|
+
// import /**/type { propertyName as [|name|] } from ...;
|
|
446
|
+
// import /**/type * as [|name|] from ...;
|
|
447
|
+
if (node.importClause.namedBindings) {
|
|
448
|
+
if (isNamedImports(node.importClause.namedBindings)) {
|
|
449
|
+
// do nothing if there is more than one binding
|
|
450
|
+
const onlyBinding = singleOrUndefined(node.importClause.namedBindings.elements);
|
|
451
|
+
if (!onlyBinding) {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
return onlyBinding.name;
|
|
455
|
+
}
|
|
456
|
+
else if (isNamespaceImport(node.importClause.namedBindings)) {
|
|
457
|
+
return node.importClause.namedBindings.name;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (!forRename) {
|
|
462
|
+
// /**/import "[|module|]";
|
|
463
|
+
// /**/import ... from "[|module|]";
|
|
464
|
+
// import /**/type ... from "[|module|]";
|
|
465
|
+
return node.moduleSpecifier;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
function getAdjustedLocationForExportDeclaration(node, forRename) {
|
|
469
|
+
if (node.exportClause) {
|
|
470
|
+
// /**/export { [|name|] } ...
|
|
471
|
+
// /**/export { propertyName as [|name|] } ...
|
|
472
|
+
// /**/export * as [|name|] ...
|
|
473
|
+
// export /**/type { [|name|] } from ...
|
|
474
|
+
// export /**/type { propertyName as [|name|] } from ...
|
|
475
|
+
// export /**/type * as [|name|] ...
|
|
476
|
+
if (isNamedExports(node.exportClause)) {
|
|
477
|
+
// do nothing if there is more than one binding
|
|
478
|
+
const onlyBinding = singleOrUndefined(node.exportClause.elements);
|
|
479
|
+
if (!onlyBinding) {
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
return node.exportClause.elements[0].name;
|
|
483
|
+
}
|
|
484
|
+
else if (isNamespaceExport(node.exportClause)) {
|
|
485
|
+
return node.exportClause.name;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
if (!forRename) {
|
|
489
|
+
// /**/export * from "[|module|]";
|
|
490
|
+
// export /**/type * from "[|module|]";
|
|
491
|
+
return node.moduleSpecifier;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
function getAdjustedLocation(node, forRename) {
|
|
495
|
+
const { parent } = node;
|
|
496
|
+
// /**/<modifier> [|name|] ...
|
|
497
|
+
// /**/<modifier> <type|namespace> [|name|] ...
|
|
498
|
+
// /**/<type|namespace> [|name|] ...
|
|
499
|
+
//
|
|
500
|
+
// Na tag, também a palavra da classe, da interface, do enum, da `function`, do acessor e do `module` (CK-02, CK-56) e a
|
|
501
|
+
// do `import =` (CK-03). E, fora do rename, a tag não ajustava o modificador `default`; a cópia não o tem: ele só
|
|
502
|
+
// existia diante da `function` e da classe, e o `export default` que fica é de expressão (CK-46).
|
|
503
|
+
if (isModifier(node) ? contains(parent.modifiers, node) :
|
|
504
|
+
node.kind === SyntaxKind.TypeKeyword ? isTypeAliasDeclaration(parent) :
|
|
505
|
+
node.kind === SyntaxKind.NamespaceKeyword ? isModuleDeclaration(parent) :
|
|
506
|
+
false) {
|
|
507
|
+
const location = getAdjustedLocationForDeclaration(parent);
|
|
508
|
+
if (location) {
|
|
509
|
+
return location;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
// /**/<let|const> [|name|] ...
|
|
513
|
+
// Na tag, também o `var` (CK-54).
|
|
514
|
+
if ((node.kind === SyntaxKind.ConstKeyword || node.kind === SyntaxKind.LetKeyword) &&
|
|
515
|
+
isVariableDeclarationList(parent) && parent.declarations.length === 1) {
|
|
516
|
+
const decl = parent.declarations[0];
|
|
517
|
+
if (isIdentifier(decl.name)) {
|
|
518
|
+
return decl.name;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
if (node.kind === SyntaxKind.TypeKeyword) {
|
|
522
|
+
// import /**/type [|name|] from ...;
|
|
523
|
+
// import /**/type { [|name|] } from ...;
|
|
524
|
+
// import /**/type { propertyName as [|name|] } from ...;
|
|
525
|
+
// import /**/type ... from "[|module|]";
|
|
526
|
+
if (isImportClause(parent) && parent.isTypeOnly) {
|
|
527
|
+
const location = getAdjustedLocationForImportDeclaration(parent.parent, forRename);
|
|
528
|
+
if (location) {
|
|
529
|
+
return location;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
// export /**/type { [|name|] } from ...;
|
|
533
|
+
// export /**/type { propertyName as [|name|] } from ...;
|
|
534
|
+
// export /**/type * from "[|module|]";
|
|
535
|
+
// export /**/type * as ... from "[|module|]";
|
|
536
|
+
if (isExportDeclaration(parent) && parent.isTypeOnly) {
|
|
537
|
+
const location = getAdjustedLocationForExportDeclaration(parent, forRename);
|
|
538
|
+
if (location) {
|
|
539
|
+
return location;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// import { propertyName /**/as [|name|] } ...
|
|
544
|
+
// import * /**/as [|name|] ...
|
|
545
|
+
// export { propertyName /**/as [|name|] } ...
|
|
546
|
+
// export * /**/as [|name|] ...
|
|
547
|
+
if (node.kind === SyntaxKind.AsKeyword) {
|
|
548
|
+
if (isImportSpecifier(parent) && parent.propertyName ||
|
|
549
|
+
isExportSpecifier(parent) && parent.propertyName ||
|
|
550
|
+
isNamespaceImport(parent) ||
|
|
551
|
+
isNamespaceExport(parent)) {
|
|
552
|
+
return parent.name;
|
|
553
|
+
}
|
|
554
|
+
if (isExportDeclaration(parent) && parent.exportClause && isNamespaceExport(parent.exportClause)) {
|
|
555
|
+
return parent.exportClause.name;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
// /**/import [|name|] from ...;
|
|
559
|
+
// /**/import { [|name|] } from ...;
|
|
560
|
+
// /**/import { propertyName as [|name|] } from ...;
|
|
561
|
+
// /**/import ... from "[|module|]";
|
|
562
|
+
// /**/import "[|module|]";
|
|
563
|
+
if (node.kind === SyntaxKind.ImportKeyword && isImportDeclaration(parent)) {
|
|
564
|
+
const location = getAdjustedLocationForImportDeclaration(parent, forRename);
|
|
565
|
+
if (location) {
|
|
566
|
+
return location;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (node.kind === SyntaxKind.ExportKeyword) {
|
|
570
|
+
// /**/export { [|name|] } ...;
|
|
571
|
+
// /**/export { propertyName as [|name|] } ...;
|
|
572
|
+
// /**/export * from "[|module|]";
|
|
573
|
+
// /**/export * as ... from "[|module|]";
|
|
574
|
+
if (isExportDeclaration(parent)) {
|
|
575
|
+
const location = getAdjustedLocationForExportDeclaration(parent, forRename);
|
|
576
|
+
if (location) {
|
|
577
|
+
return location;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
// NOTE: We don't adjust the location of the `default` keyword as that is handled specially by `getSymbolAtLocation`.
|
|
581
|
+
// /**/export default [|name|];
|
|
582
|
+
// /**/export = [|name|];
|
|
583
|
+
if (isExportAssignment(parent)) {
|
|
584
|
+
return skipOuterExpressions(parent.expression);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
// import ... /**/from "[|module|]";
|
|
588
|
+
// export ... /**/from "[|module|]";
|
|
589
|
+
if (node.kind === SyntaxKind.FromKeyword && (isImportDeclaration(parent) || isExportDeclaration(parent)) && parent.moduleSpecifier) {
|
|
590
|
+
return parent.moduleSpecifier;
|
|
591
|
+
}
|
|
592
|
+
// Na tag, também o `require` do `import =` e o `extends` e o `implements` de classe e de interface (CK-02, CK-03).
|
|
593
|
+
if (node.kind === SyntaxKind.ExtendsKeyword) {
|
|
594
|
+
// ... <T /**/extends [|U|]> ...
|
|
595
|
+
if (isTypeParameterDeclaration(parent) && parent.constraint && isTypeReferenceNode(parent.constraint)) {
|
|
596
|
+
return parent.constraint.typeName;
|
|
597
|
+
}
|
|
598
|
+
// ... T /**/extends [|U|] ? ...
|
|
599
|
+
if (isConditionalTypeNode(parent) && isTypeReferenceNode(parent.extendsType)) {
|
|
600
|
+
return parent.extendsType.typeName;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
// ... T extends /**/infer [|U|] ? ...
|
|
604
|
+
if (node.kind === SyntaxKind.InferKeyword && isInferTypeNode(parent)) {
|
|
605
|
+
return parent.typeParameter.name;
|
|
606
|
+
}
|
|
607
|
+
// { [ [|K|] /**/in keyof T]: ... }
|
|
608
|
+
if (node.kind === SyntaxKind.InKeyword && isTypeParameterDeclaration(parent) && isMappedTypeNode(parent.parent)) {
|
|
609
|
+
return parent.name;
|
|
610
|
+
}
|
|
611
|
+
// /**/keyof [|T|]
|
|
612
|
+
if (node.kind === SyntaxKind.KeyOfKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.KeyOfKeyword &&
|
|
613
|
+
isTypeReferenceNode(parent.type)) {
|
|
614
|
+
return parent.type.typeName;
|
|
615
|
+
}
|
|
616
|
+
// /**/readonly [|name|][]
|
|
617
|
+
if (node.kind === SyntaxKind.ReadonlyKeyword && isTypeOperatorNode(parent) && parent.operator === SyntaxKind.ReadonlyKeyword &&
|
|
618
|
+
isArrayTypeNode(parent.type) && isTypeReferenceNode(parent.type.elementType)) {
|
|
619
|
+
return parent.type.elementType.typeName;
|
|
620
|
+
}
|
|
621
|
+
if (!forRename) {
|
|
622
|
+
// /**/typeof [|name|]
|
|
623
|
+
// /**/typeof obj.[|name|]
|
|
624
|
+
// /**/await [|name|]
|
|
625
|
+
// /**/await obj.[|name|]
|
|
626
|
+
// /**/delete obj.[|name|]
|
|
627
|
+
// Na tag, também o `new`, o `void` e o `yield` (CK-02, CK-63).
|
|
628
|
+
if (node.kind === SyntaxKind.TypeOfKeyword && isTypeOfExpression(parent) ||
|
|
629
|
+
node.kind === SyntaxKind.AwaitKeyword && isAwaitExpression(parent) ||
|
|
630
|
+
node.kind === SyntaxKind.DeleteKeyword && isDeleteExpression(parent)) {
|
|
631
|
+
if (parent.expression) {
|
|
632
|
+
return skipOuterExpressions(parent.expression);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
// left /**/in [|name|]
|
|
636
|
+
// Na tag, também o `instanceof` (CK-02).
|
|
637
|
+
if (node.kind === SyntaxKind.InKeyword && isBinaryExpression(parent) && parent.operatorToken === node) {
|
|
638
|
+
return skipOuterExpressions(parent.right);
|
|
639
|
+
}
|
|
640
|
+
// left /**/as [|name|]
|
|
641
|
+
if (node.kind === SyntaxKind.AsKeyword && isAsExpression(parent) && isTypeReferenceNode(parent.type)) {
|
|
642
|
+
return parent.type.typeName;
|
|
643
|
+
}
|
|
644
|
+
// for (... /**/in [|name|])
|
|
645
|
+
// for (... /**/of [|name|])
|
|
646
|
+
if (node.kind === SyntaxKind.InKeyword && isForInStatement(parent) ||
|
|
647
|
+
node.kind === SyntaxKind.OfKeyword && isForOfStatement(parent)) {
|
|
648
|
+
return skipOuterExpressions(parent.expression);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
return node;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* Adjusts the location used for "find references" and "go to definition" when the cursor was not
|
|
655
|
+
* on a property name.
|
|
656
|
+
*/
|
|
657
|
+
export function getAdjustedReferenceLocation(node) {
|
|
658
|
+
return getAdjustedLocation(node, /*forRename*/ false);
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Adjusts the location used for "rename" when the cursor was not on a property name.
|
|
662
|
+
*/
|
|
663
|
+
export function getAdjustedRenameLocation(node) {
|
|
664
|
+
return getAdjustedLocation(node, /*forRename*/ true);
|
|
665
|
+
}
|
|
666
|
+
/**
|
|
667
|
+
* O token cujo texto contém a posição, ou o que termina nela quando é um nome, um literal ou uma palavra-chave. Na tag,
|
|
668
|
+
* também o nome `#private` (CK-02).
|
|
669
|
+
*/
|
|
670
|
+
export function getTouchingPropertyName(sourceFile, position) {
|
|
671
|
+
return getTouchingToken(sourceFile, position, n => isPropertyNameLiteral(n) || isKeyword(n.kind));
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Returns the token if position is in [start, end).
|
|
675
|
+
* If position === end, returns the preceding token if includeItemAtEndPosition(previousToken) === true
|
|
676
|
+
*/
|
|
677
|
+
export function getTouchingToken(sourceFile, position, includePrecedingTokenAtEndPosition) {
|
|
678
|
+
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includePrecedingTokenAtEndPosition, /*includeEndPosition*/ false);
|
|
679
|
+
}
|
|
680
|
+
/** Returns a token if position is in [start-of-leading-trivia, end) */
|
|
681
|
+
export function getTokenAtPosition(sourceFile, position) {
|
|
682
|
+
return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, /*includeEndPosition*/ false);
|
|
683
|
+
}
|
|
684
|
+
/** Get the token whose text contains the position */
|
|
685
|
+
function getTokenAtPositionWorker(sourceFile, position, allowPositionInLeadingTrivia, includePrecedingTokenAtEndPosition, includeEndPosition) {
|
|
686
|
+
let current = sourceFile;
|
|
687
|
+
outer: while (true) {
|
|
688
|
+
// find the child that contains 'position'
|
|
689
|
+
for (const child of current.getChildren(sourceFile)) {
|
|
690
|
+
// Na tag, o começo do filho contava o JSDoc dele (CK-03).
|
|
691
|
+
const start = allowPositionInLeadingTrivia ? child.getFullStart() : child.getStart(sourceFile);
|
|
692
|
+
if (start > position) {
|
|
693
|
+
// If this child begins after position, then all subsequent children will as well.
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
const end = child.getEnd();
|
|
697
|
+
if (position < end || (position === end && (child.kind === SyntaxKind.EndOfFileToken || includeEndPosition))) {
|
|
698
|
+
current = child;
|
|
699
|
+
continue outer;
|
|
700
|
+
}
|
|
701
|
+
else if (includePrecedingTokenAtEndPosition && end === position) {
|
|
702
|
+
const previousToken = findPrecedingToken(position, sourceFile, child);
|
|
703
|
+
if (previousToken && includePrecedingTokenAtEndPosition(previousToken)) {
|
|
704
|
+
return previousToken;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
return current;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* The token on the left of the position is the token that strictly includes the position
|
|
713
|
+
* or sits to the left of the cursor if it is on a boundary. For example
|
|
714
|
+
*
|
|
715
|
+
* fo|o -> will return foo
|
|
716
|
+
* foo <comment> |bar -> will return foo
|
|
717
|
+
*
|
|
718
|
+
*/
|
|
719
|
+
export function findTokenOnLeftOfPosition(file, position) {
|
|
720
|
+
// Ideally, getTokenAtPosition should return a token. However, it is currently
|
|
721
|
+
// broken, so we do a check to make sure the result was indeed a token.
|
|
722
|
+
const tokenAtPosition = getTokenAtPosition(file, position);
|
|
723
|
+
if (isToken(tokenAtPosition) && position > tokenAtPosition.getStart(file) && position < tokenAtPosition.getEnd()) {
|
|
724
|
+
return tokenAtPosition;
|
|
725
|
+
}
|
|
726
|
+
return findPrecedingToken(position, file);
|
|
727
|
+
}
|
|
728
|
+
export function findNextToken(previousToken, parent, sourceFile) {
|
|
729
|
+
return find(parent);
|
|
730
|
+
function find(n) {
|
|
731
|
+
if (isToken(n) && n.pos === previousToken.end) {
|
|
732
|
+
// this is token that starts at the end of previous token - return it
|
|
733
|
+
return n;
|
|
734
|
+
}
|
|
735
|
+
return firstDefined(n.getChildren(sourceFile), child => {
|
|
736
|
+
const shouldDiveInChildNode =
|
|
737
|
+
// previous token is enclosed somewhere in the child
|
|
738
|
+
(child.pos <= previousToken.pos && child.end > previousToken.end) ||
|
|
739
|
+
// previous token ends exactly at the beginning of child
|
|
740
|
+
(child.pos === previousToken.end);
|
|
741
|
+
return shouldDiveInChildNode && nodeHasTokens(child, sourceFile) ? find(child) : undefined;
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
/**
|
|
746
|
+
* O token mais à direita que termina até a posição, fora o `JsxText` só de espaço. Na tag, o `excludeJsdoc` escolhia se
|
|
747
|
+
* o começo de um filho contava o JSDoc dele; a cópia não tem o JSDoc (CK-03).
|
|
748
|
+
*/
|
|
749
|
+
export function findPrecedingToken(position, sourceFile, startNode) {
|
|
750
|
+
const result = find(startNode || sourceFile);
|
|
751
|
+
Debug.assert(!(result && isWhiteSpaceOnlyJsxText(result)));
|
|
752
|
+
return result;
|
|
753
|
+
function find(n) {
|
|
754
|
+
if (isNonWhitespaceToken(n) && n.kind !== SyntaxKind.EndOfFileToken) {
|
|
755
|
+
return n;
|
|
756
|
+
}
|
|
757
|
+
const children = n.getChildren(sourceFile);
|
|
758
|
+
for (let i = 0; i < children.length; i++) {
|
|
759
|
+
const child = children[i];
|
|
760
|
+
// Note that the span of a node's tokens is [node.getStart(...), node.end).
|
|
761
|
+
// Given that `position < child.end` and child has constituent tokens, we distinguish these cases:
|
|
762
|
+
// 1) `position` precedes `child`'s tokens or `child` has no tokens (ie: in a comment or whitespace preceding `child`):
|
|
763
|
+
// we need to find the last token in a previous child.
|
|
764
|
+
// 2) `position` is within the same span: we recurse on `child`.
|
|
765
|
+
if (position < child.end) {
|
|
766
|
+
const start = child.getStart(sourceFile);
|
|
767
|
+
const lookInPreviousChild = (start >= position) || // cursor in the leading trivia
|
|
768
|
+
!nodeHasTokens(child, sourceFile) ||
|
|
769
|
+
isWhiteSpaceOnlyJsxText(child);
|
|
770
|
+
if (lookInPreviousChild) {
|
|
771
|
+
// actual start of the node is past the position - previous token should be at the end of previous child
|
|
772
|
+
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ i, sourceFile);
|
|
773
|
+
return candidate && findRightmostToken(candidate, sourceFile);
|
|
774
|
+
}
|
|
775
|
+
else {
|
|
776
|
+
// candidate should be in this node
|
|
777
|
+
return find(child);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
// Na tag, também o nó de JSDoc (CK-03).
|
|
782
|
+
Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || n.kind === SyntaxKind.EndOfFileToken);
|
|
783
|
+
// Here we know that none of child token nodes embrace the position,
|
|
784
|
+
// the only known case is when position is at the end of the file.
|
|
785
|
+
// Try to find the rightmost token in the file without filtering.
|
|
786
|
+
// Namely we are skipping the check: 'position < node.end'
|
|
787
|
+
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile);
|
|
788
|
+
return candidate && findRightmostToken(candidate, sourceFile);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
function isNonWhitespaceToken(n) {
|
|
792
|
+
return isToken(n) && !isWhiteSpaceOnlyJsxText(n);
|
|
793
|
+
}
|
|
794
|
+
function findRightmostToken(n, sourceFile) {
|
|
795
|
+
if (isNonWhitespaceToken(n)) {
|
|
796
|
+
return n;
|
|
797
|
+
}
|
|
798
|
+
const children = n.getChildren(sourceFile);
|
|
799
|
+
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile);
|
|
800
|
+
return candidate && findRightmostToken(candidate, sourceFile);
|
|
801
|
+
}
|
|
802
|
+
/**
|
|
803
|
+
* Finds the rightmost child to the left of `children[exclusiveStartPosition]` which is a non-all-whitespace token or has constituent tokens.
|
|
804
|
+
*/
|
|
805
|
+
function findRightmostChildNodeWithTokens(children, exclusiveStartPosition, sourceFile) {
|
|
806
|
+
for (let i = exclusiveStartPosition - 1; i >= 0; i--) {
|
|
807
|
+
const child = children[i];
|
|
808
|
+
if (isWhiteSpaceOnlyJsxText(child)) {
|
|
809
|
+
Debug.assert(i > 0, "`JsxText` tokens should not be the first child of `JsxElement | JsxSelfClosingElement`");
|
|
810
|
+
}
|
|
811
|
+
else if (nodeHasTokens(children[i], sourceFile)) {
|
|
812
|
+
return children[i];
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
export function isInString(sourceFile, position, previousToken = findPrecedingToken(position, sourceFile)) {
|
|
817
|
+
if (previousToken && isStringTextContainingNode(previousToken)) {
|
|
818
|
+
const start = previousToken.getStart(sourceFile);
|
|
819
|
+
const end = previousToken.getEnd();
|
|
820
|
+
// To be "in" one of these literals, the position has to be:
|
|
821
|
+
// 1. entirely within the token text.
|
|
822
|
+
// 2. at the end position of an unterminated token.
|
|
823
|
+
// 3. at the end of a regular expression (due to trailing flags like '/foo/g').
|
|
824
|
+
if (start < position && position < end) {
|
|
825
|
+
return true;
|
|
826
|
+
}
|
|
827
|
+
if (position === end) {
|
|
828
|
+
return !!previousToken.isUnterminated;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
return false;
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* returns true if the position is in between the open and close elements of an JSX expression.
|
|
835
|
+
*/
|
|
836
|
+
export function isInsideJsxElementOrAttribute(sourceFile, position) {
|
|
837
|
+
const token = getTokenAtPosition(sourceFile, position);
|
|
838
|
+
if (!token) {
|
|
839
|
+
return false;
|
|
840
|
+
}
|
|
841
|
+
if (token.kind === SyntaxKind.JsxText) {
|
|
842
|
+
return true;
|
|
843
|
+
}
|
|
844
|
+
// <div>Hello |</div>
|
|
845
|
+
if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxText) {
|
|
846
|
+
return true;
|
|
847
|
+
}
|
|
848
|
+
// <div> { | </div> or <div a={| </div>
|
|
849
|
+
if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxExpression) {
|
|
850
|
+
return true;
|
|
851
|
+
}
|
|
852
|
+
// <div> {
|
|
853
|
+
// |
|
|
854
|
+
// } < /div>
|
|
855
|
+
if (token && token.kind === SyntaxKind.CloseBraceToken && token.parent.kind === SyntaxKind.JsxExpression) {
|
|
856
|
+
return true;
|
|
857
|
+
}
|
|
858
|
+
// <div>|</div>
|
|
859
|
+
if (token.kind === SyntaxKind.LessThanToken && token.parent.kind === SyntaxKind.JsxClosingElement) {
|
|
860
|
+
return true;
|
|
861
|
+
}
|
|
862
|
+
return false;
|
|
863
|
+
}
|
|
864
|
+
function isWhiteSpaceOnlyJsxText(node) {
|
|
865
|
+
return isJsxText(node) && node.containsOnlyTriviaWhiteSpaces;
|
|
866
|
+
}
|
|
867
|
+
export function isInTemplateString(sourceFile, position) {
|
|
868
|
+
const token = getTokenAtPosition(sourceFile, position);
|
|
869
|
+
return isTemplateLiteralKind(token.kind) && position > token.getStart(sourceFile);
|
|
870
|
+
}
|
|
871
|
+
export function isInJSXText(sourceFile, position) {
|
|
872
|
+
const token = getTokenAtPosition(sourceFile, position);
|
|
873
|
+
if (isJsxText(token)) {
|
|
874
|
+
return true;
|
|
875
|
+
}
|
|
876
|
+
if (token.kind === SyntaxKind.OpenBraceToken && isJsxExpression(token.parent) && isJsxElement(token.parent.parent)) {
|
|
877
|
+
return true;
|
|
878
|
+
}
|
|
879
|
+
if (token.kind === SyntaxKind.LessThanToken && isJsxOpeningLikeElement(token.parent) && isJsxElement(token.parent.parent)) {
|
|
880
|
+
return true;
|
|
881
|
+
}
|
|
882
|
+
return false;
|
|
883
|
+
}
|
|
884
|
+
export function findPrecedingMatchingToken(token, matchingTokenKind, sourceFile) {
|
|
885
|
+
const tokenKind = token.kind;
|
|
886
|
+
let remainingMatchingTokens = 0;
|
|
887
|
+
while (true) {
|
|
888
|
+
const preceding = findPrecedingToken(token.getFullStart(), sourceFile);
|
|
889
|
+
if (!preceding) {
|
|
890
|
+
return undefined;
|
|
891
|
+
}
|
|
892
|
+
token = preceding;
|
|
893
|
+
if (token.kind === matchingTokenKind) {
|
|
894
|
+
if (remainingMatchingTokens === 0) {
|
|
895
|
+
return token;
|
|
896
|
+
}
|
|
897
|
+
remainingMatchingTokens--;
|
|
898
|
+
}
|
|
899
|
+
else if (token.kind === tokenKind) {
|
|
900
|
+
remainingMatchingTokens++;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
export function removeOptionality(type, isOptionalExpression, isOptionalChain) {
|
|
905
|
+
return isOptionalExpression ? type.getNonNullableType() :
|
|
906
|
+
isOptionalChain ? type.getNonOptionalType() :
|
|
907
|
+
type;
|
|
908
|
+
}
|
|
909
|
+
export function isPossiblyTypeArgumentPosition(token, sourceFile, checker) {
|
|
910
|
+
const info = getPossibleTypeArgumentsInfo(token, sourceFile);
|
|
911
|
+
return info !== undefined && (isPartOfTypeNode(info.called) ||
|
|
912
|
+
getPossibleGenericSignatures(info.called, info.nTypeArguments, checker).length !== 0 ||
|
|
913
|
+
isPossiblyTypeArgumentPosition(info.called, sourceFile, checker));
|
|
914
|
+
}
|
|
915
|
+
export function getPossibleGenericSignatures(called, typeArgumentCount, checker) {
|
|
916
|
+
let type = checker.getTypeAtLocation(called);
|
|
917
|
+
if (isOptionalChain(called.parent)) {
|
|
918
|
+
type = removeOptionality(type, isOptionalChainRoot(called.parent), /*isOptionalChain*/ true);
|
|
919
|
+
}
|
|
920
|
+
// Na tag, a construct signature do `new` (CK-02).
|
|
921
|
+
const signatures = type.getCallSignatures();
|
|
922
|
+
return signatures.filter(candidate => !!candidate.typeParameters && candidate.typeParameters.length >= typeArgumentCount);
|
|
923
|
+
}
|
|
924
|
+
// Get info for an expression like `f <` that may be the start of type arguments.
|
|
925
|
+
export function getPossibleTypeArgumentsInfo(tokenIn, sourceFile) {
|
|
926
|
+
let token = tokenIn;
|
|
927
|
+
// This function determines if the node could be type argument position
|
|
928
|
+
// Since during editing, when type argument list is not complete,
|
|
929
|
+
// the tree could be of any shape depending on the tokens parsed before current node,
|
|
930
|
+
// scanning of the previous identifier followed by "<" before current node would give us better result
|
|
931
|
+
// Note that we also balance out the already provided type arguments, arrays, object literals while doing so
|
|
932
|
+
let remainingLessThanTokens = 0;
|
|
933
|
+
let nTypeArguments = 0;
|
|
934
|
+
while (token) {
|
|
935
|
+
switch (token.kind) {
|
|
936
|
+
case SyntaxKind.LessThanToken:
|
|
937
|
+
// Found the beginning of the generic argument expression
|
|
938
|
+
token = findPrecedingToken(token.getFullStart(), sourceFile);
|
|
939
|
+
if (token && token.kind === SyntaxKind.QuestionDotToken) {
|
|
940
|
+
token = findPrecedingToken(token.getFullStart(), sourceFile);
|
|
941
|
+
}
|
|
942
|
+
if (!token || !isIdentifier(token))
|
|
943
|
+
return undefined;
|
|
944
|
+
if (!remainingLessThanTokens) {
|
|
945
|
+
return isDeclarationName(token) ? undefined : { called: token, nTypeArguments };
|
|
946
|
+
}
|
|
947
|
+
remainingLessThanTokens--;
|
|
948
|
+
break;
|
|
949
|
+
case SyntaxKind.GreaterThanGreaterThanGreaterThanToken:
|
|
950
|
+
remainingLessThanTokens = +3;
|
|
951
|
+
break;
|
|
952
|
+
case SyntaxKind.GreaterThanGreaterThanToken:
|
|
953
|
+
remainingLessThanTokens = +2;
|
|
954
|
+
break;
|
|
955
|
+
case SyntaxKind.GreaterThanToken:
|
|
956
|
+
remainingLessThanTokens++;
|
|
957
|
+
break;
|
|
958
|
+
case SyntaxKind.CloseBraceToken:
|
|
959
|
+
// This can be object type, skip until we find the matching open brace token
|
|
960
|
+
// Skip until the matching open brace token
|
|
961
|
+
token = findPrecedingMatchingToken(token, SyntaxKind.OpenBraceToken, sourceFile);
|
|
962
|
+
if (!token)
|
|
963
|
+
return undefined;
|
|
964
|
+
break;
|
|
965
|
+
case SyntaxKind.CloseParenToken:
|
|
966
|
+
// This can be object type, skip until we find the matching open brace token
|
|
967
|
+
// Skip until the matching open brace token
|
|
968
|
+
token = findPrecedingMatchingToken(token, SyntaxKind.OpenParenToken, sourceFile);
|
|
969
|
+
if (!token)
|
|
970
|
+
return undefined;
|
|
971
|
+
break;
|
|
972
|
+
case SyntaxKind.CloseBracketToken:
|
|
973
|
+
// This can be object type, skip until we find the matching open brace token
|
|
974
|
+
// Skip until the matching open brace token
|
|
975
|
+
token = findPrecedingMatchingToken(token, SyntaxKind.OpenBracketToken, sourceFile);
|
|
976
|
+
if (!token)
|
|
977
|
+
return undefined;
|
|
978
|
+
break;
|
|
979
|
+
// Valid tokens in a type name. Skip.
|
|
980
|
+
case SyntaxKind.CommaToken:
|
|
981
|
+
nTypeArguments++;
|
|
982
|
+
break;
|
|
983
|
+
case SyntaxKind.EqualsGreaterThanToken:
|
|
984
|
+
// falls through
|
|
985
|
+
case SyntaxKind.Identifier:
|
|
986
|
+
case SyntaxKind.StringLiteral:
|
|
987
|
+
case SyntaxKind.NumericLiteral:
|
|
988
|
+
case SyntaxKind.BigIntLiteral:
|
|
989
|
+
case SyntaxKind.TrueKeyword:
|
|
990
|
+
case SyntaxKind.FalseKeyword:
|
|
991
|
+
// falls through
|
|
992
|
+
case SyntaxKind.TypeOfKeyword:
|
|
993
|
+
case SyntaxKind.ExtendsKeyword:
|
|
994
|
+
case SyntaxKind.KeyOfKeyword:
|
|
995
|
+
case SyntaxKind.DotToken:
|
|
996
|
+
case SyntaxKind.BarToken:
|
|
997
|
+
case SyntaxKind.QuestionToken:
|
|
998
|
+
case SyntaxKind.ColonToken:
|
|
999
|
+
break;
|
|
1000
|
+
default:
|
|
1001
|
+
if (isTypeNode(token)) {
|
|
1002
|
+
break;
|
|
1003
|
+
}
|
|
1004
|
+
// Invalid token in type
|
|
1005
|
+
return undefined;
|
|
1006
|
+
}
|
|
1007
|
+
token = findPrecedingToken(token.getFullStart(), sourceFile);
|
|
1008
|
+
}
|
|
1009
|
+
return undefined;
|
|
1010
|
+
}
|
|
1011
|
+
/**
|
|
1012
|
+
* Returns true if the cursor at position in sourceFile is within a comment.
|
|
1013
|
+
*
|
|
1014
|
+
* @param tokenAtPosition Must equal `getTokenAtPosition(sourceFile, position)
|
|
1015
|
+
* @param predicate Additional predicate to test on the comment range.
|
|
1016
|
+
*/
|
|
1017
|
+
export function isInComment(sourceFile, position, tokenAtPosition) {
|
|
1018
|
+
return getRangeOfEnclosingComment(sourceFile, position, /*precedingToken*/ undefined, tokenAtPosition);
|
|
1019
|
+
}
|
|
1020
|
+
function nodeHasTokens(n, sourceFile) {
|
|
1021
|
+
// O token ou o nó de largura não nula tem tokens; a largura não conta a trivia. Na tag, o fim do arquivo tinha tokens
|
|
1022
|
+
// quando levava um JSDoc; a cópia não tem o JSDoc (CK-03).
|
|
1023
|
+
return n.kind !== SyntaxKind.EndOfFileToken && n.getWidth(sourceFile) !== 0;
|
|
1024
|
+
}
|
|
1025
|
+
export function getNodeModifiers(node) {
|
|
1026
|
+
const flags = isDeclaration(node) ? getCombinedModifierFlags(node) : ModifierFlags.None;
|
|
1027
|
+
const result = [];
|
|
1028
|
+
// Na tag, também os modificadores de membro de classe: o de acesso, o `static` e o `abstract` (CK-02).
|
|
1029
|
+
if (flags & ModifierFlags.Export)
|
|
1030
|
+
result.push("export" /* ScriptElementKindModifier.exportedModifier */);
|
|
1031
|
+
if (node.flags & NodeFlags.Ambient)
|
|
1032
|
+
result.push("declare" /* ScriptElementKindModifier.ambientModifier */);
|
|
1033
|
+
if (node.kind === SyntaxKind.ExportAssignment)
|
|
1034
|
+
result.push("export" /* ScriptElementKindModifier.exportedModifier */);
|
|
1035
|
+
return result.length > 0 ? result.join(",") : "" /* ScriptElementKindModifier.none */;
|
|
1036
|
+
}
|
|
1037
|
+
/** Na tag, também os parâmetros de tipo de uma classe e de uma interface declaradas (CK-02). */
|
|
1038
|
+
export function getTypeArgumentOrTypeParameterList(node) {
|
|
1039
|
+
if (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.CallExpression) {
|
|
1040
|
+
return node.typeArguments;
|
|
1041
|
+
}
|
|
1042
|
+
if (isFunctionLike(node)) {
|
|
1043
|
+
return node.typeParameters;
|
|
1044
|
+
}
|
|
1045
|
+
return undefined;
|
|
1046
|
+
}
|
|
1047
|
+
export function isComment(kind) {
|
|
1048
|
+
return kind === SyntaxKind.SingleLineCommentTrivia || kind === SyntaxKind.MultiLineCommentTrivia;
|
|
1049
|
+
}
|
|
1050
|
+
/** A string e o template. Na tag, também o literal de regex (CK-02). */
|
|
1051
|
+
export function isStringOrRegularExpressionOrTemplateLiteral(kind) {
|
|
1052
|
+
if (kind === SyntaxKind.StringLiteral
|
|
1053
|
+
|| isTemplateLiteralKind(kind)) {
|
|
1054
|
+
return true;
|
|
1055
|
+
}
|
|
1056
|
+
return false;
|
|
1057
|
+
}
|
|
1058
|
+
export function isPunctuation(kind) {
|
|
1059
|
+
return SyntaxKind.FirstPunctuation <= kind && kind <= SyntaxKind.LastPunctuation;
|
|
1060
|
+
}
|
|
1061
|
+
export function isArrayLiteralOrObjectLiteralDestructuringPattern(node) {
|
|
1062
|
+
if (node.kind === SyntaxKind.ArrayLiteralExpression ||
|
|
1063
|
+
node.kind === SyntaxKind.ObjectLiteralExpression) {
|
|
1064
|
+
// [a,b,c] from:
|
|
1065
|
+
// [a, b, c] = someExpression;
|
|
1066
|
+
if (node.parent.kind === SyntaxKind.BinaryExpression &&
|
|
1067
|
+
node.parent.left === node &&
|
|
1068
|
+
node.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
|
|
1069
|
+
return true;
|
|
1070
|
+
}
|
|
1071
|
+
// [a, b, c] from:
|
|
1072
|
+
// for([a, b, c] of expression)
|
|
1073
|
+
if (node.parent.kind === SyntaxKind.ForOfStatement &&
|
|
1074
|
+
node.parent.initializer === node) {
|
|
1075
|
+
return true;
|
|
1076
|
+
}
|
|
1077
|
+
// [a, b, c] of
|
|
1078
|
+
// [x, [a, b, c] ] = someExpression
|
|
1079
|
+
// or
|
|
1080
|
+
// {x, a: {a, b, c} } = someExpression
|
|
1081
|
+
if (isArrayLiteralOrObjectLiteralDestructuringPattern(node.parent.kind === SyntaxKind.PropertyAssignment ? node.parent.parent : node.parent)) {
|
|
1082
|
+
return true;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
return false;
|
|
1086
|
+
}
|
|
1087
|
+
export function isInNonReferenceComment(sourceFile, position) {
|
|
1088
|
+
return isInReferenceCommentWorker(sourceFile, position, /*shouldBeReference*/ false);
|
|
1089
|
+
}
|
|
1090
|
+
function isInReferenceCommentWorker(sourceFile, position, shouldBeReference) {
|
|
1091
|
+
const range = isInComment(sourceFile, position, /*tokenAtPosition*/ undefined);
|
|
1092
|
+
return !!range && shouldBeReference === tripleSlashDirectivePrefixRegex.test(sourceFile.text.substring(range.pos, range.end));
|
|
1093
|
+
}
|
|
1094
|
+
export function getReplacementSpanForContextToken(contextToken) {
|
|
1095
|
+
if (!contextToken)
|
|
1096
|
+
return undefined;
|
|
1097
|
+
switch (contextToken.kind) {
|
|
1098
|
+
case SyntaxKind.StringLiteral:
|
|
1099
|
+
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
|
1100
|
+
return createTextSpanFromStringLiteralLikeContent(contextToken);
|
|
1101
|
+
default:
|
|
1102
|
+
return createTextSpanFromNode(contextToken);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
export function createTextSpanFromNode(node, sourceFile, endNode) {
|
|
1106
|
+
return createTextSpanFromBounds(node.getStart(sourceFile), (endNode || node).getEnd());
|
|
1107
|
+
}
|
|
1108
|
+
export function createTextSpanFromStringLiteralLikeContent(node) {
|
|
1109
|
+
if (node.isUnterminated)
|
|
1110
|
+
return undefined;
|
|
1111
|
+
return createTextSpanFromBounds(node.getStart() + 1, node.getEnd() - 1);
|
|
1112
|
+
}
|
|
1113
|
+
export function createTextSpanFromRange(range) {
|
|
1114
|
+
return createTextSpanFromBounds(range.pos, range.end);
|
|
1115
|
+
}
|
|
1116
|
+
export function createTextRangeFromSpan(span) {
|
|
1117
|
+
return createRange(span.start, span.start + span.length);
|
|
1118
|
+
}
|
|
1119
|
+
export function createTextChangeFromStartLength(start, length, newText) {
|
|
1120
|
+
return createTextChange(createTextSpan(start, length), newText);
|
|
1121
|
+
}
|
|
1122
|
+
export function createTextChange(span, newText) {
|
|
1123
|
+
return { span, newText };
|
|
1124
|
+
}
|
|
1125
|
+
export const typeKeywords = [
|
|
1126
|
+
SyntaxKind.AnyKeyword,
|
|
1127
|
+
SyntaxKind.AssertsKeyword,
|
|
1128
|
+
SyntaxKind.BigIntKeyword,
|
|
1129
|
+
SyntaxKind.BooleanKeyword,
|
|
1130
|
+
SyntaxKind.FalseKeyword,
|
|
1131
|
+
SyntaxKind.KeyOfKeyword,
|
|
1132
|
+
SyntaxKind.NeverKeyword,
|
|
1133
|
+
SyntaxKind.NullKeyword,
|
|
1134
|
+
SyntaxKind.NumberKeyword,
|
|
1135
|
+
SyntaxKind.ObjectKeyword,
|
|
1136
|
+
SyntaxKind.ReadonlyKeyword,
|
|
1137
|
+
SyntaxKind.StringKeyword,
|
|
1138
|
+
SyntaxKind.SymbolKeyword,
|
|
1139
|
+
SyntaxKind.TrueKeyword,
|
|
1140
|
+
SyntaxKind.VoidKeyword,
|
|
1141
|
+
SyntaxKind.UndefinedKeyword,
|
|
1142
|
+
// Na tag, também o `unique`, que saiu do scanner com o `unique symbol` (CK-02, CK-56).
|
|
1143
|
+
SyntaxKind.UnknownKeyword,
|
|
1144
|
+
];
|
|
1145
|
+
export function isTypeKeyword(kind) {
|
|
1146
|
+
return contains(typeKeywords, kind);
|
|
1147
|
+
}
|
|
1148
|
+
export function isTypeKeywordToken(node) {
|
|
1149
|
+
return node.kind === SyntaxKind.TypeKeyword;
|
|
1150
|
+
}
|
|
1151
|
+
/** True if the symbol is for an external module, as opposed to a namespace. */
|
|
1152
|
+
export function isExternalModuleSymbol(moduleSymbol) {
|
|
1153
|
+
return !!(moduleSymbol.flags & SymbolFlags.Module) && moduleSymbol.name.charCodeAt(0) === CharacterCodes.doubleQuote;
|
|
1154
|
+
}
|
|
1155
|
+
export function nodeSeenTracker() {
|
|
1156
|
+
const seen = [];
|
|
1157
|
+
return node => {
|
|
1158
|
+
const id = getNodeId(node);
|
|
1159
|
+
return !seen[id] && (seen[id] = true);
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
export function getSnapshotText(snap) {
|
|
1163
|
+
return snap.getText(0, snap.getLength());
|
|
1164
|
+
}
|
|
1165
|
+
export function repeatString(str, count) {
|
|
1166
|
+
let result = "";
|
|
1167
|
+
for (let i = 0; i < count; i++) {
|
|
1168
|
+
result += str;
|
|
1169
|
+
}
|
|
1170
|
+
return result;
|
|
1171
|
+
}
|
|
1172
|
+
export function skipConstraint(type) {
|
|
1173
|
+
return type.isTypeParameter() ? type.getConstraint() || type : type;
|
|
1174
|
+
}
|
|
1175
|
+
export function getNameFromPropertyName(name) {
|
|
1176
|
+
return name.kind === SyntaxKind.ComputedPropertyName
|
|
1177
|
+
// O nome computado com um literal de string ou de número vale como o literal.
|
|
1178
|
+
? isStringOrNumericLiteralLike(name.expression) ? name.expression.text : undefined
|
|
1179
|
+
: getTextOfIdentifierOrLiteral(name);
|
|
1180
|
+
}
|
|
1181
|
+
/**
|
|
1182
|
+
* O host do cálculo de um specifier. Na tag, recebia também o programa, e o host dava ainda o que a resolução do Node,
|
|
1183
|
+
* os symlinks, o cache de tipos e as project references perguntavam (CK-46, CK-47).
|
|
1184
|
+
*/
|
|
1185
|
+
export function createModuleSpecifierResolutionHost(host) {
|
|
1186
|
+
return {
|
|
1187
|
+
getCurrentDirectory: () => host.getCurrentDirectory(),
|
|
1188
|
+
useCaseSensitiveFileNames: maybeBind(host, host.useCaseSensitiveFileNames),
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
export function makeImportIfNecessary(defaultImport, namedImports, moduleSpecifier, quotePreference) {
|
|
1192
|
+
return defaultImport || namedImports && namedImports.length ? makeImport(defaultImport, namedImports, moduleSpecifier, quotePreference) : undefined;
|
|
1193
|
+
}
|
|
1194
|
+
export function makeImport(defaultImport, namedImports, moduleSpecifier, quotePreference, isTypeOnly) {
|
|
1195
|
+
return createImportDeclaration(
|
|
1196
|
+
/*modifiers*/ undefined, defaultImport || namedImports
|
|
1197
|
+
? createImportClause(defaultImport, namedImports && namedImports.length ? createNamedImports(namedImports) : undefined, isTypeOnly)
|
|
1198
|
+
: undefined, typeof moduleSpecifier === "string" ? makeStringLiteral(moduleSpecifier, quotePreference) : moduleSpecifier);
|
|
1199
|
+
}
|
|
1200
|
+
export function makeStringLiteral(text, quotePreference) {
|
|
1201
|
+
return createLiteral(text, quotePreference === 0 /* QuotePreference.Single */);
|
|
1202
|
+
}
|
|
1203
|
+
export var QuotePreference;
|
|
1204
|
+
(function (QuotePreference) {
|
|
1205
|
+
QuotePreference[QuotePreference["Single"] = 0] = "Single";
|
|
1206
|
+
QuotePreference[QuotePreference["Double"] = 1] = "Double";
|
|
1207
|
+
})(QuotePreference || (QuotePreference = {}));
|
|
1208
|
+
export function quotePreferenceFromString(str, sourceFile) {
|
|
1209
|
+
return isStringDoubleQuoted(str, sourceFile) ? 1 /* QuotePreference.Double */ : 0 /* QuotePreference.Single */;
|
|
1210
|
+
}
|
|
1211
|
+
export function getQuotePreference(sourceFile, preferences) {
|
|
1212
|
+
if (preferences.quotePreference && preferences.quotePreference !== "auto") {
|
|
1213
|
+
return preferences.quotePreference === "single" ? 0 /* QuotePreference.Single */ : 1 /* QuotePreference.Double */;
|
|
1214
|
+
}
|
|
1215
|
+
else {
|
|
1216
|
+
const firstModuleSpecifier = sourceFile.imports && find(sourceFile.imports, isStringLiteral);
|
|
1217
|
+
return firstModuleSpecifier ? quotePreferenceFromString(firstModuleSpecifier, sourceFile) : 1 /* QuotePreference.Double */;
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
export function symbolNameNoDefault(symbol) {
|
|
1221
|
+
const escaped = symbolEscapedNameNoDefault(symbol);
|
|
1222
|
+
return escaped === undefined ? undefined : unescapeLeadingUnderscores(escaped);
|
|
1223
|
+
}
|
|
1224
|
+
export function symbolEscapedNameNoDefault(symbol) {
|
|
1225
|
+
if (symbol.escapedName !== InternalSymbolName.Default) {
|
|
1226
|
+
return symbol.escapedName;
|
|
1227
|
+
}
|
|
1228
|
+
return firstDefined(symbol.declarations, decl => {
|
|
1229
|
+
const name = getNameOfDeclaration(decl);
|
|
1230
|
+
return name && name.kind === SyntaxKind.Identifier ? name.escapedText : undefined;
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
export function isObjectBindingElementWithoutPropertyName(bindingElement) {
|
|
1234
|
+
return isBindingElement(bindingElement) &&
|
|
1235
|
+
isObjectBindingPattern(bindingElement.parent) &&
|
|
1236
|
+
isIdentifier(bindingElement.name) &&
|
|
1237
|
+
!bindingElement.propertyName;
|
|
1238
|
+
}
|
|
1239
|
+
export function getPropertySymbolFromBindingElement(checker, bindingElement) {
|
|
1240
|
+
const typeOfPattern = checker.getTypeAtLocation(bindingElement.parent);
|
|
1241
|
+
return typeOfPattern && checker.getPropertyOfType(typeOfPattern, bindingElement.name.text);
|
|
1242
|
+
}
|
|
1243
|
+
export function getParentNodeInSpan(node, file, span) {
|
|
1244
|
+
if (!node)
|
|
1245
|
+
return undefined;
|
|
1246
|
+
while (node.parent) {
|
|
1247
|
+
if (isSourceFile(node.parent) || !spanContainsNode(span, node.parent, file)) {
|
|
1248
|
+
return node;
|
|
1249
|
+
}
|
|
1250
|
+
node = node.parent;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
function spanContainsNode(span, node, file) {
|
|
1254
|
+
return textSpanContainsPosition(span, node.getStart(file)) &&
|
|
1255
|
+
node.getEnd() <= textSpanEnd(span);
|
|
1256
|
+
}
|
|
1257
|
+
export function findModifier(node, kind) {
|
|
1258
|
+
return node.modifiers && find(node.modifiers, m => m.kind === kind);
|
|
1259
|
+
}
|
|
1260
|
+
export function insertImports(changes, sourceFile, imports, blankLineBetween) {
|
|
1261
|
+
// Na tag, o `const x = require(…)` novo entrava depois dos outros `require` (CK-03).
|
|
1262
|
+
const lastImportDeclaration = findLast(sourceFile.statements, statement => isAnyImportSyntax(statement));
|
|
1263
|
+
if (lastImportDeclaration) {
|
|
1264
|
+
if (isArray(imports)) {
|
|
1265
|
+
changes.insertNodesAfter(sourceFile, lastImportDeclaration, imports);
|
|
1266
|
+
}
|
|
1267
|
+
else {
|
|
1268
|
+
changes.insertNodeAfter(sourceFile, lastImportDeclaration, imports);
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
else if (isArray(imports)) {
|
|
1272
|
+
changes.insertNodesAtTopOfFile(sourceFile, imports, blankLineBetween);
|
|
1273
|
+
}
|
|
1274
|
+
else {
|
|
1275
|
+
changes.insertNodeAtTopOfFile(sourceFile, imports, blankLineBetween);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
export function getTypeKeywordOfTypeOnlyImport(importClause, sourceFile) {
|
|
1279
|
+
Debug.assert(importClause.isTypeOnly);
|
|
1280
|
+
return cast(importClause.getChildAt(0, sourceFile), isTypeKeywordToken);
|
|
1281
|
+
}
|
|
1282
|
+
export function textSpansEqual(a, b) {
|
|
1283
|
+
return !!a && !!b && a.start === b.start && a.length === b.length;
|
|
1284
|
+
}
|
|
1285
|
+
// #endregion
|
|
1286
|
+
// Display-part writer helpers
|
|
1287
|
+
// #region
|
|
1288
|
+
export function isFirstDeclarationOfSymbolParameter(symbol) {
|
|
1289
|
+
return symbol.declarations && symbol.declarations.length > 0 && symbol.declarations[0].kind === SyntaxKind.Parameter;
|
|
1290
|
+
}
|
|
1291
|
+
const displayPartWriter = getDisplayPartWriter();
|
|
1292
|
+
function getDisplayPartWriter() {
|
|
1293
|
+
const absoluteMaximumLength = defaultMaximumTruncationLength * 10; // A hard cutoff to avoid overloading the messaging channel in worst-case scenarios
|
|
1294
|
+
let displayParts;
|
|
1295
|
+
let lineStart;
|
|
1296
|
+
let indent;
|
|
1297
|
+
let length;
|
|
1298
|
+
resetWriter();
|
|
1299
|
+
const unknownWrite = (text) => writeKind(text, SymbolDisplayPartKind.text);
|
|
1300
|
+
return {
|
|
1301
|
+
displayParts: () => {
|
|
1302
|
+
const finalText = displayParts.length && displayParts[displayParts.length - 1].text;
|
|
1303
|
+
if (length > absoluteMaximumLength && finalText && finalText !== "...") {
|
|
1304
|
+
if (!isWhiteSpaceLike(finalText.charCodeAt(finalText.length - 1))) {
|
|
1305
|
+
displayParts.push(displayPart(" ", SymbolDisplayPartKind.space));
|
|
1306
|
+
}
|
|
1307
|
+
displayParts.push(displayPart("...", SymbolDisplayPartKind.punctuation));
|
|
1308
|
+
}
|
|
1309
|
+
return displayParts;
|
|
1310
|
+
},
|
|
1311
|
+
writeKeyword: text => writeKind(text, SymbolDisplayPartKind.keyword),
|
|
1312
|
+
writeOperator: text => writeKind(text, SymbolDisplayPartKind.operator),
|
|
1313
|
+
writePunctuation: text => writeKind(text, SymbolDisplayPartKind.punctuation),
|
|
1314
|
+
writeTrailingSemicolon: text => writeKind(text, SymbolDisplayPartKind.punctuation),
|
|
1315
|
+
writeSpace: text => writeKind(text, SymbolDisplayPartKind.space),
|
|
1316
|
+
writeStringLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral),
|
|
1317
|
+
writeParameter: text => writeKind(text, SymbolDisplayPartKind.parameterName),
|
|
1318
|
+
writeProperty: text => writeKind(text, SymbolDisplayPartKind.propertyName),
|
|
1319
|
+
writeLiteral: text => writeKind(text, SymbolDisplayPartKind.stringLiteral),
|
|
1320
|
+
writeSymbol,
|
|
1321
|
+
writeLine,
|
|
1322
|
+
write: unknownWrite,
|
|
1323
|
+
writeComment: unknownWrite,
|
|
1324
|
+
getText: () => "",
|
|
1325
|
+
getTextPos: () => 0,
|
|
1326
|
+
getColumn: () => 0,
|
|
1327
|
+
getLine: () => 0,
|
|
1328
|
+
isAtStartOfLine: () => false,
|
|
1329
|
+
hasTrailingWhitespace: () => false,
|
|
1330
|
+
hasTrailingComment: () => false,
|
|
1331
|
+
rawWrite: notImplemented,
|
|
1332
|
+
getIndent: () => indent,
|
|
1333
|
+
increaseIndent: () => { indent++; },
|
|
1334
|
+
decreaseIndent: () => { indent--; },
|
|
1335
|
+
clear: resetWriter,
|
|
1336
|
+
trackSymbol: noop,
|
|
1337
|
+
reportInaccessibleThisError: noop,
|
|
1338
|
+
reportInaccessibleUniqueSymbolError: noop,
|
|
1339
|
+
// Na tag, também o aviso do membro privado na base de uma class expression, que saiu do `SymbolTracker` da cópia
|
|
1340
|
+
// com a classe (CK-02).
|
|
1341
|
+
};
|
|
1342
|
+
function writeIndent() {
|
|
1343
|
+
if (length > absoluteMaximumLength)
|
|
1344
|
+
return;
|
|
1345
|
+
if (lineStart) {
|
|
1346
|
+
const indentString = getIndentString(indent);
|
|
1347
|
+
if (indentString) {
|
|
1348
|
+
length += indentString.length;
|
|
1349
|
+
displayParts.push(displayPart(indentString, SymbolDisplayPartKind.space));
|
|
1350
|
+
}
|
|
1351
|
+
lineStart = false;
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
function writeKind(text, kind) {
|
|
1355
|
+
if (length > absoluteMaximumLength)
|
|
1356
|
+
return;
|
|
1357
|
+
writeIndent();
|
|
1358
|
+
length += text.length;
|
|
1359
|
+
displayParts.push(displayPart(text, kind));
|
|
1360
|
+
}
|
|
1361
|
+
function writeSymbol(text, symbol) {
|
|
1362
|
+
if (length > absoluteMaximumLength)
|
|
1363
|
+
return;
|
|
1364
|
+
writeIndent();
|
|
1365
|
+
length += text.length;
|
|
1366
|
+
displayParts.push(symbolPart(text, symbol));
|
|
1367
|
+
}
|
|
1368
|
+
function writeLine() {
|
|
1369
|
+
if (length > absoluteMaximumLength)
|
|
1370
|
+
return;
|
|
1371
|
+
length += 1;
|
|
1372
|
+
displayParts.push(lineBreakPart());
|
|
1373
|
+
lineStart = true;
|
|
1374
|
+
}
|
|
1375
|
+
function resetWriter() {
|
|
1376
|
+
displayParts = [];
|
|
1377
|
+
lineStart = true;
|
|
1378
|
+
indent = 0;
|
|
1379
|
+
length = 0;
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
export function symbolPart(text, symbol) {
|
|
1383
|
+
return displayPart(text, displayPartKind(symbol));
|
|
1384
|
+
function displayPartKind(symbol) {
|
|
1385
|
+
const flags = symbol.flags;
|
|
1386
|
+
if (flags & SymbolFlags.Variable) {
|
|
1387
|
+
return isFirstDeclarationOfSymbolParameter(symbol) ? SymbolDisplayPartKind.parameterName : SymbolDisplayPartKind.localName;
|
|
1388
|
+
}
|
|
1389
|
+
// Na tag, também o acessor, o membro de enum, a classe e o enum (CK-02).
|
|
1390
|
+
else if (flags & SymbolFlags.Property) {
|
|
1391
|
+
return SymbolDisplayPartKind.propertyName;
|
|
1392
|
+
}
|
|
1393
|
+
else if (flags & SymbolFlags.Function) {
|
|
1394
|
+
return SymbolDisplayPartKind.functionName;
|
|
1395
|
+
}
|
|
1396
|
+
else if (flags & SymbolFlags.Interface) {
|
|
1397
|
+
return SymbolDisplayPartKind.interfaceName;
|
|
1398
|
+
}
|
|
1399
|
+
else if (flags & SymbolFlags.Module) {
|
|
1400
|
+
return SymbolDisplayPartKind.moduleName;
|
|
1401
|
+
}
|
|
1402
|
+
else if (flags & SymbolFlags.Method) {
|
|
1403
|
+
return SymbolDisplayPartKind.methodName;
|
|
1404
|
+
}
|
|
1405
|
+
else if (flags & SymbolFlags.TypeParameter) {
|
|
1406
|
+
return SymbolDisplayPartKind.typeParameterName;
|
|
1407
|
+
}
|
|
1408
|
+
else if (flags & SymbolFlags.TypeAlias) {
|
|
1409
|
+
return SymbolDisplayPartKind.aliasName;
|
|
1410
|
+
}
|
|
1411
|
+
else if (flags & SymbolFlags.Alias) {
|
|
1412
|
+
return SymbolDisplayPartKind.aliasName;
|
|
1413
|
+
}
|
|
1414
|
+
return SymbolDisplayPartKind.text;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
export function displayPart(text, kind) {
|
|
1418
|
+
return { text, kind: SymbolDisplayPartKind[kind] };
|
|
1419
|
+
}
|
|
1420
|
+
export function spacePart() {
|
|
1421
|
+
return displayPart(" ", SymbolDisplayPartKind.space);
|
|
1422
|
+
}
|
|
1423
|
+
export function keywordPart(kind) {
|
|
1424
|
+
return displayPart(tokenToString(kind), SymbolDisplayPartKind.keyword);
|
|
1425
|
+
}
|
|
1426
|
+
export function punctuationPart(kind) {
|
|
1427
|
+
return displayPart(tokenToString(kind), SymbolDisplayPartKind.punctuation);
|
|
1428
|
+
}
|
|
1429
|
+
export function operatorPart(kind) {
|
|
1430
|
+
return displayPart(tokenToString(kind), SymbolDisplayPartKind.operator);
|
|
1431
|
+
}
|
|
1432
|
+
export function textOrKeywordPart(text) {
|
|
1433
|
+
const kind = stringToToken(text);
|
|
1434
|
+
return kind === undefined
|
|
1435
|
+
? textPart(text)
|
|
1436
|
+
: keywordPart(kind);
|
|
1437
|
+
}
|
|
1438
|
+
export function textPart(text) {
|
|
1439
|
+
return displayPart(text, SymbolDisplayPartKind.text);
|
|
1440
|
+
}
|
|
1441
|
+
const carriageReturnLineFeed = "\r\n";
|
|
1442
|
+
/**
|
|
1443
|
+
* The default is CRLF.
|
|
1444
|
+
*/
|
|
1445
|
+
export function getNewLineOrDefaultFromHost(host, formatSettings) {
|
|
1446
|
+
return formatSettings?.newLineCharacter ||
|
|
1447
|
+
host.getNewLine?.() ||
|
|
1448
|
+
carriageReturnLineFeed;
|
|
1449
|
+
}
|
|
1450
|
+
export function lineBreakPart() {
|
|
1451
|
+
return displayPart("\n", SymbolDisplayPartKind.lineBreak);
|
|
1452
|
+
}
|
|
1453
|
+
export function mapToDisplayParts(writeDisplayParts) {
|
|
1454
|
+
try {
|
|
1455
|
+
writeDisplayParts(displayPartWriter);
|
|
1456
|
+
return displayPartWriter.displayParts();
|
|
1457
|
+
}
|
|
1458
|
+
finally {
|
|
1459
|
+
displayPartWriter.clear();
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
export function typeToDisplayParts(typechecker, type, enclosingDeclaration, flags = TypeFormatFlags.None) {
|
|
1463
|
+
return mapToDisplayParts(writer => {
|
|
1464
|
+
typechecker.writeType(type, enclosingDeclaration, flags | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.UseAliasDefinedOutsideCurrentScope, writer);
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
export function symbolToDisplayParts(typeChecker, symbol, enclosingDeclaration, meaning, flags = SymbolFormatFlags.None) {
|
|
1468
|
+
return mapToDisplayParts(writer => {
|
|
1469
|
+
typeChecker.writeSymbol(symbol, enclosingDeclaration, meaning, flags | SymbolFormatFlags.UseAliasDefinedOutsideCurrentScope, writer);
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
export function signatureToDisplayParts(typechecker, signature, enclosingDeclaration, flags = TypeFormatFlags.None) {
|
|
1473
|
+
flags |= TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.MultilineObjectLiterals | TypeFormatFlags.WriteTypeArgumentsOfSignature | TypeFormatFlags.OmitParameterModifiers;
|
|
1474
|
+
return mapToDisplayParts(writer => {
|
|
1475
|
+
// Na tag, também o `kind`, que imprimia a construct signature (CK-02).
|
|
1476
|
+
typechecker.writeSignature(signature, enclosingDeclaration, flags, writer);
|
|
1477
|
+
});
|
|
1478
|
+
}
|
|
1479
|
+
export function isImportOrExportSpecifierName(location) {
|
|
1480
|
+
return !!location.parent && isImportOrExportSpecifier(location.parent) && location.parent.propertyName === location;
|
|
1481
|
+
}
|
|
1482
|
+
export function getScriptKind(fileName, host) {
|
|
1483
|
+
// O host pode dar o tipo do arquivo, no lugar do que a extensão diria.
|
|
1484
|
+
return ensureScriptKind(fileName, host && host.getScriptKind && host.getScriptKind(fileName));
|
|
1485
|
+
}
|
|
1486
|
+
export function getSymbolTarget(symbol, checker) {
|
|
1487
|
+
let next = symbol;
|
|
1488
|
+
while (isAliasSymbol(next) || (isTransientSymbol(next) && next.target)) {
|
|
1489
|
+
if (isTransientSymbol(next) && next.target) {
|
|
1490
|
+
next = next.target;
|
|
1491
|
+
}
|
|
1492
|
+
else {
|
|
1493
|
+
next = skipAlias(next, checker);
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
return next;
|
|
1497
|
+
}
|
|
1498
|
+
function isTransientSymbol(symbol) {
|
|
1499
|
+
return (symbol.flags & SymbolFlags.Transient) !== 0;
|
|
1500
|
+
}
|
|
1501
|
+
function isAliasSymbol(symbol) {
|
|
1502
|
+
return (symbol.flags & SymbolFlags.Alias) !== 0;
|
|
1503
|
+
}
|
|
1504
|
+
export function getUniqueSymbolId(symbol, checker) {
|
|
1505
|
+
return getSymbolId(skipAlias(symbol, checker));
|
|
1506
|
+
}
|
|
1507
|
+
export function getFirstNonSpaceCharacterPosition(text, position) {
|
|
1508
|
+
while (isWhiteSpaceLike(text.charCodeAt(position))) {
|
|
1509
|
+
position += 1;
|
|
1510
|
+
}
|
|
1511
|
+
return position;
|
|
1512
|
+
}
|
|
1513
|
+
export function getPrecedingNonSpaceCharacterPosition(text, position) {
|
|
1514
|
+
while (position > -1 && isWhiteSpaceSingleLine(text.charCodeAt(position))) {
|
|
1515
|
+
position -= 1;
|
|
1516
|
+
}
|
|
1517
|
+
return position + 1;
|
|
1518
|
+
}
|
|
1519
|
+
/**
|
|
1520
|
+
* Creates a deep, memberwise clone of a node with no source map location.
|
|
1521
|
+
*
|
|
1522
|
+
* WARNING: This is an expensive operation and is only intended to be used in refactorings
|
|
1523
|
+
* and code fixes (because those are triggered by explicit user actions).
|
|
1524
|
+
*/
|
|
1525
|
+
export function getSynthesizedDeepClone(node, includeTrivia = true) {
|
|
1526
|
+
const clone = node && getSynthesizedDeepCloneWorker(node);
|
|
1527
|
+
if (clone && !includeTrivia)
|
|
1528
|
+
suppressLeadingAndTrailingTrivia(clone);
|
|
1529
|
+
return clone;
|
|
1530
|
+
}
|
|
1531
|
+
export function getSynthesizedDeepCloneWithRenames(node, includeTrivia = true, renameMap, checker, callback) {
|
|
1532
|
+
let clone;
|
|
1533
|
+
if (renameMap && checker && isBindingElement(node) && isIdentifier(node.name) && isObjectBindingPattern(node.parent)) {
|
|
1534
|
+
const symbol = checker.getSymbolAtLocation(node.name);
|
|
1535
|
+
const renameInfo = symbol && renameMap.get(String(getSymbolId(symbol)));
|
|
1536
|
+
if (renameInfo && renameInfo.text !== (node.name || node.propertyName).getText()) {
|
|
1537
|
+
clone = setOriginalNode(createBindingElement(node.dotDotDotToken, node.propertyName || node.name, renameInfo, node.initializer), node);
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
else if (renameMap && checker && isIdentifier(node)) {
|
|
1541
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
1542
|
+
const renameInfo = symbol && renameMap.get(String(getSymbolId(symbol)));
|
|
1543
|
+
if (renameInfo) {
|
|
1544
|
+
clone = setOriginalNode(createIdentifier(renameInfo.text), node);
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
if (!clone) {
|
|
1548
|
+
clone = getSynthesizedDeepCloneWorker(node, renameMap, checker, callback);
|
|
1549
|
+
}
|
|
1550
|
+
if (clone && !includeTrivia)
|
|
1551
|
+
suppressLeadingAndTrailingTrivia(clone);
|
|
1552
|
+
if (callback && clone)
|
|
1553
|
+
callback(node, clone);
|
|
1554
|
+
return clone;
|
|
1555
|
+
}
|
|
1556
|
+
function getSynthesizedDeepCloneWorker(node, renameMap, checker, callback) {
|
|
1557
|
+
const visited = (renameMap || checker || callback) ?
|
|
1558
|
+
visitEachChild(node, wrapper, nullTransformationContext) :
|
|
1559
|
+
visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext);
|
|
1560
|
+
if (visited === node) {
|
|
1561
|
+
// This only happens for leaf nodes - internal nodes always see their children change.
|
|
1562
|
+
const clone = getSynthesizedClone(node);
|
|
1563
|
+
if (isStringLiteral(clone)) {
|
|
1564
|
+
clone.textSourceNode = node;
|
|
1565
|
+
}
|
|
1566
|
+
else if (isNumericLiteral(clone)) {
|
|
1567
|
+
clone.numericLiteralFlags = node.numericLiteralFlags;
|
|
1568
|
+
}
|
|
1569
|
+
return setTextRange(clone, node);
|
|
1570
|
+
}
|
|
1571
|
+
// PERF: As an optimization, rather than calling getSynthesizedClone, we'll update
|
|
1572
|
+
// the new node created by visitEachChild with the extra changes getSynthesizedClone
|
|
1573
|
+
// would have made.
|
|
1574
|
+
visited.parent = undefined;
|
|
1575
|
+
return visited;
|
|
1576
|
+
function wrapper(node) {
|
|
1577
|
+
return getSynthesizedDeepCloneWithRenames(node, /*includeTrivia*/ true, renameMap, checker, callback);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
/**
|
|
1581
|
+
* Sets EmitFlags to suppress leading and trailing trivia on the node.
|
|
1582
|
+
*/
|
|
1583
|
+
export function suppressLeadingAndTrailingTrivia(node) {
|
|
1584
|
+
suppressLeadingTrivia(node);
|
|
1585
|
+
suppressTrailingTrivia(node);
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* Sets EmitFlags to suppress leading trivia on the node.
|
|
1589
|
+
*/
|
|
1590
|
+
export function suppressLeadingTrivia(node) {
|
|
1591
|
+
addEmitFlagsRecursively(node, EmitFlags.NoLeadingComments, getFirstChild);
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* Sets EmitFlags to suppress trailing trivia on the node.
|
|
1595
|
+
*/
|
|
1596
|
+
export function suppressTrailingTrivia(node) {
|
|
1597
|
+
addEmitFlagsRecursively(node, EmitFlags.NoTrailingComments, getLastChild);
|
|
1598
|
+
}
|
|
1599
|
+
export function copyComments(sourceNode, targetNode) {
|
|
1600
|
+
const sourceFile = sourceNode.getSourceFile();
|
|
1601
|
+
const text = sourceFile.text;
|
|
1602
|
+
if (hasLeadingLineBreak(sourceNode, text)) {
|
|
1603
|
+
copyLeadingComments(sourceNode, targetNode, sourceFile);
|
|
1604
|
+
}
|
|
1605
|
+
else {
|
|
1606
|
+
copyTrailingAsLeadingComments(sourceNode, targetNode, sourceFile);
|
|
1607
|
+
}
|
|
1608
|
+
copyTrailingComments(sourceNode, targetNode, sourceFile);
|
|
1609
|
+
}
|
|
1610
|
+
function hasLeadingLineBreak(node, text) {
|
|
1611
|
+
const start = node.getFullStart();
|
|
1612
|
+
const end = node.getStart();
|
|
1613
|
+
for (let i = start; i < end; i++) {
|
|
1614
|
+
if (text.charCodeAt(i) === CharacterCodes.lineFeed)
|
|
1615
|
+
return true;
|
|
1616
|
+
}
|
|
1617
|
+
return false;
|
|
1618
|
+
}
|
|
1619
|
+
function addEmitFlagsRecursively(node, flag, getChild) {
|
|
1620
|
+
addEmitFlags(node, flag);
|
|
1621
|
+
const child = getChild(node);
|
|
1622
|
+
if (child)
|
|
1623
|
+
addEmitFlagsRecursively(child, flag, getChild);
|
|
1624
|
+
}
|
|
1625
|
+
function getFirstChild(node) {
|
|
1626
|
+
return node.forEachChild(child => child);
|
|
1627
|
+
}
|
|
1628
|
+
export function getUniqueName(baseName, sourceFile) {
|
|
1629
|
+
let nameText = baseName;
|
|
1630
|
+
for (let i = 1; !isFileLevelUniqueName(sourceFile, nameText); i++) {
|
|
1631
|
+
nameText = `${baseName}_${i}`;
|
|
1632
|
+
}
|
|
1633
|
+
return nameText;
|
|
1634
|
+
}
|
|
1635
|
+
/**
|
|
1636
|
+
* @return The index of the (only) reference to the extracted symbol. We want the cursor
|
|
1637
|
+
* to be on the reference, rather than the declaration, because it's closer to where the
|
|
1638
|
+
* user was before extracting it.
|
|
1639
|
+
*/
|
|
1640
|
+
export function getRenameLocation(edits, renameFilename, name, preferLastLocation) {
|
|
1641
|
+
let delta = 0;
|
|
1642
|
+
let lastPos = -1;
|
|
1643
|
+
for (const { fileName, textChanges } of edits) {
|
|
1644
|
+
Debug.assert(fileName === renameFilename);
|
|
1645
|
+
for (const change of textChanges) {
|
|
1646
|
+
const { span, newText } = change;
|
|
1647
|
+
const index = indexInTextChange(newText, name);
|
|
1648
|
+
if (index !== -1) {
|
|
1649
|
+
lastPos = span.start + delta + index;
|
|
1650
|
+
// If the reference comes first, return immediately.
|
|
1651
|
+
if (!preferLastLocation) {
|
|
1652
|
+
return lastPos;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
delta += newText.length - span.length;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
// If the declaration comes first, return the position of the last occurrence.
|
|
1659
|
+
Debug.assert(preferLastLocation);
|
|
1660
|
+
Debug.assert(lastPos >= 0);
|
|
1661
|
+
return lastPos;
|
|
1662
|
+
}
|
|
1663
|
+
export function copyLeadingComments(sourceNode, targetNode, sourceFile, commentKind, hasTrailingNewLine) {
|
|
1664
|
+
forEachLeadingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment));
|
|
1665
|
+
}
|
|
1666
|
+
export function copyTrailingComments(sourceNode, targetNode, sourceFile, commentKind, hasTrailingNewLine) {
|
|
1667
|
+
forEachTrailingCommentRange(sourceFile.text, sourceNode.end, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticTrailingComment));
|
|
1668
|
+
}
|
|
1669
|
+
/**
|
|
1670
|
+
* This function copies the trailing comments for the token that comes before `sourceNode`, as leading comments of `targetNode`.
|
|
1671
|
+
* This is useful because sometimes a comment that refers to `sourceNode` will be a leading comment for `sourceNode`, according to the
|
|
1672
|
+
* notion of trivia ownership, and instead will be a trailing comment for the token before `sourceNode`, e.g.:
|
|
1673
|
+
* `function foo(\* not leading comment for a *\ a: string) {}`
|
|
1674
|
+
* The comment refers to `a` but belongs to the `(` token, but we might want to copy it.
|
|
1675
|
+
*/
|
|
1676
|
+
export function copyTrailingAsLeadingComments(sourceNode, targetNode, sourceFile, commentKind, hasTrailingNewLine) {
|
|
1677
|
+
forEachTrailingCommentRange(sourceFile.text, sourceNode.pos, getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, addSyntheticLeadingComment));
|
|
1678
|
+
}
|
|
1679
|
+
function getAddCommentsFunction(targetNode, sourceFile, commentKind, hasTrailingNewLine, cb) {
|
|
1680
|
+
return (pos, end, kind, htnl) => {
|
|
1681
|
+
if (kind === SyntaxKind.MultiLineCommentTrivia) {
|
|
1682
|
+
// Remove leading /*
|
|
1683
|
+
pos += 2;
|
|
1684
|
+
// Remove trailing */
|
|
1685
|
+
end -= 2;
|
|
1686
|
+
}
|
|
1687
|
+
else {
|
|
1688
|
+
// Remove leading //
|
|
1689
|
+
pos += 2;
|
|
1690
|
+
}
|
|
1691
|
+
cb(targetNode, commentKind || kind, sourceFile.text.slice(pos, end), hasTrailingNewLine !== undefined ? hasTrailingNewLine : htnl);
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
function indexInTextChange(change, name) {
|
|
1695
|
+
if (startsWith(change, name))
|
|
1696
|
+
return 0;
|
|
1697
|
+
// Add a " " to avoid references inside words
|
|
1698
|
+
let idx = change.indexOf(" " + name);
|
|
1699
|
+
if (idx === -1)
|
|
1700
|
+
idx = change.indexOf("." + name);
|
|
1701
|
+
if (idx === -1)
|
|
1702
|
+
idx = change.indexOf('"' + name);
|
|
1703
|
+
return idx === -1 ? -1 : idx + 1;
|
|
1704
|
+
}
|
|
1705
|
+
/** Na tag, também a expressão com o operador vírgula (CK-02). */
|
|
1706
|
+
export function needsParentheses(expression) {
|
|
1707
|
+
return isObjectLiteralExpression(expression);
|
|
1708
|
+
}
|
|
1709
|
+
export function getContextualTypeFromParent(node, checker) {
|
|
1710
|
+
const { parent } = node;
|
|
1711
|
+
switch (parent.kind) {
|
|
1712
|
+
// Na tag, também o `new` (CK-02).
|
|
1713
|
+
case SyntaxKind.BinaryExpression: {
|
|
1714
|
+
const { left, operatorToken, right } = parent;
|
|
1715
|
+
return isEqualityOperatorKind(operatorToken.kind)
|
|
1716
|
+
? checker.getTypeAtLocation(node === right ? left : right)
|
|
1717
|
+
: checker.getContextualType(node);
|
|
1718
|
+
}
|
|
1719
|
+
case SyntaxKind.CaseClause:
|
|
1720
|
+
return parent.expression === node ? getSwitchedType(parent, checker) : undefined;
|
|
1721
|
+
default:
|
|
1722
|
+
return checker.getContextualType(node);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1725
|
+
export function quote(text, preferences) {
|
|
1726
|
+
// Editors can pass in undefined or empty string - we want to infer the preference in those cases.
|
|
1727
|
+
const quotePreference = preferences.quotePreference || "auto";
|
|
1728
|
+
const quoted = JSON.stringify(text);
|
|
1729
|
+
switch (quotePreference) {
|
|
1730
|
+
// TODO use getQuotePreference to infer the actual quote style.
|
|
1731
|
+
case "auto":
|
|
1732
|
+
case "double":
|
|
1733
|
+
return quoted;
|
|
1734
|
+
case "single":
|
|
1735
|
+
return `'${stripQuotes(quoted).replace("'", "\\'").replace('\\"', '"')}'`;
|
|
1736
|
+
default:
|
|
1737
|
+
return Debug.assertNever(quotePreference);
|
|
1738
|
+
}
|
|
1739
|
+
}
|
|
1740
|
+
/** A igualdade da Linguagem: o `==` e o `!=`. Na tag, também o `===` e o `!==`, que a Linguagem não tem (CK-70). */
|
|
1741
|
+
export function isEqualityOperatorKind(kind) {
|
|
1742
|
+
switch (kind) {
|
|
1743
|
+
case SyntaxKind.EqualsEqualsToken:
|
|
1744
|
+
case SyntaxKind.ExclamationEqualsToken:
|
|
1745
|
+
return true;
|
|
1746
|
+
default:
|
|
1747
|
+
return false;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
/** Na tag, também o template marcado (CK-02). */
|
|
1751
|
+
export function isStringLiteralOrTemplate(node) {
|
|
1752
|
+
switch (node.kind) {
|
|
1753
|
+
case SyntaxKind.StringLiteral:
|
|
1754
|
+
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
|
1755
|
+
case SyntaxKind.TemplateExpression:
|
|
1756
|
+
return true;
|
|
1757
|
+
default:
|
|
1758
|
+
return false;
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
export function hasIndexSignature(type) {
|
|
1762
|
+
return !!type.getStringIndexType() || !!type.getNumberIndexType();
|
|
1763
|
+
}
|
|
1764
|
+
export function getSwitchedType(caseClause, checker) {
|
|
1765
|
+
return checker.getTypeAtLocation(caseClause.parent.parent.expression);
|
|
1766
|
+
}
|
|
1767
|
+
/**
|
|
1768
|
+
* O tipo como nó, se todo símbolo que ele nomeia é acessível do ponto. Na tag, o tracker recebia também os avisos do
|
|
1769
|
+
* `this`, do `private` de uma classe e do `unique symbol` inacessíveis, que o node builder da cópia não dá (CK-02), e o
|
|
1770
|
+
* host do specifier somava o diretório comum do `Program` (CK-47).
|
|
1771
|
+
*/
|
|
1772
|
+
export function getTypeNodeIfAccessible(type, enclosingScope, program, host) {
|
|
1773
|
+
const checker = program.getTypeChecker();
|
|
1774
|
+
let typeIsAccessible = true;
|
|
1775
|
+
const res = checker.typeToTypeNode(type, enclosingScope, /*flags*/ undefined, {
|
|
1776
|
+
trackSymbol: (symbol, declaration, meaning) => {
|
|
1777
|
+
typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning).accessibility === SymbolAccessibility.Accessible;
|
|
1778
|
+
},
|
|
1779
|
+
moduleResolverHost: createModuleSpecifierResolutionHost(host),
|
|
1780
|
+
});
|
|
1781
|
+
return typeIsAccessible ? res : undefined;
|
|
1782
|
+
}
|
|
1783
|
+
/** Na tag, também a construct signature (CK-02) e a method signature (CK-36). */
|
|
1784
|
+
export function syntaxRequiresTrailingCommaOrSemicolonOrASI(kind) {
|
|
1785
|
+
return kind === SyntaxKind.CallSignature
|
|
1786
|
+
|| kind === SyntaxKind.IndexSignature
|
|
1787
|
+
|| kind === SyntaxKind.PropertySignature;
|
|
1788
|
+
}
|
|
1789
|
+
// Na tag, o `syntaxRequiresTrailingFunctionBlockOrSemicolonOrASI`: a declaração com corpo de função que podia terminar
|
|
1790
|
+
// sem ele (a `function`, o construtor, o método e o acessor), que a parse tree não tem (CK-02).
|
|
1791
|
+
export function syntaxRequiresTrailingModuleBlockOrSemicolonOrASI(kind) {
|
|
1792
|
+
return kind === SyntaxKind.ModuleDeclaration;
|
|
1793
|
+
}
|
|
1794
|
+
/** Na tag, também o `debugger` e a propriedade de classe (CK-02), e o `import =` e o `export as namespace` (CK-03). */
|
|
1795
|
+
export function syntaxRequiresTrailingSemicolonOrASI(kind) {
|
|
1796
|
+
return kind === SyntaxKind.VariableStatement
|
|
1797
|
+
|| kind === SyntaxKind.ExpressionStatement
|
|
1798
|
+
|| kind === SyntaxKind.DoStatement
|
|
1799
|
+
|| kind === SyntaxKind.ContinueStatement
|
|
1800
|
+
|| kind === SyntaxKind.BreakStatement
|
|
1801
|
+
|| kind === SyntaxKind.ReturnStatement
|
|
1802
|
+
|| kind === SyntaxKind.ThrowStatement
|
|
1803
|
+
|| kind === SyntaxKind.TypeAliasDeclaration
|
|
1804
|
+
|| kind === SyntaxKind.ImportDeclaration
|
|
1805
|
+
|| kind === SyntaxKind.ExportDeclaration
|
|
1806
|
+
|| kind === SyntaxKind.ExportAssignment;
|
|
1807
|
+
}
|
|
1808
|
+
export const syntaxMayBeASICandidate = or(syntaxRequiresTrailingCommaOrSemicolonOrASI, syntaxRequiresTrailingModuleBlockOrSemicolonOrASI, syntaxRequiresTrailingSemicolonOrASI);
|
|
1809
|
+
function nodeIsASICandidate(node, sourceFile) {
|
|
1810
|
+
const lastToken = node.getLastToken(sourceFile);
|
|
1811
|
+
if (lastToken && lastToken.kind === SyntaxKind.SemicolonToken) {
|
|
1812
|
+
return false;
|
|
1813
|
+
}
|
|
1814
|
+
if (syntaxRequiresTrailingCommaOrSemicolonOrASI(node.kind)) {
|
|
1815
|
+
if (lastToken && lastToken.kind === SyntaxKind.CommaToken) {
|
|
1816
|
+
return false;
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1819
|
+
else if (syntaxRequiresTrailingModuleBlockOrSemicolonOrASI(node.kind)) {
|
|
1820
|
+
const lastChild = last(node.getChildren(sourceFile));
|
|
1821
|
+
if (lastChild && isModuleBlock(lastChild)) {
|
|
1822
|
+
return false;
|
|
1823
|
+
}
|
|
1824
|
+
}
|
|
1825
|
+
// Na tag, também a declaração que termina num corpo de função (CK-02).
|
|
1826
|
+
else if (!syntaxRequiresTrailingSemicolonOrASI(node.kind)) {
|
|
1827
|
+
return false;
|
|
1828
|
+
}
|
|
1829
|
+
// See comment in parser’s `parseDoStatement`
|
|
1830
|
+
if (node.kind === SyntaxKind.DoStatement) {
|
|
1831
|
+
return true;
|
|
1832
|
+
}
|
|
1833
|
+
const topNode = findAncestor(node, ancestor => !ancestor.parent);
|
|
1834
|
+
const nextToken = findNextToken(node, topNode, sourceFile);
|
|
1835
|
+
if (!nextToken || nextToken.kind === SyntaxKind.CloseBraceToken) {
|
|
1836
|
+
return true;
|
|
1837
|
+
}
|
|
1838
|
+
const startLine = sourceFile.getLineAndCharacterOfPosition(node.getEnd()).line;
|
|
1839
|
+
const endLine = sourceFile.getLineAndCharacterOfPosition(nextToken.getStart(sourceFile)).line;
|
|
1840
|
+
return startLine !== endLine;
|
|
1841
|
+
}
|
|
1842
|
+
export function positionIsASICandidate(pos, context, sourceFile) {
|
|
1843
|
+
const contextAncestor = findAncestor(context, ancestor => {
|
|
1844
|
+
if (ancestor.end !== pos) {
|
|
1845
|
+
return "quit";
|
|
1846
|
+
}
|
|
1847
|
+
return syntaxMayBeASICandidate(ancestor.kind);
|
|
1848
|
+
});
|
|
1849
|
+
return !!contextAncestor && nodeIsASICandidate(contextAncestor, sourceFile);
|
|
1850
|
+
}
|
|
1851
|
+
export function probablyUsesSemicolons(sourceFile) {
|
|
1852
|
+
let withSemicolon = 0;
|
|
1853
|
+
let withoutSemicolon = 0;
|
|
1854
|
+
const nStatementsToObserve = 5;
|
|
1855
|
+
forEachChild(sourceFile, function visit(node) {
|
|
1856
|
+
if (syntaxRequiresTrailingSemicolonOrASI(node.kind)) {
|
|
1857
|
+
const lastToken = node.getLastToken(sourceFile);
|
|
1858
|
+
if (lastToken && lastToken.kind === SyntaxKind.SemicolonToken) {
|
|
1859
|
+
withSemicolon++;
|
|
1860
|
+
}
|
|
1861
|
+
else {
|
|
1862
|
+
withoutSemicolon++;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
if (withSemicolon + withoutSemicolon >= nStatementsToObserve) {
|
|
1866
|
+
return true;
|
|
1867
|
+
}
|
|
1868
|
+
return forEachChild(node, visit);
|
|
1869
|
+
});
|
|
1870
|
+
// One statement missing a semicolon isn’t sufficient evidence to say the user
|
|
1871
|
+
// doesn’t want semicolons, because they may not even be done writing that statement.
|
|
1872
|
+
if (withSemicolon === 0 && withoutSemicolon <= 1) {
|
|
1873
|
+
return true;
|
|
1874
|
+
}
|
|
1875
|
+
// If even 2/5 places have a semicolon, the user probably wants semicolons
|
|
1876
|
+
return withSemicolon / withoutSemicolon > 1 / nStatementsToObserve;
|
|
1877
|
+
}
|
|
1878
|
+
export function getRefactorContextSpan({ startPosition, endPosition }) {
|
|
1879
|
+
return createTextSpanFromBounds(startPosition, endPosition === undefined ? startPosition : endPosition);
|
|
1880
|
+
}
|
|
1881
|
+
export function getNameForExportedSymbol(symbol, scriptTarget) {
|
|
1882
|
+
// Na tag, também o `export =` (CK-03).
|
|
1883
|
+
if (symbol.escapedName === InternalSymbolName.Default) {
|
|
1884
|
+
// O nome do `export default foo;` é `foo`; o do `export default 0`, o do arquivo em camelCase.
|
|
1885
|
+
return firstDefined(symbol.declarations, d => isExportAssignment(d) && isIdentifier(d.expression) ? d.expression.text : undefined)
|
|
1886
|
+
|| moduleSymbolToValidIdentifier(Debug.checkDefined(symbol.parent), scriptTarget);
|
|
1887
|
+
}
|
|
1888
|
+
return symbol.name;
|
|
1889
|
+
}
|
|
1890
|
+
/**
|
|
1891
|
+
* Useful to check whether a string contains another string at a specific index
|
|
1892
|
+
* without allocating another string or traversing the entire contents of the outer string.
|
|
1893
|
+
*
|
|
1894
|
+
* This function is useful in place of either of the following:
|
|
1895
|
+
*
|
|
1896
|
+
* ```ts
|
|
1897
|
+
* // Allocates
|
|
1898
|
+
* haystack.substr(startIndex, needle.length) === needle
|
|
1899
|
+
*
|
|
1900
|
+
* // Full traversal
|
|
1901
|
+
* haystack.indexOf(needle, startIndex) === startIndex
|
|
1902
|
+
* ```
|
|
1903
|
+
*
|
|
1904
|
+
* @param haystack The string that potentially contains `needle`.
|
|
1905
|
+
* @param needle The string whose content might sit within `haystack`.
|
|
1906
|
+
* @param startIndex The index within `haystack` to start searching for `needle`.
|
|
1907
|
+
*/
|
|
1908
|
+
export function stringContainsAt(haystack, needle, startIndex) {
|
|
1909
|
+
const needleLength = needle.length;
|
|
1910
|
+
if (needleLength + startIndex > haystack.length) {
|
|
1911
|
+
return false;
|
|
1912
|
+
}
|
|
1913
|
+
for (let i = 0; i < needleLength; i++) {
|
|
1914
|
+
if (needle.charCodeAt(i) !== haystack.charCodeAt(i + startIndex))
|
|
1915
|
+
return false;
|
|
1916
|
+
}
|
|
1917
|
+
return true;
|
|
1918
|
+
}
|
|
1919
|
+
// Do `codefixes/importFixes.ts` da tag: só cálculo de nome, que a leitura usa sem a edição (CK-67).
|
|
1920
|
+
export function moduleSymbolToValidIdentifier(moduleSymbol, target) {
|
|
1921
|
+
return moduleSpecifierToValidIdentifier(removeFileExtension(stripQuotes(moduleSymbol.name)), target);
|
|
1922
|
+
}
|
|
1923
|
+
export function moduleSpecifierToValidIdentifier(moduleSpecifier, target) {
|
|
1924
|
+
const baseName = getBaseFileName(removeSuffix(moduleSpecifier, "/index"));
|
|
1925
|
+
let res = "";
|
|
1926
|
+
let lastCharWasValid = true;
|
|
1927
|
+
const firstCharCode = baseName.charCodeAt(0);
|
|
1928
|
+
if (isIdentifierStart(firstCharCode, target)) {
|
|
1929
|
+
res += String.fromCharCode(firstCharCode);
|
|
1930
|
+
}
|
|
1931
|
+
else {
|
|
1932
|
+
lastCharWasValid = false;
|
|
1933
|
+
}
|
|
1934
|
+
for (let i = 1; i < baseName.length; i++) {
|
|
1935
|
+
const ch = baseName.charCodeAt(i);
|
|
1936
|
+
const isValid = isIdentifierPart(ch, target);
|
|
1937
|
+
if (isValid) {
|
|
1938
|
+
let char = String.fromCharCode(ch);
|
|
1939
|
+
if (!lastCharWasValid) {
|
|
1940
|
+
char = char.toUpperCase();
|
|
1941
|
+
}
|
|
1942
|
+
res += char;
|
|
1943
|
+
}
|
|
1944
|
+
lastCharWasValid = isValid;
|
|
1945
|
+
}
|
|
1946
|
+
// Need `|| "_"` to ensure result isn't empty.
|
|
1947
|
+
return !isStringANonContextualKeyword(res) ? res || "_" : `_${res}`;
|
|
1948
|
+
}
|
|
1949
|
+
// Do `formatting/formatting.ts` da tag: só usa a árvore e os comentários do texto, e a leitura o usa sem a edição (CK-67).
|
|
1950
|
+
/**
|
|
1951
|
+
* @param precedingToken pass `null` if preceding token was already computed and result was `undefined`.
|
|
1952
|
+
*/
|
|
1953
|
+
export function getRangeOfEnclosingComment(sourceFile, position, precedingToken, tokenAtPosition = getTokenAtPosition(sourceFile, position)) {
|
|
1954
|
+
// Na tag, a posição dentro de um JSDoc subia ao nó que ele documenta; a cópia não tem o JSDoc (CK-03).
|
|
1955
|
+
const tokenStart = tokenAtPosition.getStart(sourceFile);
|
|
1956
|
+
if (tokenStart <= position && position < tokenAtPosition.getEnd()) {
|
|
1957
|
+
return undefined;
|
|
1958
|
+
}
|
|
1959
|
+
// eslint-disable-next-line no-null/no-null
|
|
1960
|
+
precedingToken = precedingToken === null ? undefined : precedingToken === undefined ? findPrecedingToken(position, sourceFile) : precedingToken;
|
|
1961
|
+
// Between two consecutive tokens, all comments are either trailing on the former
|
|
1962
|
+
// or leading on the latter (and none are in both lists).
|
|
1963
|
+
const trailingRangesOfPreviousToken = precedingToken && getTrailingCommentRanges(sourceFile.text, precedingToken.end);
|
|
1964
|
+
const leadingCommentRangesOfNextToken = getLeadingCommentRangesOfNode(tokenAtPosition, sourceFile);
|
|
1965
|
+
const commentRanges = concatenate(trailingRangesOfPreviousToken, leadingCommentRangesOfNextToken);
|
|
1966
|
+
return commentRanges && find(commentRanges, range => rangeContainsPositionExclusive(range, position) ||
|
|
1967
|
+
// The end marker of a single-line comment does not include the newline character.
|
|
1968
|
+
// With caret at `^`, in the following case, we are inside a comment (^ denotes the cursor position):
|
|
1969
|
+
//
|
|
1970
|
+
// // asdf ^\n
|
|
1971
|
+
//
|
|
1972
|
+
// But for closed multi-line comments, we don't want to be inside the comment in the following case:
|
|
1973
|
+
//
|
|
1974
|
+
// /* asdf */^
|
|
1975
|
+
//
|
|
1976
|
+
// However, unterminated multi-line comments *do* contain their end.
|
|
1977
|
+
//
|
|
1978
|
+
// Internally, we represent the end of the comment at the newline and closing '/', respectively.
|
|
1979
|
+
//
|
|
1980
|
+
position === range.end && (range.kind === SyntaxKind.SingleLineCommentTrivia || position === sourceFile.getFullWidth()));
|
|
1981
|
+
}
|