idlize

Форк
0
/
DtsPrinter.ts 
188 строк · 7.3 Кб
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
import { indentedBy, stringOrNone } from "../util"
16
import { IDLCallback, IDLConstructor, IDLEntry, IDLEnum, IDLInterface, IDLKind, IDLMethod, IDLModuleType, IDLParameter, IDLProperty, IDLType, IDLTypedef, getExtAttribute,
17
    getVerbatimDts,
18
    hasExtAttribute,
19
    isCallback,
20
    isClass, isConstructor, isContainerType, isEnum, isEnumType, isInterface, isMethod, isModuleType, isPrimitiveType, isProperty, isReferenceType, isTypeParameterType, isTypedef, isUnionType } from "../idl"
21
import * as webidl2 from "webidl2"
22
import { toIDLNode } from "./deserialize"
23

24

25
export class CustomPrintVisitor  {
26
    output: string[] = []
27

28
    visit(node: IDLEntry) {
29
        if (isInterface(node) || isClass(node)) {
30
            this.printClass(node)
31
        } else if (isMethod(node) || isConstructor(node)) {
32
            this.printMethod(node)
33
        } else if (isProperty(node)) {
34
            this.printProperty(node)
35
        } else if (isTypedef(node)) {
36
            this.printTypedef(node)
37
        } else if (isEnum(node)) {
38
            this.printEnum(node)
39
        } else if (isCallback(node)) {
40
            this.printCallback(node)
41
        } else if (isModuleType(node)) {
42
            this.printModuleType(node)
43
        } else {
44
            throw new Error(`Unexpected node kind: ${IDLKind[node.kind!]}`)
45
        }
46
    }
47

48
    computeDeclaration(node: IDLInterface): string {
49
        let keyword = hasExtAttribute(node, "Class") ? "class" : "interface"
50
        let typeOrExtends = ""
51
        if (hasExtAttribute(node, "Component")) {
52
            if (node.name == "CommonMethod")
53
                typeOrExtends = "<T>"
54
            else
55
                typeOrExtends = ` extends CommonMethod<${getExtAttribute(node, "Component")}Attribute>`
56
        }
57
        if (hasExtAttribute(node, "Parametrized")) {
58
            typeOrExtends = `<${getExtAttribute(node, "Parametrized")}>`
59
        }
60
        return `${keyword} ${node.name}${typeOrExtends}`
61
    }
62

63
    currentInterface?: IDLInterface
64

65
    printClass(node: IDLInterface) {
66
        this.print(`declare ${this.computeDeclaration(node)} {`)
67
        this.currentInterface = node
68
        this.pushIndent()
69
        node.constructors.map(it => this.visit(it))
70
        node.properties.map(it => this.visit(it))
71
        node.methods.map(it => this.visit(it))
72
        node.callables.map(it => this.visit(it))
73
        let verbatim = getVerbatimDts(node)
74
        if (verbatim) {
75
            verbatim
76
                .split("\n")
77
                .map(it => this.print(it))
78
        }
79

80
        this.popIndent()
81
        this.print("}")
82
        if (hasExtAttribute(node, "Component")) {
83
            let name = getExtAttribute(node, "Component")
84
            this.print(`declare const ${name}Instance: ${name}Attribute;`)
85
            this.print(`declare const ${name}: ${name}Interface;`)
86
        }
87
    }
88

89
    printMethod(node: IDLMethod|IDLConstructor) {
90
        let returnType = node.returnType ? `: ${printTypeForTS(node.returnType, true)}` : ""
91
        let isStatic = isMethod(node) && node.isStatic
92
        let name = isConstructor(node) ? "constructor" : node.name
93
        if (hasExtAttribute(node, "CallSignature")) name = ""
94
        this.print(`${isStatic ? "static " : ""}${name}(${node.parameters.map(p => this.paramText(p)).join(", ")})${returnType};`)
95
    }
96
    paramText(param: IDLParameter): string {
97
        return `${param.name}${param.isOptional ? "?" : ""}: ${printTypeForTS(param.type)}`
98
    }
99
    printProperty(node: IDLProperty) {
100
        const isCommonMethod = hasExtAttribute(node, "CommonMethod")
101
        if (isCommonMethod) {
102
            let returnType = this.currentInterface!.name == "CommonMethod" ? "T" : this.currentInterface!.name
103
            this.print(`${node.name}(value: ${printTypeForTS(node.type)}): ${returnType};`)
104
        } else {
105
            this.print(`${node.isStatic ? "static " : ""}${node.isReadonly ? "readonly " : ""}${node.name}${node.isOptional ? "?" : ""}: ${printTypeForTS(node.type)};`)
106

107
        }
108
    }
109
    printEnum(node: IDLEnum) {
110
        this.print(`declare enum ${node.name} {`)
111
        this.pushIndent()
112
        node.elements.forEach((it, index) => {
113
            this.print(`${it.name}${it.initializer ? " = " + it.initializer : ""}${index < node.elements.length - 1 ? "," : ""}`)
114
        })
115
        this.popIndent()
116
        this.print("}")
117
    }
118
    printCallback(node: IDLCallback) {
119
        // TODO: is it correct.
120
        this.print(`declare type ${(node.name)} = (${node.parameters.map(it => `${it.name}: ${printTypeForTS(it.type)}`).join(", ")}) => ${printTypeForTS(node.returnType)};`)
121
    }
122
    printTypedef(node: IDLTypedef) {
123
        let text = getVerbatimDts(node) ?? printTypeForTS(node.type)
124
        this.print(`declare type ${(node.name)} = ${text};`)
125
    }
126

127
    printModuleType(node: IDLModuleType) {
128
        let text = getVerbatimDts(node) ?? ""
129
        this.print(`${text}`)
130
    }
131

132
    checkVerbatim(node: IDLEntry) {
133
        let verbatim = getExtAttribute(node, "VerbatimDts")
134
        if (verbatim) {
135
            verbatim
136
                .substring(1, verbatim.length - 2)
137
                .split('\n')
138
                .forEach(it => this.print(it))
139
        }
140
    }
141

142
    private indent = 0
143
    indented(input: string): string {
144
        return indentedBy(input, this.indent)
145
    }
146
    pushIndent() {
147
        this.indent++
148
    }
149
    popIndent() {
150
        this.indent--
151
    }
152
    print(value: stringOrNone) {
153
        if (value) this.output.push(this.indented(value))
154
    }
155
}
156

