Skip to content

Commit 4199038

Browse files
committed
Fix type-annotation declaration in JS files
Declaring values didn't work before.
1 parent 9b8b750 commit 4199038

2 files changed

Lines changed: 38 additions & 21 deletions

File tree

src/compiler/binder.ts

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -273,9 +273,6 @@ namespace ts {
273273
return getEscapedTextOfIdentifierOrLiteral(<Identifier | LiteralExpression>name);
274274
}
275275
switch (node.kind) {
276-
case SyntaxKind.Identifier:
277-
// TODO: THIS IS WRONG
278-
return (node as any as Identifier).escapedText;
279276
case SyntaxKind.Constructor:
280277
return InternalSymbolName.Constructor;
281278
case SyntaxKind.FunctionType:
@@ -2014,8 +2011,7 @@ namespace ts {
20142011
node.flowNode = currentFlow;
20152012
}
20162013
if (isSpecialPropertyDeclaration(node as PropertyAccessExpression)) {
2017-
// TODO: this is wrong now that I allow it anywhere
2018-
bindThisPropertyAssignment(node as PropertyAccessExpression);
2014+
bindSpecialPropertyDeclaration(node as PropertyAccessExpression);
20192015
}
20202016
break;
20212017
case SyntaxKind.BinaryExpression:
@@ -2351,6 +2347,17 @@ namespace ts {
23512347
}
23522348
}
23532349

