ungroup-transform.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /**
  2. * The MIT License (MIT)
  3. * Copyright (c) 2017-present Dmitry Soshnikov <dmitry.soshnikov@gmail.com>
  4. */
  5. 'use strict';
  6. /**
  7. * A regexp-tree plugin to remove unnecessary groups.
  8. *
  9. * /(?:a)/ -> /a/
  10. */
  11. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
  12. module.exports = {
  13. Group: function Group(path) {
  14. var node = path.node,
  15. parent = path.parent;
  16. var childPath = path.getChild();
  17. if (node.capturing || !childPath) {
  18. return;
  19. }
  20. // Don't optimize \1(?:0) to \10
  21. if (!hasAppropriateSiblings(path)) {
  22. return;
  23. }
  24. // Don't optimize /a(?:b|c)/ to /ab|c/
  25. // but /(?:b|c)/ to /b|c/ is ok
  26. if (childPath.node.type === 'Disjunction' && parent.type !== 'RegExp') {
  27. return;
  28. }
  29. // Don't optimize /(?:ab)+/ to /ab+/
  30. // but /(?:a)+/ to /a+/ is ok
  31. // and /(?:[a-d])+/ to /[a-d]+/ is ok too
  32. if (parent.type === 'Repetition' && childPath.node.type !== 'Char' && childPath.node.type !== 'CharacterClass') {
  33. return;
  34. }
  35. if (childPath.node.type === 'Alternative') {
  36. var parentPath = path.getParent();
  37. if (parentPath.node.type === 'Alternative') {
  38. // /abc(?:def)ghi/ When (?:def) is ungrouped its content must be merged with parent alternative
  39. parentPath.replace({
  40. type: 'Alternative',
  41. expressions: [].concat(_toConsumableArray(parent.expressions.slice(0, path.index)), _toConsumableArray(childPath.node.expressions), _toConsumableArray(parent.expressions.slice(path.index + 1)))
  42. });
  43. }
  44. } else {
  45. path.replace(childPath.node);
  46. }
  47. }
  48. };
  49. function hasAppropriateSiblings(path) {
  50. var parent = path.parent,
  51. index = path.index;
  52. if (parent.type !== 'Alternative') {
  53. return true;
  54. }
  55. var previousNode = parent.expressions[index - 1];
  56. if (previousNode == null) {
  57. return true;
  58. }
  59. // Don't optimized \1(?:0) to \10
  60. if (previousNode.type === 'Backreference' && previousNode.kind === 'number') {
  61. return false;
  62. }
  63. // Don't optimized \2(?:0) to \20
  64. if (previousNode.type === 'Char' && previousNode.kind === 'decimal') {
  65. return false;
  66. }
  67. return true;
  68. }