idlize
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
16import * as ts from 'ohos-typescript'17import { AbstractVisitor } from './AbstractVisitor'18import { Importer } from './Importer'19import { isDefined } from "./utils";20
21/**
22TODO:
23This is really a workaround to the entry point problem.
24I really hope we will be able to throw away this transformer.
25We 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*/
34export class AbilityTransformer extends AbstractVisitor {35constructor(36sourceFile: ts.SourceFile,37ctx: ts.TransformationContext,38private importer: Importer39) {40super(sourceFile, ctx)41}42
43private readonly defaultExportModules = ["@ohos.app.ability.UIAbility", "@ohos.app.ability.Ability"]44private readonly namedExportModules = ["@kit.AbilityKit"]45
46private isNamedRewriteModule(node: ts.ImportDeclaration): boolean {47if (!ts.isStringLiteral(node.moduleSpecifier)) return false48return this.namedExportModules.includes(node.moduleSpecifier.text)49}50
51private isDefaultRewriteModule(node: ts.ImportDeclaration): boolean {52if (!ts.isStringLiteral(node.moduleSpecifier)) return false53return this.defaultExportModules.includes(node.moduleSpecifier.text)54}55
56private isAbilityIdentifier(node: ts.Identifier | undefined): boolean {57if (node === undefined) return false58return ts.idText(node) === "UIAbility" || ts.idText(node) === "default"59}60
61private createArkoalaAbilityImport(alias: ts.Identifier): ts.ImportDeclaration {62return ts.factory.createImportDeclaration(63[],64ts.factory.createImportClause(65false,66undefined,67ts.factory.createNamedImports([68ts.factory.createImportSpecifier(69false,70ts.factory.createIdentifier("ArkoalaAbility"),71alias
72)73])74),75ts.factory.createStringLiteral("@koalaui/arkoala-arkui"),76undefined77)78}79
80visitor(node: ts.Node): ts.Node {81if (!this.importer.__isArkoalaImplementation) return node82
83if (ts.isSourceFile(node) && !this.containsArkoalaAbility(node)) {84return this.rewriteSourceFile(node)85}86
87return this.visitEachChild(node)88}89
90private rewriteSourceFile(node: ts.SourceFile): ts.SourceFile {91return ts.factory.updateSourceFile(92node,93node.statements94.map(it =>95ts.isImportDeclaration(it)96? this.rewriteImport(it)97: it98)99.flat()100)101}102
103private rewriteImport(node: ts.ImportDeclaration): ts.ImportDeclaration[] {104if (this.isDefaultRewriteModule(node)) {105const alias = node?.importClause?.name106if (alias === undefined) {107/*108import { default as ... } from ...
109*/
110return this.splitImport(node)111}112
113const namedBindings = node?.importClause?.namedBindings114const importSpecifiers =115namedBindings !== undefined && ts.isNamedImports(namedBindings)116? namedBindings.elements117: []118
119return [120ts.factory.updateImportDeclaration(121node,122node.modifiers,123ts.factory.createImportClause(124false,125undefined,126ts.factory.createNamedImports(127importSpecifiers
128)129),130node.moduleSpecifier,131node.assertClause132),133this.createArkoalaAbilityImport(alias)134]135}136if (this.isNamedRewriteModule(node)) {137return this.splitImport(node)138}139return [node]140}141
142private splitImport(node: ts.ImportDeclaration): ts.ImportDeclaration[] {143const namedBindings = node?.importClause?.namedBindings144if (namedBindings === undefined || !ts.isNamedImports(namedBindings)) return [node]145
146const ability = namedBindings.elements147.find(it => this.isAbilityIdentifier(this.getOriginalEntity(it)))148if (ability === undefined) return [node]149
150return [151ts.factory.updateImportDeclaration(152node,153node.modifiers,154ts.factory.createImportClause(155false,156undefined,157ts.factory.createNamedImports(158namedBindings.elements.filter(it => it !== ability)159)160),161node.moduleSpecifier,162node.assertClause163),164this.createArkoalaAbilityImport(ability.name)165]166}167
168private containsArkoalaAbility(node: ts.SourceFile): boolean {169return node.statements170.filter(ts.isClassDeclaration)171.map(it => it.name)172.filter(isDefined)173.some(it => ts.idText(it) === "ArkoalaAbility")174}175
176private getOriginalEntity(node: ts.ImportSpecifier): ts.Identifier {177if (node.propertyName === undefined) return node.name178return node.propertyName179}180}
181
182