idlize

Форк
0
/
idl.ts 
552 строки · 15.9 Кб
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 webidl2 from "webidl2"
17
import { indentedBy, isDefined, stringOrNone } from "./util";
18

19
export enum IDLKind {
20
    Interface,
21
    Class,
22
    AnonymousInterface,
23
    Callback,
24
    Property,
25
    Parameter,
26
    Method,
27
    Callable,
28
    Constructor,
29
    Enum,
30
    EnumMember,
31
    Typedef,
32
    PrimitiveType,
33
    ContainerType,
34
    ReferenceType,
35
    EnumType,
36
    UnionType,
37
    TypeParameterType,
38
    ModuleType
39
}
40

41
export interface IDLExtendedAttribute {
42
    name: string
43
    value?: string
44
}
45

46
export interface IDLEntry {
47
    name?: string
48
    kind?: IDLKind
49
    fileName?: string
50
    comment?: string
51
    documentation?: string
52
    extendedAttributes?: IDLExtendedAttribute[]
53
    scope?: IDLEntry[]
54
}
55

56
export interface IDLType {
57
    name: string
58
    kind: IDLKind
59
    fileName?: string
60
    extendedAttributes?: IDLExtendedAttribute[]
61
    documentation?: string
62
}
63

64
export interface IDLTypedef extends IDLEntry {
65
    kind: IDLKind.Typedef
66
    name: string
67
    type: IDLType
68
}
69

70
export interface IDLPrimitiveType extends IDLType {
71
    kind: IDLKind.PrimitiveType
72
}
73

74
export interface IDLContainerType extends IDLType {
75
    kind: IDLKind.ContainerType
76
    elementType: IDLType[]
77
}
78

79
export interface IDLReferenceType extends IDLType {
80
    kind: IDLKind.ReferenceType
81
}
82

83
export interface IDLEnumType extends IDLType {
84
    kind: IDLKind.EnumType
85
}
86

87
export interface IDLUnionType extends IDLType {
88
    kind: IDLKind.UnionType
89
    types: IDLType[]
90
}
91

92
export interface IDLTypeParameterType extends IDLType {
93
    kind: IDLKind.TypeParameterType
94
}
95

96
export interface IDLModuleType extends IDLType {
97
    kind: IDLKind.ModuleType
98
}
99

100
export interface IDLVariable extends IDLEntry {
101
    type?: IDLType;
102
}
103

104
export interface IDLTypedEntry extends IDLEntry {
105
    type?: IDLType;
106
}
107

108
export interface IDLEnum extends IDLEntry {
109
    kind: IDLKind.Enum
110
    name: string
111
    elements: IDLEnumMember[]
112
}
113

114
export interface IDLEnumMember extends IDLEntry {
115
    kind: IDLKind.EnumMember
116
    name: string
117
    type: IDLPrimitiveType
118
    initializer: number | string | undefined
119
}
120

121
export interface IDLProperty extends IDLTypedEntry {
122
    name: string
123
    kind: IDLKind.Property
124
    type: IDLType
125
    isReadonly: boolean
126
    isStatic: boolean
127
    isOptional: boolean
128
}
129

130
export interface IDLParameter extends IDLTypedEntry {
131
    kind: IDLKind.Parameter
132
    name: string
133
    isVariadic: boolean
134
    isOptional: boolean
135
}
136

137
export interface IDLSignature extends IDLEntry {
138
    parameters: IDLParameter[]
139
    returnType?: IDLType
140
}
141

142
export interface IDLFunction extends IDLSignature {
143
}
144

145
export interface IDLMethod extends IDLFunction {
146
    kind: IDLKind.Method
147
    name: string
148
    returnType: IDLType
149
    isStatic: boolean
150
}
151

152
export interface IDLCallable extends IDLFunction {
153
    kind: IDLKind.Callable
154
    isStatic: boolean
155
}
156

157
export interface IDLConstructor extends IDLSignature {
158
    kind: IDLKind.Constructor
159
}
160

161
export interface IDLInterface extends IDLEntry {
162
    name: string
163
    kind: IDLKind.Interface | IDLKind.Class | IDLKind.AnonymousInterface
164
    inheritance: IDLType[]
165
    constructors: IDLConstructor[]
166
    properties: IDLProperty[]
167
    methods: IDLMethod[]
168
    callables: IDLFunction[]
169
}
170

171
export interface IDLCallback extends IDLEntry, IDLSignature {
172
    kind: IDLKind.Callback
173
    name: string
174
    returnType: IDLType
175
}
176

