braces.js
1 'use strict'; 2 3 var extend = require('extend-shallow'); 4 var Snapdragon = require('snapdragon'); 5 var compilers = require('./compilers'); 6 var parsers = require('./parsers'); 7 var utils = require('./utils'); 8 9 /** 10 * Customize Snapdragon parser and renderer 11 */ 12 13 function Braces(options) { 14 this.options = extend({}, options); 15 } 16 17 /** 18 * Initialize braces 19 */ 20 21 Braces.prototype.init = function(options) { 22 if (this.isInitialized) return; 23 this.isInitialized = true; 24 var opts = utils.createOptions({}, this.options, options); 25 this.snapdragon = this.options.snapdragon || new Snapdragon(opts); 26 this.compiler = this.snapdragon.compiler; 27 this.parser = this.snapdragon.parser; 28 29 compilers(this.snapdragon, opts); 30 parsers(this.snapdragon, opts); 31 32 /** 33 * Call Snapdragon `.parse` method. When AST is returned, we check to 34 * see if any unclosed braces are left on the stack and, if so, we iterate 35 * over the stack and correct the AST so that compilers are called in the correct 36 * order and unbalance braces are properly escaped. 37 */ 38 39 utils.define(this.snapdragon, 'parse', function(pattern, options) { 40 var parsed = Snapdragon.prototype.parse.apply(this, arguments); 41 this.parser.ast.input = pattern; 42 43 var stack = this.parser.stack; 44 while (stack.length) { 45 addParent({type: 'brace.close', val: ''}, stack.pop()); 46 } 47 48 function addParent(node, parent) { 49 utils.define(node, 'parent', parent); 50 parent.nodes.push(node); 51 } 52 53 // add non-enumerable parser reference 54 utils.define(parsed, 'parser', this.parser); 55 return parsed; 56 }); 57 }; 58 59 /** 60 * Decorate `.parse` method 61 */ 62 63 Braces.prototype.parse = function(ast, options) { 64 if (ast && typeof ast === 'object' && ast.nodes) return ast; 65 this.init(options); 66 return this.snapdragon.parse(ast, options); 67 }; 68 69 /** 70 * Decorate `.compile` method 71 */ 72 73 Braces.prototype.compile = function(ast, options) { 74 if (typeof ast === 'string') { 75 ast = this.parse(ast, options); 76 } else { 77 this.init(options); 78 } 79 return this.snapdragon.compile(ast, options); 80 }; 81 82 /** 83 * Expand 84 */ 85 86 Braces.prototype.expand = function(pattern) { 87 var ast = this.parse(pattern, {expand: true}); 88 return this.compile(ast, {expand: true}); 89 }; 90 91 /** 92 * Optimize 93 */ 94 95 Braces.prototype.optimize = function(pattern) { 96 var ast = this.parse(pattern, {optimize: true}); 97 return this.compile(ast, {optimize: true}); 98 }; 99 100 /** 101 * Expose `Braces` 102 */ 103 104 module.exports = Braces;