Allow special element access assignments to create declarations (#33537)
* Start enabling element access special assignment * Treat element access assignment as special assignment in JS * Make declarations for bindable element access expressions * Fix navigationBar crash * Add multi-level test for JS * Propagate element access expressions to more code paths * Fix property access on `this` * Add quick info test * Uhhh I guess this is fine * Fix module["exports"] and property access chained off element access * Add test for this property assignment * Add test for and fix prototype property assignment * Fix teeeest??? * Update APIs * Fix element access declarations on `this` * Fix go-to-definition * Add declaration emit to tests * Reconcile with late-bound symbol element access assignment * Fix baselines * Add JS declaration back to tests * Fix JS declaration emit of non-late-bound string literal property names * Revert accidental auto-format * Use `isAccessExpression` * Add underscore escaping member to test * Fix and test navBar changes
This commit is contained in:
parent
053388d6d2
commit
f89de95955
|
@ -2333,17 +2333,18 @@ namespace ts {
|
|||
return checkStrictModeIdentifier(<Identifier>node);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
if (currentFlow && isNarrowableReference(<Expression>node)) {
|
||||
node.flowNode = currentFlow;
|
||||
const expr = node as PropertyAccessExpression | ElementAccessExpression;
|
||||
if (currentFlow && isNarrowableReference(expr)) {
|
||||
expr.flowNode = currentFlow;
|
||||
}
|
||||
if (isSpecialPropertyDeclaration(node as PropertyAccessExpression)) {
|
||||
bindSpecialPropertyDeclaration(node as PropertyAccessExpression);
|
||||
if (isSpecialPropertyDeclaration(expr)) {
|
||||
bindSpecialPropertyDeclaration(expr);
|
||||
}
|
||||
if (isInJSFile(node) &&
|
||||
if (isInJSFile(expr) &&
|
||||
file.commonJsModuleIndicator &&
|
||||
isModuleExportsPropertyAccessExpression(node as PropertyAccessExpression) &&
|
||||
isModuleExportsAccessExpression(expr) &&
|
||||
!lookupSymbolForNameWorker(blockScopeContainer, "module" as __String)) {
|
||||
declareSymbol(file.locals!, /*parent*/ undefined, (node as PropertyAccessExpression).expression as Identifier,
|
||||
declareSymbol(file.locals!, /*parent*/ undefined, expr.expression,
|
||||
SymbolFlags.FunctionScopedVariable | SymbolFlags.ModuleExports, SymbolFlags.FunctionScopedVariableExcludes);
|
||||
}
|
||||
break;
|
||||
|
@ -2351,22 +2352,22 @@ namespace ts {
|
|||
const specialKind = getAssignmentDeclarationKind(node as BinaryExpression);
|
||||
switch (specialKind) {
|
||||
case AssignmentDeclarationKind.ExportsProperty:
|
||||
bindExportsPropertyAssignment(node as BinaryExpression);
|
||||
bindExportsPropertyAssignment(node as BindableStaticPropertyAssignmentExpression);
|
||||
break;
|
||||
case AssignmentDeclarationKind.ModuleExports:
|
||||
bindModuleExportsAssignment(node as BinaryExpression);
|
||||
bindModuleExportsAssignment(node as BindablePropertyAssignmentExpression);
|
||||
break;
|
||||
case AssignmentDeclarationKind.PrototypeProperty:
|
||||
bindPrototypePropertyAssignment((node as BinaryExpression).left as PropertyAccessEntityNameExpression, node);
|
||||
bindPrototypePropertyAssignment((node as BindableStaticPropertyAssignmentExpression).left, node);
|
||||
break;
|
||||
case AssignmentDeclarationKind.Prototype:
|
||||
bindPrototypeAssignment(node as BinaryExpression);
|
||||
bindPrototypeAssignment(node as BindableStaticPropertyAssignmentExpression);
|
||||
break;
|
||||
case AssignmentDeclarationKind.ThisProperty:
|
||||
bindThisPropertyAssignment(node as BinaryExpression);
|
||||
bindThisPropertyAssignment(node as BindablePropertyAssignmentExpression);
|
||||
break;
|
||||
case AssignmentDeclarationKind.Property:
|
||||
bindSpecialPropertyAssignment(node as BinaryExpression);
|
||||
bindSpecialPropertyAssignment(node as BindablePropertyAssignmentExpression);
|
||||
break;
|
||||
case AssignmentDeclarationKind.None:
|
||||
// Nothing to do
|
||||
|
@ -2641,14 +2642,13 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function bindExportsPropertyAssignment(node: BinaryExpression) {
|
||||
function bindExportsPropertyAssignment(node: BindableStaticPropertyAssignmentExpression) {
|
||||
// When we create a property via 'exports.foo = bar', the 'exports.foo' property access
|
||||
// expression is the declaration
|
||||
if (!setCommonJsModuleIndicator(node)) {
|
||||
return;
|
||||
}
|
||||
const lhs = node.left as PropertyAccessEntityNameExpression;
|
||||
const symbol = forEachIdentifierInEntityName(lhs.expression, /*parent*/ undefined, (id, symbol) => {
|
||||
const symbol = forEachIdentifierInEntityName(node.left.expression, /*parent*/ undefined, (id, symbol) => {
|
||||
if (symbol) {
|
||||
addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.Assignment);
|
||||
}
|
||||
|
@ -2658,11 +2658,11 @@ namespace ts {
|
|||
const flags = isClassExpression(node.right) ?
|
||||
SymbolFlags.Property | SymbolFlags.ExportValue | SymbolFlags.Class :
|
||||
SymbolFlags.Property | SymbolFlags.ExportValue;
|
||||
declareSymbol(symbol.exports!, symbol, lhs, flags, SymbolFlags.None);
|
||||
declareSymbol(symbol.exports!, symbol, node.left, flags, SymbolFlags.None);
|
||||
}
|
||||
}
|
||||
|
||||
function bindModuleExportsAssignment(node: BinaryExpression) {
|
||||
function bindModuleExportsAssignment(node: BindablePropertyAssignmentExpression) {
|
||||
// A common practice in node modules is to set 'export = module.exports = {}', this ensures that 'exports'
|
||||
// is still pointing to 'module.exports'.
|
||||
// We do not want to consider this as 'export=' since a module can have only one of these.
|
||||
|
@ -2682,7 +2682,7 @@ namespace ts {
|
|||
declareSymbol(file.symbol.exports!, file.symbol, node, flags | SymbolFlags.Assignment, SymbolFlags.None);
|
||||
}
|
||||
|
||||
function bindThisPropertyAssignment(node: BinaryExpression | PropertyAccessExpression) {
|
||||
function bindThisPropertyAssignment(node: BindablePropertyAssignmentExpression | PropertyAccessExpression | LiteralLikeElementAccessExpression) {
|
||||
Debug.assert(isInJSFile(node));
|
||||
const thisContainer = getThisContainer(node, /*includeArrowFunctions*/ false);
|
||||
switch (thisContainer.kind) {
|
||||
|
@ -2692,7 +2692,7 @@ namespace ts {
|
|||
// For `f.prototype.m = function() { this.x = 0; }`, `this.x = 0` should modify `f`'s members, not the function expression.
|
||||
if (isBinaryExpression(thisContainer.parent) && thisContainer.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const l = thisContainer.parent.left;
|
||||
if (isPropertyAccessEntityNameExpression(l) && isPrototypeAccess(l.expression)) {
|
||||
if (isBindableStaticAccessExpression(l) && isPrototypeAccess(l.expression)) {
|
||||
constructorSymbol = lookupSymbolForPropertyAccess(l.expression.expression, thisParentContainer);
|
||||
}
|
||||
}
|
||||
|
@ -2754,11 +2754,11 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function bindSpecialPropertyDeclaration(node: PropertyAccessExpression) {
|
||||
function bindSpecialPropertyDeclaration(node: PropertyAccessExpression | LiteralLikeElementAccessExpression) {
|
||||
if (node.expression.kind === SyntaxKind.ThisKeyword) {
|
||||
bindThisPropertyAssignment(node);
|
||||
}
|
||||
else if (isPropertyAccessEntityNameExpression(node) && node.parent.parent.kind === SyntaxKind.SourceFile) {
|
||||
else if (isBindableStaticAccessExpression(node) && node.parent.parent.kind === SyntaxKind.SourceFile) {
|
||||
if (isPrototypeAccess(node.expression)) {
|
||||
bindPrototypePropertyAssignment(node, node.parent);
|
||||
}
|
||||
|
@ -2769,11 +2769,10 @@ namespace ts {
|
|||
}
|
||||
|
||||
/** For `x.prototype = { p, ... }`, declare members p,... if `x` is function/class/{}, or not declared. */
|
||||
function bindPrototypeAssignment(node: BinaryExpression) {
|
||||
function bindPrototypeAssignment(node: BindableStaticPropertyAssignmentExpression) {
|
||||
node.left.parent = node;
|
||||
node.right.parent = node;
|
||||
const lhs = node.left as PropertyAccessEntityNameExpression;
|
||||
bindPropertyAssignment(lhs.expression, lhs, /*isPrototypeProperty*/ false, /*containerIsClass*/ true);
|
||||
bindPropertyAssignment(node.left.expression, node.left, /*isPrototypeProperty*/ false, /*containerIsClass*/ true);
|
||||
}
|
||||
|
||||
function bindObjectDefinePrototypeProperty(node: BindableObjectDefinePropertyCall) {
|
||||
|
@ -2785,10 +2784,10 @@ namespace ts {
|
|||
* For `x.prototype.y = z`, declare a member `y` on `x` if `x` is a function or class, or not declared.
|
||||
* Note that jsdoc preceding an ExpressionStatement like `x.prototype.y;` is also treated as a declaration.
|
||||
*/
|
||||
function bindPrototypePropertyAssignment(lhs: PropertyAccessEntityNameExpression, parent: Node) {
|
||||
function bindPrototypePropertyAssignment(lhs: BindableStaticAccessExpression, parent: Node) {
|
||||
// Look up the function in the local scope, since prototype assignments should
|
||||
// follow the function declaration
|
||||
const classPrototype = lhs.expression as PropertyAccessEntityNameExpression;
|
||||
const classPrototype = lhs.expression as BindableStaticAccessExpression;
|
||||
const constructorFunction = classPrototype.expression;
|
||||
|
||||
// Fix up parent pointers since we're going to use these nodes before we bind into them
|
||||
|
@ -2806,30 +2805,29 @@ namespace ts {
|
|||
bindPotentiallyNewExpandoMemberToNamespace(node, namespaceSymbol, /*isPrototypeProperty*/ false);
|
||||
}
|
||||
|
||||
function bindSpecialPropertyAssignment(node: BinaryExpression) {
|
||||
const lhs = node.left as PropertyAccessEntityNameExpression;
|
||||
function bindSpecialPropertyAssignment(node: BindablePropertyAssignmentExpression) {
|
||||
// Class declarations in Typescript do not allow property declarations
|
||||
const parentSymbol = lookupSymbolForPropertyAccess(lhs.expression);
|
||||
const parentSymbol = lookupSymbolForPropertyAccess(node.left.expression);
|
||||
if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) {
|
||||
return;
|
||||
}
|
||||
// Fix up parent pointers since we're going to use these nodes before we bind into them
|
||||
node.left.parent = node;
|
||||
node.right.parent = node;
|
||||
if (isIdentifier(lhs.expression) && container === file && isExportsOrModuleExportsOrAlias(file, lhs.expression)) {
|
||||
if (isIdentifier(node.left.expression) && container === file && isExportsOrModuleExportsOrAlias(file, node.left.expression)) {
|
||||
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
|
||||
// var util = module.exports;
|
||||
// util.property = function ...
|
||||
bindExportsPropertyAssignment(node);
|
||||
bindExportsPropertyAssignment(node as BindableStaticPropertyAssignmentExpression);
|
||||
}
|
||||
else {
|
||||
if (hasDynamicName(node)) {
|
||||
bindAnonymousDeclaration(node, SymbolFlags.Property | SymbolFlags.Assignment, InternalSymbolName.Computed);
|
||||
const sym = bindPotentiallyMissingNamespaces(parentSymbol, lhs.expression, isTopLevelNamespaceAssignment(lhs), /*isPrototype*/ false, /*containerIsClass*/ false);
|
||||
const sym = bindPotentiallyMissingNamespaces(parentSymbol, node.left.expression, isTopLevelNamespaceAssignment(node.left), /*isPrototype*/ false, /*containerIsClass*/ false);
|
||||
addLateBoundAssignmentDeclarationToSymbol(node, sym);
|
||||
}
|
||||
else {
|
||||
bindStaticPropertyAssignment(lhs);
|
||||
bindStaticPropertyAssignment(cast(node.left, isBindableStaticAccessExpression));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2838,12 +2836,12 @@ namespace ts {
|
|||
* For nodes like `x.y = z`, declare a member 'y' on 'x' if x is a function (or IIFE) or class or {}, or not declared.
|
||||
* Also works for expression statements preceded by JSDoc, like / ** @type number * / x.y;
|
||||
*/
|
||||
function bindStaticPropertyAssignment(node: PropertyAccessEntityNameExpression) {
|
||||
function bindStaticPropertyAssignment(node: BindableStaticAccessExpression) {
|
||||
node.expression.parent = node;
|
||||
bindPropertyAssignment(node.expression, node, /*isPrototypeProperty*/ false, /*containerIsClass*/ false);
|
||||
}
|
||||
|
||||
function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: EntityNameExpression, isToplevel: boolean, isPrototypeProperty: boolean, containerIsClass: boolean) {
|
||||
function bindPotentiallyMissingNamespaces(namespaceSymbol: Symbol | undefined, entityName: BindableStaticNameExpression, isToplevel: boolean, isPrototypeProperty: boolean, containerIsClass: boolean) {
|
||||
if (isToplevel && !isPrototypeProperty) {
|
||||
// make symbols or add declarations for intermediate containers
|
||||
const flags = SymbolFlags.Module | SymbolFlags.Assignment;
|
||||
|
@ -2866,7 +2864,7 @@ namespace ts {
|
|||
return namespaceSymbol;
|
||||
}
|
||||
|
||||
function bindPotentiallyNewExpandoMemberToNamespace(declaration: PropertyAccessEntityNameExpression | CallExpression, namespaceSymbol: Symbol | undefined, isPrototypeProperty: boolean) {
|
||||
function bindPotentiallyNewExpandoMemberToNamespace(declaration: BindableStaticAccessExpression | CallExpression, namespaceSymbol: Symbol | undefined, isPrototypeProperty: boolean) {
|
||||
if (!namespaceSymbol || !isExpandoSymbol(namespaceSymbol)) {
|
||||
return;
|
||||
}
|
||||
|
@ -2911,13 +2909,13 @@ namespace ts {
|
|||
declareSymbol(symbolTable, namespaceSymbol, declaration, includes | SymbolFlags.Assignment, excludes & ~SymbolFlags.Assignment);
|
||||
}
|
||||
|
||||
function isTopLevelNamespaceAssignment(propertyAccess: PropertyAccessEntityNameExpression) {
|
||||
function isTopLevelNamespaceAssignment(propertyAccess: BindableAccessExpression) {
|
||||
return isBinaryExpression(propertyAccess.parent)
|
||||
? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile
|
||||
: propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
|
||||
}
|
||||
|
||||
function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean, containerIsClass: boolean) {
|
||||
function bindPropertyAssignment(name: BindableStaticNameExpression, propertyAccess: BindableStaticAccessExpression, isPrototypeProperty: boolean, containerIsClass: boolean) {
|
||||
let namespaceSymbol = lookupSymbolForPropertyAccess(name);
|
||||
const isToplevel = isTopLevelNamespaceAssignment(propertyAccess);
|
||||
namespaceSymbol = bindPotentiallyMissingNamespaces(namespaceSymbol, propertyAccess.expression, isToplevel, isPrototypeProperty, containerIsClass);
|
||||
|
@ -2962,17 +2960,17 @@ namespace ts {
|
|||
return expr.parent;
|
||||
}
|
||||
|
||||
function lookupSymbolForPropertyAccess(node: EntityNameExpression, lookupContainer: Node = container): Symbol | undefined {
|
||||
function lookupSymbolForPropertyAccess(node: BindableStaticNameExpression, lookupContainer: Node = container): Symbol | undefined {
|
||||
if (isIdentifier(node)) {
|
||||
return lookupSymbolForNameWorker(lookupContainer, node.escapedText);
|
||||
}
|
||||
else {
|
||||
const symbol = lookupSymbolForPropertyAccess(node.expression);
|
||||
return symbol && symbol.exports && symbol.exports.get(node.name.escapedText);
|
||||
return symbol && symbol.exports && symbol.exports.get(escapeLeadingUnderscores(getElementOrPropertyAccessName(node)));
|
||||
}
|
||||
}
|
||||
|
||||
function forEachIdentifierInEntityName(e: EntityNameExpression, parent: Symbol | undefined, action: (e: Identifier, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined {
|
||||
function forEachIdentifierInEntityName(e: BindableStaticNameExpression, parent: Symbol | undefined, action: (e: Declaration, symbol: Symbol | undefined, parent: Symbol | undefined) => Symbol | undefined): Symbol | undefined {
|
||||
if (isExportsOrModuleExportsOrAlias(file, e)) {
|
||||
return file.symbol;
|
||||
}
|
||||
|
@ -2981,7 +2979,7 @@ namespace ts {
|
|||
}
|
||||
else {
|
||||
const s = forEachIdentifierInEntityName(e.expression, parent, action);
|
||||
return action(e.name, s && s.exports && s.exports.get(e.name.escapedText), s);
|
||||
return action(getNameOrArgument(e), s && s.exports && s.exports.get(escapeLeadingUnderscores(getElementOrPropertyAccessName(e))), s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3255,7 +3253,7 @@ namespace ts {
|
|||
while (q.length && i < 100) {
|
||||
i++;
|
||||
node = q.shift()!;
|
||||
if (isExportsIdentifier(node) || isModuleExportsPropertyAccessExpression(node)) {
|
||||
if (isExportsIdentifier(node) || isModuleExportsAccessExpression(node)) {
|
||||
return true;
|
||||
}
|
||||
else if (isIdentifier(node)) {
|
||||
|
|
|
@ -3041,7 +3041,7 @@ namespace ts {
|
|||
return getSymbolOfNode(d.parent);
|
||||
}
|
||||
if (isClassExpression(d) && isBinaryExpression(d.parent) && d.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAccessExpression(d.parent.left) && isEntityNameExpression(d.parent.left.expression)) {
|
||||
if (isModuleExportsPropertyAccessExpression(d.parent.left) || isExportsIdentifier(d.parent.left.expression)) {
|
||||
if (isModuleExportsAccessExpression(d.parent.left) || isExportsIdentifier(d.parent.left.expression)) {
|
||||
return getSymbolOfNode(getSourceFileOfNode(d));
|
||||
}
|
||||
checkExpressionCached(d.parent.left.expression);
|
||||
|
@ -4877,6 +4877,15 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function getPropertyNameNodeForSymbol(symbol: Symbol, context: NodeBuilderContext) {
|
||||
const fromNameType = getPropertyNameNodeForSymbolFromNameType(symbol, context);
|
||||
if (fromNameType) {
|
||||
return fromNameType;
|
||||
}
|
||||
const rawName = unescapeLeadingUnderscores(symbol.escapedName);
|
||||
return createPropertyNameNodeForIdentifierOrLiteral(rawName);
|
||||
}
|
||||
|
||||
// See getNameForSymbolFromNameType for a stringy equivalent
|
||||
function getPropertyNameNodeForSymbolFromNameType(symbol: Symbol, context: NodeBuilderContext) {
|
||||
const nameType = symbol.nameType;
|
||||
|
@ -4889,7 +4898,7 @@ namespace ts {
|
|||
if (isNumericLiteralName(name) && startsWith(name, "-")) {
|
||||
return createComputedPropertyName(createLiteral(+name));
|
||||
}
|
||||
return isIdentifierText(name, compilerOptions.target) ? createIdentifier(name) : createLiteral(isNumericLiteralName(name) ? +name : name) as StringLiteral | NumericLiteral;
|
||||
return createPropertyNameNodeForIdentifierOrLiteral(name);
|
||||
}
|
||||
if (nameType.flags & TypeFlags.UniqueESSymbol) {
|
||||
return createComputedPropertyName(symbolToExpression((<UniqueESSymbolType>nameType).symbol, context, SymbolFlags.Value));
|
||||
|
@ -4897,6 +4906,10 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function createPropertyNameNodeForIdentifierOrLiteral(name: string) {
|
||||
return isIdentifierText(name, compilerOptions.target) ? createIdentifier(name) : createLiteral(isNumericLiteralName(name) ? +name : name) as StringLiteral | NumericLiteral;
|
||||
}
|
||||
|
||||
function cloneNodeBuilderContext(context: NodeBuilderContext): NodeBuilderContext {
|
||||
const initial: NodeBuilderContext = { ...context };
|
||||
// Make type parameters created within this context not consume the name outside this context
|
||||
|
@ -5772,8 +5785,7 @@ namespace ts {
|
|||
return [];
|
||||
}
|
||||
const staticFlag = isStatic ? ModifierFlags.Static : 0;
|
||||
const rawName = unescapeLeadingUnderscores(p.escapedName);
|
||||
const name = getPropertyNameNodeForSymbolFromNameType(p, context) || createIdentifier(rawName);
|
||||
const name = getPropertyNameNodeForSymbol(p, context);
|
||||
const firstPropertyLikeDecl = find(p.declarations, or(isPropertyDeclaration, isAccessor, isVariableDeclaration, isPropertySignature, isBinaryExpression, isPropertyAccessExpression));
|
||||
if (p.flags & SymbolFlags.Accessor && useAccessors) {
|
||||
const result: AccessorDeclaration[] = [];
|
||||
|
@ -6869,13 +6881,15 @@ namespace ts {
|
|||
let types: Type[] | undefined;
|
||||
for (const declaration of symbol.declarations) {
|
||||
const expression = (isBinaryExpression(declaration) || isCallExpression(declaration)) ? declaration :
|
||||
isPropertyAccessExpression(declaration) ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration :
|
||||
isAccessExpression(declaration) ? isBinaryExpression(declaration.parent) ? declaration.parent : declaration :
|
||||
undefined;
|
||||
if (!expression) {
|
||||
continue; // Non-assignment declaration merged in (eg, an Identifier to mark the thing as a namespace) - skip over it and pull type info from elsewhere
|
||||
}
|
||||
|
||||
const kind = isPropertyAccessExpression(expression) ? getAssignmentDeclarationPropertyAccessKind(expression) : getAssignmentDeclarationKind(expression);
|
||||
const kind = isAccessExpression(expression)
|
||||
? getAssignmentDeclarationPropertyAccessKind(expression)
|
||||
: getAssignmentDeclarationKind(expression);
|
||||
if (kind === AssignmentDeclarationKind.ThisProperty) {
|
||||
if (isDeclarationInConstructor(expression)) {
|
||||
definedInConstructor = true;
|
||||
|
@ -7250,12 +7264,15 @@ namespace ts {
|
|||
else if (
|
||||
isBinaryExpression(declaration) ||
|
||||
(isInJSFile(declaration) &&
|
||||
(isCallExpression(declaration) || isPropertyAccessExpression(declaration) && isBinaryExpression(declaration.parent)))) {
|
||||
(isCallExpression(declaration) || (isPropertyAccessExpression(declaration) || isBindableStaticElementAccessExpression(declaration)) && isBinaryExpression(declaration.parent)))) {
|
||||
type = getWidenedTypeForAssignmentDeclaration(symbol);
|
||||
}
|
||||
else if (isJSDocPropertyLikeTag(declaration)
|
||||
|| isPropertyAccessExpression(declaration)
|
||||
|| isElementAccessExpression(declaration)
|
||||
|| isIdentifier(declaration)
|
||||
|| isStringLiteralLike(declaration)
|
||||
|| isNumericLiteral(declaration)
|
||||
|| isClassDeclaration(declaration)
|
||||
|| isFunctionDeclaration(declaration)
|
||||
|| (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration))
|
||||
|
@ -7436,7 +7453,8 @@ namespace ts {
|
|||
return anyType;
|
||||
}
|
||||
else if (declaration.kind === SyntaxKind.BinaryExpression ||
|
||||
declaration.kind === SyntaxKind.PropertyAccessExpression && declaration.parent.kind === SyntaxKind.BinaryExpression) {
|
||||
(declaration.kind === SyntaxKind.PropertyAccessExpression || declaration.kind === SyntaxKind.ElementAccessExpression) &&
|
||||
declaration.parent.kind === SyntaxKind.BinaryExpression) {
|
||||
return getWidenedTypeForAssignmentDeclaration(symbol);
|
||||
}
|
||||
else if (symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) && declaration.commonJsModuleIndicator) {
|
||||
|
@ -32134,7 +32152,7 @@ namespace ts {
|
|||
return node;
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
do {
|
||||
if (isModuleExportsPropertyAccessExpression(node.expression)) {
|
||||
if (isModuleExportsAccessExpression(node.expression)) {
|
||||
return node.name;
|
||||
}
|
||||
node = node.expression;
|
||||
|
|
|
@ -2280,7 +2280,7 @@ namespace ts {
|
|||
// if the expression doesn't have any comments that will be emitted.
|
||||
return !expression.numericLiteralFlags && !stringContains(text, tokenToString(SyntaxKind.DotToken)!);
|
||||
}
|
||||
else if (isPropertyAccessExpression(expression) || isElementAccessExpression(expression)) {
|
||||
else if (isAccessExpression(expression)) {
|
||||
// check if constant enum value is integer
|
||||
const constantValue = getConstantValue(expression);
|
||||
// isFinite handles cases when constantValue is undefined
|
||||
|
|
|
@ -1306,7 +1306,7 @@ namespace ts {
|
|||
literal: BooleanLiteral | LiteralExpression | PrefixUnaryExpression;
|
||||
}
|
||||
|
||||
export interface StringLiteral extends LiteralExpression {
|
||||
export interface StringLiteral extends LiteralExpression, Declaration {
|
||||
kind: SyntaxKind.StringLiteral;
|
||||
/* @internal */ textSourceNode?: Identifier | StringLiteralLike | NumericLiteral; // Allows a StringLiteral to get its text from another node (used by transforms).
|
||||
/** Note: this is only set when synthesizing a node, not during parsing. */
|
||||
|
@ -1693,7 +1693,7 @@ namespace ts {
|
|||
kind: SyntaxKind.RegularExpressionLiteral;
|
||||
}
|
||||
|
||||
export interface NoSubstitutionTemplateLiteral extends LiteralExpression, TemplateLiteralLikeNode {
|
||||
export interface NoSubstitutionTemplateLiteral extends LiteralExpression, TemplateLiteralLikeNode, Declaration {
|
||||
kind: SyntaxKind.NoSubstitutionTemplateLiteral;
|
||||
}
|
||||
|
||||
|
@ -1722,7 +1722,7 @@ namespace ts {
|
|||
NumericLiteralFlags = Scientific | Octal | HexSpecifier | BinaryOrOctalSpecifier | ContainsSeparator
|
||||
}
|
||||
|
||||
export interface NumericLiteral extends LiteralExpression {
|
||||
export interface NumericLiteral extends LiteralExpression, Declaration {
|
||||
kind: SyntaxKind.NumericLiteral;
|
||||
/* @internal */
|
||||
numericLiteralFlags: TokenFlags;
|
||||
|
@ -1885,7 +1885,33 @@ namespace ts {
|
|||
;
|
||||
|
||||
/** @internal */
|
||||
export type BindableObjectDefinePropertyCall = CallExpression & { arguments: { 0: EntityNameExpression, 1: StringLiteralLike | NumericLiteral, 2: ObjectLiteralExpression } };
|
||||
export type BindableObjectDefinePropertyCall = CallExpression & { arguments: { 0: BindableStaticNameExpression, 1: StringLiteralLike | NumericLiteral, 2: ObjectLiteralExpression } };
|
||||
/** @internal */
|
||||
export type BindableStaticNameExpression = EntityNameExpression | BindableStaticElementAccessExpression;
|
||||
/** @internal */
|
||||
export type LiteralLikeElementAccessExpression = ElementAccessExpression & Declaration & {
|
||||
argumentExpression: StringLiteralLike | NumericLiteral;
|
||||
};
|
||||
/** @internal */
|
||||
export type BindableStaticElementAccessExpression = LiteralLikeElementAccessExpression & {
|
||||
expression: BindableStaticNameExpression;
|
||||
};
|
||||
/** @internal */
|
||||
export type BindableElementAccessExpression = ElementAccessExpression & {
|
||||
expression: BindableStaticNameExpression;
|
||||
};
|
||||
/** @internal */
|
||||
export type BindableStaticAccessExpression = PropertyAccessEntityNameExpression | BindableStaticElementAccessExpression;
|
||||
/** @internal */
|
||||
export type BindableAccessExpression = PropertyAccessEntityNameExpression | BindableElementAccessExpression;
|
||||
/** @internal */
|
||||
export interface BindableStaticPropertyAssignmentExpression extends BinaryExpression {
|
||||
left: BindableStaticAccessExpression;
|
||||
}
|
||||
/** @internal */
|
||||
export interface BindablePropertyAssignmentExpression extends BinaryExpression {
|
||||
left: BindableAccessExpression;
|
||||
}
|
||||
|
||||
// see: https://tc39.github.io/ecma262/#prod-SuperCall
|
||||
export interface SuperCall extends CallExpression {
|
||||
|
|
|
@ -1875,7 +1875,7 @@ namespace ts {
|
|||
decl = name;
|
||||
}
|
||||
|
||||
if (!name || !isEntityNameExpression(name) || !isSameEntityName(name, node.parent.left)) {
|
||||
if (!name || !isBindableStaticNameExpression(name) || !isSameEntityName(name, node.parent.left)) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@ -1887,7 +1887,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
export function isAssignmentDeclaration(decl: Declaration) {
|
||||
return isBinaryExpression(decl) || isPropertyAccessExpression(decl) || isIdentifier(decl) || isCallExpression(decl);
|
||||
return isBinaryExpression(decl) || isAccessExpression(decl) || isIdentifier(decl) || isCallExpression(decl);
|
||||
}
|
||||
|
||||
/** Get the initializer, taking into account defaulted Javascript initializers */
|
||||
|
@ -1907,18 +1907,23 @@ namespace ts {
|
|||
}
|
||||
|
||||
function hasExpandoValueProperty(node: ObjectLiteralExpression, isPrototypeAssignment: boolean) {
|
||||
return forEach(node.properties, p => isPropertyAssignment(p) && isIdentifier(p.name) && p.name.escapedText === "value" && p.initializer && getExpandoInitializer(p.initializer, isPrototypeAssignment));
|
||||
return forEach(node.properties, p =>
|
||||
isPropertyAssignment(p) &&
|
||||
isIdentifier(p.name) &&
|
||||
p.name.escapedText === "value" &&
|
||||
p.initializer &&
|
||||
getExpandoInitializer(p.initializer, isPrototypeAssignment));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the assignment 'initializer' -- the righthand side-- when the initializer is container-like (See getExpandoInitializer).
|
||||
* We treat the right hand side of assignments with container-like initalizers as declarations.
|
||||
*/
|
||||
export function getAssignedExpandoInitializer(node: Node | undefined) {
|
||||
export function getAssignedExpandoInitializer(node: Node | undefined): Expression | undefined {
|
||||
if (node && node.parent && isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
const isPrototypeAssignment = isPrototypeAccess(node.parent.left);
|
||||
return getExpandoInitializer(node.parent.right, isPrototypeAssignment) ||
|
||||
getDefaultedExpandoInitializer(node.parent.left as EntityNameExpression, node.parent.right, isPrototypeAssignment);
|
||||
getDefaultedExpandoInitializer(node.parent.left, node.parent.right, isPrototypeAssignment);
|
||||
}
|
||||
if (node && isCallExpression(node) && isBindableObjectDefinePropertyCall(node)) {
|
||||
const result = hasExpandoValueProperty(node.arguments[2], node.arguments[1].text === "prototype");
|
||||
|
@ -1961,9 +1966,9 @@ namespace ts {
|
|||
* The second Lhs is required to be the same as the first except that it may be prefixed with
|
||||
* 'window.', 'global.' or 'self.' The second Lhs is otherwise ignored by the binder and checker.
|
||||
*/
|
||||
function getDefaultedExpandoInitializer(name: EntityNameExpression, initializer: Expression, isPrototypeAssignment: boolean) {
|
||||
function getDefaultedExpandoInitializer(name: Expression, initializer: Expression, isPrototypeAssignment: boolean) {
|
||||
const e = isBinaryExpression(initializer) && initializer.operatorToken.kind === SyntaxKind.BarBarToken && getExpandoInitializer(initializer.right, isPrototypeAssignment);
|
||||
if (e && isSameEntityName(name, (initializer as BinaryExpression).left as EntityNameExpression)) {
|
||||
if (e && isSameEntityName(name, (initializer as BinaryExpression).left)) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
@ -1998,19 +2003,20 @@ namespace ts {
|
|||
* my.app = self.my.app || class { }
|
||||
*/
|
||||
function isSameEntityName(name: Expression, initializer: Expression): boolean {
|
||||
if (isIdentifier(name) && isIdentifier(initializer)) {
|
||||
return name.escapedText === initializer.escapedText;
|
||||
if (isPropertyNameLiteral(name) && isPropertyNameLiteral(initializer)) {
|
||||
return getTextOfIdentifierOrLiteral(name) === getTextOfIdentifierOrLiteral(name);
|
||||
}
|
||||
if (isIdentifier(name) && isPropertyAccessExpression(initializer)) {
|
||||
return (initializer.expression.kind as SyntaxKind.ThisKeyword === SyntaxKind.ThisKeyword ||
|
||||
if (isIdentifier(name) && (isLiteralLikeAccess(initializer))) {
|
||||
return (initializer.expression.kind === SyntaxKind.ThisKeyword ||
|
||||
isIdentifier(initializer.expression) &&
|
||||
(initializer.expression.escapedText === "window" as __String ||
|
||||
initializer.expression.escapedText === "self" as __String ||
|
||||
initializer.expression.escapedText === "global" as __String)) &&
|
||||
isSameEntityName(name, initializer.name);
|
||||
(initializer.expression.escapedText === "window" ||
|
||||
initializer.expression.escapedText === "self" ||
|
||||
initializer.expression.escapedText === "global")) &&
|
||||
isSameEntityName(name, getNameOrArgument(initializer));
|
||||
}
|
||||
if (isPropertyAccessExpression(name) && isPropertyAccessExpression(initializer)) {
|
||||
return name.name.escapedText === initializer.name.escapedText && isSameEntityName(name.expression, initializer.expression);
|
||||
if (isLiteralLikeAccess(name) && isLiteralLikeAccess(initializer)) {
|
||||
return getElementOrPropertyAccessName(name) === getElementOrPropertyAccessName(initializer)
|
||||
&& isSameEntityName(name.expression, initializer.expression);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -2026,8 +2032,11 @@ namespace ts {
|
|||
return isIdentifier(node) && node.escapedText === "exports";
|
||||
}
|
||||
|
||||
export function isModuleExportsPropertyAccessExpression(node: Node) {
|
||||
return isPropertyAccessExpression(node) && isIdentifier(node.expression) && node.expression.escapedText === "module" && node.name.escapedText === "exports";
|
||||
export function isModuleExportsAccessExpression(node: Node): node is LiteralLikeElementAccessExpression & { expression: Identifier } {
|
||||
return (isPropertyAccessExpression(node) || isLiteralLikeElementAccess(node))
|
||||
&& isIdentifier(node.expression)
|
||||
&& node.expression.escapedText === "module"
|
||||
&& getElementOrPropertyAccessName(node) === "exports";
|
||||
}
|
||||
|
||||
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
|
||||
|
@ -2044,7 +2053,38 @@ namespace ts {
|
|||
idText(expr.expression.expression) === "Object" &&
|
||||
idText(expr.expression.name) === "defineProperty" &&
|
||||
isStringOrNumericLiteralLike(expr.arguments[1]) &&
|
||||
isEntityNameExpression(expr.arguments[0]);
|
||||
isBindableStaticNameExpression(expr.arguments[0]);
|
||||
}
|
||||
|
||||
export function isBindableStaticElementAccessExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticElementAccessExpression {
|
||||
return isLiteralLikeElementAccess(node)
|
||||
&& ((!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword) ||
|
||||
isEntityNameExpression(node.expression) ||
|
||||
isBindableStaticElementAccessExpression(node.expression, /*excludeThisKeyword*/ true));
|
||||
}
|
||||
|
||||
export function isLiteralLikeAccess(node: Node): node is LiteralLikeElementAccessExpression | PropertyAccessExpression {
|
||||
return isPropertyAccessExpression(node) || isLiteralLikeElementAccess(node);
|
||||
}
|
||||
|
||||
export function isLiteralLikeElementAccess(node: Node): node is LiteralLikeElementAccessExpression {
|
||||
return isElementAccessExpression(node) && isStringOrNumericLiteralLike(node.argumentExpression);
|
||||
}
|
||||
|
||||
export function isBindableStaticAccessExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticAccessExpression {
|
||||
return isPropertyAccessExpression(node) && (!excludeThisKeyword && node.expression.kind === SyntaxKind.ThisKeyword || isBindableStaticNameExpression(node.expression, /*excludeThisKeyword*/ true))
|
||||
|| isBindableStaticElementAccessExpression(node, excludeThisKeyword);
|
||||
}
|
||||
|
||||
export function isBindableStaticNameExpression(node: Node, excludeThisKeyword?: boolean): node is BindableStaticNameExpression {
|
||||
return isEntityNameExpression(node) || isBindableStaticAccessExpression(node, excludeThisKeyword);
|
||||
}
|
||||
|
||||
export function getNameOrArgument(expr: PropertyAccessExpression | LiteralLikeElementAccessExpression) {
|
||||
if (isPropertyAccessExpression(expr)) {
|
||||
return expr.name;
|
||||
}
|
||||
return expr.argumentExpression;
|
||||
}
|
||||
|
||||
function getAssignmentDeclarationKindWorker(expr: BinaryExpression | CallExpression): AssignmentDeclarationKind {
|
||||
|
@ -2053,26 +2093,22 @@ namespace ts {
|
|||
return AssignmentDeclarationKind.None;
|
||||
}
|
||||
const entityName = expr.arguments[0];
|
||||
if (isExportsIdentifier(entityName) || isModuleExportsPropertyAccessExpression(entityName)) {
|
||||
if (isExportsIdentifier(entityName) || isModuleExportsAccessExpression(entityName)) {
|
||||
return AssignmentDeclarationKind.ObjectDefinePropertyExports;
|
||||
}
|
||||
if (isPropertyAccessExpression(entityName) && entityName.name.escapedText === "prototype" && isEntityNameExpression(entityName.expression)) {
|
||||
if (isBindableStaticAccessExpression(entityName) && getElementOrPropertyAccessName(entityName) === "prototype") {
|
||||
return AssignmentDeclarationKind.ObjectDefinePrototypeProperty;
|
||||
}
|
||||
return AssignmentDeclarationKind.ObjectDefinePropertyValue;
|
||||
}
|
||||
if (expr.operatorToken.kind !== SyntaxKind.EqualsToken) {
|
||||
if (expr.operatorToken.kind !== SyntaxKind.EqualsToken || !isAccessExpression(expr.left)) {
|
||||
return AssignmentDeclarationKind.None;
|
||||
}
|
||||
const lhs = expr.left;
|
||||
if (isAccessExpression(lhs)) {
|
||||
if (isEntityNameExpression(lhs.expression) && getElementOrPropertyAccessName(lhs) === "prototype" && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr))) {
|
||||
// F.prototype = { ... }
|
||||
return AssignmentDeclarationKind.Prototype;
|
||||
}
|
||||
return getAssignmentDeclarationPropertyAccessKind(lhs);
|
||||
if (isBindableStaticNameExpression(expr.left.expression) && getElementOrPropertyAccessName(expr.left) === "prototype" && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr))) {
|
||||
// F.prototype = { ... }
|
||||
return AssignmentDeclarationKind.Prototype;
|
||||
}
|
||||
return AssignmentDeclarationKind.None;
|
||||
return getAssignmentDeclarationPropertyAccessKind(expr.left);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2092,6 +2128,8 @@ namespace ts {
|
|||
}
|
||||
|
||||
/* @internal */
|
||||
export function getElementOrPropertyAccessName(node: LiteralLikeElementAccessExpression | PropertyAccessExpression): string;
|
||||
export function getElementOrPropertyAccessName(node: AccessExpression): string | undefined;
|
||||
export function getElementOrPropertyAccessName(node: AccessExpression): string | undefined {
|
||||
const name = getElementOrPropertyAccessArgumentExpressionOrName(node);
|
||||
if (name) {
|
||||
|
@ -2109,22 +2147,21 @@ namespace ts {
|
|||
if (lhs.expression.kind === SyntaxKind.ThisKeyword) {
|
||||
return AssignmentDeclarationKind.ThisProperty;
|
||||
}
|
||||
else if (isModuleExportsPropertyAccessExpression(lhs)) {
|
||||
else if (isModuleExportsAccessExpression(lhs)) {
|
||||
// module.exports = expr
|
||||
return AssignmentDeclarationKind.ModuleExports;
|
||||
}
|
||||
else if (isEntityNameExpression(lhs.expression)) {
|
||||
else if (isBindableStaticNameExpression(lhs.expression, /*excludeThisKeyword*/ true)) {
|
||||
if (isPrototypeAccess(lhs.expression)) {
|
||||
// F.G....prototype.x = expr
|
||||
return AssignmentDeclarationKind.PrototypeProperty;
|
||||
}
|
||||
|
||||
let nextToLast = lhs;
|
||||
while (isAccessExpression(nextToLast.expression)) {
|
||||
nextToLast = nextToLast.expression;
|
||||
while (!isIdentifier(nextToLast.expression)) {
|
||||
nextToLast = nextToLast.expression as Exclude<BindableStaticNameExpression, Identifier>;
|
||||
}
|
||||
Debug.assert(isIdentifier(nextToLast.expression));
|
||||
const id = nextToLast.expression as Identifier;
|
||||
const id = nextToLast.expression;
|
||||
if (id.escapedText === "exports" ||
|
||||
id.escapedText === "module" && getElementOrPropertyAccessName(nextToLast) === "exports") {
|
||||
// exports.name = expr OR module.exports.name = expr
|
||||
|
@ -2148,9 +2185,10 @@ namespace ts {
|
|||
return isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.PrototypeProperty;
|
||||
}
|
||||
|
||||
export function isSpecialPropertyDeclaration(expr: PropertyAccessExpression): boolean {
|
||||
export function isSpecialPropertyDeclaration(expr: PropertyAccessExpression | ElementAccessExpression): expr is PropertyAccessExpression | LiteralLikeElementAccessExpression {
|
||||
return isInJSFile(expr) &&
|
||||
expr.parent && expr.parent.kind === SyntaxKind.ExpressionStatement &&
|
||||
(!isElementAccessExpression(expr) || isLiteralLikeElementAccess(expr)) &&
|
||||
!!getJSDocTypeTag(expr.parent);
|
||||
}
|
||||
|
||||
|
@ -4147,8 +4185,8 @@ namespace ts {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export function isPrototypeAccess(node: Node): node is PropertyAccessExpression {
|
||||
return isPropertyAccessExpression(node) && node.name.escapedText === "prototype";
|
||||
export function isPrototypeAccess(node: Node): node is BindableStaticAccessExpression {
|
||||
return isBindableStaticAccessExpression(node) && getElementOrPropertyAccessName(node) === "prototype";
|
||||
}
|
||||
|
||||
export function isRightSideOfQualifiedNameOrPropertyAccess(node: Node) {
|
||||
|
@ -5378,6 +5416,11 @@ namespace ts {
|
|||
const { expression } = declaration as ExportAssignment;
|
||||
return isIdentifier(expression) ? expression : undefined;
|
||||
}
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
const expr = declaration as ElementAccessExpression;
|
||||
if (isBindableStaticElementAccessExpression(expr)) {
|
||||
return expr.argumentExpression;
|
||||
}
|
||||
}
|
||||
return (declaration as NamedDeclaration).name;
|
||||
}
|
||||
|
@ -5399,8 +5442,8 @@ namespace ts {
|
|||
if (isIdentifier(node.parent.left)) {
|
||||
return node.parent.left;
|
||||
}
|
||||
else if (isPropertyAccessExpression(node.parent.left)) {
|
||||
return node.parent.left.name;
|
||||
else if (isAccessExpression(node.parent.left)) {
|
||||
return getElementOrPropertyAccessArgumentExpressionOrName(node.parent.left);
|
||||
}
|
||||
}
|
||||
else if (isVariableDeclaration(node.parent) && isIdentifier(node.parent.name)) {
|
||||
|
|
|
@ -135,12 +135,13 @@ namespace ts.NavigationBar {
|
|||
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;
|
||||
function startNestedNodes(targetNode: Node, entityName: BindableStaticNameExpression) {
|
||||
const names: PropertyNameLiteral[] = [];
|
||||
while (!isPropertyNameLiteral(entityName)) {
|
||||
const name = getNameOrArgument(entityName);
|
||||
const nameText = getElementOrPropertyAccessName(entityName);
|
||||
entityName = entityName.expression;
|
||||
if (name.escapedText === "prototype") continue;
|
||||
if (nameText === "prototype") continue;
|
||||
names.push(name);
|
||||
}
|
||||
names.push(entityName);
|
||||
|
@ -333,7 +334,7 @@ namespace ts.NavigationBar {
|
|||
assignmentTarget;
|
||||
|
||||
let depth = 0;
|
||||
let className: Identifier;
|
||||
let className: PropertyNameLiteral;
|
||||
// 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)) {
|
||||
|
@ -384,16 +385,16 @@ namespace ts.NavigationBar {
|
|||
}
|
||||
case AssignmentDeclarationKind.Property: {
|
||||
const binaryExpression = (node as BinaryExpression);
|
||||
const assignmentTarget = binaryExpression.left as PropertyAccessExpression;
|
||||
const assignmentTarget = binaryExpression.left as PropertyAccessExpression | BindableElementAccessExpression;
|
||||
const targetFunction = assignmentTarget.expression;
|
||||
if (isIdentifier(targetFunction) && assignmentTarget.name.escapedText !== "prototype" &&
|
||||
if (isIdentifier(targetFunction) && getElementOrPropertyAccessName(assignmentTarget) !== "prototype" &&
|
||||
trackedEs5Classes && trackedEs5Classes.has(targetFunction.text)) {
|
||||
if (isFunctionExpression(binaryExpression.right) || isArrowFunction(binaryExpression.right)) {
|
||||
addNodeWithRecursiveChild(node, binaryExpression.right, targetFunction);
|
||||
}
|
||||
else {
|
||||
else if (isBindableStaticAccessExpression(assignmentTarget)) {
|
||||
startNode(binaryExpression, targetFunction);
|
||||
addNodeWithRecursiveChild(binaryExpression.left, binaryExpression.right, assignmentTarget.name);
|
||||
addNodeWithRecursiveChild(binaryExpression.left, binaryExpression.right, getNameOrArgument(assignmentTarget));
|
||||
endNode();
|
||||
}
|
||||
return;
|
||||
|
|
|
@ -852,7 +852,7 @@ declare namespace ts {
|
|||
kind: SyntaxKind.LiteralType;
|
||||
literal: BooleanLiteral | LiteralExpression | PrefixUnaryExpression;
|
||||
}
|
||||
export interface StringLiteral extends LiteralExpression {
|
||||
export interface StringLiteral extends LiteralExpression, Declaration {
|
||||
kind: SyntaxKind.StringLiteral;
|
||||
}
|
||||
export type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral;
|
||||
|
@ -1016,7 +1016,7 @@ declare namespace ts {
|
|||
export interface RegularExpressionLiteral extends LiteralExpression {
|
||||
kind: SyntaxKind.RegularExpressionLiteral;
|
||||
}
|
||||
export interface NoSubstitutionTemplateLiteral extends LiteralExpression, TemplateLiteralLikeNode {
|
||||
export interface NoSubstitutionTemplateLiteral extends LiteralExpression, TemplateLiteralLikeNode, Declaration {
|
||||
kind: SyntaxKind.NoSubstitutionTemplateLiteral;
|
||||
}
|
||||
export enum TokenFlags {
|
||||
|
@ -1027,7 +1027,7 @@ declare namespace ts {
|
|||
BinarySpecifier = 128,
|
||||
OctalSpecifier = 256,
|
||||
}
|
||||
export interface NumericLiteral extends LiteralExpression {
|
||||
export interface NumericLiteral extends LiteralExpression, Declaration {
|
||||
kind: SyntaxKind.NumericLiteral;
|
||||
}
|
||||
export interface BigIntLiteral extends LiteralExpression {
|
||||
|
|
|
@ -852,7 +852,7 @@ declare namespace ts {
|
|||
kind: SyntaxKind.LiteralType;
|
||||
literal: BooleanLiteral | LiteralExpression | PrefixUnaryExpression;
|
||||
}
|
||||
export interface StringLiteral extends LiteralExpression {
|
||||
export interface StringLiteral extends LiteralExpression, Declaration {
|
||||
kind: SyntaxKind.StringLiteral;
|
||||
}
|
||||
export type StringLiteralLike = StringLiteral | NoSubstitutionTemplateLiteral;
|
||||
|
@ -1016,7 +1016,7 @@ declare namespace ts {
|
|||
export interface RegularExpressionLiteral extends LiteralExpression {
|
||||
kind: SyntaxKind.RegularExpressionLiteral;
|
||||
}
|
||||
export interface NoSubstitutionTemplateLiteral extends LiteralExpression, TemplateLiteralLikeNode {
|
||||
export interface NoSubstitutionTemplateLiteral extends LiteralExpression, TemplateLiteralLikeNode, Declaration {
|
||||
kind: SyntaxKind.NoSubstitutionTemplateLiteral;
|
||||
}
|
||||
export enum TokenFlags {
|
||||
|
@ -1027,7 +1027,7 @@ declare namespace ts {
|
|||
BinarySpecifier = 128,
|
||||
OctalSpecifier = 256,
|
||||
}
|
||||
export interface NumericLiteral extends LiteralExpression {
|
||||
export interface NumericLiteral extends LiteralExpression, Declaration {
|
||||
kind: SyntaxKind.NumericLiteral;
|
||||
}
|
||||
export interface BigIntLiteral extends LiteralExpression {
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
//// [tests/cases/conformance/jsdoc/moduleExportsElementAccessAssignment.ts] ////
|
||||
|
||||
//// [mod1.js]
|
||||
exports.a = { x: "x" };
|
||||
exports["b"] = { x: "x" };
|
||||
exports["default"] = { x: "x" };
|
||||
module.exports["c"] = { x: "x" };
|
||||
module["exports"]["d"] = {};
|
||||
module["exports"]["d"].e = 0;
|
||||
|
||||
//// [mod2.js]
|
||||
const mod1 = require("./mod1");
|
||||
mod1.a;
|
||||
mod1.b;
|
||||
mod1.c;
|
||||
mod1.d;
|
||||
mod1.d.e;
|
||||
mod1.default;
|
||||
|
||||
|
||||
|
||||
//// [mod1.d.ts]
|
||||
export namespace a {
|
||||
export const x: string;
|
||||
}
|
||||
export namespace b {
|
||||
const x_1: string;
|
||||
export { x_1 as x };
|
||||
}
|
||||
declare namespace _default {
|
||||
const x_2: string;
|
||||
export { x_2 as x };
|
||||
}
|
||||
export default _default;
|
||||
export namespace c {
|
||||
const x_3: string;
|
||||
export { x_3 as x };
|
||||
}
|
||||
export namespace d {
|
||||
export const e: number;
|
||||
}
|
||||
//// [mod2.d.ts]
|
||||
export {};
|
|
@ -0,0 +1,74 @@
|
|||
=== tests/cases/conformance/jsdoc/mod2.js ===
|
||||
const mod1 = require("./mod1");
|
||||
>mod1 : Symbol(mod1, Decl(mod2.js, 0, 5))
|
||||
>require : Symbol(require)
|
||||
>"./mod1" : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0))
|
||||
|
||||
mod1.a;
|
||||
>mod1.a : Symbol(a, Decl(mod1.js, 0, 0))
|
||||
>mod1 : Symbol(mod1, Decl(mod2.js, 0, 5))
|
||||
>a : Symbol(a, Decl(mod1.js, 0, 0))
|
||||
|
||||
mod1.b;
|
||||
>mod1.b : Symbol("b", Decl(mod1.js, 0, 23))
|
||||
>mod1 : Symbol(mod1, Decl(mod2.js, 0, 5))
|
||||
>b : Symbol("b", Decl(mod1.js, 0, 23))
|
||||
|
||||
mod1.c;
|
||||
>mod1.c : Symbol("c", Decl(mod1.js, 2, 32))
|
||||
>mod1 : Symbol(mod1, Decl(mod2.js, 0, 5))
|
||||
>c : Symbol("c", Decl(mod1.js, 2, 32))
|
||||
|
||||
mod1.d;
|
||||
>mod1.d : Symbol("d", Decl(mod1.js, 3, 33), Decl(mod1.js, 5, 18))
|
||||
>mod1 : Symbol(mod1, Decl(mod2.js, 0, 5))
|
||||
>d : Symbol("d", Decl(mod1.js, 3, 33), Decl(mod1.js, 5, 18))
|
||||
|
||||
mod1.d.e;
|
||||
>mod1.d.e : Symbol("d".e, Decl(mod1.js, 4, 28))
|
||||
>mod1.d : Symbol("d", Decl(mod1.js, 3, 33), Decl(mod1.js, 5, 18))
|
||||
>mod1 : Symbol(mod1, Decl(mod2.js, 0, 5))
|
||||
>d : Symbol("d", Decl(mod1.js, 3, 33), Decl(mod1.js, 5, 18))
|
||||
>e : Symbol("d".e, Decl(mod1.js, 4, 28))
|
||||
|
||||
mod1.default;
|
||||
>mod1.default : Symbol(default, Decl(mod1.js, 1, 26))
|
||||
>mod1 : Symbol(mod1, Decl(mod2.js, 0, 5))
|
||||
>default : Symbol(default, Decl(mod1.js, 1, 26))
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod1.js ===
|
||||
exports.a = { x: "x" };
|
||||
>exports.a : Symbol(a, Decl(mod1.js, 0, 0))
|
||||
>exports : Symbol(a, Decl(mod1.js, 0, 0))
|
||||
>a : Symbol(a, Decl(mod1.js, 0, 0))
|
||||
>x : Symbol(x, Decl(mod1.js, 0, 13))
|
||||
|
||||
exports["b"] = { x: "x" };
|
||||
>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0))
|
||||
>"b" : Symbol("b", Decl(mod1.js, 0, 23))
|
||||
>x : Symbol(x, Decl(mod1.js, 1, 16))
|
||||
|
||||
exports["default"] = { x: "x" };
|
||||
>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0))
|
||||
>"default" : Symbol("default", Decl(mod1.js, 1, 26))
|
||||
>x : Symbol(x, Decl(mod1.js, 2, 22))
|
||||
|
||||
module.exports["c"] = { x: "x" };
|
||||
>module.exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0))
|
||||
>module : Symbol(module, Decl(mod1.js, 2, 32))
|
||||
>exports : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0))
|
||||
>"c" : Symbol("c", Decl(mod1.js, 2, 32))
|
||||
>x : Symbol(x, Decl(mod1.js, 3, 23))
|
||||
|
||||
module["exports"]["d"] = {};
|
||||
>module : Symbol(module, Decl(mod1.js, 2, 32))
|
||||
>"exports" : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0))
|
||||
>"d" : Symbol("d", Decl(mod1.js, 3, 33), Decl(mod1.js, 5, 18))
|
||||
|
||||
module["exports"]["d"].e = 0;
|
||||
>module["exports"]["d"].e : Symbol("d".e, Decl(mod1.js, 4, 28))
|
||||
>module : Symbol(module, Decl(mod1.js, 2, 32))
|
||||
>"exports" : Symbol("tests/cases/conformance/jsdoc/mod1", Decl(mod1.js, 0, 0))
|
||||
>"d" : Symbol("d", Decl(mod1.js, 3, 33), Decl(mod1.js, 5, 18))
|
||||
>e : Symbol("d".e, Decl(mod1.js, 4, 28))
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
=== tests/cases/conformance/jsdoc/mod2.js ===
|
||||
const mod1 = require("./mod1");
|
||||
>mod1 : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>require("./mod1") : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>require : any
|
||||
>"./mod1" : "./mod1"
|
||||
|
||||
mod1.a;
|
||||
>mod1.a : { x: string; }
|
||||
>mod1 : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>a : { x: string; }
|
||||
|
||||
mod1.b;
|
||||
>mod1.b : { x: string; }
|
||||
>mod1 : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>b : { x: string; }
|
||||
|
||||
mod1.c;
|
||||
>mod1.c : { x: string; }
|
||||
>mod1 : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>c : { x: string; }
|
||||
|
||||
mod1.d;
|
||||
>mod1.d : typeof import("tests/cases/conformance/jsdoc/mod1").d
|
||||
>mod1 : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>d : typeof import("tests/cases/conformance/jsdoc/mod1").d
|
||||
|
||||
mod1.d.e;
|
||||
>mod1.d.e : number
|
||||
>mod1.d : typeof import("tests/cases/conformance/jsdoc/mod1").d
|
||||
>mod1 : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>d : typeof import("tests/cases/conformance/jsdoc/mod1").d
|
||||
>e : number
|
||||
|
||||
mod1.default;
|
||||
>mod1.default : { x: string; }
|
||||
>mod1 : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>default : { x: string; }
|
||||
|
||||
=== tests/cases/conformance/jsdoc/mod1.js ===
|
||||
exports.a = { x: "x" };
|
||||
>exports.a = { x: "x" } : { x: string; }
|
||||
>exports.a : { x: string; }
|
||||
>exports : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>a : { x: string; }
|
||||
>{ x: "x" } : { x: string; }
|
||||
>x : string
|
||||
>"x" : "x"
|
||||
|
||||
exports["b"] = { x: "x" };
|
||||
>exports["b"] = { x: "x" } : { x: string; }
|
||||
>exports["b"] : { x: string; }
|
||||
>exports : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>"b" : "b"
|
||||
>{ x: "x" } : { x: string; }
|
||||
>x : string
|
||||
>"x" : "x"
|
||||
|
||||
exports["default"] = { x: "x" };
|
||||
>exports["default"] = { x: "x" } : { x: string; }
|
||||
>exports["default"] : { x: string; }
|
||||
>exports : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>"default" : "default"
|
||||
>{ x: "x" } : { x: string; }
|
||||
>x : string
|
||||
>"x" : "x"
|
||||
|
||||
module.exports["c"] = { x: "x" };
|
||||
>module.exports["c"] = { x: "x" } : { x: string; }
|
||||
>module.exports["c"] : { x: string; }
|
||||
>module.exports : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>module : { "tests/cases/conformance/jsdoc/mod1": typeof import("tests/cases/conformance/jsdoc/mod1"); }
|
||||
>exports : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>"c" : "c"
|
||||
>{ x: "x" } : { x: string; }
|
||||
>x : string
|
||||
>"x" : "x"
|
||||
|
||||
module["exports"]["d"] = {};
|
||||
>module["exports"]["d"] = {} : typeof "d"
|
||||
>module["exports"]["d"] : typeof "d"
|
||||
>module["exports"] : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>module : { "tests/cases/conformance/jsdoc/mod1": typeof import("tests/cases/conformance/jsdoc/mod1"); }
|
||||
>"exports" : "exports"
|
||||
>"d" : "d"
|
||||
>{} : {}
|
||||
|
||||
module["exports"]["d"].e = 0;
|
||||
>module["exports"]["d"].e = 0 : 0
|
||||
>module["exports"]["d"].e : number
|
||||
>module["exports"]["d"] : typeof "d"
|
||||
>module["exports"] : typeof import("tests/cases/conformance/jsdoc/mod1")
|
||||
>module : { "tests/cases/conformance/jsdoc/mod1": typeof import("tests/cases/conformance/jsdoc/mod1"); }
|
||||
>"exports" : "exports"
|
||||
>"d" : "d"
|
||||
>e : number
|
||||
>0 : 0
|
||||
|
43
tests/baselines/reference/thisPropertyAssignment.errors.txt
Normal file
43
tests/baselines/reference/thisPropertyAssignment.errors.txt
Normal file
|
@ -0,0 +1,43 @@
|
|||
tests/cases/conformance/salsa/a.js(9,8): error TS2339: Property 'y' does not exist on type '{}'.
|
||||
tests/cases/conformance/salsa/a.js(11,1): error TS7053: Element implicitly has an 'any' type because expression of type '"z"' can't be used to index type '{}'.
|
||||
Property 'z' does not exist on type '{}'.
|
||||
tests/cases/conformance/salsa/a.js(16,10): error TS2339: Property 'b' does not exist on type '{}'.
|
||||
tests/cases/conformance/salsa/a.js(18,3): error TS7053: Element implicitly has an 'any' type because expression of type '"c"' can't be used to index type '{}'.
|
||||
Property 'c' does not exist on type '{}'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/salsa/a.js (4 errors) ====
|
||||
// This test is asserting that a single property/element access
|
||||
// on `this` is a special assignment declaration, but chaining
|
||||
// off that does not create additional declarations. I’m not sure
|
||||
// if it needs to be that way in JavaScript; the test simply
|
||||
// ensures no accidental changes were introduced while allowing
|
||||
// element access assignments to create declarations.
|
||||
|
||||
this.x = {};
|
||||
this.x.y = {};
|
||||
~
|
||||
!!! error TS2339: Property 'y' does not exist on type '{}'.
|
||||
this["y"] = {};
|
||||
this["y"]["z"] = {};
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS7053: Element implicitly has an 'any' type because expression of type '"z"' can't be used to index type '{}'.
|
||||
!!! error TS7053: Property 'z' does not exist on type '{}'.
|
||||
|
||||
/** @constructor */
|
||||
function F() {
|
||||
this.a = {};
|
||||
this.a.b = {};
|
||||
~
|
||||
!!! error TS2339: Property 'b' does not exist on type '{}'.
|
||||
this["b"] = {};
|
||||
this["b"]["c"] = {};
|
||||
~~~~~~~~~~~~~~
|
||||
!!! error TS7053: Element implicitly has an 'any' type because expression of type '"c"' can't be used to index type '{}'.
|
||||
!!! error TS7053: Property 'c' does not exist on type '{}'.
|
||||
}
|
||||
|
||||
const f = new F();
|
||||
f.a;
|
||||
f.b;
|
||||
|
38
tests/baselines/reference/thisPropertyAssignment.js
Normal file
38
tests/baselines/reference/thisPropertyAssignment.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
//// [a.js]
|
||||
// This test is asserting that a single property/element access
|
||||
// on `this` is a special assignment declaration, but chaining
|
||||
// off that does not create additional declarations. I’m not sure
|
||||
// if it needs to be that way in JavaScript; the test simply
|
||||
// ensures no accidental changes were introduced while allowing
|
||||
// element access assignments to create declarations.
|
||||
|
||||
this.x = {};
|
||||
this.x.y = {};
|
||||
this["y"] = {};
|
||||
this["y"]["z"] = {};
|
||||
|
||||
/** @constructor */
|
||||
function F() {
|
||||
this.a = {};
|
||||
this.a.b = {};
|
||||
this["b"] = {};
|
||||
this["b"]["c"] = {};
|
||||
}
|
||||
|
||||
const f = new F();
|
||||
f.a;
|
||||
f.b;
|
||||
|
||||
|
||||
|
||||
|
||||
//// [a.d.ts]
|
||||
/** @constructor */
|
||||
declare function F(): void;
|
||||
declare class F {
|
||||
a: {};
|
||||
b: {};
|
||||
}
|
||||
declare var x: {} | undefined;
|
||||
declare var y: {} | undefined;
|
||||
declare const f: F;
|
63
tests/baselines/reference/thisPropertyAssignment.symbols
Normal file
63
tests/baselines/reference/thisPropertyAssignment.symbols
Normal file
|
@ -0,0 +1,63 @@
|
|||
=== tests/cases/conformance/salsa/a.js ===
|
||||
// This test is asserting that a single property/element access
|
||||
// on `this` is a special assignment declaration, but chaining
|
||||
// off that does not create additional declarations. I’m not sure
|
||||
// if it needs to be that way in JavaScript; the test simply
|
||||
// ensures no accidental changes were introduced while allowing
|
||||
// element access assignments to create declarations.
|
||||
|
||||
this.x = {};
|
||||
>this.x : Symbol(x, Decl(a.js, 0, 0))
|
||||
>this : Symbol(globalThis)
|
||||
>x : Symbol(x, Decl(a.js, 0, 0))
|
||||
|
||||
this.x.y = {};
|
||||
>this.x : Symbol(x, Decl(a.js, 0, 0))
|
||||
>this : Symbol(globalThis)
|
||||
>x : Symbol(x, Decl(a.js, 0, 0))
|
||||
|
||||
this["y"] = {};
|
||||
>this : Symbol(globalThis)
|
||||
>"y" : Symbol("y", Decl(a.js, 8, 14))
|
||||
|
||||
this["y"]["z"] = {};
|
||||
>this : Symbol(globalThis)
|
||||
>"y" : Symbol("y", Decl(a.js, 8, 14))
|
||||
|
||||
/** @constructor */
|
||||
function F() {
|
||||
>F : Symbol(F, Decl(a.js, 10, 20))
|
||||
|
||||
this.a = {};
|
||||
>this.a : Symbol(F.a, Decl(a.js, 13, 14))
|
||||
>this : Symbol(F, Decl(a.js, 10, 20))
|
||||
>a : Symbol(F.a, Decl(a.js, 13, 14))
|
||||
|
||||
this.a.b = {};
|
||||
>this.a : Symbol(F.a, Decl(a.js, 13, 14))
|
||||
>this : Symbol(F, Decl(a.js, 10, 20))
|
||||
>a : Symbol(F.a, Decl(a.js, 13, 14))
|
||||
|
||||
this["b"] = {};
|
||||
>this : Symbol(F, Decl(a.js, 10, 20))
|
||||
>"b" : Symbol(F["b"], Decl(a.js, 15, 16))
|
||||
|
||||
this["b"]["c"] = {};
|
||||
>this : Symbol(F, Decl(a.js, 10, 20))
|
||||
>"b" : Symbol(F["b"], Decl(a.js, 15, 16))
|
||||
}
|
||||
|
||||
const f = new F();
|
||||
>f : Symbol(f, Decl(a.js, 20, 5))
|
||||
>F : Symbol(F, Decl(a.js, 10, 20))
|
||||
|
||||
f.a;
|
||||
>f.a : Symbol(F.a, Decl(a.js, 13, 14))
|
||||
>f : Symbol(f, Decl(a.js, 20, 5))
|
||||
>a : Symbol(F.a, Decl(a.js, 13, 14))
|
||||
|
||||
f.b;
|
||||
>f.b : Symbol(F["b"], Decl(a.js, 15, 16))
|
||||
>f : Symbol(f, Decl(a.js, 20, 5))
|
||||
>b : Symbol(F["b"], Decl(a.js, 15, 16))
|
||||
|
92
tests/baselines/reference/thisPropertyAssignment.types
Normal file
92
tests/baselines/reference/thisPropertyAssignment.types
Normal file
|
@ -0,0 +1,92 @@
|
|||
=== tests/cases/conformance/salsa/a.js ===
|
||||
// This test is asserting that a single property/element access
|
||||
// on `this` is a special assignment declaration, but chaining
|
||||
// off that does not create additional declarations. I’m not sure
|
||||
// if it needs to be that way in JavaScript; the test simply
|
||||
// ensures no accidental changes were introduced while allowing
|
||||
// element access assignments to create declarations.
|
||||
|
||||
this.x = {};
|
||||
>this.x = {} : {}
|
||||
>this.x : {} | undefined
|
||||
>this : typeof globalThis
|
||||
>x : {} | undefined
|
||||
>{} : {}
|
||||
|
||||
this.x.y = {};
|
||||
>this.x.y = {} : {}
|
||||
>this.x.y : any
|
||||
>this.x : {}
|
||||
>this : typeof globalThis
|
||||
>x : {}
|
||||
>y : any
|
||||
>{} : {}
|
||||
|
||||
this["y"] = {};
|
||||
>this["y"] = {} : {}
|
||||
>this["y"] : {} | undefined
|
||||
>this : typeof globalThis
|
||||
>"y" : "y"
|
||||
>{} : {}
|
||||
|
||||
this["y"]["z"] = {};
|
||||
>this["y"]["z"] = {} : {}
|
||||
>this["y"]["z"] : any
|
||||
>this["y"] : {}
|
||||
>this : typeof globalThis
|
||||
>"y" : "y"
|
||||
>"z" : "z"
|
||||
>{} : {}
|
||||
|
||||
/** @constructor */
|
||||
function F() {
|
||||
>F : typeof F
|
||||
|
||||
this.a = {};
|
||||
>this.a = {} : {}
|
||||
>this.a : {}
|
||||
>this : this
|
||||
>a : {}
|
||||
>{} : {}
|
||||
|
||||
this.a.b = {};
|
||||
>this.a.b = {} : {}
|
||||
>this.a.b : any
|
||||
>this.a : {}
|
||||
>this : this
|
||||
>a : {}
|
||||
>b : any
|
||||
>{} : {}
|
||||
|
||||
this["b"] = {};
|
||||
>this["b"] = {} : {}
|
||||
>this["b"] : {}
|
||||
>this : this
|
||||
>"b" : "b"
|
||||
>{} : {}
|
||||
|
||||
this["b"]["c"] = {};
|
||||
>this["b"]["c"] = {} : {}
|
||||
>this["b"]["c"] : any
|
||||
>this["b"] : {}
|
||||
>this : this
|
||||
>"b" : "b"
|
||||
>"c" : "c"
|
||||
>{} : {}
|
||||
}
|
||||
|
||||
const f = new F();
|
||||
>f : F
|
||||
>new F() : F
|
||||
>F : typeof F
|
||||
|
||||
f.a;
|
||||
>f.a : {}
|
||||
>f : F
|
||||
>a : {}
|
||||
|
||||
f.b;
|
||||
>f.b : {}
|
||||
>f : F
|
||||
>b : {}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
=== tests/cases/conformance/salsa/typeFromPropertyAssignment38.ts ===
|
||||
function F() {}
|
||||
>F : Symbol(F, Decl(typeFromPropertyAssignment38.ts, 0, 0), Decl(typeFromPropertyAssignment38.ts, 0, 15))
|
||||
|
||||
F["prop"] = 3;
|
||||
>F : Symbol(F, Decl(typeFromPropertyAssignment38.ts, 0, 0), Decl(typeFromPropertyAssignment38.ts, 0, 15))
|
||||
>"prop" : Symbol(F["prop"], Decl(typeFromPropertyAssignment38.ts, 0, 15))
|
||||
|
||||
const f = function () {};
|
||||
>f : Symbol(f, Decl(typeFromPropertyAssignment38.ts, 3, 5), Decl(typeFromPropertyAssignment38.ts, 3, 25))
|
||||
|
||||
f["prop"] = 3;
|
||||
>f : Symbol(f, Decl(typeFromPropertyAssignment38.ts, 3, 5), Decl(typeFromPropertyAssignment38.ts, 3, 25))
|
||||
>"prop" : Symbol(f["prop"], Decl(typeFromPropertyAssignment38.ts, 3, 25))
|
||||
|
22
tests/baselines/reference/typeFromPropertyAssignment38.types
Normal file
22
tests/baselines/reference/typeFromPropertyAssignment38.types
Normal file
|
@ -0,0 +1,22 @@
|
|||
=== tests/cases/conformance/salsa/typeFromPropertyAssignment38.ts ===
|
||||
function F() {}
|
||||
>F : typeof F
|
||||
|
||||
F["prop"] = 3;
|
||||
>F["prop"] = 3 : 3
|
||||
>F["prop"] : number
|
||||
>F : typeof F
|
||||
>"prop" : "prop"
|
||||
>3 : 3
|
||||
|
||||
const f = function () {};
|
||||
>f : { (): void; "prop": number; }
|
||||
>function () {} : { (): void; "prop": number; }
|
||||
|
||||
f["prop"] = 3;
|
||||
>f["prop"] = 3 : 3
|
||||
>f["prop"] : number
|
||||
>f : { (): void; "prop": number; }
|
||||
>"prop" : "prop"
|
||||
>3 : 3
|
||||
|
14
tests/baselines/reference/typeFromPropertyAssignment39.js
Normal file
14
tests/baselines/reference/typeFromPropertyAssignment39.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
//// [a.js]
|
||||
const foo = {};
|
||||
foo["baz"] = {};
|
||||
foo["baz"]["blah"] = 3;
|
||||
|
||||
|
||||
|
||||
|
||||
//// [a.d.ts]
|
||||
declare namespace foo {
|
||||
namespace baz {
|
||||
const blah: number;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
=== tests/cases/conformance/salsa/a.js ===
|
||||
const foo = {};
|
||||
>foo : Symbol(foo, Decl(a.js, 0, 5), Decl(a.js, 0, 15), Decl(a.js, 1, 16))
|
||||
|
||||
foo["baz"] = {};
|
||||
>foo : Symbol(foo, Decl(a.js, 0, 5), Decl(a.js, 0, 15), Decl(a.js, 1, 16))
|
||||
>"baz" : Symbol(foo["baz"], Decl(a.js, 0, 15), Decl(a.js, 2, 4))
|
||||
|
||||
foo["baz"]["blah"] = 3;
|
||||
>foo : Symbol(foo, Decl(a.js, 0, 5), Decl(a.js, 0, 15), Decl(a.js, 1, 16))
|
||||
>"baz" : Symbol(foo["baz"], Decl(a.js, 0, 15), Decl(a.js, 2, 4))
|
||||
>"blah" : Symbol(foo["baz"]["blah"], Decl(a.js, 1, 16))
|
||||
|
21
tests/baselines/reference/typeFromPropertyAssignment39.types
Normal file
21
tests/baselines/reference/typeFromPropertyAssignment39.types
Normal file
|
@ -0,0 +1,21 @@
|
|||
=== tests/cases/conformance/salsa/a.js ===
|
||||
const foo = {};
|
||||
>foo : typeof foo
|
||||
>{} : {}
|
||||
|
||||
foo["baz"] = {};
|
||||
>foo["baz"] = {} : typeof foo.baz
|
||||
>foo["baz"] : typeof foo.baz
|
||||
>foo : typeof foo
|
||||
>"baz" : "baz"
|
||||
>{} : {}
|
||||
|
||||
foo["baz"]["blah"] = 3;
|
||||
>foo["baz"]["blah"] = 3 : 3
|
||||
>foo["baz"]["blah"] : number
|
||||
>foo["baz"] : typeof foo.baz
|
||||
>foo : typeof foo
|
||||
>"baz" : "baz"
|
||||
>"blah" : "blah"
|
||||
>3 : 3
|
||||
|
42
tests/baselines/reference/typeFromPrototypeAssignment4.js
Normal file
42
tests/baselines/reference/typeFromPrototypeAssignment4.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
//// [a.js]
|
||||
function Multimap4() {
|
||||
this._map = {};
|
||||
};
|
||||
|
||||
Multimap4["prototype"] = {
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {number} the value ok
|
||||
*/
|
||||
get(key) {
|
||||
return this._map[key + ''];
|
||||
}
|
||||
};
|
||||
|
||||
Multimap4["prototype"]["add-on"] = function() {};
|
||||
Multimap4["prototype"]["addon"] = function() {};
|
||||
Multimap4["prototype"]["__underscores__"] = function() {};
|
||||
|
||||
const map4 = new Multimap4();
|
||||
map4.get("");
|
||||
map4["add-on"]();
|
||||
map4.addon();
|
||||
map4.__underscores__();
|
||||
|
||||
|
||||
|
||||
|
||||
//// [a.d.ts]
|
||||
declare function Multimap4(): void;
|
||||
declare class Multimap4 {
|
||||
_map: {};
|
||||
"add-on"(): void;
|
||||
addon(): void;
|
||||
__underscores__(): void;
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {number} the value ok
|
||||
*/
|
||||
get(key: string): number;
|
||||
}
|
||||
declare const map4: Multimap4;
|
|
@ -0,0 +1,64 @@
|
|||
=== tests/cases/conformance/salsa/a.js ===
|
||||
function Multimap4() {
|
||||
>Multimap4 : Symbol(Multimap4, Decl(a.js, 0, 0), Decl(a.js, 2, 2))
|
||||
|
||||
this._map = {};
|
||||
>_map : Symbol(Multimap4._map, Decl(a.js, 0, 22))
|
||||
|
||||
};
|
||||
|
||||
Multimap4["prototype"] = {
|
||||
>Multimap4 : Symbol(Multimap4, Decl(a.js, 0, 0), Decl(a.js, 2, 2))
|
||||
>"prototype" : Symbol(Multimap4["prototype"], Decl(a.js, 2, 2))
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {number} the value ok
|
||||
*/
|
||||
get(key) {
|
||||
>get : Symbol(get, Decl(a.js, 4, 26))
|
||||
>key : Symbol(key, Decl(a.js, 9, 6))
|
||||
|
||||
return this._map[key + ''];
|
||||
>this._map : Symbol(Multimap4._map, Decl(a.js, 0, 22))
|
||||
>this : Symbol(Multimap4, Decl(a.js, 0, 0), Decl(a.js, 2, 2))
|
||||
>_map : Symbol(Multimap4._map, Decl(a.js, 0, 22))
|
||||
>key : Symbol(key, Decl(a.js, 9, 6))
|
||||
}
|
||||
};
|
||||
|
||||
Multimap4["prototype"]["add-on"] = function() {};
|
||||
>Multimap4 : Symbol(Multimap4, Decl(a.js, 0, 0), Decl(a.js, 2, 2))
|
||||
>"prototype" : Symbol(Multimap4["prototype"], Decl(a.js, 2, 2))
|
||||
|
||||
Multimap4["prototype"]["addon"] = function() {};
|
||||
>Multimap4 : Symbol(Multimap4, Decl(a.js, 0, 0), Decl(a.js, 2, 2))
|
||||
>"prototype" : Symbol(Multimap4["prototype"], Decl(a.js, 2, 2))
|
||||
|
||||
Multimap4["prototype"]["__underscores__"] = function() {};
|
||||
>Multimap4 : Symbol(Multimap4, Decl(a.js, 0, 0), Decl(a.js, 2, 2))
|
||||
>"prototype" : Symbol(Multimap4["prototype"], Decl(a.js, 2, 2))
|
||||
|
||||
const map4 = new Multimap4();
|
||||
>map4 : Symbol(map4, Decl(a.js, 18, 5))
|
||||
>Multimap4 : Symbol(Multimap4, Decl(a.js, 0, 0), Decl(a.js, 2, 2))
|
||||
|
||||
map4.get("");
|
||||
>map4.get : Symbol(get, Decl(a.js, 4, 26))
|
||||
>map4 : Symbol(map4, Decl(a.js, 18, 5))
|
||||
>get : Symbol(get, Decl(a.js, 4, 26))
|
||||
|
||||
map4["add-on"]();
|
||||
>map4 : Symbol(map4, Decl(a.js, 18, 5))
|
||||
>"add-on" : Symbol(Multimap4["add-on"], Decl(a.js, 12, 2))
|
||||
|
||||
map4.addon();
|
||||
>map4.addon : Symbol(Multimap4["addon"], Decl(a.js, 14, 49))
|
||||
>map4 : Symbol(map4, Decl(a.js, 18, 5))
|
||||
>addon : Symbol(Multimap4["addon"], Decl(a.js, 14, 49))
|
||||
|
||||
map4.__underscores__();
|
||||
>map4.__underscores__ : Symbol(Multimap4["__underscores__"], Decl(a.js, 15, 48))
|
||||
>map4 : Symbol(map4, Decl(a.js, 18, 5))
|
||||
>__underscores__ : Symbol(Multimap4["__underscores__"], Decl(a.js, 15, 48))
|
||||
|
96
tests/baselines/reference/typeFromPrototypeAssignment4.types
Normal file
96
tests/baselines/reference/typeFromPrototypeAssignment4.types
Normal file
|
@ -0,0 +1,96 @@
|
|||
=== tests/cases/conformance/salsa/a.js ===
|
||||
function Multimap4() {
|
||||
>Multimap4 : typeof Multimap4
|
||||
|
||||
this._map = {};
|
||||
>this._map = {} : {}
|
||||
>this._map : any
|
||||
>this : any
|
||||
>_map : any
|
||||
>{} : {}
|
||||
|
||||
};
|
||||
|
||||
Multimap4["prototype"] = {
|
||||
>Multimap4["prototype"] = { /** * @param {string} key * @returns {number} the value ok */ get(key) { return this._map[key + '']; }} : { get(key: string): number; }
|
||||
>Multimap4["prototype"] : { get(key: string): number; }
|
||||
>Multimap4 : typeof Multimap4
|
||||
>"prototype" : "prototype"
|
||||
>{ /** * @param {string} key * @returns {number} the value ok */ get(key) { return this._map[key + '']; }} : { get(key: string): number; }
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {number} the value ok
|
||||
*/
|
||||
get(key) {
|
||||
>get : (key: string) => number
|
||||
>key : string
|
||||
|
||||
return this._map[key + ''];
|
||||
>this._map[key + ''] : any
|
||||
>this._map : {}
|
||||
>this : this
|
||||
>_map : {}
|
||||
>key + '' : string
|
||||
>key : string
|
||||
>'' : ""
|
||||
}
|
||||
};
|
||||
|
||||
Multimap4["prototype"]["add-on"] = function() {};
|
||||
>Multimap4["prototype"]["add-on"] = function() {} : () => void
|
||||
>Multimap4["prototype"]["add-on"] : any
|
||||
>Multimap4["prototype"] : { get(key: string): number; }
|
||||
>Multimap4 : typeof Multimap4
|
||||
>"prototype" : "prototype"
|
||||
>"add-on" : "add-on"
|
||||
>function() {} : () => void
|
||||
|
||||
Multimap4["prototype"]["addon"] = function() {};
|
||||
>Multimap4["prototype"]["addon"] = function() {} : () => void
|
||||
>Multimap4["prototype"]["addon"] : any
|
||||
>Multimap4["prototype"] : { get(key: string): number; }
|
||||
>Multimap4 : typeof Multimap4
|
||||
>"prototype" : "prototype"
|
||||
>"addon" : "addon"
|
||||
>function() {} : () => void
|
||||
|
||||
Multimap4["prototype"]["__underscores__"] = function() {};
|
||||
>Multimap4["prototype"]["__underscores__"] = function() {} : () => void
|
||||
>Multimap4["prototype"]["__underscores__"] : any
|
||||
>Multimap4["prototype"] : { get(key: string): number; }
|
||||
>Multimap4 : typeof Multimap4
|
||||
>"prototype" : "prototype"
|
||||
>"__underscores__" : "__underscores__"
|
||||
>function() {} : () => void
|
||||
|
||||
const map4 = new Multimap4();
|
||||
>map4 : Multimap4
|
||||
>new Multimap4() : Multimap4
|
||||
>Multimap4 : typeof Multimap4
|
||||
|
||||
map4.get("");
|
||||
>map4.get("") : number
|
||||
>map4.get : (key: string) => number
|
||||
>map4 : Multimap4
|
||||
>get : (key: string) => number
|
||||
>"" : ""
|
||||
|
||||
map4["add-on"]();
|
||||
>map4["add-on"]() : void
|
||||
>map4["add-on"] : () => void
|
||||
>map4 : Multimap4
|
||||
>"add-on" : "add-on"
|
||||
|
||||
map4.addon();
|
||||
>map4.addon() : void
|
||||
>map4.addon : () => void
|
||||
>map4 : Multimap4
|
||||
>addon : () => void
|
||||
|
||||
map4.__underscores__();
|
||||
>map4.__underscores__() : void
|
||||
>map4.__underscores__ : () => void
|
||||
>map4 : Multimap4
|
||||
>__underscores__ : () => void
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// @allowJs: true
|
||||
// @strict: true
|
||||
// @checkJs: true
|
||||
// @emitDeclarationOnly: true
|
||||
// @declaration: true
|
||||
// @filename: mod1.js
|
||||
exports.a = { x: "x" };
|
||||
exports["b"] = { x: "x" };
|
||||
exports["default"] = { x: "x" };
|
||||
module.exports["c"] = { x: "x" };
|
||||
module["exports"]["d"] = {};
|
||||
module["exports"]["d"].e = 0;
|
||||
|
||||
// @filename: mod2.js
|
||||
const mod1 = require("./mod1");
|
||||
mod1.a;
|
||||
mod1.b;
|
||||
mod1.c;
|
||||
mod1.d;
|
||||
mod1.d.e;
|
||||
mod1.default;
|
30
tests/cases/conformance/salsa/thisPropertyAssignment.ts
Normal file
30
tests/cases/conformance/salsa/thisPropertyAssignment.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
// @checkJs: true
|
||||
// @allowJs: true
|
||||
// @strict: true
|
||||
// @emitDeclarationOnly: true
|
||||
// @declaration: true
|
||||
// @Filename: a.js
|
||||
|
||||
// This test is asserting that a single property/element access
|
||||
// on `this` is a special assignment declaration, but chaining
|
||||
// off that does not create additional declarations. I’m not sure
|
||||
// if it needs to be that way in JavaScript; the test simply
|
||||
// ensures no accidental changes were introduced while allowing
|
||||
// element access assignments to create declarations.
|
||||
|
||||
this.x = {};
|
||||
this.x.y = {};
|
||||
this["y"] = {};
|
||||
this["y"]["z"] = {};
|
||||
|
||||
/** @constructor */
|
||||
function F() {
|
||||
this.a = {};
|
||||
this.a.b = {};
|
||||
this["b"] = {};
|
||||
this["b"]["c"] = {};
|
||||
}
|
||||
|
||||
const f = new F();
|
||||
f.a;
|
||||
f.b;
|
|
@ -0,0 +1,9 @@
|
|||
// @noEmit: true
|
||||
// @strict: true
|
||||
// @declaration: true
|
||||
|
||||
function F() {}
|
||||
F["prop"] = 3;
|
||||
|
||||
const f = function () {};
|
||||
f["prop"] = 3;
|
|
@ -0,0 +1,10 @@
|
|||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @strict: true
|
||||
// @emitDeclarationOnly: true
|
||||
// @declaration: true
|
||||
// @Filename: a.js
|
||||
|
||||
const foo = {};
|
||||
foo["baz"] = {};
|
||||
foo["baz"]["blah"] = 3;
|
|
@ -0,0 +1,30 @@
|
|||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @emitDeclarationOnly: true
|
||||
// @declaration: true
|
||||
// @outDir: out
|
||||
// @Filename: a.js
|
||||
|
||||
function Multimap4() {
|
||||
this._map = {};
|
||||
};
|
||||
|
||||
Multimap4["prototype"] = {
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns {number} the value ok
|
||||
*/
|
||||
get(key) {
|
||||
return this._map[key + ''];
|
||||
}
|
||||
};
|
||||
|
||||
Multimap4["prototype"]["add-on"] = function() {};
|
||||
Multimap4["prototype"]["addon"] = function() {};
|
||||
Multimap4["prototype"]["__underscores__"] = function() {};
|
||||
|
||||
const map4 = new Multimap4();
|
||||
map4.get("");
|
||||
map4["add-on"]();
|
||||
map4.addon();
|
||||
map4.__underscores__();
|
|
@ -0,0 +1,7 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
////function f() {}
|
||||
////f[/*0*/"x"] = 0;
|
||||
////f[[|/*1*/"x"|]] = 1;
|
||||
|
||||
verify.goToDefinition("1", "0");
|
|
@ -7,13 +7,19 @@
|
|||
////A.prototype = { m() {} };
|
||||
////A.prototype.a = function() { };
|
||||
////A.b = function() { };
|
||||
////
|
||||
////var B;
|
||||
////B["prototype"] = { };
|
||||
////B["prototype"] = { m() {} };
|
||||
////B["prototype"]["a"] = function() { };
|
||||
////B["b"] = function() { };
|
||||
|
||||
verify.navigationTree({
|
||||
"text": "<global>",
|
||||
"kind": "script",
|
||||
"childItems": [
|
||||
"childItems": [{ name: "A", quoted: false }, { name: "B", quoted: true }].map(({ name, quoted }) => (
|
||||
{
|
||||
"text": "A",
|
||||
"text": name,
|
||||
"kind": "class",
|
||||
"childItems": [
|
||||
{
|
||||
|
@ -25,31 +31,31 @@ verify.navigationTree({
|
|||
"kind": "method"
|
||||
},
|
||||
{
|
||||
"text": "a",
|
||||
"text": quoted ? `"a"` : "a",
|
||||
"kind": "function"
|
||||
},
|
||||
{
|
||||
"text": "b",
|
||||
"text": quoted ? `"b"` : "b",
|
||||
"kind": "function"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
))
|
||||
});
|
||||
|
||||
verify.navigationBar([
|
||||
{
|
||||
"text": "<global>",
|
||||
"kind": "script",
|
||||
"childItems": [
|
||||
"childItems": ["A", "B"].map(name => (
|
||||
{
|
||||
"text": "A",
|
||||
"text": name,
|
||||
"kind": "class"
|
||||
}
|
||||
]
|
||||
))
|
||||
},
|
||||
{
|
||||
"text": "A",
|
||||
...[{ name: "A", quoted: false }, { name: "B", quoted: true }].map(({ name, quoted }) => ({
|
||||
"text": name,
|
||||
"kind": "class",
|
||||
"childItems": [
|
||||
{
|
||||
|
@ -61,14 +67,14 @@ verify.navigationBar([
|
|||
"kind": "method"
|
||||
},
|
||||
{
|
||||
"text": "a",
|
||||
"text": quoted ? `"a"` : "a",
|
||||
"kind": "function"
|
||||
},
|
||||
{
|
||||
"text": "b",
|
||||
"text": quoted ? `"b"` : "b",
|
||||
"kind": "function"
|
||||
}
|
||||
],
|
||||
"indent": 1
|
||||
}
|
||||
}))
|
||||
]);
|
||||
|
|
12
tests/cases/fourslash/quickInfoElementAccessDeclaration.ts
Normal file
12
tests/cases/fourslash/quickInfoElementAccessDeclaration.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @checkJs: true
|
||||
// @allowJs: true
|
||||
// @Filename: a.js
|
||||
////const mod = {};
|
||||
////mod["@@thing1"] = {};
|
||||
////mod["/**/@@thing1"]["@@thing2"] = 0;
|
||||
|
||||
goTo.marker();
|
||||
verify.quickInfoIs(`module mod["@@thing1"]
|
||||
(property) mod["@@thing1"]: typeof mod.@@thing1`);
|
Loading…
Reference in a new issue