"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("@typescript-eslint/utils"); const load_1 = require("../utils/load"); const utils_2 = require("../utils/utils"); const getFunction_1 = require("../utils/getFunction"); exports.default = utils_1.ESLintUtils.RuleCreator(() => "https://docs.microsoft.com/office/dev/add-ins/develop/application-specific-api-model#load")({ name: "load-object-before-read", meta: { type: "problem", messages: { loadBeforeRead: "An explicit load call on '{{name}}' for property '{{loadValue}}' needs to be made before the property can be read.", }, docs: { description: "Before you can read the properties of a proxy object, you must explicitly load the properties.", }, schema: [], }, create: function (context) { var _a; const sourceCode = (_a = context.sourceCode) !== null && _a !== void 0 ? _a : context.getSourceCode(); function isInsideWriteStatement(node) { while (node.parent) { node = node.parent; if (node.type === utils_1.TSESTree.AST_NODE_TYPES.AssignmentExpression) return true; } return false; } function hasBeenLoaded(node, loadLocation, propertyName) { var _a; return (loadLocation.has(propertyName) && // If reference came after load, return node.range[1] > ((_a = loadLocation.get(propertyName)) !== null && _a !== void 0 ? _a : 0)); } function findLoadBeforeRead(scope) { scope.variables.forEach((variable) => { const loadLocation = new Map(); let getFound = false; variable.references.forEach((reference) => { const node = reference.identifier; const parent = node.parent; if ((parent === null || parent === void 0 ? void 0 : parent.type) === utils_1.TSESTree.AST_NODE_TYPES.VariableDeclarator) { getFound = false; // In case of reassignment if (parent.init && (0, getFunction_1.isGetFunction)(parent.init) && !(0, getFunction_1.isGetOrNullObjectFunction)(parent.init)) { getFound = true; return; } } if ((parent === null || parent === void 0 ? void 0 : parent.type) === utils_1.TSESTree.AST_NODE_TYPES.AssignmentExpression) { getFound = false; // In case of reassignment if ((0, getFunction_1.isGetFunction)(parent.right) && !(0, getFunction_1.isGetOrNullObjectFunction)(parent.right)) { getFound = true; return; } } if (!getFound) { // If reference was not related to a previous get return; } // Look for .load(...) call if ((parent === null || parent === void 0 ? void 0 : parent.type) === utils_1.TSESTree.AST_NODE_TYPES.MemberExpression) { const methodCall = (0, utils_2.findCallExpression)(parent); if (methodCall && (0, load_1.isLoadCall)(methodCall)) { const argument = methodCall.arguments[0]; const propertyNames = argument ? (0, load_1.parsePropertiesArgument)(argument) : ["*"]; propertyNames.forEach((propertyName) => { loadLocation.set(propertyName, node.range[1]); }); return; } } // Look for context.load(, "...") call if ((parent === null || parent === void 0 ? void 0 : parent.type) === utils_1.TSESTree.AST_NODE_TYPES.CallExpression) { const args = parent === null || parent === void 0 ? void 0 : parent.arguments; if ((0, load_1.isLoadCall)(parent) && args[0] == node && args.length < 3) { const propertyNames = args[1] ? (0, load_1.parsePropertiesArgument)(args[1]) : ["*"]; propertyNames.forEach((propertyName) => { loadLocation.set(propertyName, node.range[1]); }); return; } } const propertyName = (0, utils_2.findPropertiesRead)(parent); if (!propertyName || hasBeenLoaded(node, loadLocation, propertyName) || hasBeenLoaded(node, loadLocation, "*") || isInsideWriteStatement(node)) { return; } context.report({ node: node, messageId: "loadBeforeRead", data: { name: node.name, loadValue: propertyName }, }); }); }); scope.childScopes.forEach(findLoadBeforeRead); } return { Program(node) { const scope = sourceCode.getScope ? sourceCode.getScope(node) : context.getScope(); findLoadBeforeRead(scope); }, }; }, defaultOptions: [], }); //# sourceMappingURL=load-object-before-read.js.map