16
import * as webidl2 from "webidl2"
18
isAttribute, isCallback, isClass, isConstructor, isDictionary, isEnum, isInterface, isOperation, isOptional,
19
isPromiseTypeDescription,
20
isRecordTypeDescription,
21
isSequenceTypeDescription,
22
isSingleTypeDescription, isTypedef, isUnionTypeDescription
23
} from "./webidl2-utils"
24
import { toString } from "./toString"
26
createContainerType, createNumberType, createUnionType, hasExtAttribute, IDLCallback, IDLConstructor, IDLEntry, IDLEnum, IDLEnumMember, IDLExtendedAttribute, IDLInterface, IDLKind,
27
IDLMethod, IDLModuleType, IDLParameter, IDLPrimitiveType, IDLProperty, IDLType, IDLTypedef
29
import { isDefined, stringOrNone } from "../util"
31
export function toIDLNode(file: string, node: webidl2.IDLRootType): IDLEntry {
33
return toIDLEnum(file, node)
36
return toIDLInterface(file, node)
38
if (isInterface(node)) {
39
return toIDLInterface(file, node)
41
if (isCallback(node)) {
42
return toIDLCallback(file, node)
44
if (isTypedef(node)) {
45
return toIDLTypedef(file, node)
47
if (isDictionary(node)) {
48
return toIDLDictionary(file, node)
50
if (isNamespace(node)) {
51
return toIDLNamespcae(file, node)
54
throw new Error(`unexpected node type: ${toString(node)}`)
58
function isNamespace(node: webidl2.IDLRootType): node is webidl2.NamespaceType {
59
return node.type === 'namespace'
61
function isCallable(node: webidl2.IDLInterfaceMemberType): boolean {
62
return node.extAttrs.some(it => it.name == "Invoke")
65
function toIDLInterface(file: string, node: webidl2.InterfaceType): IDLInterface {
67
kind: isClass(node) ? IDLKind.Class : IDLKind.Interface,
70
documentation: makeDocs(node),
71
inheritance: [node.inheritance]
73
.map(it => toIDLType(file, it)),
74
constructors: node.members
75
.filter(isConstructor)
76
.map(it => toIDLConstructor(file, it)),
78
properties: node.members
80
.map(it => toIDLProperty(file, it)),
83
.filter(it => !isCallable(it))
84
.map(it => toIDLMethod(file, it)),
85
extendedAttributes: toExtendedAttributes(node.extAttrs),
86
callables: node.members
88
.filter(it => isCallable(it))
89
.map(it => toIDLMethod(file, it)),
93
function toTypeParams(extAttrs: webidl2.ExtendedAttribute[] | undefined) {
94
let result = undefined
95
extAttrs?.forEach(it => {
96
if (it.name === "TypeParameters") result = toExtendedAttributeValue(it)
101
function toIDLType(file: string, type: webidl2.IDLTypeDescription | string, extAttrs?: webidl2.ExtendedAttribute[]): IDLType {
102
if (typeof type === "string") {
103
const typeParams = toTypeParams(extAttrs)
107
kind: IDLKind.ReferenceType,
108
extendedAttributes: typeParams ? [{ "name": "TypeParameters", value: typeParams }] : []
111
if (isUnionTypeDescription(type)) {
112
const unionTypes = type.idlType
113
return createUnionType(unionTypes
114
.map(it => toIDLType(file, it))
117
if (isSingleTypeDescription(type)) {
121
kind: IDLKind.ReferenceType,
122
extendedAttributes: toExtendedAttributes(type.extAttrs)?.concat(
123
toExtendedAttributes(extAttrs ?? []) ?? [])
126
if (isSequenceTypeDescription(type) || isPromiseTypeDescription(type) || isRecordTypeDescription(type)) {
127
return createContainerType(
129
type.idlType.map(it => toIDLType(file, it))
133
throw new Error(`unexpected type: ${toString(type)}`)
137
function toIDLMethod(file: string, node: webidl2.OperationMemberType): IDLMethod {
139
throw new Error(`method with no type ${toString(node)}`)
142
name: node.name ?? "",
143
isStatic: node.special === "static",
144
parameters: node.arguments.map(it => toIDLParameter(file, it)),
145
documentation: makeDocs(node),
146
returnType: toIDLType(file, node.idlType, node.extAttrs),
147
extendedAttributes: toExtendedAttributes(node.extAttrs),
148
kind: IDLKind.Method,
149
isOptional: isOptional(node)
153
function toIDLConstructor(file: string, node: webidl2.ConstructorMemberType): IDLConstructor {
155
parameters: node.arguments.map(it => toIDLParameter(file, it)),
156
documentation: makeDocs(node),
157
kind: IDLKind.Constructor
161
function toIDLParameter(file: string, node: webidl2.Argument): IDLParameter {
163
kind: IDLKind.Parameter,
165
isVariadic: node.variadic,
166
isOptional: node.optional,
167
type: toIDLType(file, node.idlType, node.extAttrs),
172
function toIDLCallback(file: string, node: webidl2.CallbackType): IDLCallback {
174
kind: IDLKind.Callback,
177
parameters: node.arguments.map(it => toIDLParameter(file, it)),
178
extendedAttributes: toExtendedAttributes(node.extAttrs),
179
documentation: makeDocs(node),
180
returnType: toIDLType(file, node.idlType)
184
function toIDLTypedef(file: string, node: webidl2.TypedefType): IDLTypedef {
186
kind: IDLKind.Typedef,
187
type: toIDLType(file, node.idlType),
188
extendedAttributes: toExtendedAttributes(node.extAttrs),
189
documentation: makeDocs(node),
195
function toIDLDictionary(file: string, node: webidl2.DictionaryType): IDLEnum {
199
documentation: makeDocs(node),
200
extendedAttributes: toExtendedAttributes(node.extAttrs),
202
elements: node.members.map(it => toIDLEnumMember(file, it))
206
function toIDLNamespcae(file: string, node: webidl2.NamespaceType): IDLModuleType {
209
kind: IDLKind.ModuleType,
211
extendedAttributes: toExtendedAttributes(node.extAttrs),
216
function toIDLProperty(file: string, node: webidl2.AttributeMemberType): IDLProperty {
218
kind: IDLKind.Property,
220
documentation: makeDocs(node),
222
type: toIDLType(file, node.idlType),
223
isReadonly: node.readonly,
224
isStatic: node.special === "static",
225
isOptional: isOptional(node),
226
extendedAttributes: toExtendedAttributes(node.extAttrs)
230
function toIDLEnumMember(file: string, node: webidl2.DictionaryMemberType): IDLEnumMember {
231
let initializer = undefined
232
if (node.default?.type == "string") {
233
initializer = node.default?.value
234
} else if (node.default?.type == "number") {
235
initializer = +(node.default?.value)
236
} else if (node.default == null) {
237
initializer = undefined
239
throw new Error(`Not representable enum initializer: ${node.default}`)
242
kind: IDLKind.EnumMember,
244
type: toIDLType(file, node.idlType) as IDLPrimitiveType,
245
extendedAttributes: toExtendedAttributes(node.extAttrs),
246
initializer: initializer
250
function toExtendedAttributes(extAttrs: webidl2.ExtendedAttribute[]): IDLExtendedAttribute[]|undefined {
251
return extAttrs.map(it => {
252
return { name: it.name, value: toExtendedAttributeValue(it) }
256
function toExtendedAttributeValue(attr: webidl2.ExtendedAttribute): stringOrNone {
258
return attr.rhs?.value instanceof Array
259
? attr.rhs.value.map(v => v.value).join(",")
263
function makeDocs(node: webidl2.AbstractBase): stringOrNone {
265
node.extAttrs.forEach(it => {
266
if (it.name == "Documentation") docs = it.rhs?.value
271
function toIDLEnum(file: string, node: webidl2.EnumType): IDLEnum {
276
documentation: makeDocs(node),
277
extendedAttributes: toExtendedAttributes(node.extAttrs),
278
elements: node.values.map((it: { value: string }) => {
280
kind: IDLKind.EnumMember,
282
type: createNumberType(),
283
initializer: undefined