177
export function forEachChild(node: IDLEntry, cb: (entry: IDLEntry) => void): void {
178
    cb(node)
179
    switch (node.kind) {
180
        case IDLKind.Interface:
181
        case IDLKind.Class:
182
        case IDLKind.AnonymousInterface: {
183
            let iface = node as IDLInterface
184
            iface.inheritance.forEach((value) => forEachChild(value, cb))
185
            iface.constructors?.forEach((value) => forEachChild(value, cb))
186
            iface.properties.forEach((value) => forEachChild(value, cb))
187
            iface.methods.forEach((value) => forEachChild(value, cb))
188
            iface.callables.forEach((value) => forEachChild(value, cb))
189
            iface.scope?.forEach((value) => forEachChild(value, cb))
190
            break
191
        }
192
        case IDLKind.Method:
193
        case IDLKind.Callable:
194
        case IDLKind.Callback:
195
        case IDLKind.Constructor: {
196
            let param = node as IDLSignature
197
            param.parameters?.forEach((value) => forEachChild(value, cb))
198
            if (param.returnType) forEachChild(param.returnType, cb)
199
            break
200
        }
201
        case IDLKind.UnionType: {
202
            let param = node as IDLUnionType
203
            param.types?.forEach((value) => forEachChild(value, cb))
204
            break
205
        }
206
        case IDLKind.Enum: {
207
            break
208
        }
209
        case IDLKind.Property:
210
        case IDLKind.Parameter:
211
        case IDLKind.Typedef:
212
        case IDLKind.EnumType:
213
        case IDLKind.PrimitiveType:
214
        case IDLKind.ContainerType:
215
        case IDLKind.TypeParameterType:
216
        case IDLKind.ReferenceType: {
217
            break
218
        }
219
        case IDLKind.ModuleType: {
220
            break
221
        }
222
        default: {
223
            throw new Error(`Unhandled ${node.kind}`)
224
        }
225
    }
226
}
227

228
export function isPrimitiveType(type: IDLType): type is IDLPrimitiveType {
229
    return type.kind == IDLKind.PrimitiveType
230
}
231
export function isContainerType(type: IDLType): type is IDLContainerType {
232
    return type.kind == IDLKind.ContainerType
233
}
234
export function isReferenceType(type: IDLType): type is IDLReferenceType {
235
    return type.kind == IDLKind.ReferenceType
236
}
237
export function isEnumType(type: IDLType): type is IDLEnumType {
238
    return type.kind == IDLKind.EnumType
239
}
240
export function isEnum(type: IDLEntry): type is IDLEnum {
241
    return type.kind == IDLKind.Enum
242
}
243
export function isUnionType(type: IDLType): type is IDLUnionType {
244
    return type.kind == IDLKind.UnionType
245
}
246
export function isTypeParameterType(type: IDLType): type is IDLTypeParameterType {
247
    return type.kind == IDLKind.TypeParameterType
248
}
249
export function isInterface(node: IDLEntry): node is IDLInterface {
250
    return node.kind === IDLKind.Interface
251
}
252
export function isClass(node: IDLEntry): node is IDLInterface {
253
    return node.kind === IDLKind.Class
254
}
255
export function isMethod(node: IDLEntry): node is IDLMethod {
256
    return node.kind === IDLKind.Method
257
}
258
export function isConstructor(node: IDLEntry): node is IDLConstructor {
259
    return node.kind === IDLKind.Constructor
260
}
261
export function isProperty(node: IDLEntry): node is IDLProperty {
262
    return node.kind === IDLKind.Property
263
}
264
export function isCallback(node: IDLEntry): node is IDLCallback {
265
    return node.kind === IDLKind.Callback
266
}
267
export function isTypedef(node: IDLEntry): node is IDLTypedef {
268
    return node.kind === IDLKind.Typedef
269
}
270

271
export function isModuleType(node: IDLEntry): node is IDLModuleType {
272
    return node.kind === IDLKind.ModuleType
273
}
274

275
export function createStringType(): IDLPrimitiveType {
276
    return {
277
        kind: IDLKind.PrimitiveType,
278
        name: "DOMString"
279
    }
280
}
281

282
export function createNumberType(): IDLPrimitiveType {
283
    return {
284
        kind: IDLKind.PrimitiveType,
285
        name: "number"
286
    }
287
}
288

289
export function createUndefinedType(): IDLPrimitiveType {
290
    return {
291
        kind: IDLKind.PrimitiveType,
292
        name: "undefined"
293
    }
294
}
295

296
export function createAnyType(documentation?: string): IDLPrimitiveType {
297
    return {
298
        kind: IDLKind.PrimitiveType,
299
        name: "any",
300
        documentation: documentation
301
    }
302
}
303

304
export function createReferenceType(name: string): IDLReferenceType {
305
    return {
306
        kind: IDLKind.ReferenceType,
307
        name: name
308
    }
309
}
310

311
export function createEnumType(name: string): IDLEnumType {
312
    return {
313
        kind: IDLKind.EnumType,
314
        name: name
315
    }
316
}
317

