blob: baf6bf1bc2bde790ca232866d3fd81f1efb660e9 [file] [log] [blame]
Leo Repp58b9f112021-11-22 11:57:47 +01001'use strict';
2
3var extend = require('extend-shallow');
4var Snapdragon = require('snapdragon');
5var compilers = require('./compilers');
6var parsers = require('./parsers');
7var utils = require('./utils');
8
9/**
10 * Customize Snapdragon parser and renderer
11 */
12
13function Braces(options) {
14 this.options = extend({}, options);
15}
16
17/**
18 * Initialize braces
19 */
20
21Braces.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
63Braces.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
73Braces.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
86Braces.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
95Braces.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
104module.exports = Braces;