idlize

Форк
0
/
ComponentsPrinter.ts 
187 строк · 8.4 Кб
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

16
import * as path from "path"
17
import { IndentedPrinter } from "../../IndentedPrinter";
18
import { Language, renameDtsToComponent, renameDtsToPeer } from "../../util";
19
import { ImportsCollector } from "../ImportsCollector";
20
import { PeerClass } from "../PeerClass";
21
import { PeerFile } from "../PeerFile";
22
import { PeerLibrary } from "../PeerLibrary";
23
import { isCommonMethod } from "../inheritance";
24
import { PeerMethod } from "../PeerMethod";
25
import { componentToPeerClass } from "./PeersPrinter";
26
import { OverloadsPrinter, collapseSameNamedMethods } from "./OverloadsPrinter";
27
import { LanguageWriter, Method, MethodModifier, MethodSignature, Type, createLanguageWriter } from "../LanguageWriters";
28
import { convertToCallback } from "./EventsPrinter";
29
import { tsCopyrightAndWarning } from "../FileGenerators";
30

31
function generateArkComponentName(component: string) {
32
    return `Ark${component}Component`
33
}
34

35
class ComponentFileVisitor {
36
    private readonly overloadsPrinter = new OverloadsPrinter(this.printer, this.library)
37

38
    constructor(
39
        private library: PeerLibrary,
40
        private file: PeerFile,
41
        readonly printer: LanguageWriter,
42
    ) { }
43

44
    get targetBasename() {
45
        return renameDtsToComponent(path.basename(this.file.originalFilename), this.file.declarationTable.language)
46
    }
47

48
    private printImports(): void {
49
        const imports = new ImportsCollector()
50
        imports.addFilterByBasename(this.targetBasename)
51
        this.file.peersToGenerate.forEach(peer => {
52
            imports.addFeature("NodeAttach", "@koalaui/runtime")
53
            imports.addFeature("remember", "@koalaui/runtime")
54
            if (peer.originalParentFilename) {
55
                const parentBasename = renameDtsToComponent(path.basename(peer.originalParentFilename), this.file.declarationTable.language, false)
56
                imports.addFeature(generateArkComponentName(peer.parentComponentName!), `./${parentBasename}`)
57
            }
58
            imports.addFeatureByBasename(componentToPeerClass(peer.componentName),
59
                renameDtsToPeer(path.basename(peer.originalFilename), peer.declarationTable.language))
60
            peer.attributesTypes.forEach((attrType) =>
61
                imports.addFeatureByBasename(attrType.typeName,
62
                    renameDtsToPeer(path.basename(peer.originalFilename), peer.declarationTable.language))
63
            )
64
            imports.addFeature("ArkUINodeType", "./ArkUINodeType")
65
            imports.addFeature("runtimeType", "./SerializerBase")
66
            imports.addFeature("RuntimeType", "./SerializerBase")
67
            imports.addFeature("isPixelMap", "./SerializerBase")
68
            imports.addFeature("isResource", "./SerializerBase")
69
            imports.addFeature("isInstanceOf", "./SerializerBase")
70
            imports.addFeature('ComponentBase', './ComponentBase')
71
            imports.addFeature('unsafeCast', './generated-utils')
72
            for (const method of peer.methods) {
73
                for (const target of method.declarationTargets)
74
                    if (convertToCallback(peer, method, target))
75
                        imports.addFeature("UseEventsProperties", './use_properties')
76
            }
77
            // TBD
78
            // peer.materializedClasses.forEach(it => {
79
            //     imports.addFeature(it.className, `./Ark${peer.componentName}Peer`)
80
            // })
81
        })
82
        if (this.file.declarationTable.language === Language.TS)
83
            this.file.importFeatures.forEach(it => imports.addFeature(it.feature, it.module))
84
        imports.print(this.printer)
85
    }
86

87
    private groupOverloads(peerMethods: PeerMethod[]): PeerMethod[][] {
88
        const seenNames = new Set<string>()
89
        const groups: PeerMethod[][] = []
90
        for (const method of peerMethods) {
91
            if (seenNames.has(method.method.name))
92
                continue
93
            seenNames.add(method.method.name)
94
            groups.push(peerMethods.filter(it => it.method.name === method.method.name))
95
        }
96
        return groups
97
    }
98

99
    private printComponent(peer: PeerClass) {
100
        const callableMethods = peer.methods.filter(it => it.isCallSignature).map(it => it.method)
101
        const callableMethod = callableMethods.length ? collapseSameNamedMethods(callableMethods) : undefined
102
        const mappedCallableParams = callableMethod?.signature.args.map((it, index) => `${callableMethod.signature.argName(index)}${it.nullable ? "?" : ""}: ${it.name}`)
103
        const mappedCallableParamsValues = callableMethod?.signature.args.map((_, index) => callableMethod.signature.argName(index))
104
        const componentClassName = generateArkComponentName(peer.componentName)
105
        const parentComponentClassName = peer.parentComponentName ? generateArkComponentName(peer.parentComponentName!) : `ComponentBase`
106
        const componentFunctionName = `Ark${peer.componentName}`
107
        const peerClassName = componentToPeerClass(peer.componentName)
108

109
        this.printer.writeClass(componentClassName, (writer) => {
110
            writer.writeFieldDeclaration('peer', new Type(peerClassName), ['protected'], true)
111
            for (const grouped of this.groupOverloads(peer.methods))
112
                this.overloadsPrinter.printGroupedComponentOverloads(peer, grouped)
113
            // todo stub until we can process AttributeModifier
114
            if (isCommonMethod(peer.originalClassName!) || peer.originalClassName == "ContainerSpanAttribute")
115
                writer.print(`attributeModifier(modifier: AttributeModifier<object>): this { throw new Error("not implemented") }`)
116
            const attributesSignature = new MethodSignature(Type.Void, [])
117
            writer.writeMethodImplementation(new Method('applyAttributesFinish', attributesSignature, [MethodModifier.PUBLIC]), (writer) => {
118
                writer.print('// we calls this function outside of class, so need to make it public')
119
                writer.writeMethodCall('super', 'applyAttributesFinish', [])
120
            })
121
        }, parentComponentClassName)
122

123

124
        this.printer.print(`
125
/** @memo */
126
export function ${componentFunctionName}(
127
  /** @memo */
128
  style: ((attributes: ${componentClassName}) => void) | undefined,
129
  /** @memo */
130
  content_: (() => void) | undefined,
131
  ${mappedCallableParams?.join(", ") ?? ""}
132
) {
133
    const receiver = remember(() => {
134
        return new ${componentClassName}()
135
    })
136
    NodeAttach(() => new ${peerClassName}(ArkUINodeType.${peer.componentName}, receiver), () => {
137
        ${callableMethod ? `receiver.${callableMethod.name}(${mappedCallableParamsValues})` : ""}
138
        style?.(receiver)
139
        content_?.()
140
        receiver.applyAttributesFinish()
141
    })
142
}
143
`)
144
    }
145

146
    printFile(): void {
147
        this.printImports()
148
        this.file.peersToGenerate.forEach(peer => {
149
            this.printComponent(peer)
150
        })
151
    }
152
}
153

154
class ComponentsVisitor {
155
    readonly components: Map<string, LanguageWriter> = new Map()
156

157
    constructor(
158
        private readonly peerLibrary: PeerLibrary,
159
    ) { }
160

161
    printComponents(): void {
162
        for (const file of this.peerLibrary.files.values()) {
163
            if (!file.peersToGenerate.length)
164
                continue
165
            const writer = createLanguageWriter(Language.TS)
166
            const visitor = new ComponentFileVisitor(this.peerLibrary, file, writer)
167
            visitor.printFile()
168
            this.components.set(visitor.targetBasename, writer)
169
        }
170
    }
171
}
172

173
export function printComponents(peerLibrary: PeerLibrary): Map<string, string> {
174
    // TODO: support other output languages
175
    if (peerLibrary.declarationTable.language != Language.TS)
176
        return new Map()
177

178
    const visitor = new ComponentsVisitor(peerLibrary)
179
    visitor.printComponents()
180
    const result = new Map<string, string>()
181
    for (const [key, writer] of visitor.components) {
182
        if (writer.getOutput().length === 0) continue
183
        const text = tsCopyrightAndWarning(writer.getOutput().join('\n'))
184
        result.set(key, text)
185
    }
186
    return result
187
}

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

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

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

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