in src/schema/firefox-schemas-import.js [350:421]
export function rewriteExtend(schemas, schemaId) {
const definitions = {};
const refs = {};
const types = {};
schemas.forEach((extendSchema) => {
const extendId = extendSchema.namespace;
const { max_manifest_version, min_manifest_version } = extendSchema;
const extendDefinitions = {};
const extendTypes = {};
(extendSchema.types || []).forEach((type) => {
const { $extend, id, ...rest } = type;
if ($extend) {
// Throw an explicit error if we are going to deep merge a set of properties which may be
// overriding an existing one, instead of extending the type with new ones as expected.
if (rest.properties) {
const newProps = Object.keys(rest.properties);
if (
!newProps.every(
// Make sure that the value set of each property name that we are going to merge
// is null or undefined.
(k) => extendDefinitions?.[$extend]?.properties?.[k] == null
)
) {
throw new Error(oneLine`Unsupported schema format:
detected multiple extend schema entries overwriting existing properties
while processing "${schemaId}" namespace
`);
}
}
// Move the $extend into definitions.
//
// NOTE: some schema files, like browser_action.json, may contain more than one extends
// and so here we use deepmerge to merge the multiple extended definitions instead
// of overwriting it with the last one processed.
extendDefinitions[$extend] = deepmerge(
extendDefinitions[$extend] ?? {},
rest
);
// Remember the location of this file so we can $ref it later.
refs[`${schemaId}#/definitions/${$extend}`] = {
namespace: extendId,
type: $extend,
};
} else if (id) {
// Move this type into types.
extendTypes[id] = rest;
types[id] = rest;
} else {
throw new Error('cannot handle extend, $extend or id is required');
}
});
Object.keys(extendDefinitions).forEach((id) => {
// Update $refs to point to the right namespace.
const definition = extendDefinitions[id];
if (extendId === 'manifest') {
// if the definition is extending the manifest types, we have to
// propagate the min/max_manifest_version keyword to the definitions
// attributes (which make sure we will collect validation errors if
// the manifest property is part of an API namespace unsupported on
// the addon manifest version.
propagateManifestVersionRestrictions({
definition,
max_manifest_version,
min_manifest_version,
});
}
definitions[id] = rewriteExtendRefs(definition, extendId, extendTypes);
});
});
return { definitions, refs, types };
}