Naming and duplication cleanup

This commit is contained in:
Nathan Shively-Sanders 2018-02-15 09:13:06 -08:00
parent 0cadfcf6df
commit 4fdef85608
3 changed files with 25 additions and 36 deletions

View File

@ -2403,34 +2403,25 @@ namespace ts {
return lookupSymbolForNameWorker(container, node.escapedText);
}
else {
const symbol = follow(lookupSymbolForPropertyAccess(node.expression));
const symbol = getJSInitializerSymbol(lookupSymbolForPropertyAccess(node.expression));
return symbol && symbol.exports && symbol.exports.get(node.name.escapedText);
}
}
function isNamespaceableInitializer(initializer: Node) {
return initializer.kind === SyntaxKind.ClassExpression ||
initializer.kind === SyntaxKind.FunctionExpression ||
initializer.kind === SyntaxKind.ObjectLiteralExpression && (initializer as ObjectLiteralExpression).properties.length === 0 ||
initializer.kind === SyntaxKind.CallExpression && (skipParentheses((initializer as CallExpression).expression).kind === SyntaxKind.FunctionExpression ||
skipParentheses((initializer as CallExpression).expression).kind === SyntaxKind.ArrowFunction);
}
function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) {
// Look up the property in the local scope, since property assignments should follow the declaration
let symbol = follow(lookupSymbolForPropertyAccess(name));
// TODO: Should be able to structure this with less duplication
let symbol = getJSInitializerSymbol(lookupSymbolForPropertyAccess(name));
Debug.assert(propertyAccess.parent.kind === SyntaxKind.BinaryExpression ||
propertyAccess.parent.kind === SyntaxKind.ExpressionStatement ||
propertyAccess.parent.kind === SyntaxKind.PropertyAccessExpression);
const isToplevelNamespaceableInitializer = propertyAccess.parent.kind === SyntaxKind.BinaryExpression ?
propertyAccess.parent.parent.parent.kind === SyntaxKind.SourceFile && isNamespaceableInitializer((propertyAccess.parent as BinaryExpression).right) :
const isToplevelNamespaceableInitializer = isBinaryExpression(propertyAccess.parent) ?
propertyAccess.parent.parent.parent.kind === SyntaxKind.SourceFile && getJavascriptInitializer(propertyAccess.parent.right) :
propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
if (!isPrototypeProperty && (!symbol || !(symbol.flags & SymbolFlags.Namespace)) && isToplevelNamespaceableInitializer) {
const flags = SymbolFlags.Module | SymbolFlags.JSContainer;
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.JSContainer;
// addDeclarationToSymbol is only needed for things that could be further containers, because it makes the intermediate namespace symbol.
iterateEntityNameExpression(propertyAccess.expression, (id, original) => {
// make symbols are add declarations for intermediate containers
forEachIdentifierInEntityName(propertyAccess.expression, (id, original) => {
if (original) {
// Note: add declaration to original symbol, not the special-syntax's symbol, so that namespaces work for type lookup
addDeclarationToSymbol(original, id, flags);
@ -2460,12 +2451,12 @@ namespace ts {
declareSymbol(symbolTable, symbol, propertyAccess, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
}
function iterateEntityNameExpression(e: EntityNameExpression, action: (e: Identifier, symbol: Symbol) => Symbol): Symbol {
function forEachIdentifierInEntityName(e: EntityNameExpression, action: (e: Identifier, symbol: Symbol) => Symbol): Symbol {
if (isIdentifier(e)) {
return action(e, lookupSymbolForPropertyAccess(e));
}
else {
const s = follow(iterateEntityNameExpression(e.expression, action));
const s = getJSInitializerSymbol(forEachIdentifierInEntityName(e.expression, action));
Debug.assert(!!s, "lost the chant");
Debug.assert(!!s.exports, "has no exports");
return action(e.name, s.exports.get(e.name.escapedText));

View File

@ -858,11 +858,11 @@ namespace ts {
mergeSymbolTable(target.exports, source.exports);
}
if ((source.flags | target.flags) & SymbolFlags.JSContainer) {
const fs = follow(source);
const ft = follow(target);
const fs = getJSInitializerSymbol(source);
const ft = getJSInitializerSymbol(target);
if (fs !== source || ft !== target) {
// also follow the source's valueDeclaration and merge its symbol
mergeSymbol(follow(target), follow(source));
mergeSymbol(getJSInitializerSymbol(target), getJSInitializerSymbol(source));
}
}
recordMergedSymbol(target, source);
@ -18987,7 +18987,7 @@ namespace ts {
}
function checkBinaryExpression(node: BinaryExpression, checkMode?: CheckMode) {
if (node.operatorToken.kind === SyntaxKind.BarBarToken && isInJavaScriptFile(node) && getAssignedJavascriptInitializer(node)) {
if (isInJavaScriptFile(node) && getAssignedJavascriptInitializer(node)) {
return checkExpression(node.right, checkMode);
}
return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, checkMode, node);

View File

@ -1472,21 +1472,19 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote;
}
// TODO: All 5 (!) of these need to be de-duped
/**
* Returns true if the node is a variable declaration whose initializer is a function or class expression.
* This function does not test if the node is in a JavaScript file or not.
*/
export function isDeclarationOfFunctionOrClassExpression(s: Symbol) {
if (s.valueDeclaration && s.valueDeclaration.kind === SyntaxKind.VariableDeclaration) {
const declaration = s.valueDeclaration as VariableDeclaration;
return declaration.initializer &&
(declaration.initializer.kind === SyntaxKind.FunctionExpression || declaration.initializer.kind === SyntaxKind.ClassExpression);
if (s.valueDeclaration && isVariableDeclaration(s.valueDeclaration)) {
return s.valueDeclaration.initializer &&
(s.valueDeclaration.initializer.kind === SyntaxKind.FunctionExpression || s.valueDeclaration.initializer.kind === SyntaxKind.ClassExpression);
}
return false;
}
export function follow(symbol: Symbol) {
export function getJSInitializerSymbol(symbol: Symbol) {
if (!symbol || !symbol.valueDeclaration) {
return symbol;
}
@ -1495,10 +1493,6 @@ namespace ts {
return e ? e.symbol : symbol;
}
/**
* Returns true if the node is a variable declaration whose initializer is a function or class expression, or an empty object literal.
* This function does not test if the node is in a JavaScript file or not.
*/
export function getDeclaredJavascriptInitializer(node: Node) {
if (node && isVariableDeclaration(node) && node.initializer) {
return getJavascriptInitializer(node.initializer) ||
@ -1513,11 +1507,15 @@ namespace ts {
(getJavascriptInitializer(node.parent.right) || getDefaultedJavascriptInitializer(node.parent.left as EntityNameExpression, node.parent.right));
}
function getJavascriptInitializer(e: Expression) {
if(e.kind === SyntaxKind.FunctionExpression ||
e.kind === SyntaxKind.ClassExpression ||
isObjectLiteralExpression(e) && e.properties.length === 0) {
return e;
export function getJavascriptInitializer(initializer: Expression) {
if (isCallExpression(initializer)) {
const e = skipParentheses(initializer.expression);
return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer : undefined;
}
if(initializer.kind === SyntaxKind.FunctionExpression ||
initializer.kind === SyntaxKind.ClassExpression ||
isObjectLiteralExpression(initializer) && initializer.properties.length === 0) {
return initializer;
}
}