UNPKG

webpack-preprocessor-loader

Version:
138 lines (137 loc) 4.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ifComparator = exports.PlainTextFilter = void 0; /** * The filter for top-level, non-directive-related code. * * Mainly for top-level directive detecting and branching. */ class PlainTextFilter { next(block, directives, params) { const { isDirective, directive, condition } = block; if (!isDirective) { return { preserve: true, filter: this }; } if ("if" === directive) { return { preserve: false, filter: new ConditionFilter(ifComparator(params, condition), false, this), }; } if ("else" === directive || "elseif" === directive || "endif" === directive) { // TODO Better warning info const message = "[webpack-preprocessor-loader] " + `Found a top-level "#!${directive}" but missing a leading "#!if".` + "```" + `${block.raw}` + "```"; throw new Error(message); } return { preserve: false, filter: new DirectiveFilter(!!directives[directive], this), }; } } exports.PlainTextFilter = PlainTextFilter; /** * A quick filter for user-defined directives. * * Only care about the very next line under the directive declaration, * and output only if the directive for the current line is true. */ class DirectiveFilter { constructor( /** * Is the directive of the current block true */ isTrue = false, /** * Reference to the previous filter */ parent) { this.isTrue = isTrue; this.parent = parent; } next() { return { preserve: this.isTrue, filter: this.parent }; } } /** * The filter for if-conditions. */ class ConditionFilter { constructor( /** * Has the current block met its condition. */ isTrue, /** * Has any previous if-block already met its condition * * There may be multiple branches in an if-clause, so we need a flag * to indicate if one of them has met its condition. If one is *fulfilled*, * then following if-blocks and their nested blocks should be skipped */ isFulFilled, /** * Reference to the previous filter */ parent) { this.isTrue = isTrue; this.isFulFilled = isFulFilled; this.parent = parent; } next(block, directives, params) { const { isDirective, directive, condition } = block; const { isFulFilled, isTrue } = this; if ("endif" === directive) { return { preserve: false, filter: this.parent }; } if ("else" === directive) { this.isTrue = !isTrue; this.isFulFilled = isFulFilled || isTrue; return { preserve: false, filter: this, }; } if ("elseif" === directive) { this.isTrue = isFulFilled ? false : ifComparator(params, condition); this.isFulFilled = isFulFilled || isTrue; return { preserve: false, filter: this, }; } if ("if" === directive) { return { preserve: false, filter: new ConditionFilter(isFulFilled ? false : ifComparator(params, condition), isFulFilled || !isTrue, this), }; } if (isDirective) { return { preserve: false, filter: new DirectiveFilter(!isFulFilled && isTrue && !!directives[directive], this), }; } return { preserve: !isFulFilled && isTrue, filter: this }; } } /** * Get the result of the condition defined by "#!if" / "#!elseif" directive * * @param {IParamsMap} params values needed * @param {string} rawCondition the origin condition string * @returns {boolean} result */ function ifComparator(params, rawCondition) { const keys = Object.keys(params); const values = keys.map((key) => params[key]); const comparator = new Function(...keys, `return ${rawCondition};`); return !!comparator(...values); } exports.ifComparator = ifComparator;