318
export function createContainerType(container: string, element: IDLType[]): IDLContainerType {
319
    return {
320
        kind: IDLKind.ContainerType,
321
        name: container,
322
        elementType: element
323
    }
324
}
325

326
export function createUnionType(types: IDLType[]): IDLUnionType {
327
    return {
328
        kind: IDLKind.UnionType,
329
        name: "or",
330
        types: types
331
    }
332
}
333

334
export function createTypeParameterReference(name: string): IDLTypeParameterType {
335
    return {
336
        kind: IDLKind.TypeParameterType,
337
        name: name
338
    }
339
}
340

341
export function createTypedef(name: string, type: IDLType): IDLTypedef {
342
    return {
343
        kind: IDLKind.Typedef,
344
        name: name,
345
        type: type
346
    }
347
}
348

349
export function printType(type: IDLType | undefined): string {
350
    if (!type) throw new Error("Missing type")
351
    if (isPrimitiveType(type)) return type.name
352
    if (isContainerType(type)) return `${type.name}<${type.elementType.map(printType).join(", ")}>`
353
    if (isReferenceType(type)) return `${type.name}`
354
    if (isUnionType(type)) return `(${type.types.map(printType).join(" or ")})`
355
    if (isEnumType(type)) return type.name
356
    if (isTypeParameterType(type)) return type.name
357
    throw new Error(`Cannot map type: ${IDLKind[type.kind]}`)
358
}
359

360
export function printParameters(parameters: IDLParameter[] | undefined): string {
361
    return parameters
362
        ?.map(it =>
363
            nameWithType(it, it.isVariadic, it.isOptional)
364
        )
365
        ?.join(", ") ?? ""
366
}
367

368
export function printConstructor(idl: IDLFunction): stringOrNone[] {
369
    return [indentedBy(`constructor(${printParameters(idl.parameters)});`, 1)]
370
}
371

372
export function nameWithType(
373
    idl: IDLVariable,
374
    isVariadic: boolean = false,
375
    isOptional: boolean = false
376
): string {
377
    const type = printType(idl.type)
378
    const variadic = isVariadic ? "..." : ""
379
    const optional = isOptional ? "optional " : ""
380
    return `${optional}${type}${variadic} ${idl.name}`
381
}
382

383
function printProperty(idl: IDLProperty): stringOrNone[] {
384
    const staticMod = idl.isStatic ? "static " : ""
385
    const readonlyMod = idl.isReadonly ? "readonly " : ""
386

387
    return [
388
        ...printExtendedAttributes(idl, 1),
389
        indentedBy(`${staticMod}${readonlyMod}attribute ${nameWithType(idl)};`, 1)
390
    ]
391
}
392

393
function escapeDocs(input: string): string {
394
    return input.replaceAll('"', "'")
395
}
396

397
function printExtendedAttributes(idl: IDLEntry, indentLevel: number): stringOrNone[] {
398
    let attributes = idl.extendedAttributes
399
    if (idl.documentation) {
400
        let docs: IDLExtendedAttribute = {
401
            name: 'Documentation',
402
            value: `"${escapeDocs(idl.documentation)}"`
403
        }
404
        if (attributes)
405
            attributes.push(docs)
406
        else
407
            attributes = [docs]
408
    }
409
    return [attributes ? indentedBy(`[${attributes.map(it => `${it.name}${it.value ? "=" + it.value : ""}`).join(", ")}]`, indentLevel) : undefined]
410
}
411

412
export function printFunction(idl: IDLFunction): stringOrNone[] {
413
    if (idl.name?.startsWith("__")) {
414
        console.log(`Ignore ${idl.name}`)
415
        return []
416
    }
417
    return [
418
        ...printExtendedAttributes(idl, 1),
419
        indentedBy(`${printType(idl.returnType)} ${idl.name}(${printParameters(idl.parameters)});`, 1)
420
    ]
421
}
422

423
export function printMethod(idl: IDLMethod): stringOrNone[] {
424
    if (idl.name?.startsWith("__")) {
425
        console.log(`Ignore ${idl.name}`)
426
        return []
427
    }
428
    return [
429
        ...printExtendedAttributes(idl, 1),
430
        indentedBy(`${idl.isStatic ? "static " : ""}${printType(idl.returnType)} ${idl.name}(${printParameters(idl.parameters)});`, 1)
431
    ]
432
}
433

434
export function printModule(idl: IDLModuleType): stringOrNone[] {
435
    // may changes later to deal namespace. currently just VerbatimDts
436
    return [
437
        ...printExtendedAttributes(idl,0),
438
        `namespace ${idl.name} {};`
439
    ]
440
}
441

442
export function printCallback(idl: IDLCallback): stringOrNone[] {
443
    return [`callback ${idl.name} = ${printType(idl.returnType)} (${printParameters(idl.parameters)});`]
444
}
445

