OSDN Git Service

new repo
[bytom/vapor.git] / tools / side_chain_tool / web / node_modules / bootstrap / grunt / bs-lessdoc-parser.js
1 /*!
2  * Bootstrap Grunt task for parsing Less docstrings
3  * http://getbootstrap.com
4  * Copyright 2014-2015 Twitter, Inc.
5  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
6  */
7
8 'use strict';
9
10 var Markdown = require('markdown-it');
11
12 function markdown2html(markdownString) {
13   var md = new Markdown();
14
15   // the slice removes the <p>...</p> wrapper output by Markdown processor
16   return md.render(markdownString.trim()).slice(3, -5);
17 }
18
19
20 /*
21 Mini-language:
22   //== This is a normal heading, which starts a section. Sections group variables together.
23   //## Optional description for the heading
24
25   //=== This is a subheading.
26
27   //** Optional description for the following variable. You **can** use Markdown in descriptions to discuss `<html>` stuff.
28   @foo: #fff;
29
30   //-- This is a heading for a section whose variables shouldn't be customizable
31
32   All other lines are ignored completely.
33 */
34
35
36 var CUSTOMIZABLE_HEADING = /^[/]{2}={2}(.*)$/;
37 var UNCUSTOMIZABLE_HEADING = /^[/]{2}-{2}(.*)$/;
38 var SUBSECTION_HEADING = /^[/]{2}={3}(.*)$/;
39 var SECTION_DOCSTRING = /^[/]{2}#{2}(.+)$/;
40 var VAR_ASSIGNMENT = /^(@[a-zA-Z0-9_-]+):[ ]*([^ ;][^;]*);[ ]*$/;
41 var VAR_DOCSTRING = /^[/]{2}[*]{2}(.+)$/;
42
43 function Section(heading, customizable) {
44   this.heading = heading.trim();
45   this.id = this.heading.replace(/\s+/g, '-').toLowerCase();
46   this.customizable = customizable;
47   this.docstring = null;
48   this.subsections = [];
49 }
50
51 Section.prototype.addSubSection = function (subsection) {
52   this.subsections.push(subsection);
53 };
54
55 function SubSection(heading) {
56   this.heading = heading.trim();
57   this.id = this.heading.replace(/\s+/g, '-').toLowerCase();
58   this.variables = [];
59 }
60
61 SubSection.prototype.addVar = function (variable) {
62   this.variables.push(variable);
63 };
64
65 function VarDocstring(markdownString) {
66   this.html = markdown2html(markdownString);
67 }
68
69 function SectionDocstring(markdownString) {
70   this.html = markdown2html(markdownString);
71 }
72
73 function Variable(name, defaultValue) {
74   this.name = name;
75   this.defaultValue = defaultValue;
76   this.docstring = null;
77 }
78
79 function Tokenizer(fileContent) {
80   this._lines = fileContent.split('\n');
81   this._next = undefined;
82 }
83
84 Tokenizer.prototype.unshift = function (token) {
85   if (this._next !== undefined) {
86     throw new Error('Attempted to unshift twice!');
87   }
88   this._next = token;
89 };
90
91 Tokenizer.prototype._shift = function () {
92   // returning null signals EOF
93   // returning undefined means the line was ignored
94   if (this._next !== undefined) {
95     var result = this._next;
96     this._next = undefined;
97     return result;
98   }
99   if (this._lines.length <= 0) {
100     return null;
101   }
102   var line = this._lines.shift();
103   var match = null;
104   match = SUBSECTION_HEADING.exec(line);
105   if (match !== null) {
106     return new SubSection(match[1]);
107   }
108   match = CUSTOMIZABLE_HEADING.exec(line);
109   if (match !== null) {
110     return new Section(match[1], true);
111   }
112   match = UNCUSTOMIZABLE_HEADING.exec(line);
113   if (match !== null) {
114     return new Section(match[1], false);
115   }
116   match = SECTION_DOCSTRING.exec(line);
117   if (match !== null) {
118     return new SectionDocstring(match[1]);
119   }
120   match = VAR_DOCSTRING.exec(line);
121   if (match !== null) {
122     return new VarDocstring(match[1]);
123   }
124   var commentStart = line.lastIndexOf('//');
125   var varLine = commentStart === -1 ? line : line.slice(0, commentStart);
126   match = VAR_ASSIGNMENT.exec(varLine);
127   if (match !== null) {
128     return new Variable(match[1], match[2]);
129   }
130   return undefined;
131 };
132
133 Tokenizer.prototype.shift = function () {
134   while (true) {
135     var result = this._shift();
136     if (result === undefined) {
137       continue;
138     }
139     return result;
140   }
141 };
142
143 function Parser(fileContent) {
144   this._tokenizer = new Tokenizer(fileContent);
145 }
146
147 Parser.prototype.parseFile = function () {
148   var sections = [];
149   while (true) {
150     var section = this.parseSection();
151     if (section === null) {
152       if (this._tokenizer.shift() !== null) {
153         throw new Error('Unexpected unparsed section of file remains!');
154       }
155       return sections;
156     }
157     sections.push(section);
158   }
159 };
160
161 Parser.prototype.parseSection = function () {
162   var section = this._tokenizer.shift();
163   if (section === null) {
164     return null;
165   }
166   if (!(section instanceof Section)) {
167     throw new Error('Expected section heading; got: ' + JSON.stringify(section));
168   }
169   var docstring = this._tokenizer.shift();
170   if (docstring instanceof SectionDocstring) {
171     section.docstring = docstring;
172   } else {
173     this._tokenizer.unshift(docstring);
174   }
175   this.parseSubSections(section);
176
177   return section;
178 };
179
180 Parser.prototype.parseSubSections = function (section) {
181   while (true) {
182     var subsection = this.parseSubSection();
183     if (subsection === null) {
184       if (section.subsections.length === 0) {
185         // Presume an implicit initial subsection
186         subsection = new SubSection('');
187         this.parseVars(subsection);
188       } else {
189         break;
190       }
191     }
192     section.addSubSection(subsection);
193   }
194
195   if (section.subsections.length === 1 && !section.subsections[0].heading && section.subsections[0].variables.length === 0) {
196     // Ignore lone empty implicit subsection
197     section.subsections = [];
198   }
199 };
200
201 Parser.prototype.parseSubSection = function () {
202   var subsection = this._tokenizer.shift();
203   if (subsection instanceof SubSection) {
204     this.parseVars(subsection);
205     return subsection;
206   }
207   this._tokenizer.unshift(subsection);
208   return null;
209 };
210
211 Parser.prototype.parseVars = function (subsection) {
212   while (true) {
213     var variable = this.parseVar();
214     if (variable === null) {
215       return;
216     }
217     subsection.addVar(variable);
218   }
219 };
220
221 Parser.prototype.parseVar = function () {
222   var docstring = this._tokenizer.shift();
223   if (!(docstring instanceof VarDocstring)) {
224     this._tokenizer.unshift(docstring);
225     docstring = null;
226   }
227   var variable = this._tokenizer.shift();
228   if (variable instanceof Variable) {
229     variable.docstring = docstring;
230     return variable;
231   }
232   this._tokenizer.unshift(variable);
233   return null;
234 };
235
236
237 module.exports = Parser;