-
Notifications
You must be signed in to change notification settings - Fork 14
Parse Private Names #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14346,8 +14346,10 @@ namespace ts { | |
const root = getReferenceRoot(node); | ||
const parent = root.parent; | ||
const isLengthPushOrUnshift = parent.kind === SyntaxKind.PropertyAccessExpression && ( | ||
(<PropertyAccessExpression>parent).name.escapedText === "length" || | ||
parent.parent.kind === SyntaxKind.CallExpression && isPushOrUnshiftIdentifier((<PropertyAccessExpression>parent).name)); | ||
(<PropertyAccessExpression>parent).name.escapedText === "length" || ( | ||
parent.parent.kind === SyntaxKind.CallExpression | ||
&& isIdentifier((parent as PropertyAccessExpression).name) | ||
&& isPushOrUnshiftIdentifier((parent as PropertyAccessExpression).name as Identifier))); | ||
const isElementAssignment = parent.kind === SyntaxKind.ElementAccessExpression && | ||
(<ElementAccessExpression>parent).expression === root && | ||
parent.parent.kind === SyntaxKind.BinaryExpression && | ||
|
@@ -17972,7 +17974,7 @@ namespace ts { | |
return checkPropertyAccessExpressionOrQualifiedName(node, node.left, node.right); | ||
} | ||
|
||
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier) { | ||
function checkPropertyAccessExpressionOrQualifiedName(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, right: Identifier | PrivateName) { | ||
let propType: Type; | ||
const leftType = checkNonNullExpression(left); | ||
const parentSymbol = getNodeLinks(left).resolvedSymbol; | ||
|
@@ -17990,7 +17992,7 @@ namespace ts { | |
} | ||
if (!prop) { | ||
const indexInfo = getIndexInfoOfType(apparentType, IndexKind.String); | ||
if (!(indexInfo && indexInfo.type)) { | ||
if (!(indexInfo && indexInfo.type) || isPrivateName(right)) { | ||
if (isJSLiteralType(leftType)) { | ||
return anyType; | ||
} | ||
|
@@ -18048,7 +18050,7 @@ namespace ts { | |
return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType; | ||
} | ||
|
||
function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | QualifiedName, right: Identifier): void { | ||
function checkPropertyNotUsedBeforeDeclaration(prop: Symbol, node: PropertyAccessExpression | QualifiedName, right: Identifier | PrivateName): void { | ||
const { valueDeclaration } = prop; | ||
if (!valueDeclaration) { | ||
return; | ||
|
@@ -18118,7 +18120,7 @@ namespace ts { | |
return getIntersectionType(x); | ||
} | ||
|
||
function reportNonexistentProperty(propNode: Identifier, containingType: Type) { | ||
function reportNonexistentProperty(propNode: Identifier | PrivateName, containingType: Type) { | ||
let errorInfo: DiagnosticMessageChain | undefined; | ||
let relatedInfo: Diagnostic | undefined; | ||
if (containingType.flags & TypeFlags.Union && !(containingType.flags & TypeFlags.Primitive)) { | ||
|
@@ -18161,11 +18163,11 @@ namespace ts { | |
return prop !== undefined && prop.valueDeclaration && hasModifier(prop.valueDeclaration, ModifierFlags.Static); | ||
} | ||
|
||
function getSuggestedSymbolForNonexistentProperty(name: Identifier | string, containingType: Type): Symbol | undefined { | ||
function getSuggestedSymbolForNonexistentProperty(name: Identifier | PrivateName | string, containingType: Type): Symbol | undefined { | ||
return getSpellingSuggestionForName(isString(name) ? name : idText(name), getPropertiesOfType(containingType), SymbolFlags.Value); | ||
} | ||
|
||
function getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined { | ||
function getSuggestionForNonexistentProperty(name: Identifier | PrivateName | string, containingType: Type): string | undefined { | ||
const suggestion = getSuggestedSymbolForNonexistentProperty(name, containingType); | ||
return suggestion && symbolName(suggestion); | ||
} | ||
|
@@ -21876,6 +21878,9 @@ namespace ts { | |
checkGrammarDecoratorsAndModifiers(node); | ||
|
||
checkVariableLikeDeclaration(node); | ||
if (node.name && isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) { | ||
error(node, Diagnostics.Private_names_cannot_be_used_as_parameters); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we plan to undo this change is in #5 |
||
} | ||
const func = getContainingFunction(node)!; | ||
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) { | ||
if (!(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body))) { | ||
|
@@ -23523,9 +23528,9 @@ namespace ts { | |
} | ||
} | ||
|
||
function getIdentifierFromEntityNameExpression(node: Identifier | PropertyAccessExpression): Identifier; | ||
function getIdentifierFromEntityNameExpression(node: Expression): Identifier | undefined; | ||
function getIdentifierFromEntityNameExpression(node: Expression): Identifier | undefined { | ||
function getIdentifierFromEntityNameExpression(node: Identifier | PropertyAccessExpression): Identifier | PrivateName; | ||
function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateName | undefined; | ||
function getIdentifierFromEntityNameExpression(node: Expression): Identifier | PrivateName | undefined { | ||
switch (node.kind) { | ||
case SyntaxKind.Identifier: | ||
return node as Identifier; | ||
|
@@ -29288,6 +29293,10 @@ namespace ts { | |
checkESModuleMarker(node.name); | ||
} | ||
|
||
if (isIdentifier(node.name) && node.name.originalKeywordKind === SyntaxKind.PrivateName) { | ||
return grammarErrorOnNode(node.name, Diagnostics.Private_names_are_not_allowed_in_variable_declarations); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we plan to undo this change in #5 |
||
|
||
const checkLetConstNames = (isLet(node) || isVarConst(node)); | ||
|
||
// 1. LexicalDeclaration : LetOrConst BindingList ; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,7 +105,7 @@ namespace ts { | |
return node; | ||
} | ||
|
||
function createLiteralFromNode(sourceNode: PropertyNameLiteral): StringLiteral { | ||
function createLiteralFromNode(sourceNode: Exclude<PropertyNameLiteral, PrivateName>): StringLiteral { | ||
const node = createStringLiteral(getTextOfIdentifierOrLiteral(sourceNode)); | ||
node.textSourceNode = sourceNode; | ||
return node; | ||
|
@@ -995,15 +995,15 @@ namespace ts { | |
: node; | ||
} | ||
|
||
export function createPropertyAccess(expression: Expression, name: string | Identifier | undefined) { | ||
export function createPropertyAccess(expression: Expression, name: string | Identifier | PrivateName | undefined) { | ||
const node = <PropertyAccessExpression>createSynthesizedNode(SyntaxKind.PropertyAccessExpression); | ||
node.expression = parenthesizeForAccess(expression); | ||
node.name = asName(name)!; // TODO: GH#18217 | ||
setEmitFlags(node, EmitFlags.NoIndentation); | ||
return node; | ||
} | ||
|
||
export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier) { | ||
export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier | PrivateName) { | ||
// Because we are updating existed propertyAccess we want to inherit its emitFlags | ||
// instead of using the default from createPropertyAccess | ||
return node.expression !== expression | ||
|
@@ -2714,7 +2714,7 @@ namespace ts { | |
|
||
// Utilities | ||
|
||
function asName<T extends Identifier | BindingName | PropertyName | EntityName | ThisTypeNode | undefined>(name: string | T): T | Identifier { | ||
function asName<T extends Identifier | PrivateName | BindingName | PropertyName | EntityName | ThisTypeNode | undefined>(name: string | T): T | Identifier { | ||
return isString(name) ? createIdentifier(name) : name; | ||
} | ||
|
||
|
@@ -3099,7 +3099,7 @@ namespace ts { | |
} | ||
else { | ||
const expression = setTextRange( | ||
isIdentifier(memberName) | ||
(isIdentifier(memberName) || isPrivateName(memberName)) | ||
? createPropertyAccess(target, memberName) | ||
: createElementAccess(target, memberName), | ||
memberName | ||
|
@@ -3529,7 +3529,7 @@ namespace ts { | |
} | ||
} | ||
|
||
export function createExpressionForPropertyName(memberName: PropertyName): Expression { | ||
export function createExpressionForPropertyName(memberName: Exclude<PropertyName, PrivateName>): Expression { | ||
if (isIdentifier(memberName)) { | ||
return createLiteral(memberName); | ||
} | ||
|
@@ -3541,11 +3541,17 @@ namespace ts { | |
} | ||
} | ||
|
||
/** | ||
* accessor declaration that can be converted to an expression (`name` field cannot be a `PrivateName`) | ||
*/ | ||
type ExpressionableAccessorDeclaration = AccessorDeclaration & {name: Exclude<PropertyName, PrivateName>}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be more consistent to define like this: interface ExpressionableAccessorDeclaration extends AccessorDeclaration {
name: Exclude<PropertyName, PrivateName>;
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yours is easier on the eyes, for sure. But since AccessorDeclaration is a type it seems more consistent to me for ExpressionableAccessorDeclaration to be a type. |
||
|
||
export function createExpressionForObjectLiteralElementLike(node: ObjectLiteralExpression, property: ObjectLiteralElementLike, receiver: Expression): Expression | undefined { | ||
switch (property.kind) { | ||
case SyntaxKind.GetAccessor: | ||
case SyntaxKind.SetAccessor: | ||
return createExpressionForAccessorDeclaration(node.properties, property, receiver, !!node.multiLine); | ||
// type assertion `as ExpressionableAccessorDeclaration` is safe because PrivateNames are not allowed in object literals | ||
return createExpressionForAccessorDeclaration(node.properties, property as ExpressionableAccessorDeclaration, receiver, !!node.multiLine); | ||
case SyntaxKind.PropertyAssignment: | ||
return createExpressionForPropertyAssignment(property, receiver); | ||
case SyntaxKind.ShorthandPropertyAssignment: | ||
|
@@ -3555,7 +3561,7 @@ namespace ts { | |
} | ||
} | ||
|
||
function createExpressionForAccessorDeclaration(properties: NodeArray<Declaration>, property: AccessorDeclaration, receiver: Expression, multiLine: boolean) { | ||
function createExpressionForAccessorDeclaration(properties: NodeArray<Declaration>, property: ExpressionableAccessorDeclaration, receiver: Expression, multiLine: boolean) { | ||
const { firstAccessor, getAccessor, setAccessor } = getAllAccessorDeclarations(properties, property); | ||
if (property === firstAccessor) { | ||
const properties: ObjectLiteralElementLike[] = []; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ignore this: it's a mistake and to be removed in #5. Actually has no effect, since there is no way the
node
can be a private name here anyway.