100 lines
4.8 KiB
JavaScript
100 lines
4.8 KiB
JavaScript
|
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)) {
|
||
|
// <obj>.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(<obj>, "...") 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
|