/** * The MIT License (MIT) * Copyright (c) 2017-present Dmitry Soshnikov */ 'use strict'; var _require = require('../../transform/utils'), increaseQuantifierByOne = _require.increaseQuantifierByOne; /** * A regexp-tree plugin to merge quantifiers * * a+a+ -> a{2,} * a{2}a{3} -> a{5} * a{1,2}a{2,3} -> a{3,5} */ module.exports = { Repetition: function Repetition(path) { var node = path.node, parent = path.parent; if (parent.type !== 'Alternative' || !path.index) { return; } var previousSibling = path.getPreviousSibling(); if (!previousSibling) { return; } if (previousSibling.node.type === 'Repetition') { if (!previousSibling.getChild().hasEqualSource(path.getChild())) { return; } var _extractFromTo = extractFromTo(previousSibling.node.quantifier), previousSiblingFrom = _extractFromTo.from, previousSiblingTo = _extractFromTo.to; var _extractFromTo2 = extractFromTo(node.quantifier), nodeFrom = _extractFromTo2.from, nodeTo = _extractFromTo2.to; // It's does not seem reliable to merge quantifiers with different greediness // when none of both is a greedy open range if (previousSibling.node.quantifier.greedy !== node.quantifier.greedy && !isGreedyOpenRange(previousSibling.node.quantifier) && !isGreedyOpenRange(node.quantifier)) { return; } // a*a* -> a* // a*a+ -> a+ // a+a+ -> a{2,} // a{2}a{4} -> a{6} // a{1,2}a{2,3} -> a{3,5} // a{1,}a{2,} -> a{3,} // a+a{2,} -> a{3,} // a??a{2,} -> a{2,} // a*?a{2,} -> a{2,} // a+?a{2,} -> a{3,} node.quantifier.kind = 'Range'; node.quantifier.from = previousSiblingFrom + nodeFrom; if (previousSiblingTo && nodeTo) { node.quantifier.to = previousSiblingTo + nodeTo; } else { delete node.quantifier.to; } if (isGreedyOpenRange(previousSibling.node.quantifier) || isGreedyOpenRange(node.quantifier)) { node.quantifier.greedy = true; } previousSibling.remove(); } else { if (!previousSibling.hasEqualSource(path.getChild())) { return; } increaseQuantifierByOne(node.quantifier); previousSibling.remove(); } } }; function isGreedyOpenRange(quantifier) { return quantifier.greedy && (quantifier.kind === '+' || quantifier.kind === '*' || quantifier.kind === 'Range' && !quantifier.to); } function extractFromTo(quantifier) { var from = void 0, to = void 0; if (quantifier.kind === '*') { from = 0; } else if (quantifier.kind === '+') { from = 1; } else if (quantifier.kind === '?') { from = 0; to = 1; } else { from = quantifier.from; if (quantifier.to) { to = quantifier.to; } } return { from: from, to: to }; }