basic support for declaring properties on funcitons
This commit is contained in:
parent
f6ee80c675
commit
b8329a05c3
5 changed files with 71 additions and 12 deletions
|
@ -265,6 +265,7 @@ namespace ts {
|
|||
return "export=";
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
case SpecialPropertyAssignmentKind.ThisProperty:
|
||||
case SpecialPropertyAssignmentKind.Property:
|
||||
// exports.x = ... or this.y = ...
|
||||
return ((node as BinaryExpression).left as PropertyAccessExpression).name.text;
|
||||
case SpecialPropertyAssignmentKind.PrototypeProperty:
|
||||
|
@ -1921,6 +1922,9 @@ namespace ts {
|
|||
case SpecialPropertyAssignmentKind.ThisProperty:
|
||||
bindThisPropertyAssignment(<BinaryExpression>node);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.Property:
|
||||
bindPropertyAssignment(<BinaryExpression>node);
|
||||
break;
|
||||
case SpecialPropertyAssignmentKind.None:
|
||||
// Nothing to do
|
||||
break;
|
||||
|
@ -2225,6 +2229,32 @@ namespace ts {
|
|||
declareSymbol(funcSymbol.members, funcSymbol, leftSideOfAssignment, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
||||
}
|
||||
|
||||
function bindPropertyAssignment(node: BinaryExpression) {
|
||||
// We saw a node of the form 'x.y = z'. Declare a 'member' y on x if x was a function.
|
||||
|
||||
// Look up the function in the local scope, since prototype assignments should
|
||||
// follow the function declaration
|
||||
const leftSideOfAssignment = node.left as PropertyAccessExpression;
|
||||
const target = leftSideOfAssignment.expression as Identifier;
|
||||
|
||||
// Fix up parent pointers since we're going to use these nodes before we bind into them
|
||||
leftSideOfAssignment.parent = node;
|
||||
target.parent = leftSideOfAssignment;
|
||||
|
||||
const funcSymbol = container.locals[target.text];
|
||||
if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(funcSymbol))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set up the members collection if it doesn't exist already
|
||||
if (!funcSymbol.exports) {
|
||||
funcSymbol.exports = createMap<Symbol>();
|
||||
}
|
||||
|
||||
// Declare the method/property
|
||||
declareSymbol(funcSymbol.exports, funcSymbol, leftSideOfAssignment, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
||||
}
|
||||
|
||||
function bindCallExpression(node: CallExpression) {
|
||||
// We're only inspecting call expressions to detect CommonJS modules, so we can skip
|
||||
// this check if we've already seen the module indicator
|
||||
|
|
|
@ -4580,7 +4580,7 @@ namespace ts {
|
|||
// Combinations of function, class, enum and module
|
||||
let members = emptySymbols;
|
||||
let constructSignatures: Signature[] = emptyArray;
|
||||
if (symbol.flags & SymbolFlags.HasExports) {
|
||||
if (symbol.exports) {
|
||||
members = getExportsOfSymbol(symbol);
|
||||
}
|
||||
if (symbol.flags & SymbolFlags.Class) {
|
||||
|
@ -19871,22 +19871,29 @@ namespace ts {
|
|||
return getLeftSideOfImportEqualsOrExportAssignment(node) !== undefined;
|
||||
}
|
||||
|
||||
function getSpecialPropertyAssignmentSymbolFromEntityName(entityName: EntityName | PropertyAccessExpression) {
|
||||
const specialPropertyAssignmentKind = getSpecialPropertyAssignmentKind(entityName.parent.parent);
|
||||
switch (specialPropertyAssignmentKind) {
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
case SpecialPropertyAssignmentKind.PrototypeProperty:
|
||||
return getSymbolOfNode(entityName.parent);
|
||||
case SpecialPropertyAssignmentKind.ThisProperty:
|
||||
case SpecialPropertyAssignmentKind.ModuleExports:
|
||||
case SpecialPropertyAssignmentKind.Property:
|
||||
return getSymbolOfNode(entityName.parent.parent);
|
||||
}
|
||||
}
|
||||
|
||||
function getSymbolOfEntityNameOrPropertyAccessExpression(entityName: EntityName | PropertyAccessExpression): Symbol | undefined {
|
||||
if (isDeclarationName(entityName)) {
|
||||
return getSymbolOfNode(entityName.parent);
|
||||
}
|
||||
|
||||
if (isInJavaScriptFile(entityName) && entityName.parent.kind === SyntaxKind.PropertyAccessExpression) {
|
||||
const specialPropertyAssignmentKind = getSpecialPropertyAssignmentKind(entityName.parent.parent);
|
||||
switch (specialPropertyAssignmentKind) {
|
||||
case SpecialPropertyAssignmentKind.ExportsProperty:
|
||||
case SpecialPropertyAssignmentKind.PrototypeProperty:
|
||||
return getSymbolOfNode(entityName.parent);
|
||||
case SpecialPropertyAssignmentKind.ThisProperty:
|
||||
case SpecialPropertyAssignmentKind.ModuleExports:
|
||||
return getSymbolOfNode(entityName.parent.parent);
|
||||
default:
|
||||
// Fall through if it is not a special property assignment
|
||||
// Check if this is a special property assignment
|
||||
const specialPropertyAssignmentSymbol = getSpecialPropertyAssignmentSymbolFromEntityName(entityName);
|
||||
if (specialPropertyAssignmentSymbol) {
|
||||
return specialPropertyAssignmentSymbol;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3133,7 +3133,9 @@
|
|||
/// className.prototype.name = expr
|
||||
PrototypeProperty,
|
||||
/// this.name = expr
|
||||
ThisProperty
|
||||
ThisProperty,
|
||||
// F.name = expr
|
||||
Property
|
||||
}
|
||||
|
||||
export interface FileExtensionInfo {
|
||||
|
|
|
@ -1374,6 +1374,10 @@ namespace ts {
|
|||
return false;
|
||||
}
|
||||
|
||||
export function isValidSpecialPropertyAssignmentParent(parentSymbol: Symbol) {
|
||||
return parentSymbol && (parentSymbol.flags & SymbolFlags.Function || isDeclarationOfFunctionExpression(parentSymbol));
|
||||
}
|
||||
|
||||
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
|
||||
/// assignments we treat as special in the binder
|
||||
export function getSpecialPropertyAssignmentKind(expression: Node): SpecialPropertyAssignmentKind {
|
||||
|
@ -1398,6 +1402,10 @@ namespace ts {
|
|||
// module.exports = expr
|
||||
return SpecialPropertyAssignmentKind.ModuleExports;
|
||||
}
|
||||
else {
|
||||
// F.x = expr
|
||||
return SpecialPropertyAssignmentKind.Property;
|
||||
}
|
||||
}
|
||||
else if (lhs.expression.kind === SyntaxKind.ThisKeyword) {
|
||||
return SpecialPropertyAssignmentKind.ThisProperty;
|
||||
|
@ -1417,6 +1425,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
return SpecialPropertyAssignmentKind.None;
|
||||
}
|
||||
|
||||
|
|
11
tests/cases/fourslash/renameJsPropertyAssignment.ts
Normal file
11
tests/cases/fourslash/renameJsPropertyAssignment.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @allowJs: true
|
||||
// @Filename: a.js
|
||||
////function bar() {
|
||||
////}
|
||||
////bar.[|foo|] = "foo";
|
||||
////console.log(bar./**/[|foo|]);
|
||||
|
||||
goTo.marker();
|
||||
verify.renameLocations( /*findInStrings*/ false, /*findInComments*/ false);
|
Loading…
Reference in a new issue