1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import ts from 'typescript'; 17import { SUPER_ARGS, COMPONENT_SENDABLE_DECORATOR } from './pre_define'; 18 19function transformOptionalMemberForSendable(node: ts.PropertyDeclaration): ts.PropertyDeclaration { 20 let updatedTypeNode: ts.TypeNode = node.type; 21 22 if (ts.isUnionTypeNode(updatedTypeNode)) { 23 if (!updatedTypeNode.types.find(type => type.kind === ts.SyntaxKind.UndefinedKeyword)) { 24 updatedTypeNode = ts.factory.createUnionTypeNode([ 25 ...updatedTypeNode.types, 26 ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword) 27 ]); 28 } 29 } else { 30 updatedTypeNode = ts.factory.createUnionTypeNode([ 31 updatedTypeNode, 32 ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword) 33 ]); 34 } 35 36 return ts.factory.createPropertyDeclaration( 37 node.modifiers, 38 node.name, 39 undefined, 40 updatedTypeNode, 41 node.initializer ? node.initializer : ts.factory.createIdentifier('undefined') 42 ); 43} 44 45function removeSendableDecorator(modifiers: ts.NodeArray<ts.ModifierLike>): ts.NodeArray<ts.ModifierLike> { 46 return ts.factory.createNodeArray( 47 modifiers.filter(decorator => { 48 const originalDecortor: string = decorator.getText().replace(/\(.*\)$/, '').trim(); 49 return originalDecortor !== COMPONENT_SENDABLE_DECORATOR; 50 }) 51 ); 52} 53 54function updateSendableConstructor(constructor: ts.ConstructorDeclaration): ts.ConstructorDeclaration { 55 // Skip the overloaded signature of the constructor 56 if (constructor.body === undefined) { 57 return constructor; 58 } 59 const statementArray: ts.Statement[] = [ 60 ts.factory.createExpressionStatement(ts.factory.createStringLiteral('use sendable')), 61 ...constructor.body.statements 62 ]; 63 64 return ts.factory.updateConstructorDeclaration( 65 constructor, 66 constructor.modifiers, 67 constructor.parameters, 68 ts.factory.updateBlock(constructor.body, statementArray) 69 ); 70} 71 72function addConstructorForSendableClass( 73 members: ts.NodeArray<ts.ClassElement>, 74 needSuper: boolean): ts.NodeArray<ts.ClassElement> { 75 const params: ts.ParameterDeclaration[] = []; 76 const constructorStatements: ts.Statement[] = [ 77 ts.factory.createExpressionStatement(ts.factory.createStringLiteral('use sendable')) 78 ]; 79 if (needSuper) { 80 constructorStatements.push( 81 ts.factory.createExpressionStatement( 82 ts.factory.createCallExpression( 83 ts.factory.createSuper(), undefined, [ts.factory.createSpreadElement(ts.factory.createIdentifier(SUPER_ARGS))]) 84 ) 85 ); 86 params.push( 87 ts.factory.createParameterDeclaration( 88 undefined, 89 ts.factory.createToken(ts.SyntaxKind.DotDotDotToken), 90 ts.factory.createIdentifier(SUPER_ARGS), 91 undefined, 92 undefined, 93 undefined) 94 ); 95 } 96 const constructor: ts.ConstructorDeclaration = ts.factory.createConstructorDeclaration( 97 undefined, 98 params, 99 ts.factory.createBlock(constructorStatements, true) 100 ); 101 102 return ts.factory.createNodeArray([constructor, ...(members || [])]); 103} 104 105export function processSendableClass(node: ts.ClassDeclaration): ts.ClassDeclaration { 106 let hasConstructor = false; 107 let updatedMembers: ts.NodeArray<ts.ClassElement> = node.members; 108 let updatedModifiers: ts.NodeArray<ts.ModifierLike> = removeSendableDecorator(node.modifiers); 109 let needSuper: boolean = 110 node.heritageClauses?.some(clause => clause.token === ts.SyntaxKind.ExtendsKeyword) || false; 111 112 for (const member of node.members) { 113 if (ts.isPropertyDeclaration(member) && member.questionToken) { 114 const propertyDecl: ts.PropertyDeclaration = member as ts.PropertyDeclaration; 115 const updatedPropertyDecl: ts.PropertyDeclaration = transformOptionalMemberForSendable(member); 116 updatedMembers = ts.factory.createNodeArray( 117 updatedMembers.map(member => (member === propertyDecl ? updatedPropertyDecl : member)) 118 ); 119 } 120 if (ts.isConstructorDeclaration(member)) { 121 hasConstructor = true; 122 const constructor: ts.ConstructorDeclaration = member as ts.ConstructorDeclaration; 123 updatedMembers = ts.factory.createNodeArray( 124 updatedMembers.map(member => (member === constructor ? updateSendableConstructor(constructor) : member)) 125 ); 126 } 127 } 128 129 if (!hasConstructor) { 130 updatedMembers = addConstructorForSendableClass(updatedMembers, needSuper); 131 } 132 133 node = ts.factory.updateClassDeclaration(node, updatedModifiers, node.name, node.typeParameters, 134 node.heritageClauses, updatedMembers); 135 136 return node; 137} 138 139export function processSendableFunction(node: ts.FunctionDeclaration): ts.FunctionDeclaration { 140 if (node.body) { 141 const statementArray: ts.Statement[] = 142 [ts.factory.createExpressionStatement(ts.factory.createStringLiteral('use sendable')), 143 ...node.body.statements]; 144 return ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node), node.asteriskToken, node.name, 145 node.typeParameters, node.parameters, node.type, ts.factory.updateBlock(node.body, statementArray)); 146 } 147 return ts.factory.createFunctionDeclaration(undefined, node.asteriskToken, node.name, 148 node.typeParameters, node.parameters, node.type, node.body); 149} 150 151export function processSendableType(node: ts.TypeAliasDeclaration): ts.TypeAliasDeclaration { 152 return ts.factory.createTypeAliasDeclaration(undefined, node.name, node.typeParameters, node.type); 153} 154