generate.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. function noop(value) {
  2. return value;
  3. }
  4. function generateMultiplier(multiplier) {
  5. const { min, max, comma } = multiplier;
  6. if (min === 0 && max === 0) {
  7. return comma ? '#?' : '*';
  8. }
  9. if (min === 0 && max === 1) {
  10. return '?';
  11. }
  12. if (min === 1 && max === 0) {
  13. return comma ? '#' : '+';
  14. }
  15. if (min === 1 && max === 1) {
  16. return '';
  17. }
  18. return (
  19. (comma ? '#' : '') +
  20. (min === max
  21. ? '{' + min + '}'
  22. : '{' + min + ',' + (max !== 0 ? max : '') + '}'
  23. )
  24. );
  25. }
  26. function generateTypeOpts(node) {
  27. switch (node.type) {
  28. case 'Range':
  29. return (
  30. ' [' +
  31. (node.min === null ? '-∞' : node.min) +
  32. ',' +
  33. (node.max === null ? '∞' : node.max) +
  34. ']'
  35. );
  36. default:
  37. throw new Error('Unknown node type `' + node.type + '`');
  38. }
  39. }
  40. function generateSequence(node, decorate, forceBraces, compact) {
  41. const combinator = node.combinator === ' ' || compact ? node.combinator : ' ' + node.combinator + ' ';
  42. const result = node.terms
  43. .map(term => internalGenerate(term, decorate, forceBraces, compact))
  44. .join(combinator);
  45. if (node.explicit || forceBraces) {
  46. return (compact || result[0] === ',' ? '[' : '[ ') + result + (compact ? ']' : ' ]');
  47. }
  48. return result;
  49. }
  50. function internalGenerate(node, decorate, forceBraces, compact) {
  51. let result;
  52. switch (node.type) {
  53. case 'Group':
  54. result =
  55. generateSequence(node, decorate, forceBraces, compact) +
  56. (node.disallowEmpty ? '!' : '');
  57. break;
  58. case 'Multiplier':
  59. // return since node is a composition
  60. return (
  61. internalGenerate(node.term, decorate, forceBraces, compact) +
  62. decorate(generateMultiplier(node), node)
  63. );
  64. case 'Boolean':
  65. result = '<boolean-expr[' + internalGenerate(node.term, decorate, forceBraces, compact) + ']>';
  66. break;
  67. case 'Type':
  68. result = '<' + node.name + (node.opts ? decorate(generateTypeOpts(node.opts), node.opts) : '') + '>';
  69. break;
  70. case 'Property':
  71. result = '<\'' + node.name + '\'>';
  72. break;
  73. case 'Keyword':
  74. result = node.name;
  75. break;
  76. case 'AtKeyword':
  77. result = '@' + node.name;
  78. break;
  79. case 'Function':
  80. result = node.name + '(';
  81. break;
  82. case 'String':
  83. case 'Token':
  84. result = node.value;
  85. break;
  86. case 'Comma':
  87. result = ',';
  88. break;
  89. default:
  90. throw new Error('Unknown node type `' + node.type + '`');
  91. }
  92. return decorate(result, node);
  93. }
  94. export function generate(node, options) {
  95. let decorate = noop;
  96. let forceBraces = false;
  97. let compact = false;
  98. if (typeof options === 'function') {
  99. decorate = options;
  100. } else if (options) {
  101. forceBraces = Boolean(options.forceBraces);
  102. compact = Boolean(options.compact);
  103. if (typeof options.decorate === 'function') {
  104. decorate = options.decorate;
  105. }
  106. }
  107. return internalGenerate(node, decorate, forceBraces, compact);
  108. };