| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 | 
							- /*!
 
-  * Bootstrap Grunt task for parsing Less docstrings
 
-  * http://getbootstrap.com
 
-  * Copyright 2014-2015 Twitter, Inc.
 
-  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 
-  */
 
- 'use strict';
 
- var Markdown = require('markdown-it');
 
- function markdown2html(markdownString) {
 
-   var md = new Markdown();
 
-   // the slice removes the <p>...</p> wrapper output by Markdown processor
 
-   return md.render(markdownString.trim()).slice(3, -5);
 
- }
 
- /*
 
- Mini-language:
 
-   //== This is a normal heading, which starts a section. Sections group variables together.
 
-   //## Optional description for the heading
 
-   //=== This is a subheading.
 
-   //** Optional description for the following variable. You **can** use Markdown in descriptions to discuss `<html>` stuff.
 
-   @foo: #fff;
 
-   //-- This is a heading for a section whose variables shouldn't be customizable
 
-   All other lines are ignored completely.
 
- */
 
- var CUSTOMIZABLE_HEADING = /^[/]{2}={2}(.*)$/;
 
- var UNCUSTOMIZABLE_HEADING = /^[/]{2}-{2}(.*)$/;
 
- var SUBSECTION_HEADING = /^[/]{2}={3}(.*)$/;
 
- var SECTION_DOCSTRING = /^[/]{2}#{2}(.+)$/;
 
- var VAR_ASSIGNMENT = /^(@[a-zA-Z0-9_-]+):[ ]*([^ ;][^;]*);[ ]*$/;
 
- var VAR_DOCSTRING = /^[/]{2}[*]{2}(.+)$/;
 
- function Section(heading, customizable) {
 
-   this.heading = heading.trim();
 
-   this.id = this.heading.replace(/\s+/g, '-').toLowerCase();
 
-   this.customizable = customizable;
 
-   this.docstring = null;
 
-   this.subsections = [];
 
- }
 
- Section.prototype.addSubSection = function (subsection) {
 
-   this.subsections.push(subsection);
 
- };
 
- function SubSection(heading) {
 
-   this.heading = heading.trim();
 
-   this.id = this.heading.replace(/\s+/g, '-').toLowerCase();
 
-   this.variables = [];
 
- }
 
- SubSection.prototype.addVar = function (variable) {
 
-   this.variables.push(variable);
 
- };
 
- function VarDocstring(markdownString) {
 
-   this.html = markdown2html(markdownString);
 
- }
 
- function SectionDocstring(markdownString) {
 
-   this.html = markdown2html(markdownString);
 
- }
 
- function Variable(name, defaultValue) {
 
-   this.name = name;
 
-   this.defaultValue = defaultValue;
 
-   this.docstring = null;
 
- }
 
- function Tokenizer(fileContent) {
 
-   this._lines = fileContent.split('\n');
 
-   this._next = undefined;
 
- }
 
- Tokenizer.prototype.unshift = function (token) {
 
-   if (this._next !== undefined) {
 
-     throw new Error('Attempted to unshift twice!');
 
-   }
 
-   this._next = token;
 
- };
 
- Tokenizer.prototype._shift = function () {
 
-   // returning null signals EOF
 
-   // returning undefined means the line was ignored
 
-   if (this._next !== undefined) {
 
-     var result = this._next;
 
-     this._next = undefined;
 
-     return result;
 
-   }
 
-   if (this._lines.length <= 0) {
 
-     return null;
 
-   }
 
-   var line = this._lines.shift();
 
-   var match = null;
 
-   match = SUBSECTION_HEADING.exec(line);
 
-   if (match !== null) {
 
-     return new SubSection(match[1]);
 
-   }
 
-   match = CUSTOMIZABLE_HEADING.exec(line);
 
-   if (match !== null) {
 
-     return new Section(match[1], true);
 
-   }
 
-   match = UNCUSTOMIZABLE_HEADING.exec(line);
 
-   if (match !== null) {
 
-     return new Section(match[1], false);
 
-   }
 
-   match = SECTION_DOCSTRING.exec(line);
 
-   if (match !== null) {
 
-     return new SectionDocstring(match[1]);
 
-   }
 
-   match = VAR_DOCSTRING.exec(line);
 
-   if (match !== null) {
 
-     return new VarDocstring(match[1]);
 
-   }
 
-   var commentStart = line.lastIndexOf('//');
 
-   var varLine = commentStart === -1 ? line : line.slice(0, commentStart);
 
-   match = VAR_ASSIGNMENT.exec(varLine);
 
-   if (match !== null) {
 
-     return new Variable(match[1], match[2]);
 
-   }
 
-   return undefined;
 
- };
 
