diff --git a/cli.js b/cli.js index 6c69efcc..74d461e5 100644 --- a/cli.js +++ b/cli.js @@ -54,6 +54,7 @@ cli.loadConfig = function() { var _ = require('underscore'); var args = require('jsdoc/opts/args'); var Config = require('jsdoc/config'); + var config; var fs = require('jsdoc/fs'); var path = require('jsdoc/path'); @@ -88,8 +89,19 @@ cli.loadConfig = function() { } try { - env.conf = new Config( stripJsonComments(fs.readFileSync(confPath, 'utf8')) ) - .get(); + switch ( path.extname(confPath) ) { + case '.js': + config = require(confPath) || {}; + break; + case '.json': + case '.EXAMPLE': + config = fs.readFileSync(confPath, 'utf8'); + break; + default: + cli.exit(1, 'Cannot use config file ' + confPath + '. Only .js and .json files ' + + 'are supported.\n' + FATAL_ERROR_MESSAGE); + } + env.conf = new Config(config).get(); } catch (e) { cli.exit(1, 'Cannot parse the config file ' + confPath + ': ' + e + '\n' + diff --git a/lib/jsdoc/config.js b/lib/jsdoc/config.js index 5a7350ff..7617b45c 100644 --- a/lib/jsdoc/config.js +++ b/lib/jsdoc/config.js @@ -10,6 +10,7 @@ 'use strict'; var stripBom = require('jsdoc/util/stripbom'); +var stripJsonComments = require('strip-json-comments'); function mergeRecurse(target, source) { Object.keys(source).forEach(function(p) { @@ -47,11 +48,23 @@ var defaults = { /** @class @classdesc Represents a JSDoc application configuration. - @param {string} [json] - The contents of config.json. + @param {(string|object)} [jsonOrObject] - The contents of config.json, or a JavaScript object + exported from a .js config file. */ -function Config(json) { - json = JSON.parse( (stripBom.strip(json) || '{}') ); - this._config = mergeRecurse(defaults, json); +function Config(jsonOrObject) { + if (typeof jsonOrObject === 'undefined') { + jsonOrObject = {}; + } + + if (typeof jsonOrObject === 'string') { + jsonOrObject = JSON.parse( (stripJsonComments(stripBom.strip(jsonOrObject)) || '{}') ); + } + + if (typeof jsonOrObject !== 'object') { + jsonOrObject = {}; + } + + this._config = mergeRecurse(defaults, jsonOrObject); } module.exports = Config; diff --git a/test/specs/jsdoc/config.js b/test/specs/jsdoc/config.js index 0753e9cf..d8eed444 100644 --- a/test/specs/jsdoc/config.js +++ b/test/specs/jsdoc/config.js @@ -34,6 +34,13 @@ describe('jsdoc/config', function() { expect( Array.isArray(config.plugins) ).toBe(true); expect(config.plugins.length).toBe(0); }); + + it('should be possible to construct a Config with an empty JavaScript object', function() { + var config = new Config({}).get(); + + expect( Array.isArray(config.plugins) ).toBe(true); + expect(config.plugins.length).toBe(0); + }); }); describe('constructor with leading BOM', function() { @@ -46,6 +53,16 @@ describe('jsdoc/config', function() { }); }); + describe('constructor with comments', function() { + it('should be possible to construct a Config with JSON that includes comments', function() { + function getConfig() { + return new Config('{\n// comment\n}').get(); + } + + expect(getConfig).not.toThrow(); + }); + }); + describe('constructor with plugins value', function() { it('should be possible to construct a Config with JSON of an object literal that has a plugin value', function() { var config = new Config('{"plugins":[42]}').get(); @@ -54,6 +71,14 @@ describe('jsdoc/config', function() { expect(config.plugins.length).toBe(1); expect(config.plugins[0]).toBe(42); }); + + it('should be possible to construct a Config with a JavaScript object that has a plugin value', function() { + var config = new Config({'plugins': [42]}).get(); + + expect( Array.isArray(config.plugins) ).toBe(true); + expect(config.plugins.length).toBe(1); + expect(config.plugins[0]).toBe(42); + }); }); describe('constructor with source value', function() { @@ -62,5 +87,11 @@ describe('jsdoc/config', function() { expect(config.source.includePattern).toBe('hello'); }); + + it('should be possible to construct a Config with a JavaScript object that has a source value', function() { + var config = new Config({'source': {'includePattern': 'hello'}}).get(); + + expect(config.source.includePattern).toBe('hello'); + }); }); }); diff --git a/test/specs/jsdoc/opts/args.js b/test/specs/jsdoc/opts/args.js index 7a8ebe64..b848151b 100644 --- a/test/specs/jsdoc/opts/args.js +++ b/test/specs/jsdoc/opts/args.js @@ -39,20 +39,34 @@ describe('jsdoc/opts/args', function() { expect(r.template).toBe('mytemplate'); }); - it('should accept a "-c" option and return an object with a "configure" property', function() { + it('should accept a "-c" option with a JSON file and return an object with a "configure" property', function() { args.parse(['-c', 'myconf.json']); var r = args.get(); expect(r.configure).toBe('myconf.json'); }); - it('should accept a "--configure" option and return an object with a "configure" property', function() { + it('should accept a "-c" option with a JS file and return an object with a "configure" property', function() { + args.parse(['-c', 'myconf.js']); + var r = args.get(); + + expect(r.configure).toBe('myconf.js'); + }); + + it('should accept a "--configure" option with a JSON file and return an object with a "configure" property', function() { args.parse(['--configure', 'myconf.json']); var r = args.get(); expect(r.configure).toBe('myconf.json'); }); + it('should accept a "--configure" option with a JS file and return an object with a "configure" property', function() { + args.parse(['--configure', 'myconf.js']); + var r = args.get(); + + expect(r.configure).toBe('myconf.js'); + }); + it('should accept an "-e" option and return an object with a "encoding" property', function() { args.parse(['-e', 'ascii']); var r = args.get();