@azure-tools/typespec-azure-resource-manager
Version:
TypeSpec Azure Resource Manager library
91 lines • 4.87 kB
JavaScript
import { createRule, getProperty, isArrayModelType, paramMessage, } from "@typespec/compiler";
import { getExtensions } from "@typespec/openapi";
import { isArmCommonType } from "../common-types.js";
import { getArmIdentifiers, getArmKeyIdentifiers } from "../resource.js";
export const missingXmsIdentifiersRule = createRule({
name: "missing-x-ms-identifiers",
description: `Array properties should describe their identifying properties with x-ms-identifiers. Decorate the property with @OpenAPI.extension("x-ms-identifiers", #[id-prop]) where "id-prop" is a list of the names of identifying properties in the item type.`,
severity: "warning",
url: "https://azure.github.io/typespec-azure/docs/libraries/azure-resource-manager/rules/missing-x-ms-identifiers",
messages: {
default: `Missing identifying properties of objects in the array item, please add @OpenAPI.extension("x-ms-identifiers", #[<prop>]) to specify it. If there are no appropriate identifying properties, please add @OpenAPI.extension("x-ms-identifiers", #[]).`,
notArray: paramMessage `Value passed to @OpenAPI.extension("x-ms-identifiers",...) was a "${"valueType"}". Pass an array of property name.`,
missingProperty: paramMessage `Property "${"propertyName"}" is not found in "${"targetModelName"}". Make sure value of x-ms-identifiers extension are valid property name of the array element.`,
},
create(context) {
return {
modelProperty: (property) => {
const type = property.type;
if (type.kind === "Model" && isArrayModelType(context.program, type)) {
if (isArrayMissingIdentifier(context.program, type, property)) {
context.reportDiagnostic({
target: property,
});
}
}
},
};
function isArrayMissingIdentifier(program, array, property) {
const elementType = array.indexer.value;
if (elementType.kind !== "Model") {
return false;
}
if (isArmCommonType(elementType)) {
return false;
}
if (getProperty(elementType, "id") || getProperty(elementType, "name")) {
return false;
}
const xmsIdentifiers = getExtensions(program, property ?? array).get("x-ms-identifiers");
const armIdentifiers = getArmIdentifiers(program, property);
const armKeyIdentifiers = getArmKeyIdentifiers(program, array);
const identifiers = armIdentifiers ?? armKeyIdentifiers ?? xmsIdentifiers;
if (identifiers === undefined) {
return true;
}
if (Array.isArray(identifiers)) {
for (const propIdentifier of identifiers) {
if (typeof propIdentifier === "string") {
const props = propIdentifier.replace(/^\//, "").split("/");
let element = elementType;
for (const prop of props) {
if (element === undefined || element.kind !== "Model") {
context.reportDiagnostic({
messageId: "missingProperty",
format: { propertyName: prop, targetModelName: element?.name },
target: property,
});
return false;
}
const propertyValue = getProperty(element, prop);
if (propertyValue === undefined) {
context.reportDiagnostic({
messageId: "missingProperty",
format: { propertyName: prop, targetModelName: elementType.name },
target: property,
});
}
element = propertyValue?.type;
}
}
else {
context.reportDiagnostic({
messageId: "notArray",
format: { valueType: typeof propIdentifier },
target: property,
});
}
}
}
else {
context.reportDiagnostic({
messageId: "notArray",
format: { valueType: typeof xmsIdentifiers },
target: property,
});
}
return false;
}
},
});
//# sourceMappingURL=missing-x-ms-identifiers.js.map