Merge branch 'master' of https://github.com/Microsoft/TypeScript into feature/eslint

This commit is contained in:
Alexander T 2019-08-30 15:57:05 +03:00
commit b31d5b37f8
10 changed files with 1110 additions and 36 deletions

View file

@ -39,7 +39,7 @@ namespace ts.GoToDefinition {
return [sigInfo];
}
else {
const defs = getDefinitionFromSymbol(typeChecker, symbol, node) || emptyArray;
const defs = getDefinitionFromSymbol(typeChecker, symbol, node, calledDeclaration) || emptyArray;
// For a 'super()' call, put the signature first, else put the variable first.
return node.kind === SyntaxKind.SuperKeyword ? [sigInfo, ...defs] : [...defs, sigInfo];
}
@ -232,10 +232,11 @@ namespace ts.GoToDefinition {
}
}
function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node): DefinitionInfo[] | undefined {
function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node, declarationNode?: Node): DefinitionInfo[] | undefined {
// 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;
// we want to strip those extra properties.
// For deduping purposes, we also want to exclude any declarationNodes if provided.
const filteredDeclarations = filter(symbol.declarations, d => d !== declarationNode && (!isAssignmentDeclaration(d) || d === symbol.valueDeclaration)) || undefined;
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(filteredDeclarations, declaration => createDefinitionInfo(declaration, typeChecker, symbol, node));
function getConstructSignatureDefinition(): DefinitionInfo[] | undefined {
@ -258,8 +259,13 @@ namespace ts.GoToDefinition {
return undefined;
}
const declarations = signatureDeclarations.filter(selectConstructors ? isConstructorDeclaration : isFunctionLike);
const declarationsWithBody = declarations.filter(d => !!(<FunctionLikeDeclaration>d).body);
// declarations defined on the global scope can be defined on multiple files. Get all of them.
return declarations.length
? [createDefinitionInfo(find(declarations, d => !!(<FunctionLikeDeclaration>d).body) || last(declarations), typeChecker, symbol, node)]
? declarationsWithBody.length !== 0
? declarationsWithBody.map(x => createDefinitionInfo(x, typeChecker, symbol, node))
: [createDefinitionInfo(last(declarations), typeChecker, symbol, node)]
: undefined;
}
}

View file

