generate.cjs 3.4 KB

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