| import { validationError as error } from "./error.js"; |
| |
| function getMixinMap(all, unique) { |
| const map = new Map(); |
| const includes = all.filter((def) => def.type === "includes"); |
| for (const include of includes) { |
| const mixin = unique.get(include.includes); |
| if (!mixin) { |
| continue; |
| } |
| const array = map.get(include.target); |
| if (array) { |
| array.push(mixin); |
| } else { |
| map.set(include.target, [mixin]); |
| } |
| } |
| return map; |
| } |
| |
| /** |
| * @typedef {ReturnType<typeof groupDefinitions>} Definitions |
| */ |
| function groupDefinitions(all) { |
| const unique = new Map(); |
| const duplicates = new Set(); |
| const partials = new Map(); |
| for (const def of all) { |
| if (def.partial) { |
| const array = partials.get(def.name); |
| if (array) { |
| array.push(def); |
| } else { |
| partials.set(def.name, [def]); |
| } |
| continue; |
| } |
| if (!def.name) { |
| continue; |
| } |
| if (!unique.has(def.name)) { |
| unique.set(def.name, def); |
| } else { |
| duplicates.add(def); |
| } |
| } |
| return { |
| all, |
| unique, |
| partials, |
| duplicates, |
| mixinMap: getMixinMap(all, unique), |
| cache: { |
| typedefIncludesDictionary: new WeakMap(), |
| dictionaryIncludesRequiredField: new WeakMap(), |
| }, |
| }; |
| } |
| |
| function* checkDuplicatedNames({ unique, duplicates }) { |
| for (const dup of duplicates) { |
| const { name } = dup; |
| const message = `The name "${name}" of type "${ |
| unique.get(name).type |
| }" was already seen`; |
| yield error(dup.tokens.name, dup, "no-duplicate", message); |
| } |
| } |
| |
| function* validateIterable(ast) { |
| const defs = groupDefinitions(ast); |
| for (const def of defs.all) { |
| if (def.validate) { |
| yield* def.validate(defs); |
| } |
| } |
| yield* checkDuplicatedNames(defs); |
| } |
| |
| // Remove this once all of our support targets expose `.flat()` by default |
| function flatten(array) { |
| if (array.flat) { |
| return array.flat(); |
| } |
| return [].concat(...array); |
| } |
| |
| /** |
| * @param {import("./productions/base.js").Base[]} ast |
| * @return {import("./error.js").WebIDLErrorData[]} validation errors |
| */ |
| export function validate(ast) { |
| return [...validateIterable(flatten(ast))]; |
| } |