Merge master

This commit is contained in:
Orta Therox
2019-08-06 15:34:06 -04:00
324 changed files with 113384 additions and 84213 deletions
+83
View File
@@ -684,6 +684,11 @@ namespace ts {
return;
}
}
else if (kind === SyntaxKind.SingleLineCommentTrivia) {
if (tryClassifyTripleSlashComment(start, width)) {
return;
}
}
// Simple comment. Just add as is.
pushCommentRange(start, width);
@@ -756,6 +761,84 @@ namespace ts {
}
}
function tryClassifyTripleSlashComment(start: number, width: number): boolean {
const tripleSlashXMLCommentRegEx = /^(\/\/\/\s*)(<)(?:(\S+)((?:[^/]|\/[^>])*)(\/>)?)?/im;
const attributeRegex = /(\S+)(\s*)(=)(\s*)('[^']+'|"[^"]+")/img;
const text = sourceFile.text.substr(start, width);
const match = tripleSlashXMLCommentRegEx.exec(text);
if (!match) {
return false;
}
let pos = start;
pushCommentRange(pos, match[1].length); // ///
pos += match[1].length;
pushClassification(pos, match[2].length, ClassificationType.punctuation); // <
pos += match[2].length;
if (!match[3]) {
return true;
}
pushClassification(pos, match[3].length, ClassificationType.jsxSelfClosingTagName); // element name
pos += match[3].length;
const attrText = match[4];
let attrPos = pos;
while (true) {
const attrMatch = attributeRegex.exec(attrText);
if (!attrMatch) {
break;
}
const newAttrPos = pos + attrMatch.index;
if (newAttrPos > attrPos) {
pushCommentRange(attrPos, newAttrPos - attrPos);
attrPos = newAttrPos;
}
pushClassification(attrPos, attrMatch[1].length, ClassificationType.jsxAttribute); // attribute name
attrPos += attrMatch[1].length;
if (attrMatch[2].length) {
pushCommentRange(attrPos, attrMatch[2].length); // whitespace
attrPos += attrMatch[2].length;
}
pushClassification(attrPos, attrMatch[3].length, ClassificationType.operator); // =
attrPos += attrMatch[3].length;
if (attrMatch[4].length) {
pushCommentRange(attrPos, attrMatch[4].length); // whitespace
attrPos += attrMatch[4].length;
}
pushClassification(attrPos, attrMatch[5].length, ClassificationType.jsxAttributeStringLiteralValue); // attribute value
attrPos += attrMatch[5].length;
}
pos += match[4].length;
if (pos > attrPos) {
pushCommentRange(attrPos, pos - attrPos);
}
if (match[5]) {
pushClassification(pos, match[5].length, ClassificationType.punctuation); // />
pos += match[5].length;
}
const end = start + width;
if (pos < end) {
pushCommentRange(pos, end - pos);
}
return true;
}
function processJSDocTemplateTag(tag: JSDocTemplateTag) {
for (const child of tag.getChildren()) {
processElement(child);
+63 -19
View File
@@ -135,7 +135,8 @@ namespace ts.codefix {
Named,
Default,
Namespace,
Equals
Equals,
ConstEquals
}
/** Information about how a symbol is exported from a module. (We don't need to store the exported symbol, just its module.) */
@@ -163,7 +164,7 @@ namespace ts.codefix {
position: number,
preferences: UserPreferences,
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getCompilerOptions(), program.getTypeChecker(), program.getSourceFiles());
const exportInfos = getAllReExportingModules(sourceFile, exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getCompilerOptions(), program.getTypeChecker(), program.getSourceFiles());
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol));
// We sort the best codefixes first, so taking `first` is best for completions.
const moduleSpecifier = first(getNewImportInfos(program, sourceFile, position, exportInfos, host, preferences)).moduleSpecifier;
@@ -175,7 +176,7 @@ namespace ts.codefix {
return { description, changes, commands };
}
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
function getAllReExportingModules(importingFile: SourceFile, exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
const result: SymbolExportInfo[] = [];
forEachExternalModule(checker, allSourceFiles, (moduleSymbol, moduleFile) => {
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
@@ -183,7 +184,7 @@ namespace ts.codefix {
return;
}
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions);
const defaultInfo = getDefaultLikeExportInfo(importingFile, moduleSymbol, checker, compilerOptions);
if (defaultInfo && defaultInfo.name === symbolName && skipAlias(defaultInfo.symbol, checker) === exportedSymbol) {
result.push({ moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(defaultInfo.symbol, checker) });
}
@@ -329,7 +330,7 @@ namespace ts.codefix {
if (!umdSymbol) return undefined;
const symbol = checker.getAliasedSymbol(umdSymbol);
const symbolName = umdSymbol.name;
const exportInfos: ReadonlyArray<SymbolExportInfo> = [{ moduleSymbol: symbol, importKind: getUmdImportKind(program.getCompilerOptions()), exportedSymbolIsTypeOnly: false }];
const exportInfos: ReadonlyArray<SymbolExportInfo> = [{ moduleSymbol: symbol, importKind: getUmdImportKind(sourceFile, program.getCompilerOptions()), exportedSymbolIsTypeOnly: false }];
const fixes = getFixForImport(exportInfos, symbolName, isIdentifier(token) ? token.getStart(sourceFile) : undefined, program, sourceFile, host, preferences);
return { fixes, symbolName };
}
@@ -345,7 +346,7 @@ namespace ts.codefix {
: undefined;
}
function getUmdImportKind(compilerOptions: CompilerOptions): ImportKind {
function getUmdImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions): ImportKind {
// Import a synthetic `default` if enabled.
if (getAllowSyntheticDefaultImports(compilerOptions)) {
return ImportKind.Default;
@@ -357,7 +358,10 @@ namespace ts.codefix {
case ModuleKind.AMD:
case ModuleKind.CommonJS:
case ModuleKind.UMD:
return ImportKind.Equals;
if (isInJSFile(importingFile)) {
return isExternalModule(importingFile) ? ImportKind.Namespace : ImportKind.ConstEquals;
}
return ImportKind.Equals;
case ModuleKind.System:
case ModuleKind.ES2015:
case ModuleKind.ESNext:
@@ -403,7 +407,7 @@ namespace ts.codefix {
forEachExternalModuleToImportFrom(checker, sourceFile, program.getSourceFiles(), moduleSymbol => {
cancellationToken.throwIfCancellationRequested();
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, program.getCompilerOptions());
const defaultInfo = getDefaultLikeExportInfo(sourceFile, moduleSymbol, checker, program.getCompilerOptions());
if (defaultInfo && defaultInfo.name === symbolName && symbolHasMeaning(defaultInfo.symbolForMeaning, currentTokenMeaning)) {
addSymbol(moduleSymbol, defaultInfo.symbol, defaultInfo.kind);
}
@@ -418,20 +422,41 @@ namespace ts.codefix {
}
function getDefaultLikeExportInfo(
moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions,
): { readonly symbol: Symbol, readonly symbolForMeaning: Symbol, readonly name: string, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
const exported = getDefaultLikeExportWorker(moduleSymbol, checker);
importingFile: SourceFile, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions,
): { readonly symbol: Symbol, readonly symbolForMeaning: Symbol, readonly name: string, readonly kind: ImportKind } | undefined {
const exported = getDefaultLikeExportWorker(importingFile, moduleSymbol, checker, compilerOptions);
if (!exported) return undefined;
const { symbol, kind } = exported;
const info = getDefaultExportInfoWorker(symbol, moduleSymbol, checker, compilerOptions);
return info && { symbol, kind, ...info };
}
function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
function getDefaultLikeExportWorker(importingFile: SourceFile, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbol: Symbol, readonly kind: ImportKind } | undefined {
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
if (defaultExport) return { symbol: defaultExport, kind: ImportKind.Default };
const exportEquals = checker.resolveExternalModuleSymbol(moduleSymbol);
return exportEquals === moduleSymbol ? undefined : { symbol: exportEquals, kind: ImportKind.Equals };
return exportEquals === moduleSymbol ? undefined : { symbol: exportEquals, kind: getExportEqualsImportKind(importingFile, compilerOptions, checker) };
}
function getExportEqualsImportKind(importingFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker): ImportKind {
if (getAllowSyntheticDefaultImports(compilerOptions) && getEmitModuleKind(compilerOptions) >= ModuleKind.ES2015) {
return ImportKind.Default;
}
if (isInJSFile(importingFile)) {
return isExternalModule(importingFile) ? ImportKind.Default : ImportKind.ConstEquals;
}
for (const statement of importingFile.statements) {
if (isImportEqualsDeclaration(statement)) {
return ImportKind.Equals;
}
if (isImportDeclaration(statement) && statement.importClause && statement.importClause.name) {
const moduleSymbol = checker.getImmediateAliasedSymbol(statement.importClause.symbol);
if (moduleSymbol && moduleSymbol.name !== InternalSymbolName.Default) {
return ImportKind.Default;
}
}
}
return ImportKind.Equals;
}
function getDefaultExportInfoWorker(defaultExport: Symbol, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
@@ -445,9 +470,12 @@ namespace ts.codefix {
const aliased = checker.getImmediateAliasedSymbol(defaultExport);
return aliased && getDefaultExportInfoWorker(aliased, Debug.assertDefined(aliased.parent), checker, compilerOptions);
}
else {
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) };
if (defaultExport.escapedName !== InternalSymbolName.Default &&
defaultExport.escapedName !== InternalSymbolName.ExportEquals) {
return { symbolForMeaning: defaultExport, name: defaultExport.getName() };
}
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) };
}
function getNameForExportDefault(symbol: Symbol): string | undefined {
@@ -540,7 +568,10 @@ namespace ts.codefix {
interface ImportsCollection {
readonly defaultImport: string | undefined;
readonly namedImports: string[];
readonly namespaceLikeImport: { readonly importKind: ImportKind.Equals | ImportKind.Namespace, readonly name: string } | undefined;
readonly namespaceLikeImport: {
readonly importKind: ImportKind.Equals | ImportKind.Namespace | ImportKind.ConstEquals;
readonly name: string;
} | undefined;
}
function addNewImports(changes: textChanges.ChangeTracker, sourceFile: SourceFile, moduleSpecifier: string, quotePreference: QuotePreference, { defaultImport, namedImports, namespaceLikeImport }: ImportsCollection): void {
const quotedModuleSpecifier = makeStringLiteral(moduleSpecifier, quotePreference);
@@ -551,12 +582,25 @@ namespace ts.codefix {
namedImports.map(n => createImportSpecifier(/*propertyName*/ undefined, createIdentifier(n))), moduleSpecifier, quotePreference));
}
if (namespaceLikeImport) {
insertImport(changes, sourceFile, namespaceLikeImport.importKind === ImportKind.Equals
? createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createIdentifier(namespaceLikeImport.name), createExternalModuleReference(quotedModuleSpecifier))
: createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(namespaceLikeImport.name))), quotedModuleSpecifier));
insertImport(
changes,
sourceFile,
namespaceLikeImport.importKind === ImportKind.Equals ? createImportEqualsDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createIdentifier(namespaceLikeImport.name), createExternalModuleReference(quotedModuleSpecifier)) :
namespaceLikeImport.importKind === ImportKind.ConstEquals ? createConstEqualsRequireDeclaration(namespaceLikeImport.name, quotedModuleSpecifier) :
createImportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createImportClause(/*name*/ undefined, createNamespaceImport(createIdentifier(namespaceLikeImport.name))), quotedModuleSpecifier));
}
}
function createConstEqualsRequireDeclaration(name: string, quotedModuleSpecifier: StringLiteral): VariableStatement {
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([
createVariableDeclaration(
createIdentifier(name),
/*type*/ undefined,
createCall(createIdentifier("require"), /*typeArguments*/ undefined, [quotedModuleSpecifier])
)
], NodeFlags.Const));
}
function symbolHasMeaning({ declarations }: Symbol, meaning: SemanticMeaning): boolean {
return some(declarations, decl => !!(getMeaningFromDeclaration(decl) & meaning));
}
+4 -2
View File
@@ -193,7 +193,7 @@ namespace ts.DocumentHighlights {
function getNodesToSearchForModifier(declaration: Node, modifierFlag: ModifierFlags): ReadonlyArray<Node> | undefined {
// Types of node whose children might have modifiers.
const container = declaration.parent as ModuleBlock | SourceFile | Block | CaseClause | DefaultClause | ConstructorDeclaration | MethodDeclaration | FunctionDeclaration | ClassLikeDeclaration;
const container = declaration.parent as ModuleBlock | SourceFile | Block | CaseClause | DefaultClause | ConstructorDeclaration | MethodDeclaration | FunctionDeclaration | ObjectTypeDeclaration;
switch (container.kind) {
case SyntaxKind.ModuleBlock:
case SyntaxKind.SourceFile:
@@ -213,11 +213,13 @@ namespace ts.DocumentHighlights {
return [...container.parameters, ...(isClassLike(container.parent) ? container.parent.members : [])];
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeLiteral:
const nodes = container.members;
// If we're an accessibility modifier, we're in an instance member and should search
// the constructor's parameter list for instance members as well.
if (modifierFlag & ModifierFlags.AccessibilityModifier) {
if (modifierFlag & (ModifierFlags.AccessibilityModifier | ModifierFlags.Readonly)) {
const constructor = find(container.members, isConstructorDeclaration);
if (constructor) {
return [...nodes, ...constructor.parameters];
+25 -4
View File
@@ -709,10 +709,28 @@ namespace ts.FindAllReferences.Core {
return references.length ? [{ definition: { type: DefinitionKind.Symbol, symbol }, references }] : emptyArray;
}
/** As in a `readonly prop: any` or `constructor(readonly prop: any)`, not a `readonly any[]`. */
function isReadonlyTypeOperator(node: Node): boolean {
return node.kind === SyntaxKind.ReadonlyKeyword
&& isTypeOperatorNode(node.parent)
&& node.parent.operator === SyntaxKind.ReadonlyKeyword;
}
/** getReferencedSymbols for special node kinds. */
function getReferencedSymbolsSpecial(node: Node, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
if (isTypeKeyword(node.kind)) {
return getAllReferencesForKeyword(sourceFiles, node.kind, cancellationToken);
// A modifier readonly (like on a property declaration) is not special;
// a readonly type keyword (like `readonly string[]`) is.
if (node.kind === SyntaxKind.ReadonlyKeyword && !isReadonlyTypeOperator(node)) {
return undefined;
}
// Likewise, when we *are* looking for a special keyword, make sure we
// *dont* include readonly member modifiers.
return getAllReferencesForKeyword(
sourceFiles,
node.kind,
cancellationToken,
node.kind === SyntaxKind.ReadonlyKeyword ? isReadonlyTypeOperator : undefined);
}
// Labels
@@ -1235,11 +1253,14 @@ namespace ts.FindAllReferences.Core {
}
}
function getAllReferencesForKeyword(sourceFiles: ReadonlyArray<SourceFile>, keywordKind: SyntaxKind, cancellationToken: CancellationToken): SymbolAndEntries[] | undefined {
function getAllReferencesForKeyword(sourceFiles: ReadonlyArray<SourceFile>, keywordKind: SyntaxKind, cancellationToken: CancellationToken, filter?: (node: Node) => boolean): SymbolAndEntries[] | undefined {
const references = flatMap(sourceFiles, sourceFile => {
cancellationToken.throwIfCancellationRequested();
return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), referenceLocation =>
referenceLocation.kind === keywordKind ? nodeEntry(referenceLocation) : undefined);
return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, tokenToString(keywordKind)!, sourceFile), referenceLocation => {
if (referenceLocation.kind === keywordKind && (!filter || filter(referenceLocation))) {
return nodeEntry(referenceLocation);
}
});
});
return references.length ? [{ definition: { type: DefinitionKind.Keyword, node: references[0].node }, references }] : undefined;
}
+6 -3
View File
@@ -233,20 +233,23 @@ namespace ts.GoToDefinition {
}
function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node): DefinitionInfo[] | undefined {
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(symbol.declarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node));
// There are cases when you extend a function by adding properties to it afterwards,
// we want to strip those extra properties
const filteredDeclarations = filter(symbol.declarations, d => !isAssignmentDeclaration(d) || d === symbol.valueDeclaration) || undefined;
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(filteredDeclarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node));
function getConstructSignatureDefinition(): DefinitionInfo[] | undefined {
// Applicable only if we are in a new expression, or we are on a constructor declaration
// and in either case the symbol has a construct signature definition, i.e. class
if (symbol.flags & SymbolFlags.Class && (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword)) {
const cls = find(symbol.declarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration");
const cls = find(filteredDeclarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration");
return getSignatureDefinition(cls.members, /*selectConstructors*/ true);
}
}
function getCallSignatureDefinition(): DefinitionInfo[] | undefined {
return isCallOrNewExpressionTarget(node) || isNameOfFunctionDeclaration(node)
? getSignatureDefinition(symbol.declarations, /*selectConstructors*/ false)
? getSignatureDefinition(filteredDeclarations, /*selectConstructors*/ false)
: undefined;
}
+4 -4
View File
@@ -577,10 +577,10 @@ namespace ts.FindAllReferences {
// If a reference is a class expression, the exported node would be its parent.
// If a reference is a variable declaration, the exported node would be the variable statement.
function getExportNode(parent: Node, node: Node): Node | undefined {
if (parent.kind === SyntaxKind.VariableDeclaration) {
const p = parent as VariableDeclaration;
return p.name !== node ? undefined :
p.parent.kind === SyntaxKind.CatchClause ? undefined : p.parent.parent.kind === SyntaxKind.VariableStatement ? p.parent.parent : undefined;
const declaration = isVariableDeclaration(parent) ? parent : isBindingElement(parent) ? walkUpBindingElementsAndPatterns(parent) : undefined;
if (declaration) {
return (parent as VariableDeclaration | BindingElement).name !== node ? undefined :
isCatchClause(declaration.parent) ? undefined : isVariableStatement(declaration.parent.parent) ? declaration.parent.parent : undefined;
}
else {
return parent;
+2 -3
View File
@@ -71,9 +71,8 @@ namespace ts.OutliningElementsCollector {
function addRegionOutliningSpans(sourceFile: SourceFile, out: Push<OutliningSpan>): void {
const regions: OutliningSpan[] = [];
const lineStarts = sourceFile.getLineStarts();
for (let i = 0; i < lineStarts.length; i++) {
const currentLineStart = lineStarts[i];
const lineEnd = i + 1 === lineStarts.length ? sourceFile.getEnd() : lineStarts[i + 1] - 1;
for (const currentLineStart of lineStarts) {
const lineEnd = sourceFile.getLineEndOfPosition(currentLineStart);
const lineText = sourceFile.text.substring(currentLineStart, lineEnd);
const result = isRegionDelimiter(lineText);
if (!result || isInComment(sourceFile, currentLineStart)) {
+5 -1
View File
@@ -350,7 +350,11 @@ namespace ts.refactor {
}
if (namedBindings) {
if (namedBindingsUnused) {
changes.delete(sourceFile, namedBindings);
changes.replaceNode(
sourceFile,
importDecl.importClause,
updateImportClause(importDecl.importClause, name, /*namedBindings*/ undefined)
);
}
else if (namedBindings.kind === SyntaxKind.NamedImports) {
for (const element of namedBindings.elements) {
+2 -4
View File
@@ -1238,12 +1238,10 @@ namespace ts {
}
if (host.resolveModuleNames) {
compilerHost.resolveModuleNames = (moduleNames, containingFile, reusedNames, redirectedReference) => host.resolveModuleNames!(moduleNames, containingFile, reusedNames, redirectedReference);
compilerHost.resolveModuleNames = (...args) => host.resolveModuleNames!(...args);
}
if (host.resolveTypeReferenceDirectives) {
compilerHost.resolveTypeReferenceDirectives = (typeReferenceDirectiveNames, containingFile, redirectedReference) => {
return host.resolveTypeReferenceDirectives!(typeReferenceDirectiveNames, containingFile, redirectedReference);
};
compilerHost.resolveTypeReferenceDirectives = (...args) => host.resolveTypeReferenceDirectives!(...args);
}
const documentRegistryBucketKey = documentRegistry.getKeyForCompilationSettings(newSettings);
+11 -6
View File
@@ -17,7 +17,7 @@ namespace ts.SmartSelectionRange {
break outer;
}
if (positionShouldSnapToNode(pos, node, nextNode)) {
if (positionShouldSnapToNode(sourceFile, pos, node)) {
// 1. Blocks are effectively redundant with SyntaxLists.
// 2. TemplateSpans, along with the SyntaxLists containing them, are a somewhat unintuitive grouping
// of things that should be considered independently.
@@ -64,6 +64,13 @@ namespace ts.SmartSelectionRange {
parentNode = node;
break;
}
// If we made it to the end of the for loop, were done.
// In practice, Ive only seen this happen at the very end
// of a SourceFile.
if (i === children.length - 1) {
break outer;
}
}
}
@@ -90,12 +97,11 @@ namespace ts.SmartSelectionRange {
* count too, unless that position belongs to the next node. In effect, makes
* selections able to snap to preceding tokens when the cursor is on the tail
* end of them with only whitespace ahead.
* @param sourceFile The source file containing the nodes.
* @param pos The position to check.
* @param node The candidate node to snap to.
* @param nextNode The next sibling node in the tree.
* @param sourceFile The source file containing the nodes.
*/
function positionShouldSnapToNode(pos: number, node: Node, nextNode: Node | undefined) {
function positionShouldSnapToNode(sourceFile: SourceFile, pos: number, node: Node) {
// Cant use 'ts.positionBelongsToNode()' here because it cleverly accounts
// for missing nodes, which cant really be considered when deciding what
// to select.
@@ -104,9 +110,8 @@ namespace ts.SmartSelectionRange {
return true;
}
const nodeEnd = node.getEnd();
const nextNodeStart = nextNode && nextNode.getStart();
if (nodeEnd === pos) {
return pos !== nextNodeStart;
return getTouchingPropertyName(sourceFile, pos).pos < node.end;
}
return false;
}
+2 -2
View File
@@ -211,9 +211,9 @@ namespace ts {
*
* If this is implemented, `getResolvedModuleWithFailedLookupLocationsFromCache` should be too.
*/
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[], redirectedReference?: ResolvedProjectReference): (ResolvedModule | undefined)[];
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedModule | undefined)[];
getResolvedModuleWithFailedLookupLocationsFromCache?(modulename: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined;
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string, redirectedReference?: ResolvedProjectReference): (ResolvedTypeReferenceDirective | undefined)[];
resolveTypeReferenceDirectives?(typeDirectiveNames: string[], containingFile: string, redirectedReference: ResolvedProjectReference | undefined, options: CompilerOptions): (ResolvedTypeReferenceDirective | undefined)[];
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;