* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import ts from 'typescript';
import { SUPER_ARGS, COMPONENT_SENDABLE_DECORATOR } from './pre_define';
function transformOptionalMemberForSendable(node: ts.PropertyDeclaration): ts.PropertyDeclaration {
let updatedTypeNode: ts.TypeNode = node.type;
if (ts.isUnionTypeNode(updatedTypeNode)) {
if (!updatedTypeNode.types.find(type => type.kind === ts.SyntaxKind.UndefinedKeyword)) {
updatedTypeNode = ts.factory.createUnionTypeNode([
...updatedTypeNode.types,
ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)
]);
}
} else {
updatedTypeNode = ts.factory.createUnionTypeNode([
updatedTypeNode,
ts.factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword)
]);
}
return ts.factory.createPropertyDeclaration(
node.modifiers,
node.name,
undefined,
updatedTypeNode,
node.initializer ? node.initializer : ts.factory.createIdentifier('undefined')
);
}
function removeSendableDecorator(modifiers: ts.NodeArray<ts.ModifierLike>): ts.NodeArray<ts.ModifierLike> {
return ts.factory.createNodeArray(
modifiers.filter(decorator => {
const originalDecortor: string = decorator.getText().replace(/\(.*\)$/, '').trim();
return originalDecortor !== COMPONENT_SENDABLE_DECORATOR;
})
);
}
function updateSendableConstructor(constructor: ts.ConstructorDeclaration): ts.ConstructorDeclaration {
if (constructor.body === undefined) {
return constructor;
}
const statementArray: ts.Statement[] = [
ts.factory.createExpressionStatement(ts.factory.createStringLiteral('use sendable')),
...constructor.body.statements
];
return ts.factory.updateConstructorDeclaration(
constructor,
constructor.modifiers,
constructor.parameters,
ts.factory.updateBlock(constructor.body, statementArray)
);
}
function addConstructorForSendableClass(
members: ts.NodeArray<ts.ClassElement>,
needSuper: boolean): ts.NodeArray<ts.ClassElement> {
const params: ts.ParameterDeclaration[] = [];
const constructorStatements: ts.Statement[] = [
ts.factory.createExpressionStatement(ts.factory.createStringLiteral('use sendable'))
];
if (needSuper) {
constructorStatements.push(
ts.factory.createExpressionStatement(
ts.factory.createCallExpression(
ts.factory.createSuper(), undefined, [ts.factory.createSpreadElement(ts.factory.createIdentifier(SUPER_ARGS))])
)
);
params.push(
ts.factory.createParameterDeclaration(
undefined,
ts.factory.createToken(ts.SyntaxKind.DotDotDotToken),
ts.factory.createIdentifier(SUPER_ARGS),
undefined,
undefined,
undefined)
);
}
const constructor: ts.ConstructorDeclaration = ts.factory.createConstructorDeclaration(
undefined,
params,
ts.factory.createBlock(constructorStatements, true)
);
return ts.factory.createNodeArray([constructor, ...(members || [])]);
}
export function processSendableClass(node: ts.ClassDeclaration): ts.ClassDeclaration {
let hasConstructor = false;
let updatedMembers: ts.NodeArray<ts.ClassElement> = node.members;
let updatedModifiers: ts.NodeArray<ts.ModifierLike> = removeSendableDecorator(node.modifiers);
let needSuper: boolean =
node.heritageClauses?.some(clause => clause.token === ts.SyntaxKind.ExtendsKeyword) || false;
for (const member of node.members) {
if (ts.isPropertyDeclaration(member) && member.questionToken) {
const propertyDecl: ts.PropertyDeclaration = member as ts.PropertyDeclaration;
const updatedPropertyDecl: ts.PropertyDeclaration = transformOptionalMemberForSendable(member);
updatedMembers = ts.factory.createNodeArray(
updatedMembers.map(member => (member === propertyDecl ? updatedPropertyDecl : member))
);
}
if (ts.isConstructorDeclaration(member)) {
hasConstructor = true;
const constructor: ts.ConstructorDeclaration = member as ts.ConstructorDeclaration;
updatedMembers = ts.factory.createNodeArray(
updatedMembers.map(member => (member === constructor ? updateSendableConstructor(constructor) : member))
);
}
}
if (!hasConstructor) {
updatedMembers = addConstructorForSendableClass(updatedMembers, needSuper);
}
node = ts.factory.updateClassDeclaration(node, updatedModifiers, node.name, node.typeParameters,
node.heritageClauses, updatedMembers);
return node;
}
export function processSendableFunction(node: ts.FunctionDeclaration): ts.FunctionDeclaration {
if (node.body) {
const statementArray: ts.Statement[] =
[ts.factory.createExpressionStatement(ts.factory.createStringLiteral('use sendable')),
...node.body.statements];
return ts.factory.updateFunctionDeclaration(node, ts.getModifiers(node), node.asteriskToken, node.name,
node.typeParameters, node.parameters, node.type, ts.factory.updateBlock(node.body, statementArray));
}
return ts.factory.createFunctionDeclaration(undefined, node.asteriskToken, node.name,
node.typeParameters, node.parameters, node.type, node.body);
}
export function processSendableType(node: ts.TypeAliasDeclaration): ts.TypeAliasDeclaration {
return ts.factory.createTypeAliasDeclaration(undefined, node.name, node.typeParameters, node.type);
}