- Notifications
You must be signed in to change notification settings - Fork13.2k
ES private class elements#42458
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Changes from1 commit
e3a3fb84ab27a26977b9fbc8c07e2760ed804af85df048d72f8cfb814aa4c3b0ac12717da5bd9e133f60aa5dd8aa3889a78952caadee87bbaec7e9bf3bbf0fa1b59cd6b74498d51f6cdc1757704301af53a056b295df2d1590124e219ea8325da8caa2228beff4f737704727c73925dc67fd38d45c2a41356b91db3914645ebb3d67006c09b87661331a8c009219e995a27a32964fc27d2ab6fc23f6c67374e6f362b4f2fb2a692d363041e64757e068a7f807e7b0b130c7f69c924058e65116f4748c8709a5aae497e47f294cc48027bdb37bbc944dd526e7f6ecfab6c3f661ef69c6c2a646edd8136f7fbd749cf96eafe2de8a437490a36c2732581addbb3c461b92a61fd5f89f746aff24636a60e429f5816ab3b62d3c7d8a2b9d0d205593a7ca36da2cdd30805b78d77a8e8078ae0File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading.Please reload this page.
Jump to
Uh oh!
There was an error while loading.Please reload this page.
Diff view
Diff view
Signed-off-by: Kubilay Kahveci <kahvecikubilay@gmail.com>
- Loading branch information
Uh oh!
There was an error while loading.Please reload this page.
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -11,11 +11,13 @@ namespace ts { | ||
| const enum PrivateIdentifierPlacement { | ||
| InstanceField, | ||
| InstanceMethod, | ||
| InstanceAccessor | ||
| } | ||
| type PrivateIdentifierInfo = | ||
| | PrivateIdentifierInstanceField | ||
| | PrivateIdentifierInstanceMethod | ||
| | PrivateIdentifierInstanceAccessor; | ||
| interface PrivateIdentifierInstanceField { | ||
| placement: PrivateIdentifierPlacement.InstanceField; | ||
| @@ -27,6 +29,12 @@ namespace ts { | ||
| functionName: Identifier; | ||
| } | ||
| interface PrivateIdentifierInstanceAccessor { | ||
| placement: PrivateIdentifierPlacement.InstanceAccessor; | ||
| getterName?: Identifier; | ||
| setterName?: Identifier; | ||
| } | ||
| interface PrivateIdentifierEnvironment { | ||
| /** | ||
| * Used for prefixing generated variable names. | ||
| @@ -166,8 +174,7 @@ namespace ts { | ||
| case SyntaxKind.GetAccessor: | ||
| case SyntaxKind.SetAccessor: | ||
| return visitMethodDeclaration(node as AccessorDeclaration); | ||
| case SyntaxKind.MethodDeclaration: | ||
| return visitMethodDeclaration(node as MethodDeclaration); | ||
| @@ -213,7 +220,7 @@ namespace ts { | ||
| return node; | ||
| } | ||
| function visitMethodDeclaration(node: MethodDeclaration | AccessorDeclaration) { | ||
dragomirtitian marked this conversation as resolved. OutdatedShow resolvedHide resolvedUh oh!There was an error while loading.Please reload this page. | ||
| Debug.assert(!some(node.decorators)); | ||
| const transformedMethod = visitEachChild(node, classElementVisitor, context); | ||
| ||
| @@ -241,7 +248,7 @@ namespace ts { | ||
| return undefined; | ||
| } | ||
| function getHoistedFunctionName(node: MethodDeclaration | AccessorDeclaration) { | ||
| Debug.assert(isPrivateIdentifier(node.name)); | ||
| const privateIdentifierInfo = accessPrivateIdentifier(node.name); | ||
| Debug.assert(privateIdentifierInfo, "Undeclared private name for property declaration."); | ||
| @@ -250,6 +257,17 @@ namespace ts { | ||
| return privateIdentifierInfo.functionName; | ||
| } | ||
| if (privateIdentifierInfo.placement === PrivateIdentifierPlacement.InstanceAccessor) { | ||
| if (isGetAccessor(node)) { | ||
| Debug.assert(privateIdentifierInfo.getterName); | ||
| return privateIdentifierInfo.getterName; | ||
| } | ||
| if (isSetAccessor(node)) { | ||
| Debug.assert(privateIdentifierInfo.setterName); | ||
| return privateIdentifierInfo.setterName; | ||
| } | ||
| } | ||
| Debug.fail("Unexpected private identifier placement"); | ||
| } | ||
| @@ -296,6 +314,13 @@ namespace ts { | ||
| getPrivateIdentifierEnvironment().weakSetName, | ||
| info.functionName | ||
| ); | ||
| case PrivateIdentifierPlacement.InstanceAccessor: { | ||
| return context.getEmitHelperFactory().createClassPrivateAccessorGetHelper( | ||
| receiver, | ||
| getPrivateIdentifierEnvironment().weakSetName, | ||
| info.getterName! // TODO: TypeError is missing | ||
| ); | ||
| } | ||
| default: return Debug.fail("Unexpected private identifier placement"); | ||
| } | ||
| } | ||
| @@ -502,6 +527,13 @@ namespace ts { | ||
| receiver, | ||
| right | ||
| ); | ||
| case PrivateIdentifierPlacement.InstanceAccessor: | ||
| return context.getEmitHelperFactory().createClassPrivateAccessorSetHelper( | ||
| receiver, | ||
| getPrivateIdentifierEnvironment().weakSetName, | ||
| info.setterName!, // TODO: TypeError if missing | ||
| right | ||
| ); | ||
| default: return Debug.fail("Unexpected private identifier placement"); | ||
| } | ||
| } | ||
| @@ -732,7 +764,10 @@ namespace ts { | ||
| properties = filter(properties, property => !!property.initializer || isPrivateIdentifier(property.name)); | ||
| } | ||
| const privateMethods = filter( | ||
| [...getMethods(node, /*isStatic*/ false), ...getAccessors(node, /*isStatic*/ false)], | ||
| method => isPrivateIdentifier(method.name) | ||
| ); | ||
| const needsConstructorBody = some(properties) || some(privateMethods); | ||
| // Only generate synthetic constructor when there are property initializers to move. | ||
| @@ -928,7 +963,7 @@ namespace ts { | ||
| * @param methods An array of method declarations. | ||
| * @param receiver The receiver on which each method should be assigned. | ||
| */ | ||
| function addMethodStatements(statements: Statement[], methods: readonly (MethodDeclaration | AccessorDeclaration)[], receiver: LeftHandSideExpression) { | ||
| if (!shouldTransformPrivateElements || !some(methods)) { | ||
| return; | ||
| } | ||
| @@ -1039,18 +1074,18 @@ namespace ts { | ||
| function addPrivateIdentifierToEnvironment(node: PrivateClassElementDeclaration) { | ||
| const text = getTextOfPropertyName(node.name) as string; | ||
| let info: PrivateIdentifierInfo; | ||
| const assignmentExpressions: Expression[] = []; | ||
| if (isPropertyDeclaration(node)) { | ||
| const weakMapName = createHoistedVariableForPrivateName(text); | ||
| info = { | ||
| placement: PrivateIdentifierPlacement.InstanceField, | ||
| weakMapName, | ||
| }; | ||
| assignmentExpressions.push(factory.createAssignment( | ||
| weakMapName, | ||
| factory.createNewExpression( | ||
| factory.createIdentifier("WeakMap"), | ||
| /*typeArguments*/ undefined, | ||
| @@ -1061,11 +1096,27 @@ namespace ts { | ||
| else if (isMethodDeclaration(node)) { | ||
| info = { | ||
| placement: PrivateIdentifierPlacement.InstanceMethod, | ||
| functionName:createHoistedVariableForPrivateName(text) | ||
| }; | ||
| getPrivateIdentifierEnvironment().hasPrivateMethods = true; | ||
| } | ||
| else if (isAccessor(node)) { | ||
| const previousInfo = findPreviousAccessorInfo(node); | ||
| info = { | ||
| ...previousInfo, | ||
| placement: PrivateIdentifierPlacement.InstanceAccessor, | ||
| }; | ||
| if (isGetAccessor(node)) { | ||
| info.getterName = createHoistedVariableForPrivateName(text + "_get"); | ||
| } | ||
| else { | ||
| info.setterName = createHoistedVariableForPrivateName(text + "_set");; | ||
| } | ||
| getPrivateIdentifierEnvironment().hasPrivateMethods = true; | ||
| } | ||
| else { | ||
| return; | ||
| } | ||
| @@ -1074,6 +1125,13 @@ namespace ts { | ||
| getPendingExpressions().push(...assignmentExpressions); | ||
| } | ||
| function findPreviousAccessorInfo(node: PrivateIdentifierGetAccessorDeclaration | PrivateIdentifierSetAccessorDeclaration): PrivateIdentifierInstanceAccessor | undefined { | ||
| const info = getPrivateIdentifierEnvironment().identifiers.get(node.name.escapedText); | ||
| if (info && info.placement === PrivateIdentifierPlacement.InstanceAccessor) { | ||
| return info; | ||
| } | ||
| } | ||
| function createHoistedVariableForClass(name: string): Identifier { | ||
| const { className } = getPrivateIdentifierEnvironment(); | ||
| const prefix = className ? `_${className}` : ""; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -347,12 +347,22 @@ namespace ts { | ||
| * Gets all the static or all the instance method declarations of a class. | ||
| * | ||
| * @param node The class node. | ||
| * @param isStatic A value indicating whether to getmethods from the static or instance side of the class. | ||
| */ | ||
| export function getMethods(node: ClassExpression | ClassDeclaration, isStatic: boolean): readonly MethodDeclaration[] { | ||
| ||
| return filter(node.members, m => isStaticMethodDeclaration(m, isStatic)) as MethodDeclaration[]; | ||
| } | ||
| /** | ||
| * Gets all the static or all the instance accessor declarations of a class. | ||
| * | ||
| * @param node The class node. | ||
| * @param isStatic A value indicating whether to get accessors from the static or instance side of the class. | ||
| */ | ||
| export function getAccessors(node: ClassExpression | ClassDeclaration, isStatic: boolean): readonly AccessorDeclaration[] { | ||
| return filter(node.members, m => isStaticAccessorDeclaration(m, isStatic)) as AccessorDeclaration[]; | ||
| } | ||
| /** | ||
| * Is a class element either a static or an instance property declaration with an initializer? | ||
| * | ||
| @@ -386,4 +396,13 @@ namespace ts { | ||
| return isMethodDeclaration(member) && hasStaticModifier(member) === isStatic; | ||
| } | ||
| /** | ||
| * Gets a value indicating whether a class element is either a static or an instance accessor declaration. | ||
| * | ||
| * @param member The class element node. | ||
| * @param isStatic A value indicating whether the member should be a static or instance member. | ||
| */ | ||
| export function isStaticAccessorDeclaration(member: ClassElement, isStatic: boolean): member is AccessorDeclaration { | ||
| return isGetOrSetAccessorDeclaration(member) && hasStaticModifier(member) === isStatic; | ||
| } | ||
| } | ||