navigation tree / bar: Set span of anonymous function to span of VariableDeclaration containing it (#18575)
* navigation tree / bar: Set span of anonymous function to span of VariableDeclaration containing it * Add back `isFunctionOrClassExpression`
This commit is contained in:
parent
0ae42ea3de
commit
12649516cf
|
@ -2571,20 +2571,29 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
public verifyNavigationBar(json: any) {
|
||||
const items = this.languageService.getNavigationBarItems(this.activeFile.fileName);
|
||||
if (JSON.stringify(items, replacer) !== JSON.stringify(json)) {
|
||||
this.raiseError(`verifyNavigationBar failed - expected: ${stringify(json)}, got: ${stringify(items, replacer)}`);
|
||||
public verifyNavigationBar(json: any, options: { checkSpans?: boolean } | undefined) {
|
||||
this.verifyNavigationTreeOrBar(json, this.languageService.getNavigationBarItems(this.activeFile.fileName), "Bar", options);
|
||||
}
|
||||
|
||||
public verifyNavigationTree(json: any, options: { checkSpans?: boolean } | undefined) {
|
||||
this.verifyNavigationTreeOrBar(json, this.languageService.getNavigationTree(this.activeFile.fileName), "Tree", options);
|
||||
}
|
||||
|
||||
private verifyNavigationTreeOrBar(json: any, tree: any, name: "Tree" | "Bar", options: { checkSpans?: boolean } | undefined) {
|
||||
if (JSON.stringify(tree, replacer) !== JSON.stringify(json)) {
|
||||
this.raiseError(`verifyNavigation${name} failed - expected: ${stringify(json)}, got: ${stringify(tree, replacer)}`);
|
||||
}
|
||||
|
||||
// Make the data easier to read.
|
||||
function replacer(key: string, value: any) {
|
||||
switch (key) {
|
||||
case "spans":
|
||||
// We won't ever check this.
|
||||
return undefined;
|
||||
return options && options.checkSpans ? value : undefined;
|
||||
case "start":
|
||||
case "length":
|
||||
// Never omit the values in a span, even if they are 0.
|
||||
return value;
|
||||
case "childItems":
|
||||
return value.length === 0 ? undefined : value;
|
||||
return !value || value.length === 0 ? undefined : value;
|
||||
default:
|
||||
// Omit falsy values, those are presumed to be the default.
|
||||
return value || undefined;
|
||||
|
@ -2592,18 +2601,6 @@ namespace FourSlash {
|
|||
}
|
||||
}
|
||||
|
||||
public verifyNavigationTree(json: any) {
|
||||
const tree = this.languageService.getNavigationTree(this.activeFile.fileName);
|
||||
if (JSON.stringify(tree, replacer) !== JSON.stringify(json)) {
|
||||
this.raiseError(`verifyNavigationTree failed - expected: ${stringify(json)}, got: ${stringify(tree, replacer)}`);
|
||||
}
|
||||
|
||||
function replacer(key: string, value: any) {
|
||||
// Don't check "spans", and omit falsy values.
|
||||
return key === "spans" ? undefined : (value || undefined);
|
||||
}
|
||||
}
|
||||
|
||||
public printNavigationItems(searchValue: string) {
|
||||
const items = this.languageService.getNavigateToItems(searchValue);
|
||||
Harness.IO.log(`NavigationItems list (${items.length} items)`);
|
||||
|
@ -3533,6 +3530,10 @@ namespace FourSlashInterface {
|
|||
return this.state.getRanges();
|
||||
}
|
||||
|
||||
public spans(): ts.TextSpan[] {
|
||||
return this.ranges().map(r => ts.createTextSpan(r.start, r.end - r.start));
|
||||
}
|
||||
|
||||
public rangesByText(): ts.Map<FourSlash.Range[]> {
|
||||
return this.state.rangesByText();
|
||||
}
|
||||
|
@ -3966,12 +3967,12 @@ namespace FourSlashInterface {
|
|||
this.state.verifyImportFixAtPosition(expectedTextArray, errorCode);
|
||||
}
|
||||
|
||||
public navigationBar(json: any) {
|
||||
this.state.verifyNavigationBar(json);
|
||||
public navigationBar(json: any, options?: { checkSpans?: boolean }) {
|
||||
this.state.verifyNavigationBar(json, options);
|
||||
}
|
||||
|
||||
public navigationTree(json: any) {
|
||||
this.state.verifyNavigationTree(json);
|
||||
public navigationTree(json: any, options?: { checkSpans?: boolean }) {
|
||||
this.state.verifyNavigationTree(json, options);
|
||||
}
|
||||
|
||||
public navigationItemsListCount(count: number, searchValue: string, matchKind?: string, fileName?: string) {
|
||||
|
|
|
@ -209,17 +209,24 @@ namespace ts.NavigationBar {
|
|||
|
||||
case SyntaxKind.BindingElement:
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
const decl = <VariableDeclaration>node;
|
||||
const name = decl.name;
|
||||
const { name, initializer } = <VariableDeclaration | BindingElement>node;
|
||||
if (isBindingPattern(name)) {
|
||||
addChildrenRecursively(name);
|
||||
}
|
||||
else if (decl.initializer && isFunctionOrClassExpression(decl.initializer)) {
|
||||
// For `const x = function() {}`, just use the function node, not the const.
|
||||
addChildrenRecursively(decl.initializer);
|
||||
else if (initializer && isFunctionOrClassExpression(initializer)) {
|
||||
if (initializer.name) {
|
||||
// Don't add a node for the VariableDeclaration, just for the initializer.
|
||||
addChildrenRecursively(initializer);
|
||||
}
|
||||
else {
|
||||
// Add a node for the VariableDeclaration, but not for the initializer.
|
||||
startNode(node);
|
||||
forEachChild(initializer, addChildrenRecursively);
|
||||
endNode();
|
||||
}
|
||||
}
|
||||
else {
|
||||
addNodeWithRecursiveChild(decl, decl.initializer);
|
||||
addNodeWithRecursiveChild(node, initializer);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -644,7 +651,14 @@ namespace ts.NavigationBar {
|
|||
}
|
||||
}
|
||||
|
||||
function isFunctionOrClassExpression(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.FunctionExpression || node.kind === SyntaxKind.ArrowFunction || node.kind === SyntaxKind.ClassExpression;
|
||||
function isFunctionOrClassExpression(node: Node): node is ArrowFunction | FunctionExpression | ClassExpression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ArrowFunction:
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ClassExpression:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,6 +114,7 @@ declare namespace FourSlashInterface {
|
|||
markerNames(): string[];
|
||||
marker(name?: string): Marker;
|
||||
ranges(): Range[];
|
||||
spans(): Array<{ start: number, length: number }>;
|
||||
rangesByText(): ts.Map<Range[]>;
|
||||
markerByName(s: string): Marker;
|
||||
symbolsInScope(range: Range): any[];
|
||||
|
@ -250,8 +251,8 @@ declare namespace FourSlashInterface {
|
|||
fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, formattingOptions?: FormatCodeOptions): void;
|
||||
importFixAtPosition(expectedTextArray: string[], errorCode?: number): void;
|
||||
|
||||
navigationBar(json: any): void;
|
||||
navigationTree(json: any): void;
|
||||
navigationBar(json: any, options?: { checkSpans?: boolean }): void;
|
||||
navigationTree(json: any, options?: { checkSpans?: boolean }): void;
|
||||
navigationItemsListCount(count: number, searchValue: string, matchKind?: string, fileName?: string): void;
|
||||
navigationItemsListContains(name: string, kind: string, searchValue: string, matchKind: string, fileName?: string, parentName?: string): void;
|
||||
occurrencesAtPositionContains(range: Range, isWriteAccess?: boolean): void;
|
||||
|
|
|
@ -46,7 +46,7 @@ verify.navigationTree({
|
|||
},
|
||||
{
|
||||
"text": "x",
|
||||
"kind": "function",
|
||||
"kind": "const",
|
||||
"childItems": [
|
||||
{
|
||||
"text": "xx",
|
||||
|
@ -90,7 +90,7 @@ verify.navigationTree({
|
|||
},
|
||||
{
|
||||
"text": "cls2",
|
||||
"kind": "class"
|
||||
"kind": "const"
|
||||
},
|
||||
{
|
||||
"text": "cls3",
|
||||
|
@ -138,7 +138,7 @@ verify.navigationBar([
|
|||
},
|
||||
{
|
||||
"text": "x",
|
||||
"kind": "function"
|
||||
"kind": "const"
|
||||
},
|
||||
{
|
||||
"text": "y",
|
||||
|
@ -160,7 +160,7 @@ verify.navigationBar([
|
|||
},
|
||||
{
|
||||
"text": "x",
|
||||
"kind": "function",
|
||||
"kind": "const",
|
||||
"childItems": [
|
||||
{
|
||||
"text": "xx",
|
||||
|
@ -205,7 +205,7 @@ verify.navigationBar([
|
|||
},
|
||||
{
|
||||
"text": "cls2",
|
||||
"kind": "class"
|
||||
"kind": "const"
|
||||
},
|
||||
{
|
||||
"text": "cls3",
|
||||
|
@ -219,11 +219,6 @@ verify.navigationBar([
|
|||
"kind": "class",
|
||||
"indent": 2
|
||||
},
|
||||
{
|
||||
"text": "cls2",
|
||||
"kind": "class",
|
||||
"indent": 2
|
||||
},
|
||||
{
|
||||
"text": "cls3",
|
||||
"kind": "class",
|
||||
|
|
51
tests/cases/fourslash/navigationBarInitializerSpans.ts
Normal file
51
tests/cases/fourslash/navigationBarInitializerSpans.ts
Normal file
|
@ -0,0 +1,51 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////const [|x = () => 0|];
|
||||
////const f = [|function f() {}|];
|
||||
|
||||
const [s0, s1] = test.spans();
|
||||
const sGlobal = { start: 0, length: 45 };
|
||||
|
||||
verify.navigationTree({
|
||||
text: "<global>",
|
||||
kind: "script",
|
||||
spans: [sGlobal],
|
||||
childItems: [
|
||||
{
|
||||
text: "f",
|
||||
kind: "function",
|
||||
spans: [s1],
|
||||
},
|
||||
{
|
||||
text: "x",
|
||||
kind: "const",
|
||||
spans: [s0],
|
||||
},
|
||||
]
|
||||
}, { checkSpans: true });
|
||||
|
||||
verify.navigationBar([
|
||||
{
|
||||
text: "<global>",
|
||||
kind: "script",
|
||||
spans: [sGlobal],
|
||||
childItems: [
|
||||
{
|
||||
text: "f",
|
||||
kind: "function",
|
||||
spans: [s1],
|
||||
},
|
||||
{
|
||||
text: "x",
|
||||
kind: "const",
|
||||
spans: [s0],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
text: "f",
|
||||
kind: "function",
|
||||
spans: [s1],
|
||||
indent: 1,
|
||||
},
|
||||
], { checkSpans: true });
|
|
@ -17,11 +17,13 @@ verify.navigationBar([
|
|||
},
|
||||
{
|
||||
"text": "func",
|
||||
"kind": "function"
|
||||
"kind": "const",
|
||||
"kindModifiers": "export",
|
||||
},
|
||||
{
|
||||
"text": "func2",
|
||||
"kind": "function"
|
||||
"kind": "const",
|
||||
"kindModifiers": "export",
|
||||
},
|
||||
{
|
||||
"text": "value",
|
||||
|
@ -35,18 +37,6 @@ verify.navigationBar([
|
|||
"kind": "function",
|
||||
"kindModifiers": "export",
|
||||
"indent": 1
|
||||
},
|
||||
{
|
||||
"text": "func",
|
||||
"kind": "function",
|
||||
"kindModifiers": "export",
|
||||
"indent": 1
|
||||
},
|
||||
{
|
||||
"text": "func2",
|
||||
"kind": "function",
|
||||
"kindModifiers": "export",
|
||||
"indent": 1
|
||||
}
|
||||
]);
|
||||
|
||||
|
@ -61,12 +51,12 @@ verify.navigationTree({
|
|||
},
|
||||
{
|
||||
"text": "func",
|
||||
"kind": "function",
|
||||
"kind": "const",
|
||||
"kindModifiers": "export"
|
||||
},
|
||||
{
|
||||
"text": "func2",
|
||||
"kind": "function",
|
||||
"kind": "const",
|
||||
"kindModifiers": "export"
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue