Outlook_Addin_LLM/node_modules/eslint-plugin-office-addins/lib/rules/load-object-before-read.js

112 lines
5.5 KiB
JavaScript

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");
module.exports = {
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.",
category: "Possible Errors",
recommended: false,
url: "https://docs.microsoft.com/office/dev/add-ins/develop/application-specific-api-model#load",
},
schema: [],
},
create: function (context) {
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) => {
let 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 <obj>.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];
let propertyNames = argument
? (0, load_1.parsePropertiesArgument)(argument)
: ["*"];
propertyNames.forEach((propertyName) => {
loadLocation.set(propertyName, node.range[1]);
});
return;
}
}
// Look for context.load(<obj>, "...") 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() {
findLoadBeforeRead(context.getScope());
},
};
},
};
//# sourceMappingURL=load-object-before-read.js.map