@ -33,6 +33,9 @@ namespace ts.NavigationBar {
let parentsStack: NavigationBarNode[] = [];
let parent: NavigationBarNode;
const trackedEs5ClassesStack: (Map<boolean> | undefined)[] = [];
let trackedEs5Classes: Map<boolean> | undefined;
// NavigationBarItem requires an array, but will not mutate it, so just give it this for performance.
let emptyChildItemArray: NavigationBarItem[] = [];
@ -112,10 +115,10 @@ namespace ts.NavigationBar {
pushChild(parent, emptyNavigationBarNode(node));
}
function emptyNavigationBarNode(node: Node): NavigationBarNode {
function emptyNavigationBarNode(node: Node, name?: DeclarationName): NavigationBarNode {
return {
node,
name: isDeclaration(node) || isExpression(node) ? getNameOfDeclaration(node) : undefined,
name: name || (isDeclaration(node) || isExpression(node) ? getNameOfDeclaration(node) : undefined),
additionalNodes: undefined,
parent,
children: undefined,
@ -123,16 +126,42 @@ namespace ts.NavigationBar {
};
}
function addTrackedEs5Class(name: string) {
if (!trackedEs5Classes) {
trackedEs5Classes = createMap();
}
trackedEs5Classes.set(name, true);
}
function endNestedNodes(depth: number): void {
for (let i = 0; i < depth; i++) endNode();
}
function startNestedNodes(targetNode: Node, entityName: EntityNameExpression) {
const names: Identifier[] = [];
while (!isIdentifier(entityName)) {
const name = entityName.name;
entityName = entityName.expression;
if (name.escapedText === "prototype") continue;
names.push(name);
}
names.push(entityName);
for (let i = names.length - 1; i > 0; i--) {
const name = names[i];
startNode(targetNode, name);
}
return [names.length - 1, names[0]] as const;
}
/**
* Add a new level of NavigationBarNodes.
* This pushes to the stack, so you must call `endNode` when you are done adding to this node.
*/
function startNode(node: Node): void {
const navNode: NavigationBarNode = emptyNavigationBarNode(node);
function startNode(node: Node, name?: DeclarationName): void {
const navNode: NavigationBarNode = emptyNavigationBarNode(node, name);
pushChild(parent, navNode);
// Save the old parent
parentsStack.push(parent);
trackedEs5ClassesStack.push(trackedEs5Classes);
parent = navNode;
}
@ -143,10 +172,11 @@ namespace ts.NavigationBar {
sortChildren(parent.children);
}
parent = parentsStack.pop()!;
trackedEs5Classes = trackedEs5ClassesStack.pop();
}
function addNodeWithRecursiveChild(node: Node, child: Node | undefined): void {
startNode(node);
function addNodeWithRecursiveChild(node: Node, child: Node | undefined, name?: DeclarationName): void {
startNode(node, name);
addChildrenRecursively(child);
endNode();
}
@ -236,8 +266,15 @@ namespace ts.NavigationBar {
}
break;
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionDeclaration:
const nameNode = (<FunctionLikeDeclaration>node).name;
// If we see a function declaration track as a possible ES5 class
if (nameNode && isIdentifier(nameNode)) {
addTrackedEs5Class(nameNode.text);
}
addNodeWithRecursiveChild(node, (<FunctionLikeDeclaration>node).body);
break;
case SyntaxKind.ArrowFunction:
case SyntaxKind.FunctionExpression:
addNodeWithRecursiveChild(node, (<FunctionLikeDeclaration>node).body);
break;
@ -275,21 +312,94 @@ namespace ts.NavigationBar {
addLeafNode(node);
break;
case SyntaxKind.CallExpression:
case SyntaxKind.BinaryExpression: {
const special = getAssignmentDeclarationKind(node as BinaryExpression);
switch (special) {
case AssignmentDeclarationKind.ExportsProperty:
case AssignmentDeclarationKind.ModuleExports:
case AssignmentDeclarationKind.PrototypeProperty:
case AssignmentDeclarationKind.Prototype:
addNodeWithRecursiveChild(node, (node as BinaryExpression).right);
return;
case AssignmentDeclarationKind.ThisProperty:
case AssignmentDeclarationKind.Property:
case AssignmentDeclarationKind.None:
case AssignmentDeclarationKind.Prototype:
case AssignmentDeclarationKind.PrototypeProperty: {
const binaryExpression = (node as BinaryExpression);
const assignmentTarget = binaryExpression.left as PropertyAccessExpression;
const prototypeAccess = special === AssignmentDeclarationKind.PrototypeProperty ?
assignmentTarget.expression as PropertyAccessExpression :
assignmentTarget;
let depth = 0;
let className: Identifier;
// If we see a prototype assignment, start tracking the target as a class
// This is only done for simple classes not nested assignments.
if (isIdentifier(prototypeAccess.expression)) {
addTrackedEs5Class(prototypeAccess.expression.text);
className = prototypeAccess.expression;
}
else {
[depth, className] = startNestedNodes(binaryExpression, prototypeAccess.expression as EntityNameExpression);
}
if (special === AssignmentDeclarationKind.Prototype) {
if (isObjectLiteralExpression(binaryExpression.right)) {
if (binaryExpression.right.properties.length > 0) {
startNode(binaryExpression, className);
forEachChild(binaryExpression.right, addChildrenRecursively);
endNode();
}
}
}
else if (isFunctionExpression(binaryExpression.right) || isArrowFunction(binaryExpression.right)) {
addNodeWithRecursiveChild(node,
binaryExpression.right,
className);
}
else {
startNode(binaryExpression, className);
addNodeWithRecursiveChild(node, binaryExpression.right, assignmentTarget.name);
endNode();
}
endNestedNodes(depth);
return;
}
case AssignmentDeclarationKind.ObjectDefinePropertyValue:
case AssignmentDeclarationKind.ObjectDefinePrototypeProperty: {
const defineCall = node as BindableObjectDefinePropertyCall;
const className = special === AssignmentDeclarationKind.ObjectDefinePropertyValue ?
defineCall.arguments[0] :
(defineCall.arguments[0] as PropertyAccessExpression).expression as EntityNameExpression;
const memberName = defineCall.arguments[1];
const [depth, classNameIdentifier] = startNestedNodes(node, className);
startNode(node, classNameIdentifier);
startNode(node, setTextRange(createIdentifier(memberName.text), memberName));
addChildrenRecursively((node as CallExpression).arguments[2]);
endNode();
endNode();
endNestedNodes(depth);
return;
}
case AssignmentDeclarationKind.Property: {
const binaryExpression = (node as BinaryExpression);
const assignmentTarget = binaryExpression.left as PropertyAccessExpression;
const targetFunction = assignmentTarget.expression;
if (isIdentifier(targetFunction) && assignmentTarget.name.escapedText !== "prototype" &&
trackedEs5Classes && trackedEs5Classes.has(targetFunction.text)) {
if (isFunctionExpression(binaryExpression.right) || isArrowFunction(binaryExpression.right)) {
addNodeWithRecursiveChild(node, binaryExpression.right, targetFunction);
}
else {
startNode(binaryExpression, targetFunction);
addNodeWithRecursiveChild(binaryExpression.left, binaryExpression.right, assignmentTarget.name);
endNode();
}
return;
}
break;
}
case AssignmentDeclarationKind.ThisProperty:
case AssignmentDeclarationKind.None:
case AssignmentDeclarationKind.ObjectDefinePropertyExports:
case AssignmentDeclarationKind.ObjectDefinePrototypeProperty:
break;
default:
Debug.assertNever(special);
@ -315,8 +425,8 @@ namespace ts.NavigationBar {
/** Merge declarations of the same kind. */
function mergeChildren(children: NavigationBarNode[], node: NavigationBarNode): void {
const nameToItems = createMap<NavigationBarNode | NavigationBarNode[]>();
filterMutate(children, child => {
const declName = getNameOfDeclaration(<Declaration>child.node);
filterMutate(children, (child, index) => {
const declName = child.name || getNameOfDeclaration(<Declaration>child.node);
const name = declName && nodeText(declName);
if (!name) {
// Anonymous items are never merged.
@ -331,7 +441,7 @@ namespace ts.NavigationBar {
if (itemsWithSameName instanceof Array) {
for (const itemWithSameName of itemsWithSameName) {
if (tryMerge(itemWithSameName, child, node)) {
if (tryMerge(itemWithSameName, child, index, node)) {
return false;
}
}
@ -340,7 +450,7 @@ namespace ts.NavigationBar {
}
else {
const itemWithSameName = itemsWithSameName;
if (tryMerge(itemWithSameName, child, node)) {
if (tryMerge(itemWithSameName, child, index, node)) {
return false;
}
nameToItems.set(name, [itemWithSameName, child]);
@ -348,8 +458,116 @@ namespace ts.NavigationBar {
}
});
}
const isEs5ClassMember: Record<AssignmentDeclarationKind, boolean> = {
[AssignmentDeclarationKind.Property]: true,
[AssignmentDeclarationKind.PrototypeProperty]: true,
[AssignmentDeclarationKind.ObjectDefinePropertyValue]: true,
[AssignmentDeclarationKind.ObjectDefinePrototypeProperty]: true,
[AssignmentDeclarationKind.None]: false,
[AssignmentDeclarationKind.ExportsProperty]: false,
[AssignmentDeclarationKind.ModuleExports]: false,
[AssignmentDeclarationKind.ObjectDefinePropertyExports]: false,
[AssignmentDeclarationKind.Prototype]: true,
[AssignmentDeclarationKind.ThisProperty]: false,
};
function tryMergeEs5Class(a: NavigationBarNode, b: NavigationBarNode, bIndex: number, parent: NavigationBarNode): boolean | undefined {
function tryMerge(a: NavigationBarNode, b: NavigationBarNode, parent: NavigationBarNode): boolean {
function isPossibleConstructor(node: Node) {
return isFunctionExpression(node) || isFunctionDeclaration(node) || isVariableDeclaration(node);
}
const bAssignmentDeclarationKind = isBinaryExpression(b.node) || isCallExpression(b.node) ?
getAssignmentDeclarationKind(b.node) :
AssignmentDeclarationKind.None;
const aAssignmentDeclarationKind = isBinaryExpression(a.node) || isCallExpression(a.node) ?
getAssignmentDeclarationKind(a.node) :
AssignmentDeclarationKind.None;
// We treat this as an es5 class and merge the nodes in in one of several cases
if ((isEs5ClassMember[bAssignmentDeclarationKind] && isEs5ClassMember[aAssignmentDeclarationKind]) // merge two class elements
|| (isPossibleConstructor(a.node) && isEs5ClassMember[bAssignmentDeclarationKind]) // ctor function & member
|| (isPossibleConstructor(b.node) && isEs5ClassMember[aAssignmentDeclarationKind]) // member & ctor function
|| (isClassDeclaration(a.node) && isEs5ClassMember[bAssignmentDeclarationKind]) // class (generated) & member
|| (isClassDeclaration(b.node) && isEs5ClassMember[aAssignmentDeclarationKind]) // member & class (generated)
|| (isClassDeclaration(a.node) && isPossibleConstructor(b.node)) // class (generated) & ctor
|| (isClassDeclaration(b.node) && isPossibleConstructor(a.node)) // ctor & class (generated)
) {
let lastANode = a.additionalNodes && lastOrUndefined(a.additionalNodes) || a.node;
if ((!isClassDeclaration(a.node) && !isClassDeclaration(b.node)) // If neither outline node is a class
|| isPossibleConstructor(a.node) || isPossibleConstructor(b.node) // If either function is a constructor function
) {
const ctorFunction = isPossibleConstructor(a.node) ? a.node :
isPossibleConstructor(b.node) ? b.node :
undefined;
if (ctorFunction !== undefined) {
const ctorNode = setTextRange(
createConstructor(/* decorators */ undefined, /* modifiers */ undefined, [], /* body */ undefined),
ctorFunction);
const ctor = emptyNavigationBarNode(ctorNode);
ctor.indent = a.indent + 1;
ctor.children = a.node === ctorFunction ? a.children : b.children;
a.children = a.node === ctorFunction ? concatenate([ctor], b.children || [b]) : concatenate(a.children || [a], [ctor]);
}
else {
if (a.children || b.children) {
a.children = concatenate(a.children || [a], b.children || [b]);
if (a.children) {
mergeChildren(a.children, a);
sortChildren(a.children);
}
}
}
lastANode = a.node = setTextRange(createClassDeclaration(
/* decorators */ undefined,
/* modifiers */ undefined,
a.name as Identifier || createIdentifier("__class__"),
/* typeParameters */ undefined,
/* heritageClauses */ undefined,
[]
), a.node);
}
else {
a.children = concatenate(a.children, b.children);
if (a.children) {
mergeChildren(a.children, a);
}
}
const bNode = b.node;
// We merge if the outline node previous to b (bIndex - 1) is already part of the current class
// We do this so that statements between class members that do not generate outline nodes do not split up the class outline:
// Ex This should produce one outline node C:
// function C() {}; a = 1; C.prototype.m = function () {}
// Ex This will produce 3 outline nodes: C, a, C
// function C() {}; let a = 1; C.prototype.m = function () {}
if (parent.children![bIndex - 1].node.end === lastANode.end) {
setTextRange(lastANode, { pos: lastANode.pos, end: bNode.end });
}
else {
if (!a.additionalNodes) a.additionalNodes = [];
a.additionalNodes.push(setTextRange(createClassDeclaration(
/* decorators */ undefined,
/* modifiers */ undefined,
a.name as Identifier || createIdentifier("__class__"),
/* typeParameters */ undefined,
/* heritageClauses */ undefined,
[]
), b.node));
}
return true;
}
return bAssignmentDeclarationKind === AssignmentDeclarationKind.None ? false : true;
}
function tryMerge(a: NavigationBarNode, b: NavigationBarNode, bIndex: number, parent: NavigationBarNode): boolean {
// const v = false as boolean;
if (tryMergeEs5Class(a, b, bIndex, parent)) {
return true;
}
if (shouldReallyMerge(a.node, b.node, parent)) {
merge(a, b);
return true;
@ -444,7 +662,7 @@ namespace ts.NavigationBar {
}
if (name) {
const text = nodeText(name);
const text = isIdentifier(name) ? name.text : nodeText(name);
if (text.length > 0) {
return cleanText(text);
}

View file

@ -7,8 +7,16 @@
////var /*def2*/x: number;
//@Filename: c.ts
////var /*def3*/x: number;
//@Filename: d.ts
////var /*def4*/x: number;
//@Filename: e.ts
/////// <reference path="a.ts" />
/////// <reference path="b.ts" />
/////// <reference path="c.ts" />
/////// <reference path="d.ts" />
////[|/*use*/x|]++;
verify.goToDefinition("use", ["def1", "def2"]);
verify.goToDefinition("use", ["def1", "def2", "def3", "def4"]);

View file

@ -3,6 +3,18 @@
// @Filename: foo.js
////function f() {}
////f.prototype.x = 0;
////f.y = 0;
////f.prototype.method = function () {};
////Object.defineProperty(f, 'staticProp', {
//// set: function() {},
//// get: function(){
//// }
////});
////Object.defineProperty(f.prototype, 'name', {
//// set: function() {},
//// get: function(){
//// }
////});
verify.navigationTree({
"text": "<global>",
@ -10,11 +22,50 @@ verify.navigationTree({
"childItems": [
{
"text": "f",
"kind": "function"
},
{
"text": "x",
"kind": "property"
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "x",
"kind": "property"
},
{
"text": "y"
},
{
"text": "method",
"kind": "function"
},
{
"text": "staticProp",
"childItems": [
{
"text": "get",
"kind": "function"
},
{
"text": "set",
"kind": "function"
}
]
},
{
"text": "name",
"childItems": [
{
"text": "get",
"kind": "function"
},
{
"text": "set",
"kind": "function"
}
]
}
]
}
]
});
@ -26,17 +77,36 @@ verify.navigationBar([
"childItems": [
{
"text": "f",
"kind": "function"
},
{
"text": "x",
"kind": "property"
"kind": "class"
}
]
},
{
"text": "f",
"kind": "function",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "x",
"kind": "property"
},
{
"text": "y"
},
{
"text": "method",
"kind": "function"
},
{
"text": "staticProp"
},
{
"text": "name"
}
],
"indent": 1
}
]);

View file

@ -0,0 +1,64 @@
/// <reference path="fourslash.ts"/>
// @Filename: foo.js
////A.prototype.a = function() { };
////A.prototype.b = function() { };
////function A() {}
verify.navigationTree({
"text": "<global>",
"kind": "script",
"childItems": [
{
"text": "A",
"kind": "class",
"childItems": [
{
"text": "a",
"kind": "function"
},
{
"text": "b",
"kind": "function"
},
{
"text": "constructor",
"kind": "constructor"
}
]
}
]
});
verify.navigationBar([
{
"text": "<global>",
"kind": "script",
"childItems": [
{
"text": "A",
"kind": "class"
}
]
},
{
"text": "A",
"kind": "class",
"childItems": [
{
"text": "a",
"kind": "function"
},
{
"text": "b",
"kind": "function"
},
{
"text": "constructor",
"kind": "constructor"
}
],
"indent": 1
}
]);

View file

@ -0,0 +1,64 @@
/// <reference path="fourslash.ts"/>
// @Filename: foo.js
////var A;
////A.prototype.a = function() { };
////A.b = function() { };
verify.navigationTree({
"text": "<global>",
"kind": "script",
"childItems": [
{
"text": "A",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "a",
"kind": "function"
},
{
"text": "b",
"kind": "function"
}
]
}
]
});
verify.navigationBar([
{
"text": "<global>",
"kind": "script",
"childItems": [
{
"text": "A",
"kind": "class"
}
]
},
{
"text": "A",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "a",
"kind": "function"
},
{
"text": "b",
"kind": "function"
}
],
"indent": 1
}
]);

View file

@ -0,0 +1,74 @@
/// <reference path="fourslash.ts"/>
// @Filename: foo.js
////var A;
////A.prototype = { };
////A.prototype = { m() {} };
////A.prototype.a = function() { };
////A.b = function() { };
verify.navigationTree({
"text": "<global>",
"kind": "script",
"childItems": [
{
"text": "A",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "m",
"kind": "method"
},
{
"text": "a",
"kind": "function"
},
{
"text": "b",
"kind": "function"
}
]
}
]
});
verify.navigationBar([
{
"text": "<global>",
"kind": "script",
"childItems": [
{
"text": "A",
"kind": "class"
}
]
},
{
"text": "A",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "m",
"kind": "method"
},
{
"text": "a",
"kind": "function"
},
{
"text": "b",
"kind": "function"
}
],
"indent": 1
}
]);

View file

@ -0,0 +1,156 @@
/// <reference path="fourslash.ts"/>
// @Filename: foo.js
////function A() {}
////A. // Started typing something here
////A.prototype.a = function() { };
////G. // Started typing something here
////A.prototype.a = function() { };
verify.navigationTree({
"text": "<global>",
"kind": "script",
"spans": [
{
"start": 0,
"length": 151
}
],
"childItems": [
{
"text": "G",
"kind": "method",
"spans": [
{
"start": 84,
"length": 66
}
],
"nameSpan": {
"start": 84,
"length": 1
},
"childItems": [
{
"text": "A",
"kind": "method",
"spans": [
{
"start": 84,
"length": 66
}
],
"nameSpan": {
"start": 120,
"length": 1
},
"childItems": [
{
"text": "a",
"kind": "function",
"spans": [
{
"start": 136,
"length": 14
}
],
"nameSpan": {
"start": 132,
"length": 1
}
}
]
}
]
},
{
"text": "A",
"kind": "class",
"spans": [
{
"start": 0,
"length": 82
}
],
"nameSpan": {
"start": 9,
"length": 1
},
"childItems": [
{
"text": "constructor",
"kind": "constructor",
"spans": [
{
"start": 0,
"length": 15
}
]
},
{
"text": "A",
"kind": "method",
"spans": [
{
"start": 16,
"length": 66
}
],
"nameSpan": {
"start": 52,
"length": 1
},
"childItems": [
{
"text": "a",
"kind": "function",
"spans": [
{
"start": 68,
"length": 14
}
],
"nameSpan": {
"start": 64,
"length": 1
}
}
]
}
]
}
]
}, { checkSpans: true });
verify.navigationBar([
{
"text": "<global>",
"kind": "script",
"childItems": [
{
"text": "G",
"kind": "method"
},
{
"text": "A",
"kind": "class"
}
]
},
{
"text": "A",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "A",
"kind": "method"
}
],
"indent": 1
}
]);

View file

@ -0,0 +1,188 @@
/// <reference path="fourslash.ts"/>
// @Filename: foo.js
////var b = 1;
////function A() {};
////A.prototype.a = function() { };
////A.b = function() { };
////b = 2
/////* Comment */
////A.prototype.c = function() { }
////var b = 2
////A.prototype.d = function() { }
verify.navigationTree({
"text": "<global>",
"kind": "script",
"spans": [
{
"start": 0,
"length": 174
}
],
"childItems": [
{
"text": "A",
"kind": "class",
"spans": [
{
"start": 11,
"length": 122
},
{
"start": 144,
"length": 30
}
],
"nameSpan": {
"start": 20,
"length": 1
},
"childItems": [
{
"text": "constructor",
"kind": "constructor",
"spans": [
{
"start": 11,
"length": 15
}
]
},
{
"text": "a",
"kind": "function",
"spans": [
{
"start": 45,
"length": 14
}
],
"nameSpan": {
"start": 41,
"length": 1
}
},
{
"text": "b",
"kind": "function",
"spans": [
{
"start": 67,
"length": 14
}
],
"nameSpan": {
"start": 63,
"length": 1
}
},
{
"text": "c",
"kind": "function",
"spans": [
{
"start": 119,
"length": 14
}
],
"nameSpan": {
"start": 115,
"length": 1
}
},
{
"text": "d",
"kind": "function",
"spans": [
{
"start": 160,
"length": 14
}
],
"nameSpan": {
"start": 156,
"length": 1
}
}
]
},
{
"text": "b",
"kind": "var",
"spans": [
{
"start": 4,
"length": 5
}
],
"nameSpan": {
"start": 4,
"length": 1
}
},
{
"text": "b",
"kind": "var",
"spans": [
{
"start": 138,
"length": 5
}
],
"nameSpan": {
"start": 138,
"length": 1
}
}
]
}, { checkSpans: true });
verify.navigationBar([
{
"text": "<global>",
"kind": "script",
"childItems": [
{
"text": "A",
"kind": "class"
},
{
"text": "b",
"kind": "var"
},
{
"text": "b",
"kind": "var"
}
]
},
{
"text": "A",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "a",
"kind": "function"
},
{
"text": "b",
"kind": "function"
},
{
"text": "c",
"kind": "function"
},
{
"text": "d",
"kind": "function"
}
],
"indent": 1
}
]);

View file

@ -0,0 +1,226 @@
/// <reference path="fourslash.ts"/>
// @Filename: foo.js
////function A() {}
////A.B = function () { }
////A.B.prototype.d = function () { }
////Object.defineProperty(A.B.prototype, "x", {
//// get() {}
////})
////A.prototype.D = function () { }
////A.prototype.D.prototype.d = function () { }
verify.navigationTree({
"text": "<global>",
"kind": "script",
"spans": [
{
"start": 0,
"length": 216
}
],
"childItems": [
{
"text": "A",
"kind": "class",
"spans": [
{
"start": 0,
"length": 215
}
],
"nameSpan": {
"start": 9,
"length": 1
},
"childItems": [
{
"text": "constructor",
"kind": "constructor",
"spans": [
{
"start": 0,
"length": 15
}
]
},
{
"text": "B",
"kind": "class",
"spans": [
{
"start": 22,
"length": 114
}
],
"nameSpan": {
"start": 18,
"length": 1
},
"childItems": [
{
"text": "constructor",
"kind": "constructor",
"spans": [
{
"start": 22,
"length": 16
}
]
},
{
"text": "d",
"kind": "function",
"spans": [
{
"start": 58,
"length": 16
}
],
"nameSpan": {
"start": 54,
"length": 1
}
},
{
"text": "x",
"spans": [
{
"start": 77,
"length": 59
}
],
"nameSpan": {
"start": 114,
"length": 3
},
"childItems": [
{
"text": "get",
"kind": "method",
"spans": [
{
"start": 125,
"length": 8
}
],
"nameSpan": {
"start": 125,
"length": 3
}
}
]
}
]
},
{
"text": "D",
"kind": "class",
"spans": [
{
"start": 153,
"length": 62
}
],
"nameSpan": {
"start": 149,
"length": 1
},
"childItems": [
{
"text": "constructor",
"kind": "constructor",
"spans": [
{
"start": 153,
"length": 16
}
]
},
{
"text": "d",
"kind": "function",
"spans": [
{
"start": 199,
"length": 16
}
],
"nameSpan": {
"start": 195,
"length": 1
}
}
]
}
]
}
]
}, { checkSpans: true });
verify.navigationBar([
{
"text": "<global>",
"kind": "script",
"childItems": [
{
"text": "A",
"kind": "class"
}
]
},
{
"text": "A",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "B",
"kind": "class"
},
{
"text": "D",
"kind": "class"
}
],
"indent": 1
},
{
"text": "B",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "d",
"kind": "function"
},
{
"text": "x"
}
],
"indent": 2
},
{
"text": "D",
"kind": "class",
"childItems": [
{
"text": "constructor",
"kind": "constructor"
},
{
"text": "d",
"kind": "function"
}
],
"indent": 2
}
]);