idlize

Форк
0
/
AbilityTransformer.ts 
180 строк · 6.1 Кб
1
/*
2
 * Copyright (c) 2022-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

16
import * as ts from 'ohos-typescript'
17
import { AbstractVisitor } from './AbstractVisitor'
18
import { Importer } from './Importer'
19
import { isDefined } from "./utils";
20

21
/**
22
 TODO:
23
   This is really a workaround to the entry point problem.
24
   I really hope we will be able to throw away this transformer.
25
   We should not rewrite anything outside the UI code realm. :-(
26
 */
27

28
/**
29
 * Rewrites
30
 *   import { Ability } from "@kit.AbilityKit"
31
 * to
32
 *   import { ArkoalaAbility as Ability } from "@koalaui/arkoala-arkui";
33
 */
34
export class AbilityTransformer extends AbstractVisitor {
35
    constructor(
36
        sourceFile: ts.SourceFile,
37
        ctx: ts.TransformationContext,
38
        private importer: Importer
39
    ) {
40
        super(sourceFile, ctx)
41
    }
42

43
    private readonly defaultExportModules = ["@ohos.app.ability.UIAbility", "@ohos.app.ability.Ability"]
44
    private readonly namedExportModules = ["@kit.AbilityKit"]
45

46
    private isNamedRewriteModule(node: ts.ImportDeclaration): boolean {
47
        if (!ts.isStringLiteral(node.moduleSpecifier)) return false
48
        return this.namedExportModules.includes(node.moduleSpecifier.text)
49
    }
50

51
    private isDefaultRewriteModule(node: ts.ImportDeclaration): boolean {
52
        if (!ts.isStringLiteral(node.moduleSpecifier)) return false
53
        return this.defaultExportModules.includes(node.moduleSpecifier.text)
54
    }
55

56
    private isAbilityIdentifier(node: ts.Identifier | undefined): boolean {
57
        if (node === undefined) return false
58
        return ts.idText(node) === "UIAbility" || ts.idText(node) === "default"
59
    }
60

61
    private createArkoalaAbilityImport(alias: ts.Identifier): ts.ImportDeclaration {
62
        return ts.factory.createImportDeclaration(
63
            [],
64
            ts.factory.createImportClause(
65
                false,
66
                undefined,
67
                ts.factory.createNamedImports([
68
                    ts.factory.createImportSpecifier(
69
                        false,
70
                        ts.factory.createIdentifier("ArkoalaAbility"),
71
                        alias
72
                    )
73
                ])
74
            ),
75
            ts.factory.createStringLiteral("@koalaui/arkoala-arkui"),
76
            undefined
77
        )
78
    }
79

80
    visitor(node: ts.Node): ts.Node {
81
        if (!this.importer.__isArkoalaImplementation) return node
82

83
        if (ts.isSourceFile(node) && !this.containsArkoalaAbility(node)) {
84
            return this.rewriteSourceFile(node)
85
        }
86

87
        return this.visitEachChild(node)
88
    }
89

90
    private rewriteSourceFile(node: ts.SourceFile): ts.SourceFile {
91
        return ts.factory.updateSourceFile(
92
            node,
93
            node.statements
94
                .map(it =>
95
                    ts.isImportDeclaration(it)
96
                        ? this.rewriteImport(it)
97
                        : it
98
                )
99
                .flat()
100
        )
101
    }
102

103
    private rewriteImport(node: ts.ImportDeclaration): ts.ImportDeclaration[] {
104
        if (this.isDefaultRewriteModule(node)) {
105
            const alias = node?.importClause?.name
106
            if (alias === undefined) {
107
                /*
108
                  import { default as ... } from ...
109
                 */
110
                return this.splitImport(node)
111
            }
112

113
            const namedBindings = node?.importClause?.namedBindings
114
            const importSpecifiers =
115
                namedBindings !== undefined && ts.isNamedImports(namedBindings)
116
                    ? namedBindings.elements
117
                    : []
118

119
            return [
120
                ts.factory.updateImportDeclaration(
121
                    node,
122
                    node.modifiers,
123
                    ts.factory.createImportClause(
124
                        false,
125
                        undefined,
126
                        ts.factory.createNamedImports(
127
                            importSpecifiers
128
                        )
129
                    ),
130
                    node.moduleSpecifier,
131
                    node.assertClause
132
                ),
133
                this.createArkoalaAbilityImport(alias)
134
            ]
135
        }
136
        if (this.isNamedRewriteModule(node)) {
137
            return this.splitImport(node)
138
        }
139
        return [node]
140
    }
141

142
    private splitImport(node: ts.ImportDeclaration): ts.ImportDeclaration[] {
143
        const namedBindings = node?.importClause?.namedBindings
144
        if (namedBindings === undefined || !ts.isNamedImports(namedBindings)) return [node]
145

146
        const ability = namedBindings.elements
147
            .find(it => this.isAbilityIdentifier(this.getOriginalEntity(it)))
148
        if (ability === undefined) return [node]
149

150
        return [
151
            ts.factory.updateImportDeclaration(
152
                node,
153
                node.modifiers,
154
                ts.factory.createImportClause(
155
                    false,
156
                    undefined,
157
                    ts.factory.createNamedImports(
158
                        namedBindings.elements.filter(it => it !== ability)
159
                    )
160
                ),
161
                node.moduleSpecifier,
162
                node.assertClause
163
            ),
164
            this.createArkoalaAbilityImport(ability.name)
165
        ]
166
    }
167

168
    private containsArkoalaAbility(node: ts.SourceFile): boolean {
169
        return node.statements
170
            .filter(ts.isClassDeclaration)
171
            .map(it => it.name)
172
            .filter(isDefined)
173
            .some(it => ts.idText(it) === "ArkoalaAbility")
174
    }
175

176
    private getOriginalEntity(node: ts.ImportSpecifier): ts.Identifier {
177
        if (node.propertyName === undefined) return node.name
178
        return node.propertyName
179
    }
180
}
181

182

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.