@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
package/dist/services.js
ADDED
|
@@ -0,0 +1,1480 @@
|
|
|
1
|
+
// Modificado de microsoft/TypeScript v3.9.10, src/services/services.ts: o namespace virou módulo ES, com os imports explícitos.
|
|
2
|
+
// O arquivo entra com o modelo de objetos do language service, a casca e os serviços dos grupos que já vieram; o resto
|
|
3
|
+
// dele vem com o grupo que o usa (o docs/ARCHITECTURE.md do pacote).
|
|
4
|
+
import * as ts from "./_namespaces/ts.js";
|
|
5
|
+
import { AssignmentDeclarationKind, CharacterCodes, Debug, DocumentHighlights, FindAllReferences, GoToDefinition, IndexKind, ModifierFlags, NavigationBar, NodeFlags, ObjectFlags, OperationCanceledException, OutliningElementsCollector, Rename, ScriptKind, ScriptTarget, SignatureHelp, SmartSelectionRange, SymbolDisplay, SyntaxKind, TransformFlags, TypeFlags, arrayIsEqualTo, check, compareValues, computePositionOfLineAndCharacter, Completions, computeSuggestionDiagnostics, createDocumentRegistry, createGetCanonicalFileName, createMap, createMapFromTemplate, createMultiMap, createSourceFile, createTextSpanFromBounds, createTextSpanFromNode, createTextSpanFromRange, createUnderscoreEscapedMap, deduplicate, emptyArray, emptyOptions, equateValues, find, findChildOfKind, findPrecedingToken, first, flatMap, forEach, forEachChild, getAdjustedRenameLocation, getAssignmentDeclarationKind, getContainerNode, getEscapedTextOfIdentifierOrLiteral, getLineAndCharacterOfPosition, getLineStarts, getNameFromPropertyName, getNonAssignedNameOfDeclaration, getObjectFlags, getRangeOfEnclosingComment, getScriptKind, getSnapshotText, getSourceFileOfNode, getTokenPosOfNode, getTouchingPropertyName, getTouchingToken, hasProperty, hostUsesCaseSensitiveFileNames, idText, identity, isBindingPattern, isComputedPropertyName, isDeclarationName, isIdentifier, isInComment, isInString, isInTemplateString, isInsideJsxElementOrAttribute, isIntrinsicJsxName, isJsxAttributes, isJsxClosingElement, isJsxElement, isJsxOpeningElement, isJsxText, isLiteralComputedPropertyDeclarationName, isNamedExports, isNodeKind, isObjectLiteralElement, isObjectLiteralExpression, isPropertyAccessExpression, isPropertyName, isString, isStringOrNumericLiteralLike, lastOrUndefined, localizedDiagnosticMessages, map, mapDefined, normalizePath, positionIsSynthesized, scanner, setLocalizedDiagnosticMessages, setObjectAllocator, setTypeObjectAllocator, symbolName, tagNamesAreEquivalent, textSpanEnd, timestamp, toPath, typeToDisplayParts, updateSourceFile, } from "./_namespaces/ts.js";
|
|
6
|
+
/** A versão da API do language service. */
|
|
7
|
+
export const servicesVersion = "0.8";
|
|
8
|
+
function createNode(kind, pos, end, parent) {
|
|
9
|
+
const node = isNodeKind(kind) ? new NodeObject(kind, pos, end) :
|
|
10
|
+
kind === SyntaxKind.Identifier ? new IdentifierObject(SyntaxKind.Identifier, pos, end) :
|
|
11
|
+
new TokenObject(kind, pos, end);
|
|
12
|
+
node.parent = parent;
|
|
13
|
+
node.flags = parent.flags & NodeFlags.ContextFlags;
|
|
14
|
+
return node;
|
|
15
|
+
}
|
|
16
|
+
class NodeObject {
|
|
17
|
+
constructor(kind, pos, end) {
|
|
18
|
+
this.pos = pos;
|
|
19
|
+
this.end = end;
|
|
20
|
+
this.flags = NodeFlags.None;
|
|
21
|
+
this.modifierFlagsCache = ModifierFlags.None;
|
|
22
|
+
this.transformFlags = TransformFlags.None;
|
|
23
|
+
this.parent = undefined;
|
|
24
|
+
this.kind = kind;
|
|
25
|
+
}
|
|
26
|
+
assertHasRealPosition(message) {
|
|
27
|
+
// eslint-disable-next-line debug-assert
|
|
28
|
+
Debug.assert(!positionIsSynthesized(this.pos) && !positionIsSynthesized(this.end), message || "Node must have a real position for this operation");
|
|
29
|
+
}
|
|
30
|
+
getSourceFile() {
|
|
31
|
+
return getSourceFileOfNode(this);
|
|
32
|
+
}
|
|
33
|
+
getStart(sourceFile) {
|
|
34
|
+
this.assertHasRealPosition();
|
|
35
|
+
return getTokenPosOfNode(this, sourceFile);
|
|
36
|
+
}
|
|
37
|
+
getFullStart() {
|
|
38
|
+
this.assertHasRealPosition();
|
|
39
|
+
return this.pos;
|
|
40
|
+
}
|
|
41
|
+
getEnd() {
|
|
42
|
+
this.assertHasRealPosition();
|
|
43
|
+
return this.end;
|
|
44
|
+
}
|
|
45
|
+
getWidth(sourceFile) {
|
|
46
|
+
this.assertHasRealPosition();
|
|
47
|
+
return this.getEnd() - this.getStart(sourceFile);
|
|
48
|
+
}
|
|
49
|
+
getFullWidth() {
|
|
50
|
+
this.assertHasRealPosition();
|
|
51
|
+
return this.end - this.pos;
|
|
52
|
+
}
|
|
53
|
+
getLeadingTriviaWidth(sourceFile) {
|
|
54
|
+
this.assertHasRealPosition();
|
|
55
|
+
return this.getStart(sourceFile) - this.pos;
|
|
56
|
+
}
|
|
57
|
+
getFullText(sourceFile) {
|
|
58
|
+
this.assertHasRealPosition();
|
|
59
|
+
return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end);
|
|
60
|
+
}
|
|
61
|
+
getText(sourceFile) {
|
|
62
|
+
this.assertHasRealPosition();
|
|
63
|
+
if (!sourceFile) {
|
|
64
|
+
sourceFile = this.getSourceFile();
|
|
65
|
+
}
|
|
66
|
+
return sourceFile.text.substring(this.getStart(sourceFile), this.getEnd());
|
|
67
|
+
}
|
|
68
|
+
getChildCount(sourceFile) {
|
|
69
|
+
return this.getChildren(sourceFile).length;
|
|
70
|
+
}
|
|
71
|
+
getChildAt(index, sourceFile) {
|
|
72
|
+
return this.getChildren(sourceFile)[index];
|
|
73
|
+
}
|
|
74
|
+
getChildren(sourceFile) {
|
|
75
|
+
this.assertHasRealPosition("Node without a real position cannot be scanned and thus has no token nodes - use forEachChild and collect the result if that's fine");
|
|
76
|
+
return this._children || (this._children = createChildren(this, sourceFile));
|
|
77
|
+
}
|
|
78
|
+
getFirstToken(sourceFile) {
|
|
79
|
+
this.assertHasRealPosition();
|
|
80
|
+
const children = this.getChildren(sourceFile);
|
|
81
|
+
if (!children.length) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
const child = find(children, kid => kid.kind < SyntaxKind.FirstJSDocNode || kid.kind > SyntaxKind.LastJSDocNode);
|
|
85
|
+
return child.kind < SyntaxKind.FirstNode ?
|
|
86
|
+
child :
|
|
87
|
+
child.getFirstToken(sourceFile);
|
|
88
|
+
}
|
|
89
|
+
getLastToken(sourceFile) {
|
|
90
|
+
this.assertHasRealPosition();
|
|
91
|
+
const children = this.getChildren(sourceFile);
|
|
92
|
+
const child = lastOrUndefined(children);
|
|
93
|
+
if (!child) {
|
|
94
|
+
return undefined;
|
|
95
|
+
}
|
|
96
|
+
return child.kind < SyntaxKind.FirstNode ? child : child.getLastToken(sourceFile);
|
|
97
|
+
}
|
|
98
|
+
forEachChild(cbNode, cbNodeArray) {
|
|
99
|
+
return forEachChild(this, cbNode, cbNodeArray);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function createChildren(node, sourceFile) {
|
|
103
|
+
if (!isNodeKind(node.kind)) {
|
|
104
|
+
return emptyArray;
|
|
105
|
+
}
|
|
106
|
+
const children = [];
|
|
107
|
+
scanner.setText((sourceFile || node.getSourceFile()).text);
|
|
108
|
+
let pos = node.pos;
|
|
109
|
+
const processNode = (child) => {
|
|
110
|
+
addSyntheticNodes(children, pos, child.pos, node);
|
|
111
|
+
children.push(child);
|
|
112
|
+
pos = child.end;
|
|
113
|
+
};
|
|
114
|
+
const processNodes = (nodes) => {
|
|
115
|
+
addSyntheticNodes(children, pos, nodes.pos, node);
|
|
116
|
+
children.push(createSyntaxList(nodes, node));
|
|
117
|
+
pos = nodes.end;
|
|
118
|
+
};
|
|
119
|
+
node.forEachChild(processNode, processNodes);
|
|
120
|
+
addSyntheticNodes(children, pos, node.end, node);
|
|
121
|
+
scanner.setText(undefined);
|
|
122
|
+
return children;
|
|
123
|
+
}
|
|
124
|
+
function addSyntheticNodes(nodes, pos, end, parent) {
|
|
125
|
+
scanner.setTextPos(pos);
|
|
126
|
+
while (pos < end) {
|
|
127
|
+
const token = scanner.scan();
|
|
128
|
+
const textPos = scanner.getTextPos();
|
|
129
|
+
if (textPos <= end) {
|
|
130
|
+
if (token === SyntaxKind.Identifier) {
|
|
131
|
+
Debug.fail(`Did not expect ${Debug.formatSyntaxKind(parent.kind)} to have an Identifier in its trivia`);
|
|
132
|
+
}
|
|
133
|
+
nodes.push(createNode(token, pos, textPos, parent));
|
|
134
|
+
}
|
|
135
|
+
pos = textPos;
|
|
136
|
+
if (token === SyntaxKind.EndOfFileToken) {
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function createSyntaxList(nodes, parent) {
|
|
142
|
+
const list = createNode(SyntaxKind.SyntaxList, nodes.pos, nodes.end, parent);
|
|
143
|
+
list._children = [];
|
|
144
|
+
let pos = nodes.pos;
|
|
145
|
+
for (const node of nodes) {
|
|
146
|
+
addSyntheticNodes(list._children, pos, node.pos, parent);
|
|
147
|
+
list._children.push(node);
|
|
148
|
+
pos = node.end;
|
|
149
|
+
}
|
|
150
|
+
addSyntheticNodes(list._children, pos, nodes.end, parent);
|
|
151
|
+
return list;
|
|
152
|
+
}
|
|
153
|
+
class TokenOrIdentifierObject {
|
|
154
|
+
constructor(pos, end) {
|
|
155
|
+
// Os campos na mesma ordem que no `NodeObject`.
|
|
156
|
+
this.pos = pos;
|
|
157
|
+
this.end = end;
|
|
158
|
+
this.flags = NodeFlags.None;
|
|
159
|
+
this.modifierFlagsCache = ModifierFlags.None;
|
|
160
|
+
this.transformFlags = TransformFlags.None;
|
|
161
|
+
this.parent = undefined;
|
|
162
|
+
}
|
|
163
|
+
getSourceFile() {
|
|
164
|
+
return getSourceFileOfNode(this);
|
|
165
|
+
}
|
|
166
|
+
getStart(sourceFile) {
|
|
167
|
+
return getTokenPosOfNode(this, sourceFile);
|
|
168
|
+
}
|
|
169
|
+
getFullStart() {
|
|
170
|
+
return this.pos;
|
|
171
|
+
}
|
|
172
|
+
getEnd() {
|
|
173
|
+
return this.end;
|
|
174
|
+
}
|
|
175
|
+
getWidth(sourceFile) {
|
|
176
|
+
return this.getEnd() - this.getStart(sourceFile);
|
|
177
|
+
}
|
|
178
|
+
getFullWidth() {
|
|
179
|
+
return this.end - this.pos;
|
|
180
|
+
}
|
|
181
|
+
getLeadingTriviaWidth(sourceFile) {
|
|
182
|
+
return this.getStart(sourceFile) - this.pos;
|
|
183
|
+
}
|
|
184
|
+
getFullText(sourceFile) {
|
|
185
|
+
return (sourceFile || this.getSourceFile()).text.substring(this.pos, this.end);
|
|
186
|
+
}
|
|
187
|
+
getText(sourceFile) {
|
|
188
|
+
if (!sourceFile) {
|
|
189
|
+
sourceFile = this.getSourceFile();
|
|
190
|
+
}
|
|
191
|
+
return sourceFile.text.substring(this.getStart(sourceFile), this.getEnd());
|
|
192
|
+
}
|
|
193
|
+
getChildCount() {
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
getChildAt() {
|
|
197
|
+
return undefined;
|
|
198
|
+
}
|
|
199
|
+
getChildren() {
|
|
200
|
+
return emptyArray;
|
|
201
|
+
}
|
|
202
|
+
getFirstToken() {
|
|
203
|
+
return undefined;
|
|
204
|
+
}
|
|
205
|
+
getLastToken() {
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
forEachChild() {
|
|
209
|
+
return undefined;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
class SymbolObject {
|
|
213
|
+
constructor(flags, name) {
|
|
214
|
+
this.flags = flags;
|
|
215
|
+
this.escapedName = name;
|
|
216
|
+
}
|
|
217
|
+
getFlags() {
|
|
218
|
+
return this.flags;
|
|
219
|
+
}
|
|
220
|
+
get name() {
|
|
221
|
+
return symbolName(this);
|
|
222
|
+
}
|
|
223
|
+
getEscapedName() {
|
|
224
|
+
return this.escapedName;
|
|
225
|
+
}
|
|
226
|
+
getName() {
|
|
227
|
+
return this.name;
|
|
228
|
+
}
|
|
229
|
+
getDeclarations() {
|
|
230
|
+
return this.declarations;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
class TokenObject extends TokenOrIdentifierObject {
|
|
234
|
+
constructor(kind, pos, end) {
|
|
235
|
+
super(pos, end);
|
|
236
|
+
this.kind = kind;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
class IdentifierObject extends TokenOrIdentifierObject {
|
|
240
|
+
constructor(_kind, pos, end) {
|
|
241
|
+
super(pos, end);
|
|
242
|
+
this.kind = SyntaxKind.Identifier;
|
|
243
|
+
}
|
|
244
|
+
get text() {
|
|
245
|
+
return idText(this);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
IdentifierObject.prototype.kind = SyntaxKind.Identifier;
|
|
249
|
+
class TypeObject {
|
|
250
|
+
constructor(checker, flags) {
|
|
251
|
+
this.checker = checker;
|
|
252
|
+
this.flags = flags;
|
|
253
|
+
}
|
|
254
|
+
getFlags() {
|
|
255
|
+
return this.flags;
|
|
256
|
+
}
|
|
257
|
+
getSymbol() {
|
|
258
|
+
return this.symbol;
|
|
259
|
+
}
|
|
260
|
+
getProperties() {
|
|
261
|
+
return this.checker.getPropertiesOfType(this);
|
|
262
|
+
}
|
|
263
|
+
getProperty(propertyName) {
|
|
264
|
+
return this.checker.getPropertyOfType(this, propertyName);
|
|
265
|
+
}
|
|
266
|
+
getApparentProperties() {
|
|
267
|
+
return this.checker.getAugmentedPropertiesOfType(this);
|
|
268
|
+
}
|
|
269
|
+
getCallSignatures() {
|
|
270
|
+
return this.checker.getSignaturesOfType(this);
|
|
271
|
+
}
|
|
272
|
+
getStringIndexType() {
|
|
273
|
+
return this.checker.getIndexTypeOfType(this, IndexKind.String);
|
|
274
|
+
}
|
|
275
|
+
getNumberIndexType() {
|
|
276
|
+
return this.checker.getIndexTypeOfType(this, IndexKind.Number);
|
|
277
|
+
}
|
|
278
|
+
isNullableType() {
|
|
279
|
+
return this.checker.isNullableType(this);
|
|
280
|
+
}
|
|
281
|
+
getNonNullableType() {
|
|
282
|
+
return this.checker.getNonNullableType(this);
|
|
283
|
+
}
|
|
284
|
+
getNonOptionalType() {
|
|
285
|
+
return this.checker.getNonOptionalType(this);
|
|
286
|
+
}
|
|
287
|
+
getConstraint() {
|
|
288
|
+
return this.checker.getBaseConstraintOfType(this);
|
|
289
|
+
}
|
|
290
|
+
getDefault() {
|
|
291
|
+
return this.checker.getDefaultFromTypeParameter(this);
|
|
292
|
+
}
|
|
293
|
+
isUnion() {
|
|
294
|
+
return !!(this.flags & TypeFlags.Union);
|
|
295
|
+
}
|
|
296
|
+
isIntersection() {
|
|
297
|
+
return !!(this.flags & TypeFlags.Intersection);
|
|
298
|
+
}
|
|
299
|
+
isUnionOrIntersection() {
|
|
300
|
+
return !!(this.flags & TypeFlags.UnionOrIntersection);
|
|
301
|
+
}
|
|
302
|
+
isLiteral() {
|
|
303
|
+
return !!(this.flags & TypeFlags.StringOrNumberLiteral);
|
|
304
|
+
}
|
|
305
|
+
isStringLiteral() {
|
|
306
|
+
return !!(this.flags & TypeFlags.StringLiteral);
|
|
307
|
+
}
|
|
308
|
+
isNumberLiteral() {
|
|
309
|
+
return !!(this.flags & TypeFlags.NumberLiteral);
|
|
310
|
+
}
|
|
311
|
+
isTypeParameter() {
|
|
312
|
+
return !!(this.flags & TypeFlags.TypeParameter);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* O `referenceType.typeArguments` para quem usa a API.
|
|
316
|
+
*/
|
|
317
|
+
get typeArguments() {
|
|
318
|
+
if (getObjectFlags(this) & ObjectFlags.Reference) {
|
|
319
|
+
return this.checker.getTypeArguments(this);
|
|
320
|
+
}
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
class SignatureObject {
|
|
325
|
+
constructor(checker, flags) {
|
|
326
|
+
this.checker = checker;
|
|
327
|
+
this.flags = flags;
|
|
328
|
+
}
|
|
329
|
+
getDeclaration() {
|
|
330
|
+
return this.declaration;
|
|
331
|
+
}
|
|
332
|
+
getTypeParameters() {
|
|
333
|
+
return this.typeParameters;
|
|
334
|
+
}
|
|
335
|
+
getParameters() {
|
|
336
|
+
return this.parameters;
|
|
337
|
+
}
|
|
338
|
+
getReturnType() {
|
|
339
|
+
return this.checker.getReturnTypeOfSignature(this);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
class SourceFileObject extends NodeObject {
|
|
343
|
+
constructor(kind, pos, end) {
|
|
344
|
+
super(kind, pos, end);
|
|
345
|
+
this.kind = SyntaxKind.SourceFile;
|
|
346
|
+
}
|
|
347
|
+
update(newText, textChangeRange) {
|
|
348
|
+
return updateSourceFile(this, newText, textChangeRange);
|
|
349
|
+
}
|
|
350
|
+
getLineAndCharacterOfPosition(position) {
|
|
351
|
+
return getLineAndCharacterOfPosition(this, position);
|
|
352
|
+
}
|
|
353
|
+
getLineStarts() {
|
|
354
|
+
return getLineStarts(this);
|
|
355
|
+
}
|
|
356
|
+
getPositionOfLineAndCharacter(line, character, allowEdits) {
|
|
357
|
+
return computePositionOfLineAndCharacter(getLineStarts(this), line, character, this.text, allowEdits);
|
|
358
|
+
}
|
|
359
|
+
getLineEndOfPosition(pos) {
|
|
360
|
+
const { line } = this.getLineAndCharacterOfPosition(pos);
|
|
361
|
+
const lineStarts = this.getLineStarts();
|
|
362
|
+
let lastCharPos;
|
|
363
|
+
if (line + 1 >= lineStarts.length) {
|
|
364
|
+
lastCharPos = this.getEnd();
|
|
365
|
+
}
|
|
366
|
+
if (!lastCharPos) {
|
|
367
|
+
lastCharPos = lineStarts[line + 1] - 1;
|
|
368
|
+
}
|
|
369
|
+
const fullText = this.getFullText();
|
|
370
|
+
// Com a quebra de linha "\r\n", a posição é a do último caractere antes dela.
|
|
371
|
+
return fullText[lastCharPos] === "\n" && fullText[lastCharPos - 1] === "\r" ? lastCharPos - 1 : lastCharPos;
|
|
372
|
+
}
|
|
373
|
+
getNamedDeclarations() {
|
|
374
|
+
if (!this.namedDeclarations) {
|
|
375
|
+
this.namedDeclarations = this.computeNamedDeclarations();
|
|
376
|
+
}
|
|
377
|
+
return this.namedDeclarations;
|
|
378
|
+
}
|
|
379
|
+
computeNamedDeclarations() {
|
|
380
|
+
const result = createMultiMap();
|
|
381
|
+
this.forEachChild(visit);
|
|
382
|
+
return result;
|
|
383
|
+
function addDeclaration(declaration) {
|
|
384
|
+
const name = getDeclarationName(declaration);
|
|
385
|
+
if (name) {
|
|
386
|
+
result.add(name, declaration);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
function getDeclarationName(declaration) {
|
|
390
|
+
const name = getNonAssignedNameOfDeclaration(declaration);
|
|
391
|
+
return name && (isComputedPropertyName(name) && isPropertyAccessExpression(name.expression) ? name.expression.name.text
|
|
392
|
+
: isPropertyName(name) ? getNameFromPropertyName(name) : undefined);
|
|
393
|
+
}
|
|
394
|
+
function visit(node) {
|
|
395
|
+
switch (node.kind) {
|
|
396
|
+
case SyntaxKind.TypeAliasDeclaration:
|
|
397
|
+
case SyntaxKind.ModuleDeclaration:
|
|
398
|
+
case SyntaxKind.ExportSpecifier:
|
|
399
|
+
case SyntaxKind.ImportSpecifier:
|
|
400
|
+
case SyntaxKind.ImportClause:
|
|
401
|
+
case SyntaxKind.NamespaceImport:
|
|
402
|
+
case SyntaxKind.TypeLiteral:
|
|
403
|
+
addDeclaration(node);
|
|
404
|
+
forEachChild(node, visit);
|
|
405
|
+
break;
|
|
406
|
+
case SyntaxKind.VariableDeclaration:
|
|
407
|
+
case SyntaxKind.BindingElement: {
|
|
408
|
+
const decl = node;
|
|
409
|
+
if (isBindingPattern(decl.name)) {
|
|
410
|
+
forEachChild(decl.name, visit);
|
|
411
|
+
break;
|
|
412
|
+
}
|
|
413
|
+
if (decl.initializer) {
|
|
414
|
+
visit(decl.initializer);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// falls through
|
|
418
|
+
case SyntaxKind.PropertySignature:
|
|
419
|
+
addDeclaration(node);
|
|
420
|
+
break;
|
|
421
|
+
case SyntaxKind.ExportDeclaration:
|
|
422
|
+
// O export nomeado: `export {a, b as B} from "mod";`
|
|
423
|
+
const exportDeclaration = node;
|
|
424
|
+
if (exportDeclaration.exportClause) {
|
|
425
|
+
if (isNamedExports(exportDeclaration.exportClause)) {
|
|
426
|
+
forEach(exportDeclaration.exportClause.elements, visit);
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
visit(exportDeclaration.exportClause.name);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
break;
|
|
433
|
+
case SyntaxKind.ImportDeclaration:
|
|
434
|
+
const importClause = node.importClause;
|
|
435
|
+
if (importClause) {
|
|
436
|
+
// O import default: `import d from "mod";`
|
|
437
|
+
if (importClause.name) {
|
|
438
|
+
addDeclaration(importClause.name);
|
|
439
|
+
}
|
|
440
|
+
// As ligações nomeadas: `import * as NS from "mod";` e `import {a, b as B} from "mod";`
|
|
441
|
+
if (importClause.namedBindings) {
|
|
442
|
+
if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) {
|
|
443
|
+
addDeclaration(importClause.namedBindings);
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
forEach(importClause.namedBindings.elements, visit);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
break;
|
|
451
|
+
case SyntaxKind.BinaryExpression:
|
|
452
|
+
if (getAssignmentDeclarationKind(node) !== AssignmentDeclarationKind.None) {
|
|
453
|
+
addDeclaration(node);
|
|
454
|
+
}
|
|
455
|
+
// falls through
|
|
456
|
+
default:
|
|
457
|
+
forEachChild(node, visit);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
class SourceMapSourceObject {
|
|
463
|
+
constructor(fileName, text, skipTrivia) {
|
|
464
|
+
this.fileName = fileName;
|
|
465
|
+
this.text = text;
|
|
466
|
+
this.skipTrivia = skipTrivia;
|
|
467
|
+
}
|
|
468
|
+
getLineAndCharacterOfPosition(pos) {
|
|
469
|
+
return getLineAndCharacterOfPosition(this, pos);
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
function getServicesObjectAllocator() {
|
|
473
|
+
return {
|
|
474
|
+
getNodeConstructor: () => NodeObject,
|
|
475
|
+
getTokenConstructor: () => TokenObject,
|
|
476
|
+
getIdentifierConstructor: () => IdentifierObject,
|
|
477
|
+
getSourceFileConstructor: () => SourceFileObject,
|
|
478
|
+
getSymbolConstructor: () => SymbolObject,
|
|
479
|
+
getSourceMapSourceConstructor: () => SourceMapSourceObject,
|
|
480
|
+
};
|
|
481
|
+
}
|
|
482
|
+
// O `Type` e a `Signature` têm alocador próprio, no checker (CK-64); na tag, eram do mesmo alocador do nó.
|
|
483
|
+
function getServicesTypeObjectAllocator() {
|
|
484
|
+
return {
|
|
485
|
+
getTypeConstructor: () => TypeObject,
|
|
486
|
+
getSignatureConstructor: () => SignatureObject,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
export function toEditorSettings(optionsAsMap) {
|
|
490
|
+
let allPropertiesAreCamelCased = true;
|
|
491
|
+
for (const key in optionsAsMap) {
|
|
492
|
+
if (hasProperty(optionsAsMap, key) && !isCamelCase(key)) {
|
|
493
|
+
allPropertiesAreCamelCased = false;
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
if (allPropertiesAreCamelCased) {
|
|
498
|
+
return optionsAsMap;
|
|
499
|
+
}
|
|
500
|
+
const settings = {};
|
|
501
|
+
for (const key in optionsAsMap) {
|
|
502
|
+
if (hasProperty(optionsAsMap, key)) {
|
|
503
|
+
const newKey = isCamelCase(key) ? key : key.charAt(0).toLowerCase() + key.substr(1);
|
|
504
|
+
settings[newKey] = optionsAsMap[key];
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
return settings;
|
|
508
|
+
}
|
|
509
|
+
function isCamelCase(s) {
|
|
510
|
+
return !s.length || s.charAt(0) === s.charAt(0).toLowerCase();
|
|
511
|
+
}
|
|
512
|
+
export function displayPartsToString(displayParts) {
|
|
513
|
+
if (displayParts) {
|
|
514
|
+
return map(displayParts, displayPart => displayPart.text).join("");
|
|
515
|
+
}
|
|
516
|
+
return "";
|
|
517
|
+
}
|
|
518
|
+
// O que o host diz dos arquivos, numa foto: refeita a cada entrada pública do language service, porque não se sabe
|
|
519
|
+
// quando o conjunto de arquivos do host muda.
|
|
520
|
+
class HostCache {
|
|
521
|
+
constructor(host, getCanonicalFileName) {
|
|
522
|
+
this.host = host;
|
|
523
|
+
this.currentDirectory = host.getCurrentDirectory();
|
|
524
|
+
this.fileNameToEntry = createMap();
|
|
525
|
+
// A lista começa com os arquivos do programa.
|
|
526
|
+
const rootFileNames = host.getScriptFileNames();
|
|
527
|
+
for (const fileName of rootFileNames) {
|
|
528
|
+
this.createEntry(fileName, toPath(fileName, this.currentDirectory, getCanonicalFileName));
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
createEntry(fileName, path) {
|
|
532
|
+
let entry;
|
|
533
|
+
const scriptSnapshot = this.host.getScriptSnapshot(fileName);
|
|
534
|
+
if (scriptSnapshot) {
|
|
535
|
+
entry = {
|
|
536
|
+
hostFileName: fileName,
|
|
537
|
+
version: this.host.getScriptVersion(fileName),
|
|
538
|
+
scriptSnapshot,
|
|
539
|
+
scriptKind: getScriptKind(fileName, this.host)
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
entry = fileName;
|
|
544
|
+
}
|
|
545
|
+
this.fileNameToEntry.set(path, entry);
|
|
546
|
+
return entry;
|
|
547
|
+
}
|
|
548
|
+
getEntryByPath(path) {
|
|
549
|
+
return this.fileNameToEntry.get(path);
|
|
550
|
+
}
|
|
551
|
+
getHostFileInformation(path) {
|
|
552
|
+
const entry = this.fileNameToEntry.get(path);
|
|
553
|
+
return !isString(entry) ? entry : undefined;
|
|
554
|
+
}
|
|
555
|
+
getRootFileNames() {
|
|
556
|
+
const names = [];
|
|
557
|
+
this.fileNameToEntry.forEach(entry => {
|
|
558
|
+
if (isString(entry)) {
|
|
559
|
+
names.push(entry);
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
names.push(entry.hostFileName);
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
return names;
|
|
566
|
+
}
|
|
567
|
+
getScriptSnapshot(path) {
|
|
568
|
+
const file = this.getHostFileInformation(path);
|
|
569
|
+
return (file && file.scriptSnapshot);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
class SyntaxTreeCache {
|
|
573
|
+
constructor(host) {
|
|
574
|
+
this.host = host;
|
|
575
|
+
}
|
|
576
|
+
getCurrentSourceFile(fileName) {
|
|
577
|
+
const scriptSnapshot = this.host.getScriptSnapshot(fileName);
|
|
578
|
+
if (!scriptSnapshot) {
|
|
579
|
+
// O host não conhece o arquivo. Na tag, um `Error` comum; aqui, o `Debug.fail`, como a pergunta por um arquivo
|
|
580
|
+
// fora do programa (o `getValidSourceFile`).
|
|
581
|
+
return Debug.fail(`Could not find file: '${fileName}'.`);
|
|
582
|
+
}
|
|
583
|
+
const scriptKind = getScriptKind(fileName, this.host);
|
|
584
|
+
const version = this.host.getScriptVersion(fileName);
|
|
585
|
+
let sourceFile;
|
|
586
|
+
if (this.currentFileName !== fileName) {
|
|
587
|
+
// This is a new file, just parse it
|
|
588
|
+
sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, ScriptTarget.Latest, version, /*setNodeParents*/ true, scriptKind);
|
|
589
|
+
}
|
|
590
|
+
else if (this.currentFileVersion !== version) {
|
|
591
|
+
// This is the same file, just a newer version. Incrementally parse the file.
|
|
592
|
+
const editRange = scriptSnapshot.getChangeRange(this.currentFileScriptSnapshot);
|
|
593
|
+
sourceFile = updateLanguageServiceSourceFile(this.currentSourceFile, scriptSnapshot, version, editRange);
|
|
594
|
+
}
|
|
595
|
+
if (sourceFile) {
|
|
596
|
+
// All done, ensure state is up to date
|
|
597
|
+
this.currentFileVersion = version;
|
|
598
|
+
this.currentFileName = fileName;
|
|
599
|
+
this.currentFileScriptSnapshot = scriptSnapshot;
|
|
600
|
+
this.currentSourceFile = sourceFile;
|
|
601
|
+
}
|
|
602
|
+
return this.currentSourceFile;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
function setSourceFileFields(sourceFile, scriptSnapshot, version) {
|
|
606
|
+
sourceFile.version = version;
|
|
607
|
+
sourceFile.scriptSnapshot = scriptSnapshot;
|
|
608
|
+
}
|
|
609
|
+
export function createLanguageServiceSourceFile(fileName, scriptSnapshot, scriptTarget, version, setNodeParents, scriptKind) {
|
|
610
|
+
const sourceFile = createSourceFile(fileName, getSnapshotText(scriptSnapshot), scriptTarget, setNodeParents, scriptKind);
|
|
611
|
+
setSourceFileFields(sourceFile, scriptSnapshot, version);
|
|
612
|
+
return sourceFile;
|
|
613
|
+
}
|
|
614
|
+
export function updateLanguageServiceSourceFile(sourceFile, scriptSnapshot, version, textChangeRange, aggressiveChecks) {
|
|
615
|
+
// Com o trecho que mudou, e a versão mudada, o arquivo se reparseia só onde mudou.
|
|
616
|
+
if (textChangeRange) {
|
|
617
|
+
if (version !== sourceFile.version) {
|
|
618
|
+
let newText;
|
|
619
|
+
// o texto do começo do original até o começo do trecho
|
|
620
|
+
const prefix = textChangeRange.span.start !== 0
|
|
621
|
+
? sourceFile.text.substr(0, textChangeRange.span.start)
|
|
622
|
+
: "";
|
|
623
|
+
// o texto do fim do trecho até o fim do original
|
|
624
|
+
const suffix = textSpanEnd(textChangeRange.span) !== sourceFile.text.length
|
|
625
|
+
? sourceFile.text.substr(textSpanEnd(textChangeRange.span))
|
|
626
|
+
: "";
|
|
627
|
+
if (textChangeRange.newLength === 0) {
|
|
628
|
+
// a edição apagou: junta o antes e o depois
|
|
629
|
+
newText = prefix && suffix ? prefix + suffix : prefix || suffix;
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
// a edição escreveu: o texto novo do trecho, entre o antes e o depois
|
|
633
|
+
const changedText = scriptSnapshot.getText(textChangeRange.span.start, textChangeRange.span.start + textChangeRange.newLength);
|
|
634
|
+
newText = prefix && suffix
|
|
635
|
+
? prefix + changedText + suffix
|
|
636
|
+
: prefix
|
|
637
|
+
? (prefix + changedText)
|
|
638
|
+
: (changedText + suffix);
|
|
639
|
+
}
|
|
640
|
+
const newSourceFile = updateSourceFile(sourceFile, newText, textChangeRange, aggressiveChecks);
|
|
641
|
+
setSourceFileFields(newSourceFile, scriptSnapshot, version);
|
|
642
|
+
// Depois do parse incremental, a tabela de nomes pode estar velha: sai, e se refaz quando pedida.
|
|
643
|
+
newSourceFile.nameTable = undefined;
|
|
644
|
+
// os recursos do snapshot velho se liberam
|
|
645
|
+
if (sourceFile !== newSourceFile && sourceFile.scriptSnapshot) {
|
|
646
|
+
if (sourceFile.scriptSnapshot.dispose) {
|
|
647
|
+
sourceFile.scriptSnapshot.dispose();
|
|
648
|
+
}
|
|
649
|
+
sourceFile.scriptSnapshot = undefined;
|
|
650
|
+
}
|
|
651
|
+
return newSourceFile;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
// Sem o trecho, o arquivo se parseia de novo, inteiro.
|
|
655
|
+
return createLanguageServiceSourceFile(sourceFile.fileName, scriptSnapshot, sourceFile.languageVersion, version, /*setNodeParents*/ true, sourceFile.scriptKind);
|
|
656
|
+
}
|
|
657
|
+
class CancellationTokenObject {
|
|
658
|
+
constructor(cancellationToken) {
|
|
659
|
+
this.cancellationToken = cancellationToken;
|
|
660
|
+
}
|
|
661
|
+
isCancellationRequested() {
|
|
662
|
+
return !!this.cancellationToken && this.cancellationToken.isCancellationRequested();
|
|
663
|
+
}
|
|
664
|
+
throwIfCancellationRequested() {
|
|
665
|
+
if (this.isCancellationRequested()) {
|
|
666
|
+
throw new OperationCanceledException();
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
/** O cancelamento que pergunta ao host no máximo a cada `throttleWaitMilliseconds`: perguntar custa. */
|
|
671
|
+
export class ThrottledCancellationToken {
|
|
672
|
+
constructor(hostCancellationToken, throttleWaitMilliseconds = 20) {
|
|
673
|
+
this.hostCancellationToken = hostCancellationToken;
|
|
674
|
+
this.throttleWaitMilliseconds = throttleWaitMilliseconds;
|
|
675
|
+
// Quando se perguntou ao host da última vez.
|
|
676
|
+
this.lastCancellationCheckTime = 0;
|
|
677
|
+
}
|
|
678
|
+
isCancellationRequested() {
|
|
679
|
+
const time = timestamp();
|
|
680
|
+
const duration = Math.abs(time - this.lastCancellationCheckTime);
|
|
681
|
+
if (duration >= this.throttleWaitMilliseconds) {
|
|
682
|
+
this.lastCancellationCheckTime = time;
|
|
683
|
+
return this.hostCancellationToken.isCancellationRequested();
|
|
684
|
+
}
|
|
685
|
+
return false;
|
|
686
|
+
}
|
|
687
|
+
throwIfCancellationRequested() {
|
|
688
|
+
if (this.isCancellationRequested()) {
|
|
689
|
+
throw new OperationCanceledException();
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
/**
|
|
694
|
+
* O programa está em dia com o host: os mesmos arquivos, na mesma ordem, cada um na versão que o host diz. Do
|
|
695
|
+
* `isProgramUptoDate` do `program.ts` da tag, sem o que é do host do `tsc`: as diretivas de tipo automáticas, as
|
|
696
|
+
* referências de projeto, os arquivos que faltavam e passaram a existir, as opções (a configuração é fixa) e a
|
|
697
|
+
* resolução invalidada (quem resolve é o host, e a resolução se pergunta a cada programa).
|
|
698
|
+
*/
|
|
699
|
+
function isProgramUptoDate(program, rootFileNames, getSourceVersion) {
|
|
700
|
+
// Sem programa, não está em dia.
|
|
701
|
+
if (!program) {
|
|
702
|
+
return false;
|
|
703
|
+
}
|
|
704
|
+
// Os arquivos do programa são os do host, na ordem dele.
|
|
705
|
+
if (!arrayIsEqualTo(program.getSourceFiles().map(f => f.fileName), rootFileNames)) {
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
708
|
+
// Um arquivo fora de dia tira o programa inteiro de dia.
|
|
709
|
+
if (program.getSourceFiles().some(sourceFileNotUptoDate)) {
|
|
710
|
+
return false;
|
|
711
|
+
}
|
|
712
|
+
return true;
|
|
713
|
+
function sourceFileNotUptoDate(sourceFile) {
|
|
714
|
+
return sourceFile.version !== getSourceVersion(sourceFile.resolvedPath, sourceFile.fileName);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
let editingServices;
|
|
718
|
+
/** Registra a edição na casca. O `@tslite/services/edit` o chama ao carregar; o registro vale para o processo. */
|
|
719
|
+
export function registerEditingServices(services) {
|
|
720
|
+
editingServices = services;
|
|
721
|
+
}
|
|
722
|
+
/** A edição registrada. Sem ela, o método de edição falha, como o método semântico no modo `syntaxOnly` da tag. */
|
|
723
|
+
function getEditingServices() {
|
|
724
|
+
return editingServices || Debug.fail("The editing services are not loaded: import '@tslite/services/edit'.");
|
|
725
|
+
}
|
|
726
|
+
export function createLanguageService(host, documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames(), host.getCurrentDirectory()), syntaxOnly = false) {
|
|
727
|
+
const syntaxTreeCache = new SyntaxTreeCache(host);
|
|
728
|
+
let program;
|
|
729
|
+
let lastProjectVersion;
|
|
730
|
+
const cancellationToken = new CancellationTokenObject(host.getCancellationToken && host.getCancellationToken());
|
|
731
|
+
const currentDirectory = host.getCurrentDirectory();
|
|
732
|
+
// As mensagens traduzidas, quando o host as tem.
|
|
733
|
+
if (!localizedDiagnosticMessages && host.getLocalizedDiagnosticMessages) {
|
|
734
|
+
setLocalizedDiagnosticMessages(host.getLocalizedDiagnosticMessages());
|
|
735
|
+
}
|
|
736
|
+
function log(message) {
|
|
737
|
+
if (host.log) {
|
|
738
|
+
host.log(message);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
|
|
742
|
+
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
|
|
743
|
+
function getValidSourceFile(fileName) {
|
|
744
|
+
const sourceFile = program.getSourceFile(fileName);
|
|
745
|
+
if (!sourceFile) {
|
|
746
|
+
return Debug.fail(`Could not find source file: '${fileName}'.`);
|
|
747
|
+
}
|
|
748
|
+
return sourceFile;
|
|
749
|
+
}
|
|
750
|
+
/**
|
|
751
|
+
* A foto do host num programa. Da tag, com o `check` da cópia no lugar do `createProgram` sobre um `CompilerHost`
|
|
752
|
+
* (CK-47): os arquivos do programa são os que o host lista e tem, na ordem dele, as árvores vêm do registro de
|
|
753
|
+
* documentos, como na tag, e o host resolve os imports (CK-46). O arquivo que o host lista e não tem fica fora do
|
|
754
|
+
* programa; na tag, ele era um diagnóstico do programa, que é do host.
|
|
755
|
+
*/
|
|
756
|
+
function synchronizeHostData() {
|
|
757
|
+
Debug.assert(!syntaxOnly);
|
|
758
|
+
// a conferência rápida, quando o host dá a versão do projeto
|
|
759
|
+
if (host.getProjectVersion) {
|
|
760
|
+
const hostProjectVersion = host.getProjectVersion();
|
|
761
|
+
if (hostProjectVersion) {
|
|
762
|
+
if (lastProjectVersion === hostProjectVersion) {
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
lastProjectVersion = hostProjectVersion;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
// uma foto nova do host
|
|
769
|
+
let hostCache = new HostCache(host, getCanonicalFileName);
|
|
770
|
+
const rootFileNames = hostCache.getRootFileNames().filter(fileName => hostCache.getHostFileInformation(toPath(fileName, currentDirectory, getCanonicalFileName)));
|
|
771
|
+
// o programa em dia se reaproveita
|
|
772
|
+
if (isProgramUptoDate(program, rootFileNames, (_path, fileName) => host.getScriptVersion(fileName))) {
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
// Daqui em diante, nenhum token de cancelamento se consulta: as árvores do programa anterior mudam, e um
|
|
776
|
+
// cancelamento no meio deixaria o programa apontando para árvores invalidadas pelo parse incremental.
|
|
777
|
+
const oldProgram = program;
|
|
778
|
+
const files = mapDefined(rootFileNames, fileName => getOrCreateSourceFile(fileName));
|
|
779
|
+
program = check(files, {
|
|
780
|
+
getCurrentDirectory: () => currentDirectory,
|
|
781
|
+
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
|
|
782
|
+
resolveModule: (moduleName, containingFile) => host.resolveModule(moduleName, containingFile),
|
|
783
|
+
});
|
|
784
|
+
// A árvore do programa anterior que o novo não tem se libera no registro, como o `createProgram` da tag
|
|
785
|
+
// fazia pelo `onReleaseOldSourceFile` do host.
|
|
786
|
+
if (oldProgram) {
|
|
787
|
+
for (const oldSourceFile of oldProgram.getSourceFiles()) {
|
|
788
|
+
if (!program.getSourceFile(oldSourceFile.resolvedPath)) {
|
|
789
|
+
documentRegistry.releaseDocumentWithKey(oldSourceFile.resolvedPath);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
// A foto do host não se usa depois daqui: os snapshots que ela segura se liberam.
|
|
794
|
+
hostCache = undefined;
|
|
795
|
+
// Todos os nós do programa ligados, e com o pai.
|
|
796
|
+
program.getTypeChecker();
|
|
797
|
+
return;
|
|
798
|
+
function getOrCreateSourceFile(fileName) {
|
|
799
|
+
return getOrCreateSourceFileByPath(fileName, toPath(fileName, currentDirectory, getCanonicalFileName));
|
|
800
|
+
}
|
|
801
|
+
function getOrCreateSourceFileByPath(fileName, path) {
|
|
802
|
+
Debug.assert(hostCache !== undefined, "getOrCreateSourceFileByPath called after typical CompilerHost lifetime, check the callstack something with a reference to an old host.");
|
|
803
|
+
// O arquivo que o host não tem não existe para o programa.
|
|
804
|
+
const hostFileInformation = hostCache && hostCache.getHostFileInformation(path);
|
|
805
|
+
if (!hostFileInformation) {
|
|
806
|
+
return undefined;
|
|
807
|
+
}
|
|
808
|
+
// O arquivo que o programa anterior já tinha se atualiza pelo registro, que sabe a versão que vale: outra
|
|
809
|
+
// instância do language service pode ter atualizado a árvore compartilhada, e a versão que esta segurava
|
|
810
|
+
// ficou inválida.
|
|
811
|
+
const oldSourceFile = oldProgram && oldProgram.getSourceFile(path);
|
|
812
|
+
if (oldSourceFile) {
|
|
813
|
+
// O tipo de um arquivo registrado não muda de um programa para o outro.
|
|
814
|
+
Debug.assertEqual(hostFileInformation.scriptKind, oldSourceFile.scriptKind, "Registered script kind should match new script kind.");
|
|
815
|
+
return documentRegistry.updateDocumentWithKey(fileName, path, hostFileInformation.scriptSnapshot, hostFileInformation.version, hostFileInformation.scriptKind);
|
|
816
|
+
}
|
|
817
|
+
// O arquivo novo para este programa vem do registro, que o cria se ninguém o tem.
|
|
818
|
+
return documentRegistry.acquireDocumentWithKey(fileName, path, hostFileInformation.scriptSnapshot, hostFileInformation.version, hostFileInformation.scriptKind);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
function getProgram() {
|
|
822
|
+
if (syntaxOnly) {
|
|
823
|
+
Debug.assert(program === undefined);
|
|
824
|
+
return undefined;
|
|
825
|
+
}
|
|
826
|
+
synchronizeHostData();
|
|
827
|
+
return program;
|
|
828
|
+
}
|
|
829
|
+
function cleanupSemanticCache() {
|
|
830
|
+
program = undefined;
|
|
831
|
+
}
|
|
832
|
+
function dispose() {
|
|
833
|
+
if (program) {
|
|
834
|
+
forEach(program.getSourceFiles(), f => documentRegistry.releaseDocumentWithKey(f.resolvedPath));
|
|
835
|
+
program = undefined;
|
|
836
|
+
}
|
|
837
|
+
host = undefined;
|
|
838
|
+
}
|
|
839
|
+
/// Diagnostics
|
|
840
|
+
function getSyntacticDiagnostics(fileName) {
|
|
841
|
+
synchronizeHostData();
|
|
842
|
+
return program.getSyntacticDiagnostics(getValidSourceFile(fileName)).slice();
|
|
843
|
+
}
|
|
844
|
+
/**
|
|
845
|
+
* Os erros de tipo do arquivo. Na tag, com a emissão de declarações ligada, vinham junto os erros dela; a
|
|
846
|
+
* configuração é fixa, sem emissão.
|
|
847
|
+
*/
|
|
848
|
+
function getSemanticDiagnostics(fileName) {
|
|
849
|
+
synchronizeHostData();
|
|
850
|
+
const targetSourceFile = getValidSourceFile(fileName);
|
|
851
|
+
// Só o arquivo pedido: o host pede arquivo a arquivo.
|
|
852
|
+
return program.getSemanticDiagnostics(targetSourceFile, cancellationToken).slice();
|
|
853
|
+
}
|
|
854
|
+
function getSuggestionDiagnostics(fileName) {
|
|
855
|
+
synchronizeHostData();
|
|
856
|
+
return computeSuggestionDiagnostics(getValidSourceFile(fileName), program, cancellationToken);
|
|
857
|
+
}
|
|
858
|
+
function getCompletionsAtPosition(fileName, position, options = emptyOptions) {
|
|
859
|
+
// os nomes antigos das preferências, nos novos
|
|
860
|
+
const fullPreferences = {
|
|
861
|
+
...identity(options), // sem a conferência de propriedade a mais
|
|
862
|
+
includeCompletionsForModuleExports: options.includeCompletionsForModuleExports || options.includeExternalModuleExports,
|
|
863
|
+
includeCompletionsWithInsertText: options.includeCompletionsWithInsertText || options.includeInsertTextCompletions,
|
|
864
|
+
};
|
|
865
|
+
synchronizeHostData();
|
|
866
|
+
return Completions.getCompletionsAtPosition(host, program, log, getValidSourceFile(fileName), position, fullPreferences, options.triggerCharacter);
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* O detalhe de um item. Na tag, as opções de formatação viravam aqui o contexto de formatação, que só a ação do
|
|
870
|
+
* auto-import usa; aqui, elas seguem cruas até o auto-import da edição (CK-67).
|
|
871
|
+
*/
|
|
872
|
+
function getCompletionEntryDetails(fileName, position, name, formattingOptions, source, preferences = emptyOptions) {
|
|
873
|
+
synchronizeHostData();
|
|
874
|
+
return Completions.getCompletionEntryDetails(program, log, getValidSourceFile(fileName), position, { name, source }, host, formattingOptions, preferences, cancellationToken);
|
|
875
|
+
}
|
|
876
|
+
function getCompletionEntrySymbol(fileName, position, name, source, preferences = emptyOptions) {
|
|
877
|
+
synchronizeHostData();
|
|
878
|
+
return Completions.getCompletionEntrySymbol(program, log, getValidSourceFile(fileName), position, { name, source }, host, preferences);
|
|
879
|
+
}
|
|
880
|
+
function getQuickInfoAtPosition(fileName, position) {
|
|
881
|
+
synchronizeHostData();
|
|
882
|
+
const sourceFile = getValidSourceFile(fileName);
|
|
883
|
+
const node = getTouchingPropertyName(sourceFile, position);
|
|
884
|
+
if (node === sourceFile) {
|
|
885
|
+
// Avoid giving quickInfo for the sourceFile as a whole.
|
|
886
|
+
return undefined;
|
|
887
|
+
}
|
|
888
|
+
const typeChecker = program.getTypeChecker();
|
|
889
|
+
const nodeForQuickInfo = getNodeForQuickInfo(node);
|
|
890
|
+
const symbol = getSymbolAtLocationForQuickInfo(nodeForQuickInfo, typeChecker);
|
|
891
|
+
if (!symbol || typeChecker.isUnknownSymbol(symbol)) {
|
|
892
|
+
const type = shouldGetType(sourceFile, nodeForQuickInfo, position) ? typeChecker.getTypeAtLocation(nodeForQuickInfo) : undefined;
|
|
893
|
+
return type && {
|
|
894
|
+
kind: "" /* ScriptElementKind.unknown */,
|
|
895
|
+
kindModifiers: "" /* ScriptElementKindModifier.none */,
|
|
896
|
+
textSpan: createTextSpanFromNode(nodeForQuickInfo, sourceFile),
|
|
897
|
+
displayParts: typeChecker.runWithCancellationToken(cancellationToken, typeChecker => typeToDisplayParts(typeChecker, type, getContainerNode(nodeForQuickInfo))),
|
|
898
|
+
// Na tag, a documentação e as tags do JSDoc do símbolo do tipo. Sem o JSDoc (CK-03), as duas saem vazias,
|
|
899
|
+
// como as de um símbolo sem comentário na tag.
|
|
900
|
+
documentation: type.symbol ? [] : undefined,
|
|
901
|
+
tags: type.symbol ? [] : undefined
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
const { symbolKind, displayParts, documentation, tags } = typeChecker.runWithCancellationToken(cancellationToken, typeChecker => SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, getContainerNode(nodeForQuickInfo), nodeForQuickInfo));
|
|
905
|
+
return {
|
|
906
|
+
kind: symbolKind,
|
|
907
|
+
kindModifiers: SymbolDisplay.getSymbolModifiers(symbol),
|
|
908
|
+
textSpan: createTextSpanFromNode(nodeForQuickInfo, sourceFile),
|
|
909
|
+
displayParts,
|
|
910
|
+
documentation,
|
|
911
|
+
tags,
|
|
912
|
+
};
|
|
913
|
+
}
|
|
914
|
+
/** Na tag, o nome de um `new`, na posição do próprio `new`, dava o quick info da expressão chamada (CK-02). */
|
|
915
|
+
function getNodeForQuickInfo(node) {
|
|
916
|
+
return node;
|
|
917
|
+
}
|
|
918
|
+
/**
|
|
919
|
+
* Na tag, também o `this`, o tipo `this` e o `super` (CK-02); e, num identificador, o nome de um label e o de uma tag do
|
|
920
|
+
* JSDoc não davam o tipo (CK-02, CK-03).
|
|
921
|
+
*/
|
|
922
|
+
function shouldGetType(sourceFile, node, position) {
|
|
923
|
+
switch (node.kind) {
|
|
924
|
+
case SyntaxKind.Identifier:
|
|
925
|
+
return true;
|
|
926
|
+
case SyntaxKind.PropertyAccessExpression:
|
|
927
|
+
case SyntaxKind.QualifiedName:
|
|
928
|
+
// Don't return quickInfo if inside the comment in `a/**/.b`
|
|
929
|
+
return !isInComment(sourceFile, position);
|
|
930
|
+
default:
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
/// Goto definition
|
|
935
|
+
function getDefinitionAtPosition(fileName, position) {
|
|
936
|
+
synchronizeHostData();
|
|
937
|
+
return GoToDefinition.getDefinitionAtPosition(program, getValidSourceFile(fileName), position);
|
|
938
|
+
}
|
|
939
|
+
function getDefinitionAndBoundSpan(fileName, position) {
|
|
940
|
+
synchronizeHostData();
|
|
941
|
+
return GoToDefinition.getDefinitionAndBoundSpan(program, getValidSourceFile(fileName), position);
|
|
942
|
+
}
|
|
943
|
+
function getTypeDefinitionAtPosition(fileName, position) {
|
|
944
|
+
synchronizeHostData();
|
|
945
|
+
return GoToDefinition.getTypeDefinitionAtPosition(program.getTypeChecker(), getValidSourceFile(fileName), position);
|
|
946
|
+
}
|
|
947
|
+
/// Goto implementation
|
|
948
|
+
function getImplementationAtPosition(fileName, position) {
|
|
949
|
+
synchronizeHostData();
|
|
950
|
+
return FindAllReferences.getImplementationsAtPosition(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position);
|
|
951
|
+
}
|
|
952
|
+
/// References and Occurrences
|
|
953
|
+
function getOccurrencesAtPosition(fileName, position) {
|
|
954
|
+
return flatMap(getDocumentHighlights(fileName, position, [fileName]), entry => entry.highlightSpans.map(highlightSpan => ({
|
|
955
|
+
fileName: entry.fileName,
|
|
956
|
+
textSpan: highlightSpan.textSpan,
|
|
957
|
+
isWriteAccess: highlightSpan.kind === "writtenReference" /* HighlightSpanKind.writtenReference */,
|
|
958
|
+
isDefinition: false,
|
|
959
|
+
...highlightSpan.isInString && { isInString: true },
|
|
960
|
+
...highlightSpan.contextSpan && { contextSpan: highlightSpan.contextSpan }
|
|
961
|
+
})));
|
|
962
|
+
}
|
|
963
|
+
function getDocumentHighlights(fileName, position, filesToSearch) {
|
|
964
|
+
const normalizedFileName = normalizePath(fileName);
|
|
965
|
+
Debug.assert(filesToSearch.some(f => normalizePath(f) === normalizedFileName));
|
|
966
|
+
synchronizeHostData();
|
|
967
|
+
const sourceFilesToSearch = mapDefined(filesToSearch, fileName => program.getSourceFile(fileName));
|
|
968
|
+
const sourceFile = getValidSourceFile(fileName);
|
|
969
|
+
return DocumentHighlights.getDocumentHighlights(program, cancellationToken, sourceFile, position, sourceFilesToSearch);
|
|
970
|
+
}
|
|
971
|
+
function findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename) {
|
|
972
|
+
synchronizeHostData();
|
|
973
|
+
const sourceFile = getValidSourceFile(fileName);
|
|
974
|
+
const node = getAdjustedRenameLocation(getTouchingPropertyName(sourceFile, position));
|
|
975
|
+
if (isIdentifier(node) && (isJsxOpeningElement(node.parent) || isJsxClosingElement(node.parent)) && isIntrinsicJsxName(node.escapedText)) {
|
|
976
|
+
const { openingElement, closingElement } = node.parent.parent;
|
|
977
|
+
return [openingElement, closingElement].map((node) => {
|
|
978
|
+
const textSpan = createTextSpanFromNode(node.tagName, sourceFile);
|
|
979
|
+
return {
|
|
980
|
+
fileName: sourceFile.fileName,
|
|
981
|
+
textSpan,
|
|
982
|
+
...FindAllReferences.toContextSpan(textSpan, sourceFile, node.parent)
|
|
983
|
+
};
|
|
984
|
+
});
|
|
985
|
+
}
|
|
986
|
+
else {
|
|
987
|
+
return getReferencesWorker(node, position, { findInStrings, findInComments, providePrefixAndSuffixTextForRename, use: 2 /* FindAllReferences.FindReferencesUse.Rename */ }, (entry, originalNode, checker) => FindAllReferences.toRenameLocation(entry, originalNode, checker, providePrefixAndSuffixTextForRename || false));
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
function getReferencesAtPosition(fileName, position) {
|
|
991
|
+
synchronizeHostData();
|
|
992
|
+
return getReferencesWorker(getTouchingPropertyName(getValidSourceFile(fileName), position), position, { use: 1 /* FindAllReferences.FindReferencesUse.References */ }, FindAllReferences.toReferenceEntry);
|
|
993
|
+
}
|
|
994
|
+
function getReferencesWorker(node, position, options, cb) {
|
|
995
|
+
synchronizeHostData();
|
|
996
|
+
// Exclude default library when renaming as commonly user don't want to change that file.
|
|
997
|
+
const sourceFiles = options && options.use === 2 /* FindAllReferences.FindReferencesUse.Rename */
|
|
998
|
+
? program.getSourceFiles().filter(sourceFile => !program.isSourceFileDefaultLibrary(sourceFile))
|
|
999
|
+
: program.getSourceFiles();
|
|
1000
|
+
return FindAllReferences.findReferenceOrRenameEntries(program, cancellationToken, sourceFiles, node, position, options, cb);
|
|
1001
|
+
}
|
|
1002
|
+
function findReferences(fileName, position) {
|
|
1003
|
+
synchronizeHostData();
|
|
1004
|
+
return FindAllReferences.findReferencedSymbols(program, cancellationToken, program.getSourceFiles(), getValidSourceFile(fileName), position);
|
|
1005
|
+
}
|
|
1006
|
+
function getSignatureHelpItems(fileName, position, { triggerReason } = emptyOptions) {
|
|
1007
|
+
synchronizeHostData();
|
|
1008
|
+
const sourceFile = getValidSourceFile(fileName);
|
|
1009
|
+
return SignatureHelp.getSignatureHelpItems(program, sourceFile, position, triggerReason, cancellationToken);
|
|
1010
|
+
}
|
|
1011
|
+
function getNavigationBarItems(fileName) {
|
|
1012
|
+
return NavigationBar.getNavigationBarItems(syntaxTreeCache.getCurrentSourceFile(fileName), cancellationToken);
|
|
1013
|
+
}
|
|
1014
|
+
function getNavigationTree(fileName) {
|
|
1015
|
+
return NavigationBar.getNavigationTree(syntaxTreeCache.getCurrentSourceFile(fileName), cancellationToken);
|
|
1016
|
+
}
|
|
1017
|
+
function isTsOrTsxFile(fileName) {
|
|
1018
|
+
const kind = getScriptKind(fileName, host);
|
|
1019
|
+
return kind === ScriptKind.TS || kind === ScriptKind.TSX;
|
|
1020
|
+
}
|
|
1021
|
+
function getSemanticClassifications(fileName, span) {
|
|
1022
|
+
if (!isTsOrTsxFile(fileName)) {
|
|
1023
|
+
// do not run semantic classification on non-ts-or-tsx files
|
|
1024
|
+
return [];
|
|
1025
|
+
}
|
|
1026
|
+
synchronizeHostData();
|
|
1027
|
+
return ts.getSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span);
|
|
1028
|
+
}
|
|
1029
|
+
function getEncodedSemanticClassifications(fileName, span) {
|
|
1030
|
+
if (!isTsOrTsxFile(fileName)) {
|
|
1031
|
+
// do not run semantic classification on non-ts-or-tsx files
|
|
1032
|
+
return { spans: [], endOfLineState: 0 /* EndOfLineState.None */ };
|
|
1033
|
+
}
|
|
1034
|
+
synchronizeHostData();
|
|
1035
|
+
return ts.getEncodedSemanticClassifications(program.getTypeChecker(), cancellationToken, getValidSourceFile(fileName), program.getClassifiableNames(), span);
|
|
1036
|
+
}
|
|
1037
|
+
function getSyntacticClassifications(fileName, span) {
|
|
1038
|
+
// doesn't use compiler - no need to synchronize with host
|
|
1039
|
+
return ts.getSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span);
|
|
1040
|
+
}
|
|
1041
|
+
function getEncodedSyntacticClassifications(fileName, span) {
|
|
1042
|
+
// doesn't use compiler - no need to synchronize with host
|
|
1043
|
+
return ts.getEncodedSyntacticClassifications(cancellationToken, syntaxTreeCache.getCurrentSourceFile(fileName), span);
|
|
1044
|
+
}
|
|
1045
|
+
function getOutliningSpans(fileName) {
|
|
1046
|
+
// doesn't use compiler - no need to synchronize with host
|
|
1047
|
+
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
|
1048
|
+
return OutliningElementsCollector.collectElements(sourceFile, cancellationToken);
|
|
1049
|
+
}
|
|
1050
|
+
const braceMatching = createMapFromTemplate({
|
|
1051
|
+
[SyntaxKind.OpenBraceToken]: SyntaxKind.CloseBraceToken,
|
|
1052
|
+
[SyntaxKind.OpenParenToken]: SyntaxKind.CloseParenToken,
|
|
1053
|
+
[SyntaxKind.OpenBracketToken]: SyntaxKind.CloseBracketToken,
|
|
1054
|
+
[SyntaxKind.GreaterThanToken]: SyntaxKind.LessThanToken,
|
|
1055
|
+
});
|
|
1056
|
+
braceMatching.forEach((value, key) => braceMatching.set(value.toString(), Number(key)));
|
|
1057
|
+
function getBraceMatchingAtPosition(fileName, position) {
|
|
1058
|
+
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
|
1059
|
+
const token = getTouchingToken(sourceFile, position);
|
|
1060
|
+
const matchKind = token.getStart(sourceFile) === position ? braceMatching.get(token.kind.toString()) : undefined;
|
|
1061
|
+
const match = matchKind && findChildOfKind(token.parent, matchKind, sourceFile);
|
|
1062
|
+
// We want to order the braces when we return the result.
|
|
1063
|
+
return match ? [createTextSpanFromNode(token, sourceFile), createTextSpanFromNode(match, sourceFile)].sort((a, b) => a.start - b.start) : emptyArray;
|
|
1064
|
+
}
|
|
1065
|
+
function getIndentationAtPosition(fileName, position, editorOptions) {
|
|
1066
|
+
const { formatting } = getEditingServices();
|
|
1067
|
+
let start = timestamp();
|
|
1068
|
+
const settings = toEditorSettings(editorOptions);
|
|
1069
|
+
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
|
1070
|
+
log("getIndentationAtPosition: getCurrentSourceFile: " + (timestamp() - start));
|
|
1071
|
+
start = timestamp();
|
|
1072
|
+
const result = formatting.SmartIndenter.getIndentation(position, sourceFile, settings);
|
|
1073
|
+
log("getIndentationAtPosition: computeIndentation : " + (timestamp() - start));
|
|
1074
|
+
return result;
|
|
1075
|
+
}
|
|
1076
|
+
function getFormattingEditsForRange(fileName, start, end, options) {
|
|
1077
|
+
const { formatting } = getEditingServices();
|
|
1078
|
+
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
|
1079
|
+
return formatting.formatSelection(start, end, sourceFile, formatting.getFormatContext(toEditorSettings(options), host));
|
|
1080
|
+
}
|
|
1081
|
+
function getFormattingEditsForDocument(fileName, options) {
|
|
1082
|
+
const { formatting } = getEditingServices();
|
|
1083
|
+
return formatting.formatDocument(syntaxTreeCache.getCurrentSourceFile(fileName), formatting.getFormatContext(toEditorSettings(options), host));
|
|
1084
|
+
}
|
|
1085
|
+
function getFormattingEditsAfterKeystroke(fileName, position, key, options) {
|
|
1086
|
+
const { formatting } = getEditingServices();
|
|
1087
|
+
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
|
1088
|
+
const formatContext = formatting.getFormatContext(toEditorSettings(options), host);
|
|
1089
|
+
if (!isInComment(sourceFile, position)) {
|
|
1090
|
+
switch (key) {
|
|
1091
|
+
case "{":
|
|
1092
|
+
return formatting.formatOnOpeningCurly(position, sourceFile, formatContext);
|
|
1093
|
+
case "}":
|
|
1094
|
+
return formatting.formatOnClosingCurly(position, sourceFile, formatContext);
|
|
1095
|
+
case ";":
|
|
1096
|
+
return formatting.formatOnSemicolon(position, sourceFile, formatContext);
|
|
1097
|
+
case "\n":
|
|
1098
|
+
return formatting.formatOnEnter(position, sourceFile, formatContext);
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
return [];
|
|
1102
|
+
}
|
|
1103
|
+
function getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences = emptyOptions) {
|
|
1104
|
+
const { formatting, codefix } = getEditingServices();
|
|
1105
|
+
synchronizeHostData();
|
|
1106
|
+
const sourceFile = getValidSourceFile(fileName);
|
|
1107
|
+
const span = createTextSpanFromBounds(start, end);
|
|
1108
|
+
const formatContext = formatting.getFormatContext(formatOptions, host);
|
|
1109
|
+
return flatMap(deduplicate(errorCodes, equateValues, compareValues), errorCode => {
|
|
1110
|
+
cancellationToken.throwIfCancellationRequested();
|
|
1111
|
+
return codefix.getFixes({ errorCode, sourceFile, span, program, host, cancellationToken, formatContext, preferences });
|
|
1112
|
+
});
|
|
1113
|
+
}
|
|
1114
|
+
function getCombinedCodeFix(scope, fixId, formatOptions, preferences = emptyOptions) {
|
|
1115
|
+
const { formatting, codefix } = getEditingServices();
|
|
1116
|
+
synchronizeHostData();
|
|
1117
|
+
Debug.assert(scope.type === "file");
|
|
1118
|
+
const sourceFile = getValidSourceFile(scope.fileName);
|
|
1119
|
+
const formatContext = formatting.getFormatContext(formatOptions, host);
|
|
1120
|
+
return codefix.getAllFixes({ fixId, sourceFile, program, host, cancellationToken, formatContext, preferences });
|
|
1121
|
+
}
|
|
1122
|
+
// Na tag, também o `applyCodeActionCommand`, que pedia ao host a instalação de um pacote de tipos (CK-47).
|
|
1123
|
+
function organizeImports(scope, formatOptions, preferences = emptyOptions) {
|
|
1124
|
+
const { formatting, OrganizeImports } = getEditingServices();
|
|
1125
|
+
synchronizeHostData();
|
|
1126
|
+
Debug.assert(scope.type === "file");
|
|
1127
|
+
const sourceFile = getValidSourceFile(scope.fileName);
|
|
1128
|
+
const formatContext = formatting.getFormatContext(formatOptions, host);
|
|
1129
|
+
return OrganizeImports.organizeImports(sourceFile, formatContext, host, program, preferences);
|
|
1130
|
+
}
|
|
1131
|
+
// Na tag, também o mapa de fontes (o `sourceMapper`), que é do host (CK-47).
|
|
1132
|
+
function getEditsForFileRename(oldFilePath, newFilePath, formatOptions, preferences = emptyOptions) {
|
|
1133
|
+
const { formatting, getEditsForFileRename } = getEditingServices();
|
|
1134
|
+
return getEditsForFileRename(getProgram(), oldFilePath, newFilePath, host, formatting.getFormatContext(formatOptions, host), preferences);
|
|
1135
|
+
}
|
|
1136
|
+
function isValidBraceCompletionAtPosition(fileName, position, openingBrace) {
|
|
1137
|
+
// '<' is currently not supported, figuring out if we're in a Generic Type vs. a comparison is too
|
|
1138
|
+
// expensive to do during typing scenarios
|
|
1139
|
+
// i.e. whether we're dealing with:
|
|
1140
|
+
// var x = new foo<| ( with class foo<T>{} )
|
|
1141
|
+
// or
|
|
1142
|
+
// var y = 3 <|
|
|
1143
|
+
if (openingBrace === CharacterCodes.lessThan) {
|
|
1144
|
+
return false;
|
|
1145
|
+
}
|
|
1146
|
+
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
|
1147
|
+
// Check if in a context where we don't want to perform any insertion
|
|
1148
|
+
if (isInString(sourceFile, position)) {
|
|
1149
|
+
return false;
|
|
1150
|
+
}
|
|
1151
|
+
if (isInsideJsxElementOrAttribute(sourceFile, position)) {
|
|
1152
|
+
return openingBrace === CharacterCodes.openBrace;
|
|
1153
|
+
}
|
|
1154
|
+
if (isInTemplateString(sourceFile, position)) {
|
|
1155
|
+
return false;
|
|
1156
|
+
}
|
|
1157
|
+
switch (openingBrace) {
|
|
1158
|
+
case CharacterCodes.singleQuote:
|
|
1159
|
+
case CharacterCodes.doubleQuote:
|
|
1160
|
+
case CharacterCodes.backtick:
|
|
1161
|
+
return !isInComment(sourceFile, position);
|
|
1162
|
+
}
|
|
1163
|
+
return true;
|
|
1164
|
+
}
|
|
1165
|
+
function getJsxClosingTagAtPosition(fileName, position) {
|
|
1166
|
+
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
|
1167
|
+
const token = findPrecedingToken(position, sourceFile);
|
|
1168
|
+
if (!token)
|
|
1169
|
+
return undefined;
|
|
1170
|
+
const element = token.kind === SyntaxKind.GreaterThanToken && isJsxOpeningElement(token.parent) ? token.parent.parent
|
|
1171
|
+
: isJsxText(token) ? token.parent : undefined;
|
|
1172
|
+
if (element && isUnclosedTag(element)) {
|
|
1173
|
+
return { newText: `</${element.openingElement.tagName.getText(sourceFile)}>` };
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
function isUnclosedTag({ openingElement, closingElement, parent }) {
|
|
1177
|
+
return !tagNamesAreEquivalent(openingElement.tagName, closingElement.tagName) ||
|
|
1178
|
+
isJsxElement(parent) && tagNamesAreEquivalent(openingElement.tagName, parent.openingElement.tagName) && isUnclosedTag(parent);
|
|
1179
|
+
}
|
|
1180
|
+
function getSpanOfEnclosingComment(fileName, position, onlyMultiLine) {
|
|
1181
|
+
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
|
|
1182
|
+
const range = getRangeOfEnclosingComment(sourceFile, position);
|
|
1183
|
+
return range && (!onlyMultiLine || range.kind === SyntaxKind.MultiLineCommentTrivia) ? createTextSpanFromRange(range) : undefined;
|
|
1184
|
+
}
|
|
1185
|
+
function getTodoComments(fileName, descriptors) {
|
|
1186
|
+
// Note: while getting todo comments seems like a syntactic operation, we actually
|
|
1187
|
+
// treat it as a semantic operation here. This is because we expect our host to call
|
|
1188
|
+
// this on every single file. If we treat this syntactically, then that will cause
|
|
1189
|
+
// us to populate and throw away the tree in our syntax tree cache for each file. By
|
|
1190
|
+
// treating this as a semantic operation, we can access any tree without throwing
|
|
1191
|
+
// anything away.
|
|
1192
|
+
synchronizeHostData();
|
|
1193
|
+
const sourceFile = getValidSourceFile(fileName);
|
|
1194
|
+
cancellationToken.throwIfCancellationRequested();
|
|
1195
|
+
const fileContents = sourceFile.text;
|
|
1196
|
+
const result = [];
|
|
1197
|
+
// Na tag, o arquivo de dentro de um `node_modules` ficava de fora, como lib de terceiros; o `node_modules` é da
|
|
1198
|
+
// resolução do host, e o nome de um arquivo é uma chave virtual (CK-46, CK-47).
|
|
1199
|
+
if (descriptors.length > 0) {
|
|
1200
|
+
const regExp = getTodoCommentsRegExp();
|
|
1201
|
+
let matchArray;
|
|
1202
|
+
while (matchArray = regExp.exec(fileContents)) {
|
|
1203
|
+
cancellationToken.throwIfCancellationRequested();
|
|
1204
|
+
// If we got a match, here is what the match array will look like. Say the source text is:
|
|
1205
|
+
//
|
|
1206
|
+
// " // hack 1"
|
|
1207
|
+
//
|
|
1208
|
+
// The result array with the regexp: will be:
|
|
1209
|
+
//
|
|
1210
|
+
// ["// hack 1", "// ", "hack 1", undefined, "hack"]
|
|
1211
|
+
//
|
|
1212
|
+
// Here are the relevant capture groups:
|
|
1213
|
+
// 0) The full match for the entire regexp.
|
|
1214
|
+
// 1) The preamble to the message portion.
|
|
1215
|
+
// 2) The message portion.
|
|
1216
|
+
// 3...N) The descriptor that was matched - by index. 'undefined' for each
|
|
1217
|
+
// descriptor that didn't match. an actual value if it did match.
|
|
1218
|
+
//
|
|
1219
|
+
// i.e. 'undefined' in position 3 above means TODO(jason) didn't match.
|
|
1220
|
+
// "hack" in position 4 means HACK did match.
|
|
1221
|
+
const firstDescriptorCaptureIndex = 3;
|
|
1222
|
+
Debug.assert(matchArray.length === descriptors.length + firstDescriptorCaptureIndex);
|
|
1223
|
+
const preamble = matchArray[1];
|
|
1224
|
+
const matchPosition = matchArray.index + preamble.length;
|
|
1225
|
+
// OK, we have found a match in the file. This is only an acceptable match if
|
|
1226
|
+
// it is contained within a comment.
|
|
1227
|
+
if (!isInComment(sourceFile, matchPosition)) {
|
|
1228
|
+
continue;
|
|
1229
|
+
}
|
|
1230
|
+
let descriptor;
|
|
1231
|
+
for (let i = 0; i < descriptors.length; i++) {
|
|
1232
|
+
if (matchArray[i + firstDescriptorCaptureIndex]) {
|
|
1233
|
+
descriptor = descriptors[i];
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
if (descriptor === undefined)
|
|
1237
|
+
return Debug.fail();
|
|
1238
|
+
// We don't want to match something like 'TODOBY', so we make sure a non
|
|
1239
|
+
// letter/digit follows the match.
|
|
1240
|
+
if (isLetterOrDigit(fileContents.charCodeAt(matchPosition + descriptor.text.length))) {
|
|
1241
|
+
continue;
|
|
1242
|
+
}
|
|
1243
|
+
const message = matchArray[2];
|
|
1244
|
+
result.push({ descriptor, message, position: matchPosition });
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
return result;
|
|
1248
|
+
function escapeRegExp(str) {
|
|
1249
|
+
return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
|
1250
|
+
}
|
|
1251
|
+
function getTodoCommentsRegExp() {
|
|
1252
|
+
// NOTE: `?:` means 'non-capture group'. It allows us to have groups without having to
|
|
1253
|
+
// filter them out later in the final result array.
|
|
1254
|
+
// TODO comments can appear in one of the following forms:
|
|
1255
|
+
//
|
|
1256
|
+
// 1) // TODO or /////////// TODO
|
|
1257
|
+
//
|
|
1258
|
+
// 2) /* TODO or /********** TODO
|
|
1259
|
+
//
|
|
1260
|
+
// 3) /*
|
|
1261
|
+
// * TODO
|
|
1262
|
+
// */
|
|
1263
|
+
//
|
|
1264
|
+
// The following three regexps are used to match the start of the text up to the TODO
|
|
1265
|
+
// comment portion.
|
|
1266
|
+
const singleLineCommentStart = /(?:\/\/+\s*)/.source;
|
|
1267
|
+
const multiLineCommentStart = /(?:\/\*+\s*)/.source;
|
|
1268
|
+
const anyNumberOfSpacesAndAsterisksAtStartOfLine = /(?:^(?:\s|\*)*)/.source;
|
|
1269
|
+
// Match any of the above three TODO comment start regexps.
|
|
1270
|
+
// Note that the outermost group *is* a capture group. We want to capture the preamble
|
|
1271
|
+
// so that we can determine the starting position of the TODO comment match.
|
|
1272
|
+
const preamble = "(" + anyNumberOfSpacesAndAsterisksAtStartOfLine + "|" + singleLineCommentStart + "|" + multiLineCommentStart + ")";
|
|
1273
|
+
// Takes the descriptors and forms a regexp that matches them as if they were literals.
|
|
1274
|
+
// For example, if the descriptors are "TODO(jason)" and "HACK", then this will be:
|
|
1275
|
+
//
|
|
1276
|
+
// (?:(TODO\(jason\))|(HACK))
|
|
1277
|
+
//
|
|
1278
|
+
// Note that the outermost group is *not* a capture group, but the innermost groups
|
|
1279
|
+
// *are* capture groups. By capturing the inner literals we can determine after
|
|
1280
|
+
// matching which descriptor we are dealing with.
|
|
1281
|
+
const literals = "(?:" + map(descriptors, d => "(" + escapeRegExp(d.text) + ")").join("|") + ")";
|
|
1282
|
+
// After matching a descriptor literal, the following regexp matches the rest of the
|
|
1283
|
+
// text up to the end of the line (or */).
|
|
1284
|
+
const endOfLineOrEndOfComment = /(?:$|\*\/)/.source;
|
|
1285
|
+
const messageRemainder = /(?:.*?)/.source;
|
|
1286
|
+
// This is the portion of the match we'll return as part of the TODO comment result. We
|
|
1287
|
+
// match the literal portion up to the end of the line or end of comment.
|
|
1288
|
+
const messagePortion = "(" + literals + messageRemainder + ")";
|
|
1289
|
+
const regExpString = preamble + messagePortion + endOfLineOrEndOfComment;
|
|
1290
|
+
// The final regexp will look like this:
|
|
1291
|
+
// /((?:\/\/+\s*)|(?:\/\*+\s*)|(?:^(?:\s|\*)*))((?:(TODO\(jason\))|(HACK))(?:.*?))(?:$|\*\/)/gim
|
|
1292
|
+
// The flags of the regexp are important here.
|
|
1293
|
+
// 'g' is so that we are doing a global search and can find matches several times
|
|
1294
|
+
// in the input.
|
|
1295
|
+
//
|
|
1296
|
+
// 'i' is for case insensitivity (We do this to match C# TODO comment code).
|
|
1297
|
+
//
|
|
1298
|
+
// 'm' is so we can find matches in a multi-line input.
|
|
1299
|
+
return new RegExp(regExpString, "gim");
|
|
1300
|
+
}
|
|
1301
|
+
function isLetterOrDigit(char) {
|
|
1302
|
+
return (char >= CharacterCodes.a && char <= CharacterCodes.z) ||
|
|
1303
|
+
(char >= CharacterCodes.A && char <= CharacterCodes.Z) ||
|
|
1304
|
+
(char >= CharacterCodes._0 && char <= CharacterCodes._9);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
function getRenameInfo(fileName, position, options) {
|
|
1308
|
+
synchronizeHostData();
|
|
1309
|
+
return Rename.getRenameInfo(program, getValidSourceFile(fileName), position, options);
|
|
1310
|
+
}
|
|
1311
|
+
function getRefactorContext(file, positionOrRange, preferences, formatOptions) {
|
|
1312
|
+
const { formatting } = getEditingServices();
|
|
1313
|
+
const [startPosition, endPosition] = typeof positionOrRange === "number" ? [positionOrRange, undefined] : [positionOrRange.pos, positionOrRange.end];
|
|
1314
|
+
return {
|
|
1315
|
+
file,
|
|
1316
|
+
startPosition,
|
|
1317
|
+
endPosition,
|
|
1318
|
+
program: getProgram(),
|
|
1319
|
+
host,
|
|
1320
|
+
formatContext: formatting.getFormatContext(formatOptions, host),
|
|
1321
|
+
cancellationToken,
|
|
1322
|
+
preferences,
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
function getSmartSelectionRange(fileName, position) {
|
|
1326
|
+
return SmartSelectionRange.getSmartSelectionRange(position, syntaxTreeCache.getCurrentSourceFile(fileName));
|
|
1327
|
+
}
|
|
1328
|
+
function getApplicableRefactors(fileName, positionOrRange, preferences = emptyOptions) {
|
|
1329
|
+
const { refactor } = getEditingServices();
|
|
1330
|
+
synchronizeHostData();
|
|
1331
|
+
const file = getValidSourceFile(fileName);
|
|
1332
|
+
return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange, preferences));
|
|
1333
|
+
}
|
|
1334
|
+
function getEditsForRefactor(fileName, formatOptions, positionOrRange, refactorName, actionName, preferences = emptyOptions) {
|
|
1335
|
+
const { refactor } = getEditingServices();
|
|
1336
|
+
synchronizeHostData();
|
|
1337
|
+
const file = getValidSourceFile(fileName);
|
|
1338
|
+
return refactor.getEditsForRefactor(getRefactorContext(file, positionOrRange, preferences, formatOptions), refactorName, actionName);
|
|
1339
|
+
}
|
|
1340
|
+
return {
|
|
1341
|
+
dispose,
|
|
1342
|
+
cleanupSemanticCache,
|
|
1343
|
+
getSyntacticDiagnostics,
|
|
1344
|
+
getSemanticDiagnostics,
|
|
1345
|
+
getSuggestionDiagnostics,
|
|
1346
|
+
getSyntacticClassifications,
|
|
1347
|
+
getSemanticClassifications,
|
|
1348
|
+
getEncodedSyntacticClassifications,
|
|
1349
|
+
getEncodedSemanticClassifications,
|
|
1350
|
+
getCompletionsAtPosition,
|
|
1351
|
+
getCompletionEntryDetails,
|
|
1352
|
+
getCompletionEntrySymbol,
|
|
1353
|
+
getSignatureHelpItems,
|
|
1354
|
+
getQuickInfoAtPosition,
|
|
1355
|
+
getDefinitionAtPosition,
|
|
1356
|
+
getDefinitionAndBoundSpan,
|
|
1357
|
+
getImplementationAtPosition,
|
|
1358
|
+
getTypeDefinitionAtPosition,
|
|
1359
|
+
getReferencesAtPosition,
|
|
1360
|
+
findReferences,
|
|
1361
|
+
getOccurrencesAtPosition,
|
|
1362
|
+
getDocumentHighlights,
|
|
1363
|
+
getRenameInfo,
|
|
1364
|
+
getSmartSelectionRange,
|
|
1365
|
+
findRenameLocations,
|
|
1366
|
+
getNavigationBarItems,
|
|
1367
|
+
getNavigationTree,
|
|
1368
|
+
getOutliningSpans,
|
|
1369
|
+
getTodoComments,
|
|
1370
|
+
getBraceMatchingAtPosition,
|
|
1371
|
+
getIndentationAtPosition,
|
|
1372
|
+
getFormattingEditsForRange,
|
|
1373
|
+
getFormattingEditsForDocument,
|
|
1374
|
+
getFormattingEditsAfterKeystroke,
|
|
1375
|
+
isValidBraceCompletionAtPosition,
|
|
1376
|
+
getJsxClosingTagAtPosition,
|
|
1377
|
+
getSpanOfEnclosingComment,
|
|
1378
|
+
getCodeFixesAtPosition,
|
|
1379
|
+
getCombinedCodeFix,
|
|
1380
|
+
organizeImports,
|
|
1381
|
+
getEditsForFileRename,
|
|
1382
|
+
getProgram,
|
|
1383
|
+
getApplicableRefactors,
|
|
1384
|
+
getEditsForRefactor,
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
/** Names in the name table are escaped, so an identifier `__foo` will have a name table entry `___foo`. */
|
|
1388
|
+
export function getNameTable(sourceFile) {
|
|
1389
|
+
if (!sourceFile.nameTable) {
|
|
1390
|
+
initializeNameTable(sourceFile);
|
|
1391
|
+
}
|
|
1392
|
+
return sourceFile.nameTable;
|
|
1393
|
+
}
|
|
1394
|
+
function initializeNameTable(sourceFile) {
|
|
1395
|
+
const nameTable = sourceFile.nameTable = createUnderscoreEscapedMap();
|
|
1396
|
+
sourceFile.forEachChild(function walk(node) {
|
|
1397
|
+
if (isIdentifier(node) && node.escapedText || isStringOrNumericLiteralLike(node) && literalIsName(node)) {
|
|
1398
|
+
const text = getEscapedTextOfIdentifierOrLiteral(node);
|
|
1399
|
+
nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1);
|
|
1400
|
+
}
|
|
1401
|
+
// Na tag, também o nome `#private` (CK-02), e o identificador que é nome de uma tag do JSDoc ficava de fora, com
|
|
1402
|
+
// os nomes dentro do JSDoc de cada nó (CK-03).
|
|
1403
|
+
forEachChild(node, walk);
|
|
1404
|
+
});
|
|
1405
|
+
}
|
|
1406
|
+
/**
|
|
1407
|
+
* We want to store any numbers/strings if they were a name that could be
|
|
1408
|
+
* related to a declaration. So, if we have 'import x = require("something")'
|
|
1409
|
+
* then we want 'something' to be in the name table. Similarly, if we have
|
|
1410
|
+
* "a['propname']" then we want to store "propname" in the name table.
|
|
1411
|
+
*/
|
|
1412
|
+
function literalIsName(node) {
|
|
1413
|
+
// Na tag, também o `require("…")` de um `import =` (CK-03).
|
|
1414
|
+
return isDeclarationName(node) ||
|
|
1415
|
+
isArgumentOfElementAccessExpression(node) ||
|
|
1416
|
+
isLiteralComputedPropertyDeclarationName(node);
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Returns the containing object literal property declaration given a possible name node, e.g. "a" in x = { "a": 1 }
|
|
1420
|
+
*/
|
|
1421
|
+
export function getContainingObjectLiteralElement(node) {
|
|
1422
|
+
const element = getContainingObjectLiteralElementWorker(node);
|
|
1423
|
+
return element && (isObjectLiteralExpression(element.parent) || isJsxAttributes(element.parent)) ? element : undefined;
|
|
1424
|
+
}
|
|
1425
|
+
function getContainingObjectLiteralElementWorker(node) {
|
|
1426
|
+
switch (node.kind) {
|
|
1427
|
+
case SyntaxKind.StringLiteral:
|
|
1428
|
+
case SyntaxKind.NoSubstitutionTemplateLiteral:
|
|
1429
|
+
case SyntaxKind.NumericLiteral:
|
|
1430
|
+
if (node.parent.kind === SyntaxKind.ComputedPropertyName) {
|
|
1431
|
+
return isObjectLiteralElement(node.parent.parent) ? node.parent.parent : undefined;
|
|
1432
|
+
}
|
|
1433
|
+
// falls through
|
|
1434
|
+
case SyntaxKind.Identifier:
|
|
1435
|
+
return isObjectLiteralElement(node.parent) &&
|
|
1436
|
+
(node.parent.parent.kind === SyntaxKind.ObjectLiteralExpression || node.parent.parent.kind === SyntaxKind.JsxAttributes) &&
|
|
1437
|
+
node.parent.name === node ? node.parent : undefined;
|
|
1438
|
+
}
|
|
1439
|
+
return undefined;
|
|
1440
|
+
}
|
|
1441
|
+
function getSymbolAtLocationForQuickInfo(node, checker) {
|
|
1442
|
+
const object = getContainingObjectLiteralElement(node);
|
|
1443
|
+
if (object) {
|
|
1444
|
+
const contextualType = checker.getContextualType(object.parent);
|
|
1445
|
+
const properties = contextualType && getPropertySymbolsFromContextualType(object, checker, contextualType, /*unionSymbolOk*/ false);
|
|
1446
|
+
if (properties && properties.length === 1) {
|
|
1447
|
+
return first(properties);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
return checker.getSymbolAtLocation(node);
|
|
1451
|
+
}
|
|
1452
|
+
/** Gets all symbols for one property. Does not get symbols for every property. */
|
|
1453
|
+
export function getPropertySymbolsFromContextualType(node, checker, contextualType, unionSymbolOk) {
|
|
1454
|
+
const name = getNameFromPropertyName(node.name);
|
|
1455
|
+
if (!name)
|
|
1456
|
+
return emptyArray;
|
|
1457
|
+
if (!contextualType.isUnion()) {
|
|
1458
|
+
const symbol = contextualType.getProperty(name);
|
|
1459
|
+
return symbol ? [symbol] : emptyArray;
|
|
1460
|
+
}
|
|
1461
|
+
const discriminatedPropertySymbols = mapDefined(contextualType.types, t => isObjectLiteralExpression(node.parent) && checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent) ? undefined : t.getProperty(name));
|
|
1462
|
+
if (unionSymbolOk && (discriminatedPropertySymbols.length === 0 || discriminatedPropertySymbols.length === contextualType.types.length)) {
|
|
1463
|
+
const symbol = contextualType.getProperty(name);
|
|
1464
|
+
if (symbol)
|
|
1465
|
+
return [symbol];
|
|
1466
|
+
}
|
|
1467
|
+
if (discriminatedPropertySymbols.length === 0) {
|
|
1468
|
+
// Bad discriminant -- do again without discriminating
|
|
1469
|
+
return mapDefined(contextualType.types, t => t.getProperty(name));
|
|
1470
|
+
}
|
|
1471
|
+
return discriminatedPropertySymbols;
|
|
1472
|
+
}
|
|
1473
|
+
function isArgumentOfElementAccessExpression(node) {
|
|
1474
|
+
return node &&
|
|
1475
|
+
node.parent &&
|
|
1476
|
+
node.parent.kind === SyntaxKind.ElementAccessExpression &&
|
|
1477
|
+
node.parent.argumentExpression === node;
|
|
1478
|
+
}
|
|
1479
|
+
setObjectAllocator(getServicesObjectAllocator());
|
|
1480
|
+
setTypeObjectAllocator(getServicesTypeObjectAllocator());
|