157
export function idlToString(name: string, content: string): string {
158
    let printer = new CustomPrintVisitor()
159
    webidl2.parse(content)
160
        .map(it => toIDLNode(name, it))
161
        .map(it => printer.visit(it))
162
    return printer.output.join("\n")
163
}
164

165
export function printTypeForTS(type: IDLType | undefined, undefinedToVoid?: boolean): string {
166
    if (!type) throw new Error("Missing type")
167
    if (type.name == "undefined" && undefinedToVoid) return "void"
168
    if (type.name == "int32" || type.name == "float32") return "number"
169
    if (type.name == "DOMString") return "string"
170
    if (type.name == "this") return "T"
171
    if (isPrimitiveType(type)) return type.name
172
    if (isContainerType(type))
173
        return `${mapContainerType(type.name)}<${type.elementType.map(it => printTypeForTS(it)).join("\n")}>`
174
    if (isReferenceType(type)) return `${type.name}`
175
    if (isUnionType(type)) return `(${type.types.map(it => printTypeForTS(it, undefinedToVoid)).join("|")})`
176
    if (isEnumType(type)) return type.name
177
    if (isTypeParameterType(type)) return type.name
178
    throw new Error(`Cannot map type: ${IDLKind[type.kind]}`)
179
}
180

181
function mapContainerType(idlName: string): string {
182
    switch (idlName) {
183
        case "sequence": return "Array"
184
        case "record": return "Map"
185
        case "Promise": return "Promise"
186
        default: throw new Error(`Unmapped container type: ${idlName}`)
187
    }
188
}

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

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

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

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