/* global IITC */
/**
* Declarative message filter for COMM API
*
* @memberof IITC.comm
* @namespace declarativeMessageFilter
*/
IITC.comm.declarativeMessageFilter = {
_rules: {},
/**
* Adds a new filtering rule with a given ID.
*
* @param {string} id The ID of the rule to add.
* @param {Object} rule The rule to add.
*
* @example
* // Hide all messages from Resistance team
* IITC.comm.declarativeMessageFilter.addRule({
* id: "hideResistanceTeam1",
* conditions: [
* { field: "player.team", value: "Resistance" },
* ]
* });
*
* @example
* // Hide all messages except those from the Resistance team using the inverted rule
* IITC.comm.declarativeMessageFilter.addRule({
* id: "hideExceptResistanceTeam",
* conditions: [
* { field: "player.team", value: "Resistance", invert: true },
* ]
* });
*
* @example
* // Hide messages that look like spam
* IITC.comm.declarativeMessageFilter.addRule({
* id: "hideSpam",
* conditions: [
* { field: "markup[4][1].plain", condition: /ingress-(shop|store)|(store|shop)-ingress/i },
* ]
* });
*/
addRule: (id, rule) => {
if (IITC.comm.declarativeMessageFilter._rules[id]) {
console.warn(`Rule with ID '${id}' already exists. Overwriting.`);
}
IITC.comm.declarativeMessageFilter._rules[id] = rule;
},
/**
* Removes a filtering rule by its ID.
*
* @param {string} id The ID of the rule to remove.
*/
removeRule: (id) => {
if (IITC.comm.declarativeMessageFilter._rules[id]) {
delete IITC.comm.declarativeMessageFilter._rules[id];
} else {
console.error(`No rule found with ID '${id}'.`);
}
},
/**
* Gets a rule by its ID.
*
* @param {string} id The ID of the rule to get.
* @returns {Object|null} The rule object, or null if not found.
*/
getRuleById: (id) => {
return IITC.comm.declarativeMessageFilter._rules[id] || null;
},
/**
* Gets all current filtering rules.
*
* @returns {Object} The current set of filtering rules.
*/
getAllRules: () => {
return IITC.comm.declarativeMessageFilter._rules;
},
/**
* Extracts the value from the message object by a given path.
*
* @param {Object} object The message object.
* @param {String} path Path to the property in dot notation.
* @returns {*} The value of the property at the specified path or undefined if the path is not valid.
*/
getMessageValueByPath: (object, path) => {
const parts = path.replace(/\[(\w+)]/g, '.$1').split('.');
let current = object;
for (const part of parts) {
if (part in current) {
current = current[part];
} else {
return undefined; // Path is not valid
}
}
return current;
},
/**
* Checks if the message matches a single rule.
*
* @param {Object} message The message to check.
* @param {Object} rule The rule to match against.
* @returns {boolean} True if the message matches the rule, false otherwise.
*/
matchesRule: (message, rule) => {
return rule.conditions.every((condition) => {
const messageValue = IITC.comm.declarativeMessageFilter.getMessageValueByPath(message, condition.field);
let result;
if ('value' in condition) {
result = messageValue === condition.value;
} else if ('pattern' in condition) {
const regex = new RegExp(condition.pattern);
result = regex.test(messageValue);
} else {
return false; // If the condition does not contain 'value' or 'pattern', we consider that the message does not match the rule
}
// Invert the result if the condition is inverted
if (condition.invert) {
return !result;
}
return result;
});
},
/**
* Checks if a message matches any of the current filtering rules.
*
* @param {Object} message The message to check.
* @returns {boolean} True if the message matches any rule, false otherwise.
*/
filterMessage: (message) => {
const rules = IITC.comm.declarativeMessageFilter.getAllRules();
for (const ruleId in rules) {
if (IITC.comm.declarativeMessageFilter.matchesRule(message, rules[ruleId])) {
return true;
}
}
return false;
},
};