- Tokenizer.prototype.shift = function () {
 
-   while (true) {
 
-     var result = this._shift();
 
-     if (result === undefined) {
 
-       continue;
 
-     }
 
-     return result;
 
-   }
 
- };
 
- function Parser(fileContent) {
 
-   this._tokenizer = new Tokenizer(fileContent);
 
- }
 
- Parser.prototype.parseFile = function () {
 
-   var sections = [];
 
-   while (true) {
 
-     var section = this.parseSection();
 
-     if (section === null) {
 
-       if (this._tokenizer.shift() !== null) {
 
-         throw new Error('Unexpected unparsed section of file remains!');
 
-       }
 
-       return sections;
 
-     }
 
-     sections.push(section);
 
-   }
 
- };
 
- Parser.prototype.parseSection = function () {
 
-   var section = this._tokenizer.shift();
 
-   if (section === null) {
 
-     return null;
 
-   }
 
-   if (!(section instanceof Section)) {
 
-     throw new Error('Expected section heading; got: ' + JSON.stringify(section));
 
-   }
 
-   var docstring = this._tokenizer.shift();
 
-   if (docstring instanceof SectionDocstring) {
 
-     section.docstring = docstring;
 
-   } else {
 
-     this._tokenizer.unshift(docstring);
 
-   }
 
-   this.parseSubSections(section);
 
-   return section;
 
- };
 
- Parser.prototype.parseSubSections = function (section) {
 
-   while (true) {
 
-     var subsection = this.parseSubSection();
 
-     if (subsection === null) {
 
-       if (section.subsections.length === 0) {
 
-         // Presume an implicit initial subsection
 
-         subsection = new SubSection('');
 
-         this.parseVars(subsection);
 
-       } else {
 
-         break;
 
-       }
 
-     }
 
-     section.addSubSection(subsection);
 
-   }
 
-   if (section.subsections.length === 1 && !section.subsections[0].heading && section.subsections[0].variables.length === 0) {
 
-     // Ignore lone empty implicit subsection
 
-     section.subsections = [];
 
-   }
 
- };
 
- Parser.prototype.parseSubSection = function () {
 
-   var subsection = this._tokenizer.shift();
 
-   if (subsection instanceof SubSection) {
 
-     this.parseVars(subsection);
 
-     return subsection;
 
-   }
 
-   this._tokenizer.unshift(subsection);
 
-   return null;
 
- };
 
- Parser.prototype.parseVars = function (subsection) {
 
-   while (true) {
 
-     var variable = this.parseVar();
 
-     if (variable === null) {
 
-       return;
 
-     }
 
-     subsection.addVar(variable);
 
-   }
 
- };
 
- Parser.prototype.parseVar = function () {
 
-   var docstring = this._tokenizer.shift();
 
-   if (!(docstring instanceof VarDocstring)) {
 
-     this._tokenizer.unshift(docstring);
 
-     docstring = null;
 
-   }
 
-   var variable = this._tokenizer.shift();
 
-   if (variable instanceof Variable) {
 
-     variable.docstring = docstring;
 
-     return variable;
 
-   }
 
-   this._tokenizer.unshift(variable);
 
-   return null;
 
- };
 
- module.exports = Parser;
 
 
  |