Skip to content

Commit

Permalink
chore: update to spec
Browse files Browse the repository at this point in the history
  • Loading branch information
Jack-Works committed Feb 1, 2022
1 parent 2384d95 commit 3d315d6
Showing 1 changed file with 35 additions and 31 deletions.
66 changes: 35 additions & 31 deletions src/compiler/transformers/esnext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ namespace ts {
function visitClassLike(node: ClassDeclaration | ClassExpression) {
const oldClassHasInstanceTracker = currentClassHasInstanceTracker;
currentClassHasInstanceTracker = undefined;
// visit children first so currentClassHasInstanceTracker will be set on demand.
const updated = visitEachChild(node, visitor, context);
if (!currentClassHasInstanceTracker) {
currentClassHasInstanceTracker = oldClassHasInstanceTracker;
Expand All @@ -47,27 +48,8 @@ namespace ts {
)
);

// tracker.add(this);
const track = factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(currentClassHasInstanceTracker, "add"), /** generics */ undefined, [factory.createThis()]));

const originalConstructor = getFirstConstructorWithBody(node);
let updatedConstructor: ConstructorDeclaration = originalConstructor || createDefaultConstructor(isClassExtended(node), [track]);
if (originalConstructor) {
const body = updatedConstructor.body!;
const updatedBody = isClassExtended(node) ?
// extended class, add track after super()
visitEachChild(body, function visitor(node): VisitResult<Node> {
if (node.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.ClassExpression || node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.FunctionExpression) return node;
if (isCallExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) {
return factory.createCommaListExpression([node, track.expression, factory.createThis()]);
}
return visitEachChild(node, visitor, context);
}, context) :
// plain class, add track at the top
factory.updateBlock(body, [track, ...body.statements]);
updatedConstructor = factory.updateConstructorDeclaration(updatedConstructor, updatedConstructor.decorators, updatedConstructor.modifiers, updatedConstructor.parameters, updatedBody);
}

const updatedConstructor = getConstructorWithClassHasInstanceTracker(originalConstructor, isClassExtended(node), currentClassHasInstanceTracker);
const updatedMembers = originalConstructor ? updated.members.map(element => element === originalConstructor ? updatedConstructor : element) : [updatedConstructor, ...updated.members];

currentClassHasInstanceTracker = oldClassHasInstanceTracker;
Expand Down Expand Up @@ -102,24 +84,46 @@ namespace ts {
currentClassHasInstanceTracker = factory.createTempVariable(noop, /** reserveNested */ true);
}
// tracker.has()
const trackerDotHas = factory.createPropertyAccessChain(currentClassHasInstanceTracker, /** ?. */ undefined, "has");
const trackerDotHas = factory.createPropertyAccessExpression(currentClassHasInstanceTracker, "has");
const arg0 = visitEachChild(node.arguments[0] || factory.createNull(), visitor, context);
return factory.createCallExpression(trackerDotHas, /** generics */ undefined, [arg0]);
}
}
function isClassExtended(node: ClassLikeDeclaration) {
return some(node.heritageClauses, node => node.token === SyntaxKind.ExtendsKeyword);
}
function createDefaultConstructor(isExtended: boolean, additionalStatements: Statement[]) {
const params: ParameterDeclaration[] = [];
const statements: Statement[] = [];
if (isExtended) {
const rest = factory.createTempVariable(noop);
const param = factory.createParameterDeclaration(/** deco */ undefined, /** mod */ undefined, factory.createToken(SyntaxKind.DotDotDotToken), rest);
params.push(param);
statements.push(factory.createExpressionStatement(factory.createCallExpression(factory.createSuper(), /** generics */ undefined, [factory.createSpreadElement(rest)])));
type ClassConstructor = (ConstructorDeclaration & { body: Block; });

function getConstructorWithClassHasInstanceTracker(oldConstructor: ClassConstructor | undefined, isExtended: boolean, tracker: Identifier) {
let oldBody = oldConstructor?.body;
if (!oldBody) {
const defaultBody: Statement[] = [];
if (isExtended) {
defaultBody.push(factory.createExpressionStatement(factory.createCallExpression(factory.createSuper(), /** generics */ undefined, [factory.createSpreadElement(factory.createIdentifier("arguments"))])));
}
oldBody = factory.createBlock(defaultBody);
}
statements.push(...additionalStatements);
return factory.createConstructorDeclaration(/** deco */ undefined, /** modifiers */ undefined, params, factory.createBlock(statements));
const hasErrorWhenConstructingTracker = factory.createTempVariable(noop);
const catchErrVariable = factory.createTempVariable(noop);
const newBody = factory.createBlock([
// var _a
factory.createVariableStatement(/*modifiers*/ undefined, factory.createVariableDeclarationList([factory.createVariableDeclaration(hasErrorWhenConstructingTracker)])),
// try { original_statements } catch(_err) { _a = true; throw err; } finally { if (!_a) tracker.add(this); }
factory.createTryStatement(
// original_statements
oldBody,
// catch(_err) { _a = true; throw err; }
factory.createCatchClause(catchErrVariable, factory.createBlock([
factory.createExpressionStatement(factory.createAssignment(hasErrorWhenConstructingTracker, factory.createTrue())),
factory.createThrowStatement(catchErrVariable)
])),
// finally { if (!_a) tracker.add(this); }
factory.createBlock([factory.createIfStatement(
factory.createPrefixUnaryExpression(SyntaxKind.ExclamationToken, hasErrorWhenConstructingTracker),
factory.createExpressionStatement(factory.createCallExpression(factory.createPropertyAccessExpression(tracker, "add"), /** generics */ undefined, [factory.createThis()]))
)]),
)
]);
return factory.createConstructorDeclaration(oldConstructor?.decorators, oldConstructor?.modifiers, oldConstructor?.parameters || [], newBody);
}
}

0 comments on commit 3d315d6

Please sign in to comment.