446
export function printScoped(idl: IDLEntry): stringOrNone[] {
447
    if (idl.kind == IDLKind.Callback) return printCallback(idl as IDLCallback)
448
    if (idl.kind == IDLKind.AnonymousInterface) return printInterface(idl as IDLInterface)
449
    return [`/* Unexpected scoped: ${idl.kind} ${idl.name} */`]
450
}
451

452
export function printInterface(idl: IDLInterface): stringOrNone[] {
453
    return [
454
        ...printExtendedAttributes(idl, 0),
455
        `interface ${idl.name} ${idl.inheritance.length > 0 ? ": " + printType(idl.inheritance[0]) : ""} {`,
456
        // TODO: type system hack!
457
    ]
458
        .concat(idl.constructors.map(printConstructor).flat())
459
        .concat(idl.properties.map(printProperty).flat())
460
        .concat(idl.methods.map(printMethod).flat())
461
        .concat(idl.callables.map(printFunction).flat())
462
        .concat(["};"])
463
}
464

465
export function printEnumMember(idl: IDLEnumMember): stringOrNone[] {
466
    const type = printType(idl.type)
467
    const initializer = type == "DOMString" ? `"${idl.initializer}"` : idl.initializer
468
    return [indentedBy(`${type} ${idl.name}${initializer ? ` = ${initializer}` : ``};`, 1)]
469
}
470

471
export function printEnum(idl: IDLEnum, skipInitializers: boolean): stringOrNone[] {
472
    if (skipInitializers) {
473
        return [
474
            idl.documentation,
475
            ...printExtendedAttributes(idl, 0),
476
            `enum ${idl.name!} {`,
477
            ...idl.elements.map(it => indentedBy(`${it.name} ${(it.initializer ? " /* " + it.initializer + " */" : "")}`, 1)),
478
            "};"
479
        ]
480
    } else {
481
        return [
482
            idl.documentation,
483
            ...printExtendedAttributes(idl, 0),
484
            `dictionary ${idl.name!} {`,
485
            ...idl.elements.map(printEnumMember) as any,
486
            "};"
487
        ]
488
    }
489
}
490

491
export function printTypedef(idl: IDLTypedef): stringOrNone[] {
492
    return [
493
        idl.documentation,
494
        ...printExtendedAttributes(idl, 0),
495
        `typedef ${printType(idl.type)} ${idl.name!};`
496
    ]
497
}
498

499

500
export function printIDL(idl: IDLEntry, options?: Partial<IDLPrintOptions>): stringOrNone[] {
501
    if (idl.kind == IDLKind.Class
502
        || idl.kind == IDLKind.Interface
503
        || idl.kind == IDLKind.AnonymousInterface
504
    ) return printInterface(idl as IDLInterface)
505
    if (idl.kind == IDLKind.Enum) return printEnum(idl as IDLEnum, options?.disableEnumInitializers ?? false)
506
    if (idl.kind == IDLKind.Typedef) return printTypedef(idl as IDLTypedef)
507
    if (idl.kind == IDLKind.Callback) return printCallback(idl as IDLCallback)
508
    if (idl.kind == IDLKind.ModuleType) return printModule(idl as IDLModuleType)
509
    return [`unexpected kind: ${idl.kind}`]
510
}
511

512
export interface IDLPrintOptions {
513
    verifyIdl: boolean
514
    disableEnumInitializers: boolean
515
}
516

517
export function toIDLString(entries: IDLEntry[], options: Partial<IDLPrintOptions>): string {
518
    const generatedScopes = printScopes(entries)
519
    const generatedIdl = entries
520
        .map(it => printIDL(it, options))
521
        .concat(generatedScopes)
522
        .flat()
523
        .filter(isDefined)
524
        .filter(it => it.length > 0)
525
        .join("\n")
526
    if (options.verifyIdl) webidl2.validate(webidl2.parse(generatedIdl))
527
    return generatedIdl
528
}
529

530
function printScopes(entries: IDLEntry[]) {
531
    return entries
532
        .map((it: IDLEntry) => it.scope)
533
        .filter(isDefined)
534
        .flatMap((it: IDLEntry[]) => it.map(printScoped))
535
}
536

537
export function hasExtAttribute(node: IDLEntry, attribute: string): boolean {
538
    return node.extendedAttributes?.find((it) => it.name == attribute) != undefined
539
}
540

541
export function getExtAttribute(node: IDLEntry, name: string): stringOrNone {
542
    let value = undefined
543
    node.extendedAttributes?.forEach(it => {
544
        if (it.name == name) value = it.value
545
    })
546
    return value
547
}
548

549
export function getVerbatimDts(node: IDLEntry): stringOrNone {
550
    let value = getExtAttribute(node, "VerbatimDts")
551
    return value ? value.substring(1, value.length - 1) : undefined
552
}

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

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

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

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