idlize

Форк
0
/
DtsPrinter.ts 
216 строк · 8.7 Кб
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, IDLEntity, 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.printInterface(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
    currentInterface?: IDLInterface
49

50
    printInterface(node: IDLInterface) {
51
        let typeSpec = toTypeName(node)
52
        const entity = getExtAttribute(node, "Entity")
53
        if (entity === IDLEntity.Literal) {
54
            this.print(`declare type ${typeSpec} = { ${
55
                node.properties.map(it => `${it.name}: ${printTypeForTS(it.type)}`).join(", ")
56
            } }`)
57
        } else if (entity === IDLEntity.Tuple) {
58
            this.print(`declare type ${typeSpec} = [ ${
59
                node.properties.map(it => `${printTypeForTS(it.type)}`).join(", ")
60
            } ]`)
61
        } else if (entity === IDLEntity.NamedTuple) {
62
            this.print(`declare type ${typeSpec} = [ ${
63
                node.properties.map(it => `${it.name}: ${printTypeForTS(it.type)}`).join(", ")
64
            } ]`)
65
        } else {
66
            // restore globalScope
67
            if (hasExtAttribute(node,"GlobalScope")) {
68
                node.methods.map(it => this.printMethod(it, true))
69
                return
70
            }
71
            if (hasExtAttribute(node, "Component")) {
72
                typeSpec = node.name + (node.name == "CommonMethod"
73
                    ? "<T>"
74
                    : ` extends CommonMethod<${getExtAttribute(node, "Component")}Attribute>`)
75
            }
76
            this.print(`declare ${entity!.toLowerCase()} ${typeSpec} {`)
77
            this.currentInterface = node
78
            this.pushIndent()
79
            node.constructors.map(it => this.visit(it))
80
            node.properties.map(it => this.visit(it))
81
            node.methods.map(it => this.visit(it))
82
            node.callables.map(it => this.visit(it))
83
            let verbatim = getVerbatimDts(node)
84
            if (verbatim) {
85
                verbatim
86
                    .split("\n")
87
                    .map(it => this.print(it))
88
            }
89

90
            this.popIndent()
91
            this.print("}")
92
            if (hasExtAttribute(node, "Component")) {
93
                let name = getExtAttribute(node, "Component")
94
                this.print(`declare const ${name}Instance: ${name}Attribute;`)
95
                this.print(`declare const ${name}: ${name}Interface;`)
96
            }
97
        }
98
    }
99

100
    printMethod(node: IDLMethod|IDLConstructor, isGlobal : boolean = false) {
101
        let returnType = node.returnType ? `: ${printTypeForTS(node.returnType, true)}` : ""
102
        let isStatic = isMethod(node) && node.isStatic
103
        let name = isConstructor(node) ? "constructor" : node.name
104
        let isOptional = isMethod(node) && node.isOptional
105
        if (hasExtAttribute(node, "CallSignature")) name = ""
106
        if (hasExtAttribute(node,"DtsName")) {
107
            let dtsName = getExtAttribute(node, "DtsName")
108
            name = dtsName ? dtsName.replaceAll("\"","") : ""
109
        }
110
        this.print(`${isGlobal ? "declare function ": ""}${isStatic ? "static " : ""}${name}${isOptional ?"?":""}(${node.parameters.map(p => this.paramText(p)).join(", ")})${returnType};`)
111
    }
112
    paramText(param: IDLParameter): string {
113
        return `${param.isVariadic ? "..." : ""}${param.name}${param.isOptional ? "?" : ""}: ${printTypeForTS(param.type)}`
114
    }
115
    printProperty(node: IDLProperty) {
116
        const isCommonMethod = hasExtAttribute(node, "CommonMethod")
117
        if (isCommonMethod) {
118
            let returnType = this.currentInterface!.name == "CommonMethod" ? "T" : this.currentInterface!.name
119
            this.print(`${node.name}(value: ${printTypeForTS(node.type)}): ${returnType};`)
120
        } else {
121
            this.print(`${node.isStatic ? "static " : ""}${node.isReadonly ? "readonly " : ""}${node.name}${node.isOptional ? "?" : ""}: ${printTypeForTS(node.type)};`)
122

123
        }
124
    }
125
    printEnum(node: IDLEnum) {
126
        this.print(`declare enum ${node.name} {`)
127
        this.pushIndent()
128
        node.elements.forEach((it, index) => {
129
            this.print(`${it.name}${it.initializer ? " = " + it.initializer : ""}${index < node.elements.length - 1 ? "," : ""}`)
130
        })
131
        this.popIndent()
132
        this.print("}")
133
    }
134
    printCallback(node: IDLCallback) {
135
        // TODO: is it correct.
136
        this.print(`declare type ${(node.name)} = (${node.parameters.map(it => `${it.isVariadic ? "..." : ""}${it.name}: ${printTypeForTS(it.type)}`).join(", ")}) => ${printTypeForTS(node.returnType)};`)
137
    }
138
    printTypedef(node: IDLTypedef) {
139
        let text = getVerbatimDts(node) ?? printTypeForTS(node.type)
140
        this.print(`declare type ${(node.name)} = ${text};`)
141
    }
142

143
    printModuleType(node: IDLModuleType) {
144
        let text = getVerbatimDts(node) ?? ""
145
        this.print(`${text}`)
146
    }
147

148
    checkVerbatim(node: IDLEntry) {
149
        let verbatim = getExtAttribute(node, "VerbatimDts")
150
        if (verbatim) {
151
            verbatim
152
                .substring(1, verbatim.length - 2)
153
                .split('\n')
154
                .forEach(it => this.print(it))
155
        }
156
    }
157

158
    private indent = 0
159
    indented(input: string): string {
160
        return indentedBy(input, this.indent)
161
    }
162
    pushIndent() {
163
        this.indent++
164
    }
165
    popIndent() {
166
        this.indent--
167
    }
168
    print(value: stringOrNone) {
169
        if (value) this.output.push(this.indented(value))
170
    }
171
}
172

