Skip to content

Commit 5946ce2

Browse files
author
Max Heiber
committed
start private methods again
1 parent 666a02c commit 5946ce2

File tree

1 file changed

+96
-25
lines changed

1 file changed

+96
-25
lines changed

src/compiler/transformers/esnext.ts

Lines changed: 96 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,29 @@ namespace ts {
1010
ClassAliases = 1 << 1,
1111
}
1212

13+
1314
/**
1415
* A mapping of private names to information needed for transformation.
1516
*/
16-
type PrivateNameEnvironment = UnderscoreEscapedMap<PrivateNamedInstanceField>;
17+
type PrivateNameEnvironment = UnderscoreEscapedMap<PrivateNamedInstanceField | PrivateNamedInstanceMethod>;
1718

1819
/**
1920
* Identifies the type of private name.
2021
*/
21-
const enum PrivateNameType {
22-
InstanceField
22+
const enum PrivateNamePlacement {
23+
InstanceField,
24+
InstanceMethod
2325
}
2426

2527
interface PrivateNamedInstanceField {
26-
type: PrivateNameType.InstanceField;
27-
weakMapName: Identifier;
28+
placement: PrivateNamePlacement.InstanceField;
29+
accumulator: Identifier;
30+
}
31+
32+
interface PrivateNamedInstanceMethod {
33+
placement: PrivateNamePlacement.InstanceMethod;
34+
accumulator: Identifier;
35+
funcName: Identifier;
2836
}
2937

3038
export function transformESNext(context: TransformationContext) {
@@ -365,8 +373,9 @@ namespace ts {
365373

366374
function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
367375
// Declare private names.
368-
const privateProperties = filter(node.members, isPrivatePropertyDeclaration);
369-
privateProperties.forEach(property => addPrivateNameToEnvironment(property.name));
376+
node.members
377+
.filter(element => isNamedDeclaration(element) && isPrivateName(element.name))
378+
.forEach(addPrivateName);
370379

371380
const members: ClassElement[] = [];
372381
const constructor = transformConstructor(node, isDerivedClass);
@@ -528,10 +537,10 @@ namespace ts {
528537
if (isPrivateName(propertyName)) {
529538
const privateNameInfo = accessPrivateName(propertyName);
530539
if (privateNameInfo) {
531-
switch (privateNameInfo.type) {
532-
case PrivateNameType.InstanceField: {
540+
switch (privateNameInfo.placement) {
541+
case PrivateNamePlacement.InstanceField: {
533542
return createCall(
534-
createPropertyAccess(privateNameInfo.weakMapName, "set"),
543+
createPropertyAccess(privateNameInfo.accumulator, "set"),
535544
/*typeArguments*/ undefined,
536545
[receiver, initializer || createVoidZero()]
537546
);
@@ -557,17 +566,68 @@ namespace ts {
557566
privateNameEnvironmentStack.pop();
558567
}
559568

560-
function addPrivateNameToEnvironment(name: PrivateName) {
569+
function privateNamedMethodToFunction (declaration: MethodDeclaration, funcName: Identifier, accumulator: Identifier): FunctionDeclaration {
570+
const params = declaration.parameters;
571+
let body = getMutableClone(declaration.body || createBlock([], true));
572+
body = visitEachChild(body, visitor, context);
573+
const toPrepend = startOnNewLine(
574+
createStatement(
575+
createClassPrivateNamedCallCheckHelper(context, accumulator)
576+
)
577+
);
578+
body.statements = setTextRange(
579+
createNodeArray([
580+
toPrepend,
581+
...body.statements
582+
]),
583+
body.statements
584+
);
585+
const func = createFunctionDeclaration(
586+
/* decorators */ undefined,
587+
/* modifiers */ undefined,
588+
/* asteriskToken */ undefined,
589+
funcName,
590+
/* typeParameters */ undefined,
591+
params,
592+
/* type */ undefined,
593+
body) as FunctionDeclaration;
594+
return func;
595+
}
596+
597+
598+
function addPrivateName(element: ClassElement & { name: PrivateName }) {
561599
const env = last(privateNameEnvironmentStack);
562-
const text = getTextOfPropertyName(name) as string;
563-
const weakMapName = createFileLevelUniqueName("_" + text.substring(1));
564-
hoistVariableDeclaration(weakMapName);
565-
env.set(name.escapedText, { type: PrivateNameType.InstanceField, weakMapName });
566-
(pendingExpressions || (pendingExpressions = [])).push(
600+
const text = getTextOfPropertyName(element.name) as string;
601+
const accumulator = createFileLevelUniqueName("_" + text.substring(1));
602+
const { escapedText } = element.name;
603+
hoistVariableDeclaration(accumulator);
604+
605+
let identifierName: string;
606+
if (hasModifier(element, ModifierFlags.Static)) {
607+
// statics not supported yet
608+
return;
609+
}
610+
if (isPropertyDeclaration(element)) {
611+
identifierName = "WeakMap";
612+
env.set(escapedText, { placement: PrivateNamePlacement.InstanceField, accumulator });
613+
}
614+
else if (isMethodDeclaration(element)) {
615+
identifierName = "WeakSet";
616+
const escapedText = element.name.escapedText;
617+
const escapedTextNoHash = `_${`${escapedText}`.slice(1)}`;
618+
const funcName: Identifier = createFileLevelUniqueName(escapedTextNoHash);
619+
const func = privateNamedMethodToFunction(element, funcName, accumulator);
620+
env.set(escapedText, { placement: PrivateNamePlacement.InstanceMethod, accumulator, funcName });
621+
(pendingStatements = pendingStatements || []).push(func);
622+
}
623+
else {
624+
return;
625+
}
626+
(pendingExpressions = pendingExpressions || []).push(
567627
createAssignment(
568-
weakMapName,
628+
accumulator,
569629
createNew(
570-
createIdentifier("WeakMap"),
630+
createIdentifier(identifierName),
571631
/*typeArguments*/ undefined,
572632
[]
573633
)
@@ -589,14 +649,14 @@ namespace ts {
589649
if (isPrivateName(node.name)) {
590650
const privateNameInfo = accessPrivateName(node.name);
591651
if (privateNameInfo) {
592-
switch (privateNameInfo.type) {
593-
case PrivateNameType.InstanceField:
652+
switch (privateNameInfo.placement) {
653+
case PrivateNamePlacement.InstanceField:
594654
return setOriginalNode(
595655
setTextRange(
596656
createClassPrivateFieldGetHelper(
597657
context,
598658
visitNode(node.expression, visitor, isExpression),
599-
privateNameInfo.weakMapName
659+
privateNameInfo.accumulator
600660
),
601661
node
602662
),
@@ -903,7 +963,7 @@ namespace ts {
903963
}
904964
else if (isAssignmentExpression(node) && isPropertyAccessExpression(node.left) && isPrivateName(node.left.name)) {
905965
const privateNameInfo = accessPrivateName(node.left.name);
906-
if (privateNameInfo && privateNameInfo.type === PrivateNameType.InstanceField) {
966+
if (privateNameInfo && privateNameInfo.placement === PrivateNamePlacement.InstanceField) {
907967
if (isCompoundAssignment(node.operatorToken.kind)) {
908968
const isReceiverInlineable = isSimpleInlineableExpression(node.left.expression);
909969
const getReceiver = isReceiverInlineable ? node.left.expression : createTempVariable(hoistVariableDeclaration);
@@ -914,12 +974,12 @@ namespace ts {
914974
createClassPrivateFieldSetHelper(
915975
context,
916976
setReceiver,
917-
privateNameInfo.weakMapName,
977+
privateNameInfo.accumulator,
918978
createBinary(
919979
createClassPrivateFieldGetHelper(
920980
context,
921981
getReceiver,
922-
privateNameInfo.weakMapName
982+
privateNameInfo.accumulator
923983
),
924984
getOperatorForCompoundAssignment(node.operatorToken.kind),
925985
visitNode(node.right, visitor)
@@ -933,7 +993,7 @@ namespace ts {
933993
createClassPrivateFieldSetHelper(
934994
context,
935995
node.left.expression,
936-
privateNameInfo.weakMapName,
996+
privateNameInfo.accumulator,
937997
visitNode(node.right, visitor)
938998
),
939999
node
@@ -1789,4 +1849,15 @@ namespace ts {
17891849
context.requestEmitHelper(classPrivateFieldSetHelper);
17901850
return createCall(getHelperName("_classPrivateFieldSet"), /* typeArguments */ undefined, [receiver, privateField, value]);
17911851
}
1852+
const classPrivateNamedCallCheckHelper: EmitHelper = {
1853+
name: "typescript:classPrivateNamedCallCheck",
1854+
scoped: false,
1855+
text: `var _classPrivateNamedCallCheck = function (receiver, privateSet) { if (!privateSet.has(receiver)) { throw new TypeError("attempted to get weak field on non-instance"); }};`
1856+
};
1857+
1858+
function createClassPrivateNamedCallCheckHelper(context: TransformationContext, weakSet: Identifier) {
1859+
context.requestEmitHelper(classPrivateNamedCallCheckHelper);
1860+
return createCall(getHelperName("_classPrivateNamedCallCheck"), /* typeArguments */ undefined, [ createThis(), weakSet ]);
1861+
}
1862+
17921863
}

0 commit comments

Comments
 (0)