diff options
| author | Di Peng | 2011-07-09 18:15:40 -0700 |
|---|---|---|
| committer | Igor Minar | 2011-07-20 17:33:18 -0700 |
| commit | 8fa066190af2b2267a5e8111a41beb6e8af5c340 (patch) | |
| tree | 221e9b67892b9b09047ae8a8b6b50f5cbc9e2ead /docs/src | |
| parent | e90b741c9492a65e159c842afe49383f1868308e (diff) | |
| download | angular.js-8fa066190af2b2267a5e8111a41beb6e8af5c340.tar.bz2 | |
refactor(gen-docs): use q, qq, q-fs (node modules) to write gen-docs
- re-write gendocs.js, reader.js and writer.js
- all calls are asynchronous
Diffstat (limited to 'docs/src')
| -rw-r--r-- | docs/src/appCache.js | 99 | ||||
| -rw-r--r-- | docs/src/callback.js | 69 | ||||
| -rwxr-xr-x | docs/src/gen-docs.js | 139 | ||||
| -rw-r--r-- | docs/src/reader.js | 168 | ||||
| -rw-r--r-- | docs/src/templates/index.html | 4 | ||||
| -rw-r--r-- | docs/src/writer.js | 167 |
6 files changed, 303 insertions, 343 deletions
diff --git a/docs/src/appCache.js b/docs/src/appCache.js index 994054c2..cf7827bf 100644 --- a/docs/src/appCache.js +++ b/docs/src/appCache.js @@ -3,48 +3,73 @@ */ exports.appCache = appCache; -var fs = require('fs'); +var fs = require('q-fs'); +var Q = require('qq'); +function identity($) {return $;} function appCache(path) { - var blackList = [ "offline.html", - "sitemap.xml", - "robots.txt", - "docs-scenario.html", - "docs-scenario.js", - "app-cache.manifest" + if(!path) { + return appCacheTemplate(); + } + var blackList = ["offline.html", + "sitemap.xml", + "robots.txt", + "docs-scenario.html", + "docs-scenario.js", + "appcache.manifest" ]; var result = ["CACHE MANIFEST", - "# %TIMESTAMP%", - "", - "# cache all of these", - "CACHE:", - "../angular.min.js"]; + "# " + new Date().toISOString(), + "", + "# cache all of these", + "CACHE:", + "../angular.min.js"]; + + var resultPostfix = ["", + "FALLBACK:", + "/offline.html", + "", + "# allow access to google analytics and twitter when we are online", + "NETWORK:", + "*"]; + + var promise = fs.listTree(path).then(function(files){ + var fileFutures = []; + files.forEach(function(file){ + fileFutures.push(fs.isFile(file).then(function(isFile){ + if (isFile && blackList.indexOf(file) == -1) { + return file.replace('build/docs/',''); + } + })); + }); + return Q.deep(fileFutures); + }).then(function(files){ + return result.concat(files.filter(identity)).concat(resultPostfix).join('\n'); + }); - var resultPostfix = [ "", - "FALLBACK:", - "/offline.html", - "", - "# allow access to google analytics and twitter when we are online", - "NETWORK:", - "*"]; - walk(path,result,blackList); - return result.join('\n').replace(/%TIMESTAMP%/, (new Date()).toISOString()) + '\n' + resultPostfix.join('\n'); + return promise; } -function walk(path, array, blackList) { - var temp = fs.readdirSync(path); - for (var i=0; i< temp.length; i++) { - if(blackList.indexOf(temp[i]) < 0) { - var currentPath = path + '/' + temp[i]; - var stat = fs.statSync(currentPath); - - if (stat.isDirectory()) { - walk(currentPath, array, blackList); - } - else { - array.push(currentPath.replace('build/docs/','')); - } - } - } -}
\ No newline at end of file +function appCacheTemplate() { + return ["CACHE MANIFEST", + "# " + new Date().toISOString(), + "", + "# cache all of these", + "CACHE:", + "syntaxhighlighter/syntaxhighlighter-combined.js", + "../angular.min.js", + "docs-combined.js", + "docs-keywords.js", + "docs-combined.css", + "syntaxhighlighter/syntaxhighlighter-combined.css", + "img/texture_1.png", + "img/yellow_bkgnd.jpg", + "", + "FALLBACK:", + "/ offline.html", + "", + "# allow access to google analytics and twitter when we are online", + "NETWORK:", + "*"].join('\n'); +} diff --git a/docs/src/callback.js b/docs/src/callback.js deleted file mode 100644 index aaf69cde..00000000 --- a/docs/src/callback.js +++ /dev/null @@ -1,69 +0,0 @@ -function noop(){} - -function chain(delegateFn, explicitDone){ - var onDoneFn = noop; - var onErrorFn = function(e){ - console.error(e.stack || e); - process.exit(-1); - }; - var waitForCount = 1; - delegateFn = delegateFn || noop; - var stackError = new Error('capture stack'); - - function decrementWaitFor() { - waitForCount--; - if (waitForCount == 0) - onDoneFn(); - } - - function self(){ - try { - return delegateFn.apply(self, arguments); - } catch (error) { - self.error(error); - } finally { - if (!explicitDone) - decrementWaitFor(); - } - }; - self.onDone = function(callback){ - onDoneFn = callback; - return self; - }; - self.onError = function(callback){ - onErrorFn = callback; - return self; - }; - self.waitFor = function(callback){ - if (waitForCount == 0) - throw new Error("Can not wait on already called callback."); - waitForCount++; - return chain(callback).onDone(decrementWaitFor).onError(self.error); - }; - - self.waitMany = function(callback){ - if (waitForCount == 0) - throw new Error("Can not wait on already called callback."); - waitForCount++; - return chain(callback, true).onDone(decrementWaitFor).onError(self.error); - }; - - self.done = function(callback){ - decrementWaitFor(); - }; - - self.error = function(error) { - var stack = stackError.stack.split(/\n\r?/).splice(2); - var nakedStack = []; - stack.forEach(function(frame){ - if (!frame.match(/callback\.js:\d+:\d+\)$/)) - nakedStack.push(frame); - }); - error.stack = error.stack + '\nCalled from:\n' + nakedStack.join('\n'); - onErrorFn(error); - }; - - return self; -} - -exports.chain = chain; diff --git a/docs/src/gen-docs.js b/docs/src/gen-docs.js index 8ed0c563..2cbc9267 100755 --- a/docs/src/gen-docs.js +++ b/docs/src/gen-docs.js @@ -3,90 +3,77 @@ require.paths.push('lib'); var reader = require('reader.js'), ngdoc = require('ngdoc.js'), writer = require('writer.js'), - callback = require('callback.js'), SiteMap = require('SiteMap.js').SiteMap, - appCache = require('appCache.js'); + appCache = require('appCache.js').appCache, + Q = require('qq'); -var docs = []; -var start; -var work = callback.chain(function(){ - start = now(); - console.log('Generating Angular Reference Documentation...'); - reader.collect(work.waitMany(function(text, file, line){ - var doc = new ngdoc.Doc(text, file, line); - docs.push(doc); - doc.parse(); - })); +process.on('uncaughtException', function (err) { + console.error(err.stack || err); }); -var writes = callback.chain(function(){ + +var start = now(); +var docs; + +writer.makeDir('build/docs/syntaxhighlighter').then(function() { + console.log('Generating Angular Reference Documentation...'); + return reader.collect(); +}).then(function generateHtmlDocPartials(docs_) { + docs = docs_; ngdoc.merge(docs); + var fileFutures = []; docs.forEach(function(doc){ - writer.output(doc.section + '/' + doc.id + '.html', doc.html(), writes.waitFor()); + fileFutures.push(writer.output(doc.section + '/' + doc.id + '.html', doc.html())); }); + + writeTheRest(fileFutures); + + return Q.deep(fileFutures); +}).then(function generateManifestFile() { + return appCache('build/docs/').then(function(list) { + writer.output('appcache-offline.manifest',list) + }); +}).then(function printStats() { + console.log('DONE. Generated ' + docs.length + ' pages in ' + (now()-start) + 'ms.' ); +}).end(); + + +function writeTheRest(writesFuture) { var metadata = ngdoc.metadata(docs); - writer.output('docs-keywords.js', ['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';'], writes.waitFor()); - writer.copyDir('img', writes.waitFor()); - writer.copyDir('examples', writes.waitFor()); - writer.copyTpl('index.html', writes.waitFor()); - writer.copyTpl('.htaccess', writes.waitFor()); - writer.copy('docs/src/templates/index.html', 'build/docs/index-jq.html', writes.waitFor(), - '<-- jquery place holder -->', '<script src=\"jquery.min.js\"><\/script>'); - writer.copyTpl('offline.html', writes.waitFor()); - //writer.output('app-cache.manifest', - // appCacheTemplate().replace(/%TIMESTAMP%/, (new Date()).toISOString()), - // writes.waitFor()); - writer.merge(['docs.js', - 'doc_widgets.js'], - 'docs-combined.js', - writes.waitFor()); - writer.merge(['docs.css', - 'doc_widgets.css'], - 'docs-combined.css', - writes.waitFor()); - writer.copyTpl('docs-scenario.html', writes.waitFor()); - writer.output('docs-scenario.js', ngdoc.scenarios(docs), writes.waitFor()); - writer.output('sitemap.xml', new SiteMap(docs).render(), writes.waitFor()); - writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n', writes.waitFor()); - writer.merge(['syntaxhighlighter/shCore.js', - 'syntaxhighlighter/shBrushJScript.js', - 'syntaxhighlighter/shBrushXml.js'], - 'syntaxhighlighter/syntaxhighlighter-combined.js', - writes.waitFor()); - writer.merge(['syntaxhighlighter/shCore.css', - 'syntaxhighlighter/shThemeDefault.css'], - 'syntaxhighlighter/syntaxhighlighter-combined.css', - writes.waitFor()); - writer.copyTpl('jquery.min.js', writes.waitFor()); - writer.output('app-cache.manifest', appCache('build/docs/'), writes.waitFor()); -}); -writes.onDone(function(){ - console.log('DONE. Generated ' + docs.length + ' pages in ' + - (now()-start) + 'ms.' ); -}); -work.onDone(writes); -writer.makeDir('build/docs/syntaxhighlighter', work); -/////////////////////////////////// -function now(){ return new Date().getTime(); } + writesFuture.push(writer.copyDir('img')); + writesFuture.push(writer.copyDir('examples')); + writesFuture.push(writer.copyTpl('index.html')); + writesFuture.push(writer.copy('docs/src/templates/index.html', + 'build/docs/index-jq.html', + '<!-- jquery place holder -->', + '<script src=\"jquery.min.js\"><\/script>')); + writesFuture.push(writer.copyTpl('offline.html')); + writesFuture.push(writer.copyTpl('docs-scenario.html')); + writesFuture.push(writer.copyTpl('jquery.min.js')); + writesFuture.push(writer.output('docs-keywords.js', + ['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';'])); + writesFuture.push(writer.output('sitemap.xml', new SiteMap(docs).render())); + writesFuture.push(writer.output('docs-scenario.js', ngdoc.scenarios(docs))); + writesFuture.push(writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n')); + writesFuture.push(writer.output('appcache.manifest',appCache())); -function appCacheTemplate() { - return ["CACHE MANIFEST", - "# %TIMESTAMP%", - "", - "# cache all of these", - "CACHE:", - "syntaxhighlighter/syntaxhighlighter-combined.js", - "../angular.min.js", - "docs-combined.js", - "docs-keywords.js", - "docs-combined.css", - "syntaxhighlighter/syntaxhighlighter-combined.css", - "", - "FALLBACK:", - "/ offline.html", - "", - "# allow access to google analytics and twitter when we are online", - "NETWORK:", - "*"].join('\n'); + writesFuture.push(writer.merge(['docs.js', + 'doc_widgets.js'], + 'docs-combined.js')); + writesFuture.push(writer.merge(['docs.css', + 'doc_widgets.css'], + 'docs-combined.css')); + writesFuture.push(writer.merge(['syntaxhighlighter/shCore.js', + 'syntaxhighlighter/shBrushJScript.js', + 'syntaxhighlighter/shBrushXml.js'], + 'syntaxhighlighter/syntaxhighlighter-combined.js')); + writesFuture.push(writer.merge(['syntaxhighlighter/shCore.css', + 'syntaxhighlighter/shThemeDefault.css'], + 'syntaxhighlighter/syntaxhighlighter-combined.css')); } + + +function now(){ return new Date().getTime(); } + +function noop(){}; diff --git a/docs/src/reader.js b/docs/src/reader.js index 7342e6df..8ea59af9 100644 --- a/docs/src/reader.js +++ b/docs/src/reader.js @@ -2,98 +2,98 @@ * All reading related code here. This is so that we can separate the async code from sync code * for testability */ + +exports.collect = collect; + require.paths.push(__dirname); -var fs = require('fs'), - callback = require('callback'); +var ngdoc = require('ngdoc.js'), + Q = require('qq'), + qfs = require('q-fs'); var NEW_LINE = /\n\r?/; -function collect(callback){ - findJsFiles('src', callback.waitMany(function(file) { - console.log('reading', file, '...'); - findNgDocInJsFile(file, callback.waitMany(function(doc, line) { - callback('@section api\n' + doc, file, line); - })); - })); - findNgDocInDir('docs/content', callback.waitMany(callback)); - callback.done(); -} +function collect() { + var allDocs = []; -function findJsFiles(dir, callback){ - fs.readdir(dir, callback.waitFor(function(err, files){ - if (err) return this.error(err); - files.forEach(function(file){ - var path = dir + '/' + file; - fs.lstat(path, callback.waitFor(function(err, stat){ - if (err) return this.error(err); - if (stat.isDirectory()) - findJsFiles(path, callback.waitMany(callback)); - else if (/\.js$/.test(path)) - callback(path); - })); + //collect docs in JS Files + var path = 'src'; + var promiseA = Q.when(qfs.listTree(path), function(files) { + var done; + //read all files in parallel. + files.forEach(function(file) { + var work; + if(/\.js$/.test(file)) { + console.log("reading " + file + "......."); + work = Q.when(qfs.read(file), function(content) { + processJsFile(content, file).forEach (function(doc) { + allDocs.push(doc); + }); + }); + } + done = Q.when(done, function() { + return work; + }); }); - callback.done(); - })); -} + return done; + }); -function findNgDocInDir(directory, docNotify) { - fs.readdir(directory, docNotify.waitFor(function(err, files){ - if (err) return this.error(err); - files.forEach(function(file){ - fs.stat(directory + '/' + file, docNotify.waitFor(function(err, stats){ - if (err) return this.error(err); - if (stats.isFile()) { - if (!file.match(/\.ngdoc$/)) return; - console.log('reading', directory + '/' + file, '...'); - fs.readFile(directory + '/' + file, docNotify.waitFor(function(err, content){ - if (err) return this.error(err); - var section = '@section ' + directory.split('/').pop() + '\n'; - docNotify(section + content.toString(), directory + '/' +file, 1); - })); - } else if(stats.isDirectory()) { - findNgDocInDir(directory + '/' + file, docNotify.waitFor(docNotify)); - } - })); - }); - docNotify.done(); - })); -} + //collect all NG Docs in Content Folder + var path2 = 'docs/content'; + var promiseB = Q.when(qfs.listTree(path2), function(files){ + var done2; + files.forEach(function(file) { + var work2; + if (file.match(/\.ngdoc$/)) { + console.log("reading " + file + "......."); + work2 = Q.when(qfs.read(file), function(content){ + var section = '@section ' + file.split('/')[2] + '\n'; + allDocs.push(new ngdoc.Doc(section + content.toString(),file, 1).parse()); + }); + } + done2 = Q.when(done2, function() { + return work2; + }); + }); + return done2; + }); -function findNgDocInJsFile(file, callback) { - fs.readFile(file, callback.waitFor(function(err, content){ - var lines = content.toString().split(NEW_LINE); - var text; - var startingLine ; - var match; - var inDoc = false; - lines.forEach(function(line, lineNumber){ - lineNumber++; - // is the comment starting? - if (!inDoc && (match = line.match(/^\s*\/\*\*\s*(.*)$/))) { - line = match[1]; - inDoc = true; - text = []; - startingLine = lineNumber; - } - // are we done? - if (inDoc && line.match(/\*\//)) { - text = text.join('\n'); - text = text.replace(/^\n/, ''); - if (text.match(/@ngdoc/)){ - callback(text, startingLine); - } - doc = null; - inDoc = false; - } - // is the comment add text - if (inDoc){ - text.push(line.replace(/^\s*\*\s?/, '')); - } - }); - callback.done(); - })); + return Q.join(promiseA, promiseB, function() { + return allDocs; + }); } +function processJsFile(content, file) { + var docs = []; + var lines = content.toString().split(NEW_LINE); + var text; + var startingLine ; + var match; + var inDoc = false; - -exports.collect = collect; + lines.forEach(function(line, lineNumber){ + lineNumber++; + // is the comment starting? + if (!inDoc && (match = line.match(/^\s*\/\*\*\s*(.*)$/))) { + line = match[1]; + inDoc = true; + text = []; + startingLine = lineNumber; + } + // are we done? + if (inDoc && line.match(/\*\//)) { + text = text.join('\n'); + text = text.replace(/^\n/, ''); + if (text.match(/@ngdoc/)){ + //console.log(file, startingLine) + docs.push(new ngdoc.Doc('@section api\n' + text, file, startingLine).parse()); + } + doc = null; + inDoc = false; + } + // is the comment add text + if (inDoc){ + text.push(line.replace(/^\s*\*\s?/, '')); + } + }); + return docs; +}
\ No newline at end of file diff --git a/docs/src/templates/index.html b/docs/src/templates/index.html index 79c6a07c..ce8e9718 100644 --- a/docs/src/templates/index.html +++ b/docs/src/templates/index.html @@ -2,7 +2,7 @@ <html xmlns:ng="http://angularjs.org/" xmlns:doc="http://docs.angularjs.org/" ng:controller="DocsController" - manifest="app-cache.manifest"> + manifest="appcache.manifest"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title ng:bind-template="AngularJS: {{partialTitle}}">AngularJS</title> @@ -76,7 +76,7 @@ </div> <script src="syntaxhighlighter/syntaxhighlighter-combined.js"></script> - <-- jquery place holder --> + <!-- jquery place holder --> <script src="../angular.min.js" ng:autobind></script> <script src="docs-combined.js"></script> <script src="docs-keywords.js"></script> diff --git a/docs/src/writer.js b/docs/src/writer.js index 0655572d..1acf9df7 100644 --- a/docs/src/writer.js +++ b/docs/src/writer.js @@ -3,37 +3,113 @@ * for testability */ require.paths.push(__dirname); -var fs = require('fs'); +var qfs = require('q-fs'); +var Q = require('qq'); var OUTPUT_DIR = "build/docs/"; +var fs = require('fs'); -function output(docs, content, callback){ - callback(); +exports.output = function(file, content){ + console.log('writing ', file); + var fullPath = OUTPUT_DIR + file; + var dir = parent(fullPath); + return Q.when(exports.makeDir(dir), function(error) { + qfs.write(fullPath,exports.toString(content)); + }); +} + +//recursively create directory +exports.makeDir = function (path) { + var parts = path.split(/\//); + var path = "."; + //Sequentially create directories + var done = Q.defer(); + (function createPart() { + + if(!parts.length) { + done.resolve(); + } else { + path += "/" + parts.shift(); + qfs.isDirectory(path).then(function(isDir) { + if(!isDir) { + qfs.makeDirectory(path); + } + createPart(); + }); + } + })(); + return done.promise; +}; + +exports.copyTpl = function(filename) { + return exports.copy('docs/src/templates/' + filename, OUTPUT_DIR + filename); +}; + +exports.copy = function (from, to, replacementKey, replacement) { + // Have to use rb (read binary), char 'r' is infered by library. + return qfs.read(from,'b').then(function(content) { + if(replacementKey && replacement) { + content = content.toString().replace(replacementKey, replacement); + } + qfs.write(to, content); + }); +} + +exports.copyDir = function copyDir(dir) { + return qfs.listDirectoryTree('docs/' + dir).then(function(dirs) { + var done; + dirs.forEach(function(dirToMake) { + done = Q.when(done, function() { + return exports.makeDir("./build/" + dirToMake); + }); + }); + return done; + }).then(function() { + return qfs.listTree('docs/' + dir); + }).then(function(files) { + files.forEach( function(file) { + exports.copy(file,'./build/' + file); + }); + }); +}; + +exports.merge = function(srcs, to) { + return merge(srcs.map(function(src) { return 'docs/src/templates/' + src; }), OUTPUT_DIR + to); +}; + +function merge(srcs, to) { + var contents = []; + //Sequentially read file + var done; + srcs.forEach(function (src) { + done = Q.when(done, function(content) { + if(content) contents.push(content); + return qfs.read(src); + }); + }); + + // write to file + return Q.when(done, function(content) { + contents.push(content); + qfs.write(to, contents.join('\n')); + }); } +//----------------------- Synchronous Methods ---------------------------------- + function parent(file) { var parts = file.split('/'); parts.pop(); return parts.join('/'); } -exports.output = function(file, content, callback){ - console.log('write', file); - exports.makeDir(parent(OUTPUT_DIR + file), callback.waitFor(function(){ - fs.writeFile( - OUTPUT_DIR + file, - exports.toString(content), - callback); - })); -}; - -exports.toString = function toString(obj){ +exports.toString = function toString(obj) { switch (typeof obj) { case 'string': return obj; case 'object': if (obj instanceof Array) { - obj.forEach(function (value, key){ + obj.forEach(function (value, key) { obj[key] = toString(value); }); return obj.join(''); @@ -44,64 +120,5 @@ exports.toString = function toString(obj){ return obj; }; -exports.makeDir = function (path, callback) { - var parts = path.split(/\//); - path = '.'; - (function next(error){ - if (error && error.code != 'EEXIST') return callback.error(error); - if (parts.length) { - path += '/' + parts.shift(); - fs.mkdir(path, 0777, next); - } else { - callback(); - } - })(); -}; - -exports.copyTpl = function(filename, callback) { - exports.copy('docs/src/templates/' + filename, OUTPUT_DIR + filename, callback); -}; -exports.copy = function(from, to, callback, replacementKey, replacement) { - //console.log('writing', to, '...'); - fs.readFile(from, function(err, content){ - if (err) return callback.error(err); - if(replacementKey && replacement) { - content = content.toString().replace(replacementKey, replacement); - } - fs.writeFile(to, content, callback); - }); -}; - -exports.copyDir = function copyDir(dir, callback) { - exports.makeDir(OUTPUT_DIR + '/' + dir, callback.waitFor(function(){ - fs.readdir('docs/' + dir, callback.waitFor(function(err, files){ - if (err) return this.error(err); - files.forEach(function(file){ - var path = 'docs/' + dir + '/' + file; - fs.stat(path, callback.waitFor(function(err, stat) { - if (err) return this.error(err); - if (stat.isDirectory()) { - copyDir(dir + '/' + file, callback.waitFor()); - } else { - exports.copy(path, OUTPUT_DIR + '/' + dir + '/' + file, callback.waitFor()); - } - })); - }); - callback(); - })); - })); -}; - - -exports.merge = function(srcs, to, callback){ - merge(srcs.map(function(src) { return 'docs/src/templates/' + src; }), OUTPUT_DIR + to, callback); -}; - -function merge(srcs, to, callback) { - var content = []; - srcs.forEach(function (src) { - content.push(fs.readFileSync(src)); - }); - fs.writeFile(to, content.join('\n'), callback.waitFor()); -} +function noop(){}; |
