diff --git a/src/filters-downloader-creator.js b/src/filters-downloader-creator.js index cdc1fc0..45237d9 100644 --- a/src/filters-downloader-creator.js +++ b/src/filters-downloader-creator.js @@ -31,7 +31,8 @@ const FiltersDownloaderCreator = (FileDownloadWrapper) => { "use strict"; - const CONDITION_DIRECTIVE_START = "!#if"; + const CONDITION_IF_DIRECTIVE_START = "!#if"; + const CONDITION_ELSE_DIRECTIVE_START = "!#else"; const CONDITION_DIRECTIVE_END = "!#endif"; const CONDITION_OPERATOR_NOT = "!"; @@ -75,19 +76,20 @@ const FiltersDownloaderCreator = (FileDownloadWrapper) => { }; /** - * Finds end of condition block started with startIndex + * Finds end of condition block started with startIndex. * - * @param rules - * @param startIndex + * @param {string[]} rules Array of all rules. + * @param {number} startIndex Index of the start of the condition block. + * + * @returns {number} Index of the end of the condition block. */ const findConditionEnd = (rules, startIndex) => { const stack = []; for (let j = startIndex; j < rules.length; j++) { let internalRule = rules[j]; - if (internalRule.startsWith(CONDITION_DIRECTIVE_START)) { - stack.push(CONDITION_DIRECTIVE_START); - + if (internalRule.startsWith(CONDITION_IF_DIRECTIVE_START)) { + stack.push(CONDITION_IF_DIRECTIVE_START); } else if (internalRule.startsWith(CONDITION_DIRECTIVE_END)) { if (stack.length > 0) { stack.pop(); @@ -101,10 +103,14 @@ const FiltersDownloaderCreator = (FileDownloadWrapper) => { }; /** - * Resolves constant expression + * Resolves constant expression. * - * @param expression - * @param definedProperties + * @param {string} expression + * @param {object} [definedProperties] + * + * @returns {boolean} True if expression is `'true'` + * or there is a property with the same name in `definedProperties` which is set to true, + * false otherwise. */ const resolveConditionConstant = (expression, definedProperties) => { if (!expression) { @@ -118,8 +124,11 @@ const FiltersDownloaderCreator = (FileDownloadWrapper) => { /** * Calculates conditional expression * - * @param expression - * @param definedProperties + * @param {string} expression Conditional expression. + * @param {object} [definedProperties] Object with the defined properties + * where keys are platform names and values are booleans. + * + * @returns {boolean} Result of the expression */ const resolveExpression = (expression, definedProperties) => { if (!expression) { @@ -152,11 +161,11 @@ const FiltersDownloaderCreator = (FileDownloadWrapper) => { const indexOfNotOperator = expression.indexOf(CONDITION_OPERATOR_NOT); if (indexOfOrOperator !== -1) { - result = resolveExpression(expression.substring(0, indexOfOrOperator - 1), definedProperties) || - resolveExpression(expression.substring(indexOfOrOperator + CONDITION_OPERATOR_OR.length, expression.length), definedProperties); + result = resolveExpression(expression.substring(0, indexOfOrOperator - 1), definedProperties) + || resolveExpression(expression.substring(indexOfOrOperator + CONDITION_OPERATOR_OR.length, expression.length), definedProperties); } else if (indexOfAndOperator !== -1) { - result = resolveExpression(expression.substring(0, indexOfAndOperator - 1), definedProperties) && - resolveExpression(expression.substring(indexOfAndOperator + CONDITION_OPERATOR_AND.length, expression.length), definedProperties); + result = resolveExpression(expression.substring(0, indexOfAndOperator - 1), definedProperties) + && resolveExpression(expression.substring(indexOfAndOperator + CONDITION_OPERATOR_AND.length, expression.length), definedProperties); } else if (indexOfNotOperator === 0) { result = !resolveExpression(expression.substring(CONDITION_OPERATOR_NOT.length), definedProperties); } else { @@ -173,7 +182,7 @@ const FiltersDownloaderCreator = (FileDownloadWrapper) => { * @param definedProperties */ const resolveCondition = (directive, definedProperties) => { - const expression = directive.substring(CONDITION_DIRECTIVE_START.length).trim(); + const expression = directive.substring(CONDITION_IF_DIRECTIVE_START.length).trim(); return resolveExpression(expression, definedProperties); }; @@ -181,8 +190,10 @@ const FiltersDownloaderCreator = (FileDownloadWrapper) => { /** * Resolves conditions directives * - * @param rules - * @param definedProperties + * @param {string} rules Input array of rules. + * @param {object} [definedProperties] Object with the defined properties. + * + * @returns {string[]} Array of rules. */ const resolveConditions = (rules, definedProperties) => { if (!definedProperties) { @@ -192,17 +203,17 @@ const FiltersDownloaderCreator = (FileDownloadWrapper) => { let result = []; for (let i = 0; i < rules.length; i++) { - let rule = rules[i]; + const rule = rules[i]; - if (rule.indexOf(CONDITION_DIRECTIVE_START) === 0) { + if (rule.indexOf(CONDITION_IF_DIRECTIVE_START) === 0) { let endLineIndex = findConditionEnd(rules, i + 1); if (endLineIndex === -1) { throw new Error('Invalid directives: Condition end not found: ' + rule); } - let conditionValue = resolveCondition(rule, definedProperties); - if (conditionValue) { - let rulesUnderCondition = rules.slice(i + 1, endLineIndex); + const isConditionMatched = resolveCondition(rule, definedProperties); + if (isConditionMatched) { + const rulesUnderCondition = rules.slice(i + 1, endLineIndex); // Resolve inner conditions in recursion result = result.concat(resolveConditions(rulesUnderCondition, definedProperties)); } @@ -287,12 +298,15 @@ const FiltersDownloaderCreator = (FileDownloadWrapper) => { }; /** - * Compiles filter content + * Compiles filter content. * - * @param {Array} rules Array of strings - * @param {?string} filterOrigin Filter file URL origin or null - * @param {?object} definedProperties An object with the defined properties. These properties might be used in pre-processor directives (`#if`, etc) - * @returns {Promise} A promise that returns {string} with rules when if resolved and {Error} if rejected. + * @param {Array} rules Array of strings. + * @param {string} [filterOrigin] Filter file URL origin or null. + * @param {object} [definedProperties] An object with the defined properties. + * These properties might be used in pre-processor directives (`#if`, etc). + * + * @returns {Promise} A promise that returns `string` with rules when if resolved + * and `Error` if rejected. */ const compile = (rules, filterOrigin, definedProperties) => { try {