| 'use strict'; |
| |
| var extend = require('extend-shallow'); |
| var Snapdragon = require('snapdragon'); |
| var compilers = require('./compilers'); |
| var parsers = require('./parsers'); |
| var utils = require('./utils'); |
| |
| /** |
| * Customize Snapdragon parser and renderer |
| */ |
| |
| function Braces(options) { |
| this.options = extend({}, options); |
| } |
| |
| /** |
| * Initialize braces |
| */ |
| |
| Braces.prototype.init = function(options) { |
| if (this.isInitialized) return; |
| this.isInitialized = true; |
| var opts = utils.createOptions({}, this.options, options); |
| this.snapdragon = this.options.snapdragon || new Snapdragon(opts); |
| this.compiler = this.snapdragon.compiler; |
| this.parser = this.snapdragon.parser; |
| |
| compilers(this.snapdragon, opts); |
| parsers(this.snapdragon, opts); |
| |
| /** |
| * Call Snapdragon `.parse` method. When AST is returned, we check to |
| * see if any unclosed braces are left on the stack and, if so, we iterate |
| * over the stack and correct the AST so that compilers are called in the correct |
| * order and unbalance braces are properly escaped. |
| */ |
| |
| utils.define(this.snapdragon, 'parse', function(pattern, options) { |
| var parsed = Snapdragon.prototype.parse.apply(this, arguments); |
| this.parser.ast.input = pattern; |
| |
| var stack = this.parser.stack; |
| while (stack.length) { |
| addParent({type: 'brace.close', val: ''}, stack.pop()); |
| } |
| |
| function addParent(node, parent) { |
| utils.define(node, 'parent', parent); |
| parent.nodes.push(node); |
| } |
| |
| // add non-enumerable parser reference |
| utils.define(parsed, 'parser', this.parser); |
| return parsed; |
| }); |
| }; |
| |
| /** |
| * Decorate `.parse` method |
| */ |
| |
| Braces.prototype.parse = function(ast, options) { |
| if (ast && typeof ast === 'object' && ast.nodes) return ast; |
| this.init(options); |
| return this.snapdragon.parse(ast, options); |
| }; |
| |
| /** |
| * Decorate `.compile` method |
| */ |
| |
| Braces.prototype.compile = function(ast, options) { |
| if (typeof ast === 'string') { |
| ast = this.parse(ast, options); |
| } else { |
| this.init(options); |
| } |
| return this.snapdragon.compile(ast, options); |
| }; |
| |
| /** |
| * Expand |
| */ |
| |
| Braces.prototype.expand = function(pattern) { |
| var ast = this.parse(pattern, {expand: true}); |
| return this.compile(ast, {expand: true}); |
| }; |
| |
| /** |
| * Optimize |
| */ |
| |
| Braces.prototype.optimize = function(pattern) { |
| var ast = this.parse(pattern, {optimize: true}); |
| return this.compile(ast, {optimize: true}); |
| }; |
| |
| /** |
| * Expose `Braces` |
| */ |
| |
| module.exports = Braces; |