2350+
function bindSpecialPropertyDeclaration(node: PropertyAccessExpression) {
2351+
Debug.assert(isInJavaScriptFile(node));
2352+
if (node.expression.kind === SyntaxKind.ThisKeyword) {
2353+
bindThisPropertyAssignment(node);
2354+
}
2355+
else if ((node.expression.kind === SyntaxKind.Identifier || node.expression.kind === SyntaxKind.PropertyAccessExpression) &&
2356+
node.parent.parent.kind === SyntaxKind.SourceFile) {
2357+
bindStaticPropertyAssignment(node);
2358+
}
2359+
}
2360+
23542361
function bindPrototypePropertyAssignment(node: BinaryExpression) {
23552362
// We saw a node of the form 'x.prototype.y = z'. Declare a 'member' y on x if x was a function.
23562363

@@ -2368,24 +2375,27 @@ namespace ts {
23682375
bindPropertyAssignment(constructorFunction.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ true);
23692376
}
23702377

2371-
function bindStaticPropertyAssignment(node: BinaryExpression) {
2372-
// We saw a node of the form 'x.y = z'. Declare a 'member' y on x if x was a function.
2373-
2374-
// Look up the function in the local scope, since prototype assignments should
2378+
/**
2379+
* For nodes like `x.y = z`, declare a member 'y' on 'x' if x was a function.
2380+
* Also works for expression statements preceded by JSDoc, like / ** @type number * / x.y;
2381+
*/
2382+
function bindStaticPropertyAssignment(node: BinaryExpression | PropertyAccessExpression) {
2383+
// Look up the function in the local scope, since static assignments should
23752384
// follow the function declaration
2376-
const leftSideOfAssignment = node.left as PropertyAccessExpression;
2385+
const leftSideOfAssignment = node.kind === SyntaxKind.PropertyAccessExpression ? node : node.left as PropertyAccessExpression;
23772386
const target = leftSideOfAssignment.expression;
23782387

23792388
if (isIdentifier(target)) {
23802389
// Fix up parent pointers since we're going to use these nodes before we bind into them
2381-
leftSideOfAssignment.parent = node;
23822390
target.parent = leftSideOfAssignment;
2383-
2391+
if (node.kind === SyntaxKind.BinaryExpression) {
2392+
leftSideOfAssignment.parent = node;
2393+
}
23842394
if (isNameOfExportsOrModuleExportsAliasDeclaration(target)) {
23852395
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
23862396
// var util = module.exports;
23872397
// util.property = function ...
2388-
bindExportsPropertyAssignment(node);
2398+
bindExportsPropertyAssignment(node as BinaryExpression);
23892399
}
23902400
else {
23912401
bindPropertyAssignment(target.escapedText, leftSideOfAssignment, /*isPrototypeProperty*/ false);
@@ -2403,14 +2413,19 @@ namespace ts {
24032413
if (targetSymbol && isDeclarationOfFunctionOrClassExpression(targetSymbol)) {
24042414
targetSymbol = (targetSymbol.valueDeclaration as VariableDeclaration).initializer.symbol;
24052415
}
2406-
Debug.assert(propertyAccessExpression.parent.kind === SyntaxKind.BinaryExpression);
2407-
if (!isPrototypeProperty &&
2408-
(!targetSymbol || !(targetSymbol.flags & SymbolFlags.Namespace)) &&
2409-
// TODO: Rewrite to be easier to read
2410-
((propertyAccessExpression.parent as BinaryExpression).right.kind === SyntaxKind.ClassExpression || (propertyAccessExpression.parent as BinaryExpression).right.kind === SyntaxKind.FunctionExpression) &&
2411-
propertyAccessExpression.parent.parent.parent.kind === SyntaxKind.SourceFile) {
2416+
Debug.assert(propertyAccessExpression.parent.kind === SyntaxKind.BinaryExpression || propertyAccessExpression.parent.kind === SyntaxKind.ExpressionStatement);
2417+
let isLegalPosition: boolean;
2418+
if (propertyAccessExpression.parent.kind === SyntaxKind.BinaryExpression) {
2419+
const initializerKind = (propertyAccessExpression.parent as BinaryExpression).right.kind;
2420+
isLegalPosition = (initializerKind === SyntaxKind.ClassExpression || initializerKind === SyntaxKind.FunctionExpression) &&
2421+
propertyAccessExpression.parent.parent.parent.kind === SyntaxKind.SourceFile;
2422+
}
2423+
else {
2424+
isLegalPosition = propertyAccessExpression.parent.parent.kind === SyntaxKind.SourceFile;
2425+
}
2426+
if (!isPrototypeProperty && (!targetSymbol || !(targetSymbol.flags & SymbolFlags.Namespace)) && isLegalPosition) {
24122427
// TODO: Update refactoring to understand that ES5 classes now have statics in a namespace instead
2413-
const hasExportModifier = getCombinedModifierFlags(targetSymbol.valueDeclaration) & ModifierFlags.Export;
2428+
const hasExportModifier = targetSymbol && getCombinedModifierFlags(targetSymbol.valueDeclaration) & ModifierFlags.Export;
24142429
Debug.assert(isIdentifier(propertyAccessExpression.expression));
24152430
Debug.assertEqual(propertyAccessExpression.expression.kind, SyntaxKind.Identifier);
24162431
targetSymbol = declareModuleMember(propertyAccessExpression.expression as Identifier, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes, hasExportModifier);

src/compiler/utilities.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,7 @@ namespace ts {
16211621
// * @returns {number}
16221622
// */
16231623
// var x = function(name) { return name.length; }
1624-
if (parent && (parent.kind === SyntaxKind.PropertyAssignment || getNestedModuleDeclaration(parent))) {
1624+
if (parent && (parent.kind === SyntaxKind.PropertyAssignment || parent.kind === SyntaxKind.ExpressionStatement || getNestedModuleDeclaration(parent))) {
16251625
getJSDocCommentsAndTagsWorker(parent);
16261626
}
16271627
if (parent && parent.parent &&
@@ -4209,6 +4209,8 @@ namespace ts {
42094209
return undefined;
42104210
}
42114211
switch (declaration.kind) {
4212+
case SyntaxKind.Identifier:
4213+
return declaration as Identifier;
42124214
case SyntaxKind.JSDocPropertyTag:
42134215
case SyntaxKind.JSDocParameterTag: {
42144216
const { name } = declaration as JSDocPropertyLikeTag;

0 commit comments

Comments
 (0)