From 88d67b73705630013083a3ac6e461442fbe9ef05 Mon Sep 17 00:00:00 2001 From: Tim Schaub Date: Thu, 10 Apr 2014 14:38:49 -0600 Subject: [PATCH] Regenerate symbols if parents have changed The generate-symbols.js task runs JSDoc on source files. Because this takes a long time (13s) to run on the whole library, the resulting symbols file includes additional metadata to make it possible to do incremental symbol generation on subsequent runs. The 'path' and 'extends' metadata for a symbol are used to determine what needs to be regenerated. --- buildcfg/jsdoc/symbols/publish.js | 5 +-- tasks/generate-symbols.js | 64 +++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 11 deletions(-) diff --git a/buildcfg/jsdoc/symbols/publish.js b/buildcfg/jsdoc/symbols/publish.js index b28dd70150..c15c972c19 100644 --- a/buildcfg/jsdoc/symbols/publish.js +++ b/buildcfg/jsdoc/symbols/publish.js @@ -17,7 +17,7 @@ exports.publish = function(data, opts) { // get all doclets with the "api" property. var docs = data({api: {isString: true}}).get(); - // get sorted symbols, filter out those that are members of private classes + // get symbols data, filter out those that are members of private classes var symbols = docs.filter(function(doc) { var include = true; var constructor = doc.memberof; @@ -30,10 +30,9 @@ exports.publish = function(data, opts) { }).map(function(doc) { return { name: doc.longname, + extends: doc.augments, path: path.join(doc.meta.path, doc.meta.filename) }; - }).sort(function(a, b) { - return a.name < b.name ? -1 : 1; }); process.stdout.write(JSON.stringify({symbols: symbols}, null, 2)); diff --git a/tasks/generate-symbols.js b/tasks/generate-symbols.js index c5babbbb45..057a80ab91 100644 --- a/tasks/generate-symbols.js +++ b/tasks/generate-symbols.js @@ -39,6 +39,15 @@ function readSymbols(callback) { } +function makeUnique(array) { + var values = {}; + array.forEach(function(value) { + values[value] = true; + }); + return Object.keys(values); +} + + /** * Generate a list of .js paths in the source directory that are newer than * the symbols file. @@ -48,16 +57,16 @@ function readSymbols(callback) { * any error, the symbols array, and the array of newer source paths. */ function getNewer(symbols, date, callback) { - var all = []; - var newer = []; + var allPaths = []; + var newerPaths = []; var walker = walk(sourceDir); walker.on('file', function(root, stats, next) { var sourcePath = path.join(root, stats.name); if (/\.js$/.test(sourcePath)) { - all.push(sourcePath); + allPaths.push(sourcePath); if (stats.mtime > date) { - newer.push(sourcePath); + newerPaths.push(sourcePath); } } next(); @@ -67,10 +76,47 @@ function getNewer(symbols, date, callback) { }); walker.on('end', function() { // prune symbols if file no longer exists or has been modified - symbols = symbols.filter(function(symbol) { - return newer.indexOf(symbol.path) < 0 && all.indexOf(symbol.path) >= 0; + var lookup = {}; + symbols.forEach(function(symbol) { + lookup[symbol.name] = symbol; }); - callback(null, symbols, newer); + + /** + * Gather paths for all parent symbols. + * @param {Object} symbol Symbol to check. + * @param {Array.} paths Current paths. + */ + function gatherParentPaths(symbol, paths) { + if (symbol.extends) { + symbol.extends.forEach(function(name) { + if (name in lookup) { + var parent = lookup[name]; + paths.push(parent.path); + gatherParentPaths(parent, paths); + } + }); + } + } + + var dirtyPaths = []; + + symbols = symbols.filter(function(symbol) { + var dirty = allPaths.indexOf(symbol.path) < 0; + if (!dirty) { + // confirm that symbol and all parent paths are not newer + var paths = [symbol.path]; + gatherParentPaths(symbol, paths); + dirty = paths.some(function(p) { + return newerPaths.indexOf(p) >= 0; + }); + if (dirty) { + dirtyPaths.push(symbol.path); + } + } + return !dirty; + }); + + callback(null, symbols, makeUnique(newerPaths.concat(dirtyPaths))); }); } @@ -135,7 +181,9 @@ function writeSymbols(symbols, output, callback) { return; } - symbols = symbols.concat(data.symbols); + symbols = symbols.concat(data.symbols).sort(function(a, b) { + return a.name < b.name ? -1 : 1; + }); var str = JSON.stringify({symbols: symbols}, null, ' '); fse.outputFile(destPath, str, callback);