idlize
128 строк · 5.0 Кб
1/*
2* Copyright (c) 2022-2023 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 * as ts from 'ohos-typescript'
17import { AbstractVisitor } from './AbstractVisitor'
18import { getDeclarationsByNode, hasDecorator } from './ApiUtils'
19import { asString, CallTable, findBuilderLambdaRedirect, isGlobalBuilder, hasLocalDeclaration, isBuiltinComponentName, CustomDialogDecorator, ComponentDecorator } from './utils'
20import { Importer } from './Importer'
21import { ImportExport } from './import-export'
22
23
24export class CallTransformer extends AbstractVisitor {
25constructor(
26sourceFile: ts.SourceFile,
27ctx: ts.TransformationContext,
28private typechecker: ts.TypeChecker,
29private callTable: CallTable,
30private importer: Importer
31) {
32super(sourceFile, ctx)
33}
34
35private importExport = new ImportExport(this.typechecker, this.sourceFile)
36
37refersToGlobalBuilder(call: ts.CallExpression): boolean {
38const callee = call.expression
39if (ts.isIdentifier(callee)) {
40const declarations = getDeclarationsByNode(this.typechecker, callee)
41if (declarations.length == 0) return false
42const firstDeclaration = declarations[0]
43if (ts.isFunctionDeclaration(firstDeclaration) &&
44isGlobalBuilder(firstDeclaration)
45) return true
46}
47return false
48}
49
50getImportModuileSpecifier(node: ts.Identifier): ts.StringLiteral|undefined {
51const declarations = getDeclarationsByNode(this.typechecker, node)
52const declaration = declarations[0]
53if (!declaration) return undefined
54let importDeclaration = undefined
55if (ts.isImportSpecifier(declaration)) {
56importDeclaration = declaration.parent.parent.parent
57} else if (ts.isImportClause(declaration)) {
58importDeclaration = declaration.parent
59}
60if (!importDeclaration || !ts.isImportDeclaration(importDeclaration)) {
61return undefined
62}
63const moduleSpecifier = importDeclaration.moduleSpecifier
64if (!ts.isStringLiteral(moduleSpecifier)) return undefined
65return moduleSpecifier
66}
67
68isLegacyCall(node: ts.Identifier): boolean {
69if (!this.importer.__isArkoalaImplementation) return false
70
71const moduleSpecifier = this.getImportModuileSpecifier(node)
72if (!moduleSpecifier) return false
73const moduleSym = this.typechecker.getSymbolAtLocation(moduleSpecifier)
74if (moduleSym === undefined) return false
75return moduleSym.escapedName.toString().includes("library") || // TODO: don't forget to erase for production
76(this.importer.moduleInfo?.(moduleSym.escapedName.toString())?.isLegacy ?? false)
77}
78
79isComponentStructCall(node: ts.Identifier): boolean {
80const declaration = this.importExport.findRealDeclaration(node)
81if (!declaration) return false
82return ts.isStructDeclaration(declaration) && hasDecorator(declaration, ComponentDecorator)
83}
84
85visitor(beforeChildren: ts.Node): ts.Node {
86const node = this.visitEachChild(beforeChildren)
87
88/**
89* Function call is treated as ETS Component call when:
90* - it is listed in ETS components
91* - it is not user defined
92*/
93if (ts.isCallExpression(node) && ts.isIdentifier(node.expression)) {
94
95const func = node.expression
96const name = ts.idText(func)
97if (isBuiltinComponentName(this.ctx, name)) {
98if (hasLocalDeclaration(this.typechecker, func)) {
99return node
100}
101return ts.factory.createEtsComponentExpression(
102node.expression,
103node.arguments,
104undefined
105)
106}
107
108const builderLambdaRedirect = findBuilderLambdaRedirect(this.typechecker, node)
109if (builderLambdaRedirect) {
110this.callTable.builderLambdas.set(node, builderLambdaRedirect)
111}
112
113if (this.refersToGlobalBuilder(node)) {
114this.callTable.globalBuilderCalls.add(node)
115}
116
117if (this.isLegacyCall(node.expression)) {
118this.callTable.legacyCalls.add(node)
119}
120
121if (this.isComponentStructCall(node.expression)) {
122this.callTable.structCalls.add(ts.getOriginalNode(node) as ts.CallExpression)
123}
124}
125
126return node
127}
128}
129