const utils_1 = require("@typescript-eslint/utils"); const getFunction_1 = require("../utils/getFunction"); const load_1 = require("../utils/load"); const propertiesType_1 = require("../utils/propertiesType"); module.exports = { name: "no-navigational-load", meta: { type: "problem", messages: { navigationalLoad: "Calling load on the navigation property '{{loadValue}}' slows down your add-in.", }, docs: { description: "Calling load on a navigation property causes unneeded data to load and slows down your add-in.", category: "Best Practices", recommended: false, url: "https://docs.microsoft.com/office/dev/add-ins/develop/application-specific-api-model#scalar-and-navigation-properties", }, schema: [], }, create: function (context) { function isLoadingValidPropeties(propertyName) { const properties = propertyName.split("/"); const lastProperty = properties.pop(); if (!lastProperty) return false; for (const property of properties) { const propertyType = (0, propertiesType_1.getPropertyType)(property); if (propertyType !== propertiesType_1.PropertyType.navigational && propertyType !== propertiesType_1.PropertyType.ambiguous) { return false; } } if (lastProperty === "*") { return true; } const propertyType = (0, propertiesType_1.getPropertyType)(lastProperty); return (propertyType === propertiesType_1.PropertyType.scalar || propertyType === propertiesType_1.PropertyType.ambiguous); } function findNavigationalLoad(scope) { scope.variables.forEach((variable) => { let getFound = false; variable.references.forEach((reference) => { var _a, _b; const node = reference.identifier; if (reference.isWrite()) { getFound = false; // In case of reassignment if (reference.writeExpr && (0, getFunction_1.isGetFunction)(reference.writeExpr)) { getFound = true; return; } } if (!getFound) { // If reference was not related to a previous get return; } if (((_a = node.parent) === null || _a === void 0 ? void 0 : _a.type) === utils_1.TSESTree.AST_NODE_TYPES.MemberExpression && (0, load_1.isLoadFunction)(node.parent)) { // .load(...) call const propertyNames = (0, load_1.parseLoadArguments)(node.parent); propertyNames.forEach((propertyName) => { if (propertyName && !isLoadingValidPropeties(propertyName)) { context.report({ node: node.parent, messageId: "navigationalLoad", data: { name: node.name, loadValue: propertyName }, }); } }); } else if (((_b = node.parent) === null || _b === void 0 ? void 0 : _b.type) === utils_1.TSESTree.AST_NODE_TYPES.CallExpression) { //context.load(, "...") call const callee = node.parent .callee; const args = node.parent.arguments; if ((0, load_1.isLoadFunction)(callee) && args[0] == node && args.length < 3) { const propertyNames = (0, load_1.parsePropertiesArgument)(args[1]); propertyNames.forEach((propertyName) => { if (propertyName && !isLoadingValidPropeties(propertyName)) { context.report({ node: node.parent, messageId: "navigationalLoad", data: { name: node.name, loadValue: propertyName }, }); } }); } } }); }); scope.childScopes.forEach(findNavigationalLoad); } return { Program() { findNavigationalLoad(context.getScope()); }, }; }, }; //# sourceMappingURL=no-navigational-load.js.map