From d73570defcdca77618bf8fb73c420ef7110bd0e4 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Wed, 26 Dec 2012 19:03:05 -0800 Subject: [PATCH] make fs module consistent with Node.js (#211) --- jsdoc.js | 11 +++-- lib/jsdoc/fs.js | 20 +++++++++ lib/jsdoc/opts/args.js | 2 +- lib/jsdoc/readme.js | 4 +- lib/jsdoc/src/parser.js | 15 +++---- lib/jsdoc/src/scanner.js | 2 +- lib/jsdoc/template.js | 4 +- lib/jsdoc/tutorial/resolver.js | 5 ++- nodejs/jsdoc/fs.js | 17 ++++++++ nodejs/jsdoc/util/include.js | 2 +- plugins/partial.js | 5 ++- rhino/fs.js | 58 ++++++++++++++------------ templates/default/publish.js | 6 +-- templates/prettyPrintSource/publish.js | 4 +- test/jasmine-jsdoc.js | 4 +- test/runner.js | 2 +- test/spec-collection.js | 2 +- test/specs/jsdoc/src/parser.js | 8 ++-- test/specs/jshint/jshint-clean.js | 4 +- 19 files changed, 112 insertions(+), 63 deletions(-) create mode 100644 lib/jsdoc/fs.js create mode 100644 nodejs/jsdoc/fs.js diff --git a/jsdoc.js b/jsdoc.js index 3a14f36e..472931a2 100644 --- a/jsdoc.js +++ b/jsdoc.js @@ -97,7 +97,7 @@ function main() { var borrow = require('jsdoc/borrow'); var Config = require('jsdoc/config'); var Filter = require('jsdoc/src/filter').Filter; - var fs = require('fs'); + var fs = require('jsdoc/fs'); var handlers = require('jsdoc/src/handlers'); var include = require('jsdoc/util/include'); var Package = require('jsdoc/package').Package; @@ -179,13 +179,16 @@ function main() { } defaultOpts = { - destination: './out/' + destination: './out/', + encoding: 'utf8' }; env.opts = args.parse(env.args); try { - env.conf = new Config( fs.readFileSync( env.opts.configure || path.join(__dirname, 'conf.json') ) ).get(); + env.conf = new Config( + fs.readFileSync( env.opts.configure || path.join(__dirname, 'conf.json'), 'utf8' ) + ).get(); } catch (e) { try { @@ -221,7 +224,7 @@ function main() { // any source file named package.json or README.md is treated special for (i = 0, l = env.opts._.length; i < l; i++ ) { if (/\bpackage\.json$/i.test(env.opts._[i])) { - packageJson = require('fs').readFileSync( env.opts._[i] ); + packageJson = fs.readFileSync( env.opts._[i], 'utf8' ); env.opts._.splice(i--, 1); } diff --git a/lib/jsdoc/fs.js b/lib/jsdoc/fs.js new file mode 100644 index 00000000..7d26ad72 --- /dev/null +++ b/lib/jsdoc/fs.js @@ -0,0 +1,20 @@ +/** + * Extended version of the standard `fs` module. + * @module jsdoc/fs + */ + +var fs = require('fs'); +var vm = require('jsdoc/util/vm'); + +var hasOwnProp = Object.prototype.hasOwnProperty; + +// add the VM-specific implementations of the extra methods +// TODO: document extra methods here +var extras = vm.getModule('fs'); +for (var func in extras) { + if ( hasOwnProp.call(extras, func) ) { + fs[func] = extras[func]; + } +} + +module.exports = fs; diff --git a/lib/jsdoc/opts/args.js b/lib/jsdoc/opts/args.js index a1bce509..6683c67f 100644 --- a/lib/jsdoc/opts/args.js +++ b/lib/jsdoc/opts/args.js @@ -69,7 +69,7 @@ function parseQuery(str) { argParser.addOption('t', 'template', true, 'The name of the template to use. Default: the "default" template'); argParser.addOption('c', 'configure', true, 'The path to the configuration file. Default: jsdoc __dirname + /conf.json'); -argParser.addOption('e', 'encoding', true, 'Assume this encoding when reading all source files. Default: utf-8'); +argParser.addOption('e', 'encoding', true, 'Assume this encoding when reading all source files. Default: utf8'); argParser.addOption('T', 'test', false, 'Run all tests and quit.'); argParser.addOption('d', 'destination', true, 'The path to the output folder. Use "console" to dump data to the console. Default: ./out/'); argParser.addOption('p', 'private', false, 'Display symbols marked with the @private tag. Default: false'); diff --git a/lib/jsdoc/readme.js b/lib/jsdoc/readme.js index e04ed2cb..0e3ca21e 100644 --- a/lib/jsdoc/readme.js +++ b/lib/jsdoc/readme.js @@ -7,7 +7,7 @@ * @author Ben Blank */ -var fs = require('fs'), +var fs = require('jsdoc/fs'), markdown = require('jsdoc/util/markdown'); /** @@ -16,7 +16,7 @@ var fs = require('fs'), * @param {string} path - The filepath to the README. */ function ReadMe(path) { - var content = fs.readFileSync(path), + var content = fs.readFileSync(path, env.opts.encoding), parse = markdown.getParser(); this.html = parse(content); diff --git a/lib/jsdoc/src/parser.js b/lib/jsdoc/src/parser.js index d1fa7462..875b4cf1 100644 --- a/lib/jsdoc/src/parser.js +++ b/lib/jsdoc/src/parser.js @@ -1,4 +1,4 @@ -/*global Packages: true */ +/*global env: true, Packages: true */ /** * @module jsdoc/src/parser * @requires fs @@ -44,15 +44,16 @@ exports.Parser.prototype = Object.create( require('events').EventEmitter.prototy * var docs = jsdocParser.parse(myFiles); */ exports.Parser.prototype.parse = function(sourceFiles, encoding) { + encoding = encoding || env.conf.encoding || 'utf8'; + const SCHEMA = 'javascript:'; - var sourceCode = '', - filename = '', - i, - leni; + + var filename = ''; + var sourceCode = ''; if (typeof sourceFiles === 'string') { sourceFiles = [sourceFiles]; } - for (i = 0, leni = sourceFiles.length; i < leni; i++) { + for (var i = 0, leni = sourceFiles.length; i < leni; i++) { if (sourceFiles[i].indexOf(SCHEMA) === 0) { sourceCode = sourceFiles[i].substr(SCHEMA.length); filename = '[[string' + i + ']]'; @@ -60,7 +61,7 @@ exports.Parser.prototype.parse = function(sourceFiles, encoding) { else { filename = sourceFiles[i]; try { - sourceCode = require('fs').readFileSync(filename, encoding); + sourceCode = require('jsdoc/fs').readFileSync(filename, encoding); } catch(e) { console.log('FILE READ ERROR: in module:jsdoc/parser.parseFiles: "' + filename + '" ' + e); diff --git a/lib/jsdoc/src/scanner.js b/lib/jsdoc/src/scanner.js index fd2134ba..4496ce27 100644 --- a/lib/jsdoc/src/scanner.js +++ b/lib/jsdoc/src/scanner.js @@ -7,7 +7,7 @@ */ -var fs = require('fs'); +var fs = require('jsdoc/fs'); /** @constructor diff --git a/lib/jsdoc/template.js b/lib/jsdoc/template.js index 9311606c..3fb2e762 100644 --- a/lib/jsdoc/template.js +++ b/lib/jsdoc/template.js @@ -6,7 +6,7 @@ */ var _ = require('underscore'), - fs = require('fs'), + fs = require('jsdoc/fs'), path = require('path'); @@ -38,7 +38,7 @@ exports.Template = function(path) { */ exports.Template.prototype.load = function(file) { var _path = path.join(this.path, file); - return _.template(fs.readFileSync(_path), null, this.settings); + return _.template(fs.readFileSync(_path, 'utf8'), null, this.settings); }; diff --git a/lib/jsdoc/tutorial/resolver.js b/lib/jsdoc/tutorial/resolver.js index fd1819f1..1cb7884d 100644 --- a/lib/jsdoc/tutorial/resolver.js +++ b/lib/jsdoc/tutorial/resolver.js @@ -1,3 +1,4 @@ +/*global env: true */ /** @overview @author Rafał Wrzeszcz @@ -9,7 +10,7 @@ */ var tutorial = require('jsdoc/tutorial'), - fs = require('fs'), + fs = require('jsdoc/fs'), path = require('path'), hasOwnProp = Object.prototype.hasOwnProperty, conf = {}, @@ -57,7 +58,7 @@ exports.load = function(_path) { // any filetype that can apply to tutorials if (match) { name = path.basename(match[1]); - content = fs.readFileSync(file); + content = fs.readFileSync(file, env.opts.encoding); switch (match[2].toLowerCase()) { // HTML type diff --git a/nodejs/jsdoc/fs.js b/nodejs/jsdoc/fs.js new file mode 100644 index 00000000..7115ff0c --- /dev/null +++ b/nodejs/jsdoc/fs.js @@ -0,0 +1,17 @@ +var e = ' is not implemented for Node.js!'; + +exports.ls = function() { + throw new Error('fs.ls' + e); +}; + +exports.toDir = function() { + throw new Error('fs.toDir' + e); +}; + +exports.mkPath = function() { + throw new Error('fs.mkpath' + e); +}; + +exports.copyFileSync = function() { + throw new Error('fs.copyFileSync' + e); +}; diff --git a/nodejs/jsdoc/util/include.js b/nodejs/jsdoc/util/include.js index cee0369c..c5c0d4de 100644 --- a/nodejs/jsdoc/util/include.js +++ b/nodejs/jsdoc/util/include.js @@ -1,6 +1,6 @@ // TODO: not tested module.exports = function(filepath) { - var fs = require('fs'); + var fs = require('jsdoc/fs'); var vm = require('vm'); var script = fs.readFileSync(filepath, 'utf8'); diff --git a/plugins/partial.js b/plugins/partial.js index abbd7b09..61d20d26 100644 --- a/plugins/partial.js +++ b/plugins/partial.js @@ -1,10 +1,11 @@ +/*global env: true */ /** @overview Adds support for reusable partial jsdoc files. @module plugins/partial @author Ludo Antonov */ -var fs = require('fs'); +var fs = require('jsdoc/fs'); var path = require('path'); exports.handlers = { @@ -22,7 +23,7 @@ exports.handlers = { var pathArg = $.match(/\".*\"/)[0].replace(/"/g,''); var fullPath = path.join(e.filename , '..', pathArg); - var partialData = fs.readFileSync(fullPath); + var partialData = fs.readFileSync(fullPath, env.opts.encoding); return partialData; }); diff --git a/rhino/fs.js b/rhino/fs.js index 571c3cf2..ee809598 100644 --- a/rhino/fs.js +++ b/rhino/fs.js @@ -1,26 +1,34 @@ /*global Packages: true */ + +/** + * Partial Rhino shim for Node.js' `fs` module. + * @see http://nodejs.org/api/fs.html + */ + var path = require('path'); -// TODO: Should fail if encoding isn't passed in; Node.js thinks this means you want a buffer -// TODO: callers shouldn't use 'utf-8'--the method should map 'utf8' to 'utf-8' +function checkEncoding(enc, name) { + // we require the `encoding` parameter for Node.js compatibility; on Node.js, if you omit the + // encoding, you get a stream instead of a string + if (!enc || typeof enc === 'function') { + throw new Error(name + ' requires an encoding on Rhino!'); + } + + // Node.js wants 'utf8', but Java wants 'utf-8' + if (enc === 'utf8') { + enc = 'utf-8'; + } + + return enc; +} + exports.readFileSync = function(filename, encoding) { - encoding = encoding || 'utf-8'; + encoding = checkEncoding(encoding, 'fs.readFileSync'); return readFile(filename, encoding); }; exports.readFile = function(filename, encoding, callback) { - if (!encoding || typeof encoding === 'function') { - process.nextTick(function() { - callback('fs.readFile requires an encoding on Rhino!'); - }); - } - - // Node.js wants 'utf8', but Java wants 'utf-8' - if (encoding === 'utf8') { - encoding = 'utf-8'; - } - try { var data = exports.readFileSync(filename, encoding); process.nextTick(function() { @@ -50,8 +58,8 @@ var statSync = exports.statSync = function(_path) { }; var readdirSync = exports.readdirSync = function(_path) { - var dir, - files; + var dir; + var files; dir = new java.io.File(_path); if (!dir.directory) { @@ -60,7 +68,7 @@ var readdirSync = exports.readdirSync = function(_path) { files = dir.list(); - //Convert files to Javascript strings so they play nice with node modules + // Convert files to Javascript strings so they play nice with node modules files = files.map(function(fileName) { return String(fileName); }); @@ -68,8 +76,7 @@ var readdirSync = exports.readdirSync = function(_path) { return files; }; -// TODO: not part of node's "fs" module -// for node, could use wrench.readdirSyncRecursive(), although it doesn't take a 'recurse' param +// JSDoc extension to `fs` module var ls = exports.ls = function(dir, recurse, _allFiles, _path) { var files, file; @@ -112,7 +119,7 @@ var ls = exports.ls = function(dir, recurse, _allFiles, _path) { return _allFiles; }; -// TODO: not part of node's "fs" module +// JSDoc extension to `fs` module var toDir = exports.toDir = function(_path) { var f = new java.io.File(_path); @@ -123,20 +130,19 @@ var toDir = exports.toDir = function(_path) { } }; -var mkdirSync = exports.mkdirSync = function(/**string*/ _path) { +var mkdirSync = exports.mkdirSync = function(_path) { var dir_path = toDir(_path); (new java.io.File(dir_path)).mkdir(); }; -// TODO: not part of node's "fs" module -// for node, could use: https://github.com/substack/node-mkdirp +// JSDoc extension to `fs` module exports.mkPath = function(/**Array*/ _path) { - if (_path.constructor == Array) { _path = _path.join(""); } + if (_path.constructor == Array) { _path = _path.join(''); } (new java.io.File(_path)).mkdirs(); }; -// TODO: not part of node's "fs" module +// JSDoc extension to `fs` module exports.copyFileSync = function(inFile, outDir, fileName) { if (fileName == null){fileName = path.basename(inFile);} @@ -156,7 +162,7 @@ exports.copyFileSync = function(inFile, outDir, fileName) { }; exports.writeFileSync = function(filename, data, encoding) { - encoding = encoding || 'utf-8'; + encoding = checkEncoding(encoding); var out = new Packages.java.io.PrintWriter( new Packages.java.io.OutputStreamWriter( diff --git a/templates/default/publish.js b/templates/default/publish.js index 06c54f81..71b7ceab 100644 --- a/templates/default/publish.js +++ b/templates/default/publish.js @@ -1,6 +1,6 @@ /*global env: true */ var template = require('jsdoc/template'), - fs = require('fs'), + fs = require('jsdoc/fs'), path = require('path'), taffy = require('taffydb').taffy, helper = require('jsdoc/util/templateHelper'), @@ -69,7 +69,7 @@ function generate(title, docs, filename) { html = helper.resolveLinks(html); // turn {@link foo} into foo - fs.writeFileSync(outpath, html); + fs.writeFileSync(outpath, html, 'utf8'); } /** @@ -379,7 +379,7 @@ exports.publish = function(taffyData, opts, tutorials) { // yes, you can use {@link} in tutorials too! html = helper.resolveLinks(html); // turn {@link foo} into foo - fs.writeFileSync(tutorialPath, html); + fs.writeFileSync(tutorialPath, html, 'utf8'); } // tutorials can have only one parent so there is no risk for loops diff --git a/templates/prettyPrintSource/publish.js b/templates/prettyPrintSource/publish.js index 2caff43e..eafcf400 100644 --- a/templates/prettyPrintSource/publish.js +++ b/templates/prettyPrintSource/publish.js @@ -13,7 +13,7 @@ */ exports.publish = function(outputDirectory, outputFileName, sourceCode) { - var fs = require('fs'); + var fs = require('jsdoc/fs'); var path = require('path'); var helper = require('jsdoc/util/templateHelper'); var template = require('jsdoc/template'); @@ -40,7 +40,7 @@ exports.publish = function(outputDirectory, outputFileName, sourceCode) { console.log('outputContent : ' + outputContent); */ fs.mkPath(outputDirectory); - fs.writeFileSync(outputFile, outputContent); + fs.writeFileSync(outputFile, outputContent, 'utf8'); // copy static files to outdir var fromDir = path.join(templatePath, '/static'); diff --git a/test/jasmine-jsdoc.js b/test/jasmine-jsdoc.js index 8d36d0cc..b3a876a7 100644 --- a/test/jasmine-jsdoc.js +++ b/test/jasmine-jsdoc.js @@ -1,6 +1,6 @@ /*global env: true, expect: true, runs: true, waits: true */ /*jshint evil: true */ -var fs = require('fs'); +var fs = require('jsdoc/fs'); var path = require('path'); var util = require('util'); @@ -12,7 +12,7 @@ var jasmineAll = myGlobal.jasmineAll = require('test/lib/jasmine'); var jasmine = myGlobal.jasmine = jasmineAll.jasmine; // due to scoping issues, requiring this file doesn't work -eval( fs.readFileSync(__dirname + '/test/async-callback.js'), 'utf8' ); +eval( fs.readFileSync(__dirname + '/test/async-callback.js', 'utf8') ); var jasmineNode = require('test/reporter').jasmineNode; diff --git a/test/runner.js b/test/runner.js index d3d14290..b9531da7 100644 --- a/test/runner.js +++ b/test/runner.js @@ -6,7 +6,7 @@ * 3. Get the list of directories to run tests from * 4. Run Jasmine on each directory */ -var fs = require('fs'); +var fs = require('jsdoc/fs'); var jasmine = require('test/jasmine-jsdoc'); var path = require('path'); diff --git a/test/spec-collection.js b/test/spec-collection.js index 12756b56..24e23a06 100644 --- a/test/spec-collection.js +++ b/test/spec-collection.js @@ -1,7 +1,7 @@ /*global env: true */ var wrench = require('wrench'); var path = require('path'); -var fs = require('fs'); +var fs = require('jsdoc/fs'); var specs = []; var createSpecObj = function(_path, root) { diff --git a/test/specs/jsdoc/src/parser.js b/test/specs/jsdoc/src/parser.js index 4e24e08b..79f0b9d6 100644 --- a/test/specs/jsdoc/src/parser.js +++ b/test/specs/jsdoc/src/parser.js @@ -42,10 +42,10 @@ describe("jsdoc/src/parser", function() { }); it("should be able to parse its own source file", function() { - var fs = require("fs"), - path = require("path"), - parserSrc = "javascript:" + fs.readFileSync( path.join(__dirname, - "lib", "jsdoc", "src", "parser.js") ), + var fs = require('jsdoc/fs'), + path = require('path'), + parserSrc = 'javascript:' + fs.readFileSync( path.join(__dirname, + 'lib', 'jsdoc', 'src', 'parser.js'), 'utf8' ), parse = function() { parser.parse(parserSrc); }; diff --git a/test/specs/jshint/jshint-clean.js b/test/specs/jshint/jshint-clean.js index 2bc9072a..e1a3492c 100644 --- a/test/specs/jshint/jshint-clean.js +++ b/test/specs/jshint/jshint-clean.js @@ -1,9 +1,9 @@ /*global app: true, beforeEach: true, describe: true, env: true, expect: true, it: true */ var async = require('async'), - fs = require('fs'), + fs = require('jsdoc/fs'), path = require('path'); -var config = JSON.parse( fs.readFileSync( path.join(__dirname, '.jshintrc'), 'utf-8' ) ); +var config = JSON.parse( fs.readFileSync( path.join(__dirname, '.jshintrc'), 'utf8' ) ); function jsHintCheck(filename, callback) { var JSHINT = require('jshint').JSHINT;