From 46f9d27142ed81cfbcc0dc7806829756357a7505 Mon Sep 17 00:00:00 2001 From: Chris Rebert Date: Tue, 4 Feb 2014 13:18:54 -0800 Subject: reorganize all grunt tasks into one directory also fixes #12581 --- Gruntfile.js | 8 +- docs/grunt/bs-glyphicons-data-generator.js | 33 ---- docs/grunt/bs-lessdoc-parser.js | 236 ----------------------------- docs/grunt/bs-raw-files-generator.js | 31 ---- grunt/bs-glyphicons-data-generator.js | 33 ++++ grunt/bs-lessdoc-parser.js | 236 +++++++++++++++++++++++++++++ grunt/bs-raw-files-generator.js | 31 ++++ grunt/shrinkwrap.js | 24 +++ test-infra/shrinkwrap.js | 24 --- 9 files changed, 328 insertions(+), 328 deletions(-) delete mode 100644 docs/grunt/bs-glyphicons-data-generator.js delete mode 100644 docs/grunt/bs-lessdoc-parser.js delete mode 100644 docs/grunt/bs-raw-files-generator.js create mode 100644 grunt/bs-glyphicons-data-generator.js create mode 100644 grunt/bs-lessdoc-parser.js create mode 100644 grunt/bs-raw-files-generator.js create mode 100644 grunt/shrinkwrap.js delete mode 100644 test-infra/shrinkwrap.js diff --git a/Gruntfile.js b/Gruntfile.js index 55c4e46de..acef4100a 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -17,10 +17,10 @@ module.exports = function (grunt) { var fs = require('fs'); var path = require('path'); - var generateGlyphiconsData = require('./docs/grunt/bs-glyphicons-data-generator.js'); - var BsLessdocParser = require('./docs/grunt/bs-lessdoc-parser.js'); - var generateRawFilesJs = require('./docs/grunt/bs-raw-files-generator.js'); - var updateShrinkwrap = require('./test-infra/shrinkwrap.js'); + var generateGlyphiconsData = require('./grunt/bs-glyphicons-data-generator.js'); + var BsLessdocParser = require('./grunt/bs-lessdoc-parser.js'); + var generateRawFilesJs = require('./grunt/bs-raw-files-generator.js'); + var updateShrinkwrap = require('./grunt/shrinkwrap.js'); // Project configuration. grunt.initConfig({ diff --git a/docs/grunt/bs-glyphicons-data-generator.js b/docs/grunt/bs-glyphicons-data-generator.js deleted file mode 100644 index 3e32698a1..000000000 --- a/docs/grunt/bs-glyphicons-data-generator.js +++ /dev/null @@ -1,33 +0,0 @@ -/* jshint node: true */ -/*! - * Bootstrap Grunt task for Glyphicons data generation - * http://getbootstrap.com - * Copyright 2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -var fs = require('fs') - -module.exports = function generateGlyphiconsData() { - // Pass encoding, utf8, so `readFileSync` will return a string instead of a - // buffer - var glyphiconsFile = fs.readFileSync('less/glyphicons.less', 'utf8') - var glpyhiconsLines = glyphiconsFile.split('\n') - - // Use any line that starts with ".glyphicon-" and capture the class name - var iconClassName = /^\.(glyphicon-[^\s]+)/ - var glyphiconsData = '# This file is generated via Grunt task. **Do not edit directly.** \n' + - '# See the \'build-glyphicons-data\' task in Gruntfile.js.\n\n'; - for (var i = 0, len = glpyhiconsLines.length; i < len; i++) { - var match = glpyhiconsLines[i].match(iconClassName) - - if (match != null) { - glyphiconsData += '- ' + match[1] + '\n' - } - } - - // Create the `_data` directory if it doesn't already exist - if (!fs.existsSync('docs/_data')) fs.mkdirSync('docs/_data') - - fs.writeFileSync('docs/_data/glyphicons.yml', glyphiconsData) -} diff --git a/docs/grunt/bs-lessdoc-parser.js b/docs/grunt/bs-lessdoc-parser.js deleted file mode 100644 index 9d0b2ffaf..000000000 --- a/docs/grunt/bs-lessdoc-parser.js +++ /dev/null @@ -1,236 +0,0 @@ -/* jshint node: true */ -/*! - * Bootstrap Grunt task for parsing Less docstrings - * http://getbootstrap.com - * Copyright 2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -var markdown = require('markdown').markdown; - -function markdown2html(markdownString) { - // the slice removes the

