You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

234 lines
8.4 KiB

"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 || !context.gender || !audience.genders.map(function(g) { return g.toLowerCase(); }).includes(context.gender.toLowerCase())) {
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 = getSelectedOptionTokens(answer);
var hasMatch = expectedValues.some(function (v) { return actualTokens.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_1 = getSelectedOptionTokens(answer);
var expectedIds = (rule.trigger_option_ids || []).map(function (id) {
return String(id).toLowerCase().trim();
});
var isTokenMatched = function (expectedId) {
if (actualTokens_1.has(expectedId))
return true;
var lastDot = expectedId.lastIndexOf(".");
if (lastDot !== -1 && lastDot < expectedId.length - 1) {
var suffix = expectedId.slice(lastDot + 1);
if (actualTokens_1.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_1.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 parentId ? mainMatches : Boolean(!rule.audience || matchesAudience(rule.audience, context));
}
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.requiredWhen) {
if (question.requiredWhen.genders || question.requiredWhen.minAge !== undefined || question.requiredWhen.maxAge !== undefined) {
return matchesAudience(question.requiredWhen, context);
}
return ruleMatches(question.requiredWhen, answers, context);
}
return Boolean(question.baseRequired !== undefined ? question.baseRequired : question.required);
}