generate.js 3.3 KB

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