Nav apraksta

braces.js 2.5KB

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