index.js 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /**
  2. * The MIT License (MIT)
  3. * Copyright (c) 2017-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
  4. */
  5. 'use strict';
  6. var clone = require('../utils/clone');
  7. var parser = require('../parser');
  8. var transform = require('../transform');
  9. var optimizationTransforms = require('./transforms');
  10. module.exports = {
  11. /**
  12. * Optimizer transforms a regular expression into an optimized version,
  13. * replacing some sub-expressions with their idiomatic patterns.
  14. *
  15. * @param string | RegExp | AST - a regexp to optimize.
  16. *
  17. * @return TransformResult - an optimized regexp.
  18. *
  19. * Example:
  20. *
  21. * /[a-zA-Z_0-9][a-zA-Z_0-9]*\e{1,}/
  22. *
  23. * Optimized to:
  24. *
  25. * /\w+e+/
  26. */
  27. optimize: function optimize(regexp) {
  28. var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
  29. _ref$whitelist = _ref.whitelist,
  30. whitelist = _ref$whitelist === undefined ? [] : _ref$whitelist,
  31. _ref$blacklist = _ref.blacklist,
  32. blacklist = _ref$blacklist === undefined ? [] : _ref$blacklist;
  33. var transformsRaw = whitelist.length > 0 ? whitelist : Array.from(optimizationTransforms.keys());
  34. var transformToApply = transformsRaw.filter(function (transform) {
  35. return !blacklist.includes(transform);
  36. });
  37. var ast = regexp;
  38. if (regexp instanceof RegExp) {
  39. regexp = '' + regexp;
  40. }
  41. if (typeof regexp === 'string') {
  42. ast = parser.parse(regexp);
  43. }
  44. var result = new transform.TransformResult(ast);
  45. var prevResultString = void 0;
  46. do {
  47. // Get a copy of the current state here so
  48. // we can compare it with the state at the
  49. // end of the loop.
  50. prevResultString = result.toString();
  51. ast = clone(result.getAST());
  52. transformToApply.forEach(function (transformName) {
  53. if (!optimizationTransforms.has(transformName)) {
  54. throw new Error('Unknown optimization-transform: ' + transformName + '. ' + 'Available transforms are: ' + Array.from(optimizationTransforms.keys()).join(', '));
  55. }
  56. var transformer = optimizationTransforms.get(transformName);
  57. // Don't override result just yet since we
  58. // might want to rollback the transform
  59. var newResult = transform.transform(ast, transformer);
  60. if (newResult.toString() !== result.toString()) {
  61. if (newResult.toString().length <= result.toString().length) {
  62. result = newResult;
  63. } else {
  64. // Result has changed but is not shorter:
  65. // restore ast to its previous state.
  66. ast = clone(result.getAST());
  67. }
  68. }
  69. });
  70. // Keep running the optimizer until it stops
  71. // making any change to the regexp.
  72. } while (result.toString() !== prevResultString);
  73. return result;
  74. }
  75. };