...

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 - - //=== This is a subheading. - - //** Optional description for the following variable. You **can** use Markdown in descriptions to discuss `` 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 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; diff --git a/docs/grunt/bs-raw-files-generator.js b/docs/grunt/bs-raw-files-generator.js deleted file mode 100644 index 255508b7f..000000000 --- a/docs/grunt/bs-raw-files-generator.js +++ /dev/null @@ -1,31 +0,0 @@ -/* jshint node: true */ -/*! - * Bootstrap Grunt task for generating raw-files.min.js for the Customizer - * http://getbootstrap.com - * Copyright 2014 Twitter, Inc. - * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) - */ - -var btoa = require('btoa') // jshint ignore:line -var fs = require('fs') - -function getFiles(type) { - var files = {} - fs.readdirSync(type) - .filter(function (path) { - return type == 'fonts' ? true : new RegExp('\\.' + type + '$').test(path) - }) - .forEach(function (path) { - var fullPath = type + '/' + path - return files[path] = (type == 'fonts' ? btoa(fs.readFileSync(fullPath)) : fs.readFileSync(fullPath, 'utf8')) - }) - return 'var __' + type + ' = ' + JSON.stringify(files) + '\n' -} - -module.exports = function generateRawFilesJs(banner) { - if (!banner) { - banner = '' - } - var files = banner + getFiles('js') + getFiles('less') + getFiles('fonts') - fs.writeFileSync('docs/assets/js/raw-files.min.js', files) -} diff --git a/grunt/bs-glyphicons-data-generator.js b/grunt/bs-glyphicons-data-generator.js new file mode 100644 index 000000000..3e32698a1 --- /dev/null +++ b/grunt/bs-glyphicons-data-generator.js @@ -0,0 +1,33 @@ +/* jshint node: true */ +/*! + * Bootstrap Grunt task for Glyphicons data generation + * http://getbootstrap.com + * Copyright 2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +var fs = require('fs') + +module.exports = function generateGlyphiconsData() { + // Pass encoding, utf8, so `readFileSync` will return a string instead of a + // buffer + var glyphiconsFile = fs.readFileSync('less/glyphicons.less', 'utf8') + var glpyhiconsLines = glyphiconsFile.split('\n') + + // Use any line that starts with ".glyphicon-" and capture the class name + var iconClassName = /^\.(glyphicon-[^\s]+)/ + var glyphiconsData = '# This file is generated via Grunt task. **Do not edit directly.** \n' + + '# See the \'build-glyphicons-data\' task in Gruntfile.js.\n\n'; + for (var i = 0, len = glpyhiconsLines.length; i < len; i++) { + var match = glpyhiconsLines[i].match(iconClassName) + + if (match != null) { + glyphiconsData += '- ' + match[1] + '\n' + } + } + + // Create the `_data` directory if it doesn't already exist + if (!fs.existsSync('docs/_data')) fs.mkdirSync('docs/_data') + + fs.writeFileSync('docs/_data/glyphicons.yml', glyphiconsData) +} diff --git a/grunt/bs-lessdoc-parser.js b/grunt/bs-lessdoc-parser.js new file mode 100644 index 000000000..9d0b2ffaf --- /dev/null +++ b/grunt/bs-lessdoc-parser.js @@ -0,0 +1,236 @@ +/* jshint node: true */ +/*! + * Bootstrap Grunt task for parsing Less docstrings + * http://getbootstrap.com + * Copyright 2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +var markdown = require('markdown').markdown; + +function markdown2html(markdownString) { + // the slice removes the

