blob: 988a9effb69d06cbd2db0592442cf5fa2a8b4fec [file] [log] [blame]
import { validationError } from "../error.js";
/**
* @param {import("../validator.js").Definitions} defs
* @param {import("../productions/container.js").Container} i
*/
export function* checkInterfaceMemberDuplication(defs, i) {
const opNames = groupOperationNames(i);
const partials = defs.partials.get(i.name) || [];
const mixins = defs.mixinMap.get(i.name) || [];
for (const ext of [...partials, ...mixins]) {
const additions = getOperations(ext);
const statics = additions.filter((a) => a.special === "static");
const nonstatics = additions.filter((a) => a.special !== "static");
yield* checkAdditions(statics, opNames.statics, ext, i);
yield* checkAdditions(nonstatics, opNames.nonstatics, ext, i);
statics.forEach((op) => opNames.statics.add(op.name));
nonstatics.forEach((op) => opNames.nonstatics.add(op.name));
}
/**
* @param {import("../productions/operation.js").Operation[]} additions
* @param {Set<string>} existings
* @param {import("../productions/container.js").Container} ext
* @param {import("../productions/container.js").Container} base
*/
function* checkAdditions(additions, existings, ext, base) {
for (const addition of additions) {
const { name } = addition;
if (name && existings.has(name)) {
const isStatic = addition.special === "static" ? "static " : "";
const message = `The ${isStatic}operation "${name}" has already been defined for the base interface "${base.name}" either in itself or in a mixin`;
yield validationError(
addition.tokens.name,
ext,
"no-cross-overload",
message
);
}
}
}
/**
* @param {import("../productions/container.js").Container} i
* @returns {import("../productions/operation.js").Operation[]}
*/
function getOperations(i) {
return i.members.filter(({ type }) => type === "operation");
}
/**
* @param {import("../productions/container.js").Container} i
*/
function groupOperationNames(i) {
const ops = getOperations(i);
return {
statics: new Set(
ops.filter((op) => op.special === "static").map((op) => op.name)
),
nonstatics: new Set(
ops.filter((op) => op.special !== "static").map((op) => op.name)
),
};
}
}