diff options
| author | Chris Rebert <[email protected]> | 2013-10-17 19:52:16 -0700 |
|---|---|---|
| committer | Chris Rebert <[email protected]> | 2014-01-08 12:41:51 -0800 |
| commit | 39861714a80b68cd42a2e2b812be53f0b0f6b70d (patch) | |
| tree | 18c4717950db3637999d1e75d28bea1265aba810 /docs/grunt | |
| parent | c9ba678b9facc1afea0bc717a5c0f48e557e8fe9 (diff) | |
| download | bootstrap-39861714a80b68cd42a2e2b812be53f0b0f6b70d.tar.xz bootstrap-39861714a80b68cd42a2e2b812be53f0b0f6b70d.zip | |
Use JS & Jade to generate the customizer variables form HTML from variables.less; fixes #11095
also updates variables file organization (courtesy @mdo)
Diffstat (limited to 'docs/grunt')
| -rw-r--r-- | docs/grunt/bs-lessdoc-parser.js | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/docs/grunt/bs-lessdoc-parser.js b/docs/grunt/bs-lessdoc-parser.js new file mode 100644 index 000000000..8c232d80c --- /dev/null +++ b/docs/grunt/bs-lessdoc-parser.js @@ -0,0 +1,179 @@ +/* jshint node: true */ + +var markdown = require('markdown').markdown; + +function markdown2html(markdownString) { + // the slice removes the <p>...</p> wrapper output by Markdown processor + return markdown.toHTML(markdownString.trim()).slice(3, -4); +} + + +/* +Mini-language: + //== This is a normal heading, which starts a section. Sections group variables together. + //## Optional description for the heading + + //** Optional description for the following variable. You **can** use Markdown in descriptions to discuss `<html>` stuff. + @foo: #ffff; + + //-- 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 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.variables = []; + this.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 = 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.parseVars(section); + return section; +}; + +Parser.prototype.parseVars = function (section) { + while (true) { + var variable = this.parseVar(); + if (variable === null) { + return; + } + section.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; |
