112 lines
5.5 KiB
JavaScript
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
|