blob: 59308840b9e8f8c6fae929566a1851d12be185b4 [file]
/**
* @typedef {import("../productions/dictionary.js").Dictionary} Dictionary
*
* @param {*} idlType
* @param {import("../validator.js").Definitions} defs
* @param {object} [options]
* @param {boolean} [options.useNullableInner] use when the input idlType is nullable and you want to use its inner type
* @return {{ reference: *, dictionary: Dictionary }} the type reference that ultimately includes dictionary.
*/
export function idlTypeIncludesDictionary(
idlType,
defs,
{ useNullableInner } = {}
) {
if (!idlType.union) {
const def = defs.unique.get(idlType.idlType);
if (!def) {
return;
}
if (def.type === "typedef") {
const { typedefIncludesDictionary } = defs.cache;
if (typedefIncludesDictionary.has(def)) {
// Note that this also halts when it met indeterminate state
// to prevent infinite recursion
return typedefIncludesDictionary.get(def);
}
defs.cache.typedefIncludesDictionary.set(def, undefined); // indeterminate state
const result = idlTypeIncludesDictionary(def.idlType, defs);
defs.cache.typedefIncludesDictionary.set(def, result);
if (result) {
return {
reference: idlType,
dictionary: result.dictionary,
};
}
}
if (def.type === "dictionary" && (useNullableInner || !idlType.nullable)) {
return {
reference: idlType,
dictionary: def,
};
}
}
for (const subtype of idlType.subtype) {
const result = idlTypeIncludesDictionary(subtype, defs);
if (result) {
if (subtype.union) {
return result;
}
return {
reference: subtype,
dictionary: result.dictionary,
};
}
}
}
/**
* @param {*} dict dictionary type
* @param {import("../validator.js").Definitions} defs
* @return {boolean}
*/
export function dictionaryIncludesRequiredField(dict, defs) {
if (defs.cache.dictionaryIncludesRequiredField.has(dict)) {
return defs.cache.dictionaryIncludesRequiredField.get(dict);
}
// Set cached result to indeterminate to short-circuit circular definitions.
// The final result will be updated to true or false.
defs.cache.dictionaryIncludesRequiredField.set(dict, undefined);
let result = dict.members.some((field) => field.required);
if (!result && dict.inheritance) {
const superdict = defs.unique.get(dict.inheritance);
if (!superdict) {
// Assume required members in the supertype if it is unknown.
result = true;
} else if (dictionaryIncludesRequiredField(superdict, defs)) {
result = true;
}
}
defs.cache.dictionaryIncludesRequiredField.set(dict, result);
return result;
}