/** * The MIT License (MIT) * Copyright (c) 2017-present Dmitry Soshnikov */ 'use strict'; var clone = require('../utils/clone'); var parser = require('../parser'); var transform = require('../transform'); var optimizationTransforms = require('./transforms'); module.exports = { /** * Optimizer transforms a regular expression into an optimized version, * replacing some sub-expressions with their idiomatic patterns. * * @param string | RegExp | AST - a regexp to optimize. * * @return TransformResult - an optimized regexp. * * Example: * * /[a-zA-Z_0-9][a-zA-Z_0-9]*\e{1,}/ * * Optimized to: * * /\w+e+/ */ optimize: function optimize(regexp) { var transformsWhitelist = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; var transformToApply = transformsWhitelist.length > 0 ? transformsWhitelist : Object.keys(optimizationTransforms); var ast = regexp; if (regexp instanceof RegExp) { regexp = '' + regexp; } if (typeof regexp === 'string') { ast = parser.parse(regexp); } var result = new transform.TransformResult(ast); var prevResultString = void 0; do { // Get a copy of the current state here so // we can compare it with the state at the // end of the loop. prevResultString = result.toString(); ast = clone(result.getAST()); transformToApply.forEach(function (transformName) { if (!optimizationTransforms.hasOwnProperty(transformName)) { throw new Error('Unknown optimization-transform: ' + transformName + '. ' + 'Available transforms are: ' + Object.keys(optimizationTransforms).join(', ')); } var transformer = optimizationTransforms[transformName]; // Don't override result just yet since we // might want to rollback the transform var newResult = transform.transform(ast, transformer); if (newResult.toString() !== result.toString()) { if (newResult.toString().length <= result.toString().length) { result = newResult; } else { // Result has changed but is not shorter: // restore ast to its previous state. ast = clone(result.getAST()); } } }); // Keep running the optimizer until it stops // making any change to the regexp. } while (result.toString() !== prevResultString); return result; } };