From 3d315d6f6a358be452543ed29dbdaac85959bebd Mon Sep 17 00:00:00 2001 From: Jack Works Date: Tue, 1 Feb 2022 21:21:13 +0800 Subject: [PATCH] chore: update to spec --- src/compiler/transformers/esnext.ts | 66 +++++++++++++++-------------- 1 file changed, 35 insertions(+), 31 deletions(-) diff --git a/src/compiler/transformers/esnext.ts b/src/compiler/transformers/esnext.ts index 1130f6af86dd9..5c9917d3b59af 100644 --- a/src/compiler/transformers/esnext.ts +++ b/src/compiler/transformers/esnext.ts @@ -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; @@ -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 { - 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; @@ -102,7 +84,7 @@ 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]); } @@ -110,16 +92,38 @@ namespace ts { 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); } }