Rebuild examples when the sources change
This commit is contained in:
@@ -46,7 +46,9 @@
|
||||
"devDependencies": {
|
||||
"clean-css": "2.2.16",
|
||||
"coveralls": "2.11.2",
|
||||
"debounce": "^1.0.0",
|
||||
"expect.js": "0.3.1",
|
||||
"gaze": "^0.5.1",
|
||||
"istanbul": "0.3.13",
|
||||
"jquery": "2.1.1",
|
||||
"jshint": "2.5.6",
|
||||
@@ -54,9 +56,9 @@
|
||||
"mocha-phantomjs": "3.5.1",
|
||||
"phantomjs": "1.9.10",
|
||||
"proj4": "2.3.3",
|
||||
"resemblejs": "1.2.0",
|
||||
"sinon": "1.10.3",
|
||||
"slimerjs-edge": "0.10.0-pre-2",
|
||||
"resemblejs": "1.2.0"
|
||||
"slimerjs-edge": "0.10.0-pre-2"
|
||||
},
|
||||
"ext": [
|
||||
"rbush"
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
var async = require('async');
|
||||
|
||||
var buildExt = require('./build-ext');
|
||||
var parseExamples = require('./parse-examples');
|
||||
|
||||
/**
|
||||
* Parse examples and build external modules.
|
||||
*/
|
||||
async.waterfall([
|
||||
parseExamples,
|
||||
buildExt
|
||||
], function(err) {
|
||||
buildExt(function(err) {
|
||||
if (err) {
|
||||
process.stderr.write(err + '\n');
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
|
||||
var async = require('async');
|
||||
var Parser = require('htmlparser2').Parser;
|
||||
|
||||
var buildExamples = require('./build-examples');
|
||||
|
||||
var exampleDir = path.join(__dirname, '..', 'examples');
|
||||
|
||||
|
||||
/**
|
||||
* List all .html files in the example directory (excluding index.html).
|
||||
* @param {function(Error, Array.<string>)} callback Called with any error or
|
||||
* the list of paths to examples.
|
||||
*/
|
||||
function listExamples(callback) {
|
||||
fs.readdir(exampleDir, function(err, items) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
var examplePaths = items.filter(function(item) {
|
||||
return /\.html$/i.test(item) && item !== 'index.html';
|
||||
}).map(function(item) {
|
||||
return path.join(exampleDir, item);
|
||||
});
|
||||
callback(null, examplePaths);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse info from examples.
|
||||
* @param {Array.<string>} examplePaths Paths to examples.
|
||||
* @param {function(Error, Array.<Object>)} callback Called with any error or
|
||||
* the list of example info objects.
|
||||
*/
|
||||
function parseExamples(examplePaths, callback) {
|
||||
async.map(examplePaths, function(examplePath, next) {
|
||||
fs.readFile(examplePath, function(err, data) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
var name = path.basename(examplePath);
|
||||
var info = {
|
||||
link: name,
|
||||
example: name,
|
||||
title: '',
|
||||
shortdesc: '',
|
||||
tags: ''
|
||||
};
|
||||
var key;
|
||||
var openTag;
|
||||
var parser = new Parser({
|
||||
onopentag: function(tag, attrs) {
|
||||
if (attrs.id in info) {
|
||||
key = attrs.id;
|
||||
openTag = tag;
|
||||
}
|
||||
},
|
||||
ontext: function(text) {
|
||||
if (key) {
|
||||
info[key] += text.replace(/\n/g, '').trim() + ' ';
|
||||
}
|
||||
},
|
||||
onclosetag: function(tag) {
|
||||
if (tag === openTag) {
|
||||
info[key] = info[key].trim();
|
||||
key = undefined;
|
||||
openTag = undefined;
|
||||
}
|
||||
},
|
||||
onerror: function(err2) {
|
||||
var message = 'Trouble parsing ' + examplePath + '\n' + err2.message;
|
||||
next(new Error(message));
|
||||
}
|
||||
});
|
||||
parser.write(data.toString('utf8'));
|
||||
parser.end();
|
||||
next(null, info);
|
||||
});
|
||||
}, callback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create an inverted index of keywords from examples. Property names are
|
||||
* lowercased words. Property values are objects mapping example index to word
|
||||
* count.
|
||||
* @param {Array.<Object>} exampleInfos Array of example info objects.
|
||||
* @return {Object} Word index.
|
||||
*/
|
||||
function createWordIndex(exampleInfos) {
|
||||
var index = {};
|
||||
var keys = ['shortdesc', 'title', 'tags'];
|
||||
exampleInfos.forEach(function(info, i) {
|
||||
keys.forEach(function(key) {
|
||||
var text = info[key];
|
||||
var words = text ? text.split(/\W+/) : [];
|
||||
words.forEach(function(word) {
|
||||
if (word) {
|
||||
word = word.toLowerCase();
|
||||
var counts = index[word];
|
||||
if (counts) {
|
||||
if (index in counts) {
|
||||
counts[i] += 1;
|
||||
} else {
|
||||
counts[i] = 1;
|
||||
}
|
||||
} else {
|
||||
counts = {};
|
||||
counts[i] = 1;
|
||||
index[word] = counts;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write the example-list.js file with example info and word index.
|
||||
* @param {Array.<Object>} exampleInfos Array of example info objects.
|
||||
* @param {function(Error)} callback Called with any error.
|
||||
*/
|
||||
function writeExampleList(exampleInfos, callback) {
|
||||
var info = {
|
||||
examples: exampleInfos,
|
||||
index: createWordIndex(exampleInfos)
|
||||
};
|
||||
var indexPath = path.join(exampleDir, 'example-list.js');
|
||||
var str = 'var info = ' + JSON.stringify(info);
|
||||
fs.writeFile(indexPath, str, callback);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* List examples, parse them, and write example list.
|
||||
* @param {function(Error)} callback Called with any error.
|
||||
*/
|
||||
function main(callback) {
|
||||
async.waterfall([
|
||||
buildExamples,
|
||||
listExamples,
|
||||
parseExamples,
|
||||
writeExampleList
|
||||
], callback);
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
main(function(err) {
|
||||
if (err) {
|
||||
process.stderr.write(err.message + '\n');
|
||||
process.exit(1);
|
||||
} else {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = main;
|
||||
@@ -107,13 +107,10 @@ This is useful for projects that use the Closure Compiler to build, but want to
|
||||
Called internally to parse the library for annotations and write out a `build/info.json` file.
|
||||
|
||||
|
||||
## `parse-examples.js`
|
||||
|
||||
Called after install to generate an example index. After new examples are added, run `node tasks/parse-examples.js` to regenerate the example index.
|
||||
|
||||
## `build-examples.js`
|
||||
|
||||
Called internally by `parse-examples.js` to build the examples from templates.
|
||||
Builds examples and the example index.
|
||||
|
||||
|
||||
## `serve.js`
|
||||
|
||||
|
||||
@@ -7,9 +7,12 @@
|
||||
var path = require('path');
|
||||
var url = require('url');
|
||||
|
||||
var Gaze = require('gaze').Gaze;
|
||||
var closure = require('closure-util');
|
||||
var debounce = require('debounce');
|
||||
var nomnom = require('nomnom');
|
||||
|
||||
var buildExamples = require('./build-examples');
|
||||
var log = closure.log;
|
||||
|
||||
|
||||
@@ -68,6 +71,26 @@ var createServer = exports.createServer = function(callback) {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the examples and exit on any error.
|
||||
* @param {Function=} opt_callback Called when done building examples.
|
||||
*/
|
||||
function buildExamplesOrFatal(opt_callback) {
|
||||
log.info('serve', 'Building examples.');
|
||||
buildExamples(function(err) {
|
||||
if (err) {
|
||||
log.error('serve', 'Building examples failed.');
|
||||
log.error('serve', err.message);
|
||||
log.error('serve', 'Use "verbose" logging to see the full stack trace.');
|
||||
log.verbose('serve', err.stack);
|
||||
process.exit(1);
|
||||
}
|
||||
log.verbose('serve', 'Done building examples.');
|
||||
if (opt_callback) {
|
||||
opt_callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* If running this module directly start the server.
|
||||
@@ -92,21 +115,30 @@ if (require.main === module) {
|
||||
/** @type {string} */
|
||||
log.level = options.loglevel;
|
||||
|
||||
log.info('serve', 'Parsing dependencies ...');
|
||||
createServer(function(err, server) {
|
||||
if (err) {
|
||||
log.error('serve', 'Parsing failed');
|
||||
log.error('serve', err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
server.listen(options.port, function() {
|
||||
log.info('serve', 'Listening on http://localhost:' +
|
||||
options.port + '/ (Ctrl+C to stop)');
|
||||
});
|
||||
server.on('error', function(err) {
|
||||
log.error('serve', 'Server failed to start: ' + err.message);
|
||||
process.exit(1);
|
||||
buildExamplesOrFatal(function() {
|
||||
log.info('serve', 'Parsing dependencies.');
|
||||
createServer(function(err, server) {
|
||||
if (err) {
|
||||
log.error('serve', 'Parsing failed');
|
||||
log.error('serve', err.message);
|
||||
process.exit(1);
|
||||
}
|
||||
server.listen(options.port, function() {
|
||||
log.info('serve', 'Listening on http://localhost:' +
|
||||
options.port + '/ (Ctrl+C to stop)');
|
||||
});
|
||||
server.on('error', function(err) {
|
||||
log.error('serve', 'Server failed to start: ' + err.message);
|
||||
process.exit(1);
|
||||
});
|
||||
});
|
||||
|
||||
var gaze = new Gaze('examples_src/**/*');
|
||||
var debouncedBuild = debounce(buildExamplesOrFatal, 250);
|
||||
gaze.on('all', function(event, filepath) {
|
||||
log.verbose('serve', 'Watch event: ' + event + ' ' + filepath);
|
||||
debouncedBuild();
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user