"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.canonicalRule = canonicalRule; exports.isAnswerPresent = isAnswerPresent; exports.matchesAudience = matchesAudience; exports.ruleMatches = ruleMatches; exports.isQuestionVisible = isQuestionVisible; exports.isQuestionRequired = isQuestionRequired; function canonicalRule(rule) { if (!rule || typeof rule !== "object") { return null; } // If wrapped in dependsOn (legacy) if (rule.dependsOn && !rule.parent_question_id) { return { dependsOn: rule.dependsOn, }; } var operator = ["any_of", "all_of", "equals", "exists"].includes(rule.operator) ? rule.operator : "any_of"; var optionIds = []; if (Array.isArray(rule.trigger_option_ids)) { optionIds = rule.trigger_option_ids.map(String); } else if (rule.trigger_option_ids !== undefined && rule.trigger_option_ids !== null) { optionIds = [String(rule.trigger_option_ids)]; } var result = { parent_question_id: rule.parent_question_id || rule.parentQuestionId, trigger_option_ids: optionIds, operator: operator, clear_answer_when_hidden: Boolean(rule.clear_answer_when_hidden), }; if (rule.audience && typeof rule.audience === "object") { result.audience = rule.audience; } if (Array.isArray(rule.conditions)) { result.conditions = rule.conditions .map(canonicalRule) .filter(function (c) { return c !== null; }); result.conditions_operator = rule.conditions_operator === "any_of" ? "any_of" : "all_of"; result.root_operator = rule.root_operator === "any_of" ? "any_of" : "all_of"; } return result; } function isAnswerPresent(answer) { if (answer === undefined || answer === null) { return false; } var val = typeof answer === "object" && "value" in answer ? answer.value : answer; if (val === undefined || val === null) { return false; } if (typeof val === "string") { return val.trim().length > 0; } if (Array.isArray(val)) { return val.length > 0; } if (typeof val === "object") { return Object.keys(val).length > 0; } return true; } function getSelectedOptionTokens(answer) { var tokens = new Set(); if (!answer) return tokens; var rawOptionId = typeof answer === "object" && "option_id" in answer ? answer.option_id : undefined; var rawValue = typeof answer === "object" && "value" in answer ? answer.value : answer; var addToken = function (item) { if (item === undefined || item === null) return; var str = String(item).trim(); if (!str) return; tokens.add(str.toLowerCase()); // If it has a dot prefix like "sec.q.opt", also add the suffix "opt" var lastDot = str.lastIndexOf("."); if (lastDot !== -1 && lastDot < str.length - 1) { tokens.add(str.slice(lastDot + 1).toLowerCase()); } }; if (Array.isArray(rawOptionId)) { rawOptionId.forEach(addToken); } else if (rawOptionId !== undefined) { addToken(rawOptionId); } if (Array.isArray(rawValue)) { rawValue.forEach(addToken); } else if (rawValue !== undefined) { addToken(rawValue); } return tokens; } function matchesAudience(audience, context) { if (!audience || typeof audience !== "object") { return true; } if (audience.genders && audience.genders.length > 0) { if ((context === null || context === void 0 ? void 0 : context.gender) && !audience.genders.includes(context.gender)) { return false; } } if (audience.minAge !== undefined && (context === null || context === void 0 ? void 0 : context.age) !== undefined && context.age !== null) { if (context.age < audience.minAge) { return false; } } if (audience.maxAge !== undefined && (context === null || context === void 0 ? void 0 : context.age) !== undefined && context.age !== null) { if (context.age > audience.maxAge) { return false; } } return true; } function ruleMatches(rawRule, answers, context) { var rule = canonicalRule(rawRule); if (!rule) { return true; } if (rule.audience && !matchesAudience(rule.audience, context)) { return false; } // Handle legacy dependsOn if (rule.dependsOn && rule.dependsOn.key) { var parentId_1 = rule.dependsOn.key; var answer = answers[parentId_1]; if (!isAnswerPresent(answer)) { return false; } var expectedValues = (rule.dependsOn.values || []).map(function (v) { return String(v).toLowerCase().trim(); }); var actualTokens_1 = getSelectedOptionTokens(answer); var hasMatch = expectedValues.some(function (v) { return actualTokens_1.has(v); }); return hasMatch; } var mainMatches = true; var parentId = rule.parent_question_id; if (parentId) { var answer = answers[parentId]; var operator = rule.operator || "any_of"; if (operator === "exists") { mainMatches = isAnswerPresent(answer); } else if (!isAnswerPresent(answer)) { mainMatches = false; } else { var actualTokens_2 = getSelectedOptionTokens(answer); var expectedIds = (rule.trigger_option_ids || []).map(function (id) { return String(id).toLowerCase().trim(); }); var isTokenMatched = function (expectedId) { if (actualTokens_2.has(expectedId)) return true; var lastDot = expectedId.lastIndexOf("."); if (lastDot !== -1 && lastDot < expectedId.length - 1) { var suffix = expectedId.slice(lastDot + 1); if (actualTokens_2.has(suffix)) return true; } return false; }; if (operator === "all_of") { mainMatches = expectedIds.length > 0 && expectedIds.every(isTokenMatched); } else if (operator === "equals") { mainMatches = expectedIds.length > 0 && expectedIds.every(isTokenMatched) && actualTokens_2.size <= expectedIds.length * 2; } else { // default: "any_of" mainMatches = expectedIds.some(isTokenMatched); } } } if (rule.conditions && rule.conditions.length > 0) { var subMatches = rule.conditions.map(function (cond) { return ruleMatches(cond, answers, context); }); var condOperator = rule.conditions_operator || "all_of"; var conditionsResult = condOperator === "any_of" ? subMatches.some(Boolean) : subMatches.every(Boolean); if (!parentId) { return conditionsResult; } var rootOp = rule.root_operator || "all_of"; return rootOp === "any_of" ? mainMatches || conditionsResult : mainMatches && conditionsResult; } return mainMatches; } function isQuestionVisible(question, answers, context) { // 1. Audience check if (question.audience && !matchesAudience(question.audience, context)) { return false; } // 2. Canonical visibility / conditional rule var rule = question.visibility || question.conditionalRule || question.logic; if (rule) { return ruleMatches(rule, answers, context); } if (question.isVisible !== undefined) { return question.isVisible; } return true; } function isQuestionRequired(question, answers, context) { if (!isQuestionVisible(question, answers, context)) { return false; } if (question.required || question.baseRequired) { return true; } if (question.requiredWhen) { if (question.requiredWhen.genders || question.requiredWhen.minAge || question.requiredWhen.maxAge) { return matchesAudience(question.requiredWhen, context); } return ruleMatches(question.requiredWhen, answers, context); } return false; }