function noop(value) { return value; } function generateMultiplier(multiplier) { if (multiplier.min === 0 && multiplier.max === 0) { return '*'; } if (multiplier.min === 0 && multiplier.max === 1) { return '?'; } if (multiplier.min === 1 && multiplier.max === 0) { return multiplier.comma ? '#' : '+'; } if (multiplier.min === 1 && multiplier.max === 1) { return ''; } return ( (multiplier.comma ? '#' : '') + (multiplier.min === multiplier.max ? '{' + multiplier.min + '}' : '{' + multiplier.min + ',' + (multiplier.max !== 0 ? multiplier.max : '') + '}' ) ); } function generateTypeOpts(node) { switch (node.type) { case 'Range': return ( ' [' + (node.min === null ? '-∞' : node.min) + ',' + (node.max === null ? '∞' : node.max) + ']' ); default: throw new Error('Unknown node type `' + node.type + '`'); } } function generateSequence(node, forceBraces, decorate) { var result = node.terms.map(function(term) { return generate(term, forceBraces, decorate); }).join(node.combinator === ' ' ? ' ' : ' ' + node.combinator + ' '); if (node.explicit || forceBraces) { result = (result[0] !== ',' ? '[ ' : '[') + result + ' ]'; } return result; } function generate(node, forceBraces, decorate) { var result; switch (node.type) { case 'Group': result = generateSequence(node, forceBraces, decorate) + (node.disallowEmpty ? '!' : ''); break; case 'Multiplier': // return since node is a composition return ( generate(node.term, forceBraces, decorate) + decorate(generateMultiplier(node), node) ); case 'Type': result = '<' + node.name + (node.opts ? decorate(generateTypeOpts(node.opts), node.opts) : '') + '>'; break; case 'Property': result = '<\'' + node.name + '\'>'; break; case 'Keyword': result = node.name; break; case 'AtKeyword': result = '@' + node.name; break; case 'Function': result = node.name + '('; break; case 'String': case 'Token': result = node.value; break; case 'Comma': result = ','; break; default: throw new Error('Unknown node type `' + node.type + '`'); } return decorate(result, node); } module.exports = function(node, options) { var decorate = noop; var forceBraces = false; if (typeof options === 'function') { decorate = options; } else if (options) { forceBraces = Boolean(options.forceBraces); if (typeof options.decorate === 'function') { decorate = options.decorate; } } return generate(node, forceBraces, decorate); };