173
export function idlToString(name: string, content: string): string {
174
    let printer = new CustomPrintVisitor()
175
    webidl2.parse(content)
176
        .map(it => toIDLNode(name, it))
177
        .map(it => printer.visit(it))
178
    return printer.output.join("\n")
179
}
180

181
export function printTypeForTS(type: IDLType | undefined, undefinedToVoid?: boolean): string {
182
    if (!type) throw new Error("Missing type")
183
    if (type.name == "undefined" && undefinedToVoid) return "void"
184
    if (type.name == "int32" || type.name == "float32") return "number"
185
    if (type.name == "DOMString") return "string"
186
    if (type.name == "this") return "T"
187
    if (isPrimitiveType(type)) return type.name
188
    if (isContainerType(type))
189
        return `${mapContainerType(type.name)}<${type.elementType.map(it => printTypeForTS(it)).join(",")}>`
190
    if (isReferenceType(type)) return toTypeName(type)
191
    if (isUnionType(type)) return `(${type.types.map(it => printTypeForTS(it)).join("|")})`
192
    if (isEnumType(type)) return type.name
193
    if (isTypeParameterType(type)) return type.name
194
    throw new Error(`Cannot map type: ${IDLKind[type.kind]}`)
195
}
196

197
function mapContainerType(idlName: string): string {
198
    switch (idlName) {
199
        case "sequence": return "Array"
200
        case "record": return "Map"
201
        case "Promise": return "Promise"
202
        default: throw new Error(`Unmapped container type: ${idlName}`)
203
    }
204
}
205

206
function toTypeName(node: IDLEntry): string {
207
    const importAttr = getExtAttribute(node, "Import")
208
    if (importAttr) {
209
        return importAttr.slice(1, -1)
210
    }
211
    const typeParamsAttr = getExtAttribute(node, "TypeParameters")
212
    if (typeParamsAttr) {
213
        return `${node.name}<${typeParamsAttr.slice(1, -1)}>`
214
    }
215
    return node.name ?? "MISSING_TYPE_NAME"
216
}

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

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

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

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