| /** |
| * The MIT License (MIT) |
| * Copyright (c) 2017-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com> |
| */ |
| |
| '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; |
| } |
| }; |