in src/extensions/extensionsHelper.ts [212:324]
export function validateSpec(spec: any) {
const errors = [];
if (!spec.name) {
errors.push("extension.yaml is missing required field: name");
}
if (!spec.specVersion) {
errors.push("extension.yaml is missing required field: specVersion");
}
if (!spec.version) {
errors.push("extension.yaml is missing required field: version");
}
if (!spec.license) {
errors.push("extension.yaml is missing required field: license");
} else {
const formattedLicense = String(spec.license).toLocaleLowerCase();
if (!VALID_LICENSES.includes(formattedLicense)) {
errors.push(
`license field in extension.yaml is invalid. Valid value(s): ${VALID_LICENSES.join(", ")}`
);
}
}
if (!spec.resources) {
errors.push("Resources field must contain at least one resource");
} else {
for (const resource of spec.resources) {
if (!resource.name) {
errors.push("Resource is missing required field: name");
}
if (!resource.type) {
errors.push(
`Resource${resource.name ? ` ${resource.name}` : ""} is missing required field: type`
);
}
}
}
for (const api of spec.apis || []) {
if (!api.apiName) {
errors.push("API is missing required field: apiName");
}
}
for (const role of spec.roles || []) {
if (!role.role) {
errors.push("Role is missing required field: role");
}
}
for (const param of spec.params || []) {
if (!param.param) {
errors.push("Param is missing required field: param");
}
if (!param.label) {
errors.push(`Param${param.param ? ` ${param.param}` : ""} is missing required field: label`);
}
if (param.type && !_.includes(SpecParamType, param.type)) {
errors.push(
`Invalid type ${param.type} for param${
param.param ? ` ${param.param}` : ""
}. Valid types are ${_.values(SpecParamType).join(", ")}`
);
}
if (!param.type || param.type == SpecParamType.STRING) {
// ParamType defaults to STRING
if (param.options) {
errors.push(
`Param${
param.param ? ` ${param.param}` : ""
} cannot have options because it is type STRING`
);
}
}
if (
param.type &&
(param.type == SpecParamType.SELECT || param.type == SpecParamType.MULTISELECT)
) {
if (param.validationRegex) {
errors.push(
`Param${
param.param ? ` ${param.param}` : ""
} cannot have validationRegex because it is type ${param.type}`
);
}
if (!param.options) {
errors.push(
`Param${param.param ? ` ${param.param}` : ""} requires options because it is type ${
param.type
}`
);
}
for (const opt of param.options || []) {
if (opt.value == undefined) {
errors.push(
`Option for param${
param.param ? ` ${param.param}` : ""
} is missing required field: value`
);
}
}
}
if (param.type && param.type == SpecParamType.SELECTRESOURCE) {
if (!param.resourceType) {
errors.push(
`Param${param.param ? ` ${param.param}` : ""} must have resourceType because it is type ${
param.type
}`
);
}
}
}
if (errors.length) {
const formatted = errors.map((error) => ` - ${error}`);
const message = `The extension.yaml has the following errors: \n${formatted.join("\n")}`;
throw new FirebaseError(message);
}
}