...

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 + + //=== This is a subheading. + + //** Optional description for the following variable. You **can** use Markdown in descriptions to discuss `` 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 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; diff --git a/grunt/bs-raw-files-generator.js b/grunt/bs-raw-files-generator.js new file mode 100644 index 000000000..255508b7f --- /dev/null +++ b/grunt/bs-raw-files-generator.js @@ -0,0 +1,31 @@ +/* jshint node: true */ +/*! + * Bootstrap Grunt task for generating raw-files.min.js for the Customizer + * http://getbootstrap.com + * Copyright 2014 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +var btoa = require('btoa') // jshint ignore:line +var fs = require('fs') + +function getFiles(type) { + var files = {} + fs.readdirSync(type) + .filter(function (path) { + return type == 'fonts' ? true : new RegExp('\\.' + type + '$').test(path) + }) + .forEach(function (path) { + var fullPath = type + '/' + path + return files[path] = (type == 'fonts' ? btoa(fs.readFileSync(fullPath)) : fs.readFileSync(fullPath, 'utf8')) + }) + return 'var __' + type + ' = ' + JSON.stringify(files) + '\n' +} + +module.exports = function generateRawFilesJs(banner) { + if (!banner) { + banner = '' + } + var files = banner + getFiles('js') + getFiles('less') + getFiles('fonts') + fs.writeFileSync('docs/assets/js/raw-files.min.js', files) +} diff --git a/grunt/shrinkwrap.js b/grunt/shrinkwrap.js new file mode 100644 index 000000000..7a0328d41 --- /dev/null +++ b/grunt/shrinkwrap.js @@ -0,0 +1,24 @@ +/* jshint node: true */ + +/* +This Grunt task updates the npm-shrinkwrap.canonical.json file that's used as the key for Bootstrap's npm packages cache. +This task should be run and the updated file should be committed whenever Bootstrap's dependencies change. +*/ + +var canonicallyJsonStringify = require('canonical-json'); +var NON_CANONICAL_FILE = 'npm-shrinkwrap.json'; +var DEST_FILE = 'test-infra/npm-shrinkwrap.canonical.json'; + + +function updateShrinkwrap(grunt) { + // Assumption: Non-canonical shrinkwrap already generated by prerequisite Grunt task + var shrinkwrapData = grunt.file.readJSON(NON_CANONICAL_FILE); + grunt.log.writeln('Deleting ' + NON_CANONICAL_FILE.cyan + '...'); + grunt.file.delete(NON_CANONICAL_FILE); + // Output as Canonical JSON in correct location + grunt.file.write(DEST_FILE, canonicallyJsonStringify(shrinkwrapData)); + grunt.log.writeln('File ' + DEST_FILE.cyan + ' updated.'); +} + + +module.exports = updateShrinkwrap; diff --git a/test-infra/shrinkwrap.js b/test-infra/shrinkwrap.js deleted file mode 100644 index 7a0328d41..000000000 --- a/test-infra/shrinkwrap.js +++ /dev/null @@ -1,24 +0,0 @@ -/* jshint node: true */ - -/* -This Grunt task updates the npm-shrinkwrap.canonical.json file that's used as the key for Bootstrap's npm packages cache. -This task should be run and the updated file should be committed whenever Bootstrap's dependencies change. -*/ - -var canonicallyJsonStringify = require('canonical-json'); -var NON_CANONICAL_FILE = 'npm-shrinkwrap.json'; -var DEST_FILE = 'test-infra/npm-shrinkwrap.canonical.json'; - - -function updateShrinkwrap(grunt) { - // Assumption: Non-canonical shrinkwrap already generated by prerequisite Grunt task - var shrinkwrapData = grunt.file.readJSON(NON_CANONICAL_FILE); - grunt.log.writeln('Deleting ' + NON_CANONICAL_FILE.cyan + '...'); - grunt.file.delete(NON_CANONICAL_FILE); - // Output as Canonical JSON in correct location - grunt.file.write(DEST_FILE, canonicallyJsonStringify(shrinkwrapData)); - grunt.log.writeln('File ' + DEST_FILE.cyan + ' updated.'); -} - - -module.exports = updateShrinkwrap; -- cgit v1.2.3