diff --git a/jsdoc.js b/jsdoc.js index 4353576b..5f8447a0 100644 --- a/jsdoc.js +++ b/jsdoc.js @@ -155,8 +155,18 @@ function main() { throw('Configuration file cannot be evaluated. '+e); } + // allow to pass arguments from configuration file + if (env.conf.opts) { + for (var opt in env.conf.opts) { + // arguments passed in command are more important + if (!(opt in env.opts)) { + env.opts[opt] = env.conf.opts[opt]; + } + } + } + if (env.opts.query) { - env.opts.query = require('query').toObject(env.opts.query); + env.opts.query = require('common/query').toObject(env.opts.query); } // which version of javascript will be supported? (rhino only) @@ -230,10 +240,10 @@ function main() { exit(0); } - env.opts.template = env.opts.template || 'default'; + env.opts.template = env.opts.template || 'templates/default'; // should define a global "publish" function - include('templates/' + env.opts.template + '/publish.js'); + include(env.opts.template + '/publish.js'); if (typeof publish === 'function') { publish( @@ -244,4 +254,4 @@ function main() { else { // TODO throw no publish warning? } } -} \ No newline at end of file +} diff --git a/rhino_modules/jsdoc/opts/parser.js b/rhino_modules/jsdoc/opts/parser.js index f82e0f50..8ffead79 100644 --- a/rhino_modules/jsdoc/opts/parser.js +++ b/rhino_modules/jsdoc/opts/parser.js @@ -12,7 +12,7 @@ var common = { var argParser = new common.args.ArgParser(), ourOptions, defaults = { - template: 'default', + template: 'templates/default', destination: './out/' }; diff --git a/rhino_modules/jsdoc/schema.js b/rhino_modules/jsdoc/schema.js index 5cbc85e2..2e3b1e0b 100644 --- a/rhino_modules/jsdoc/schema.js +++ b/rhino_modules/jsdoc/schema.js @@ -113,6 +113,11 @@ exports.jsdocSchema = { "maxItems": 1, "enum": ["private", "protected", "public"] }, + "virtual": { // is a member left to be implemented during inheritance? + "type": "boolean", + "optional": true, + "default": false + }, "attrib": { // other attributes, like "readonly" "type": "string", "optional": true diff --git a/rhino_modules/jsdoc/tag/dictionary/definitions.js b/rhino_modules/jsdoc/tag/dictionary/definitions.js index 8f6d33ca..190e6fb5 100644 --- a/rhino_modules/jsdoc/tag/dictionary/definitions.js +++ b/rhino_modules/jsdoc/tag/dictionary/definitions.js @@ -11,6 +11,15 @@ */ exports.defineTags = function(dictionary) { + dictionary.defineTag('abstract', { + mustNotHaveValue: true, + onTagged: function(doclet, tag) { + // since "abstract" is reserved word in JavaScript let's use "virtual" in code + doclet.virtual = true; + } + }) + .synonym('virtual'); + dictionary.defineTag('access', { mustHaveValue: true, onTagged: function(doclet, tag) { diff --git a/templates/default/publish.js b/templates/default/publish.js index d2a5bcd4..b40efc9d 100644 --- a/templates/default/publish.js +++ b/templates/default/publish.js @@ -108,6 +108,10 @@ function addAttribs(f) { var attribs = []; + if (f.virtual) { + attribs.push('virtual'); + } + if (f.access && f.access !== 'public') { attribs.push(f.access); } diff --git a/templates/haruki/publish.js b/templates/haruki/publish.js index 1119d2f5..694ce6a4 100644 --- a/templates/haruki/publish.js +++ b/templates/haruki/publish.js @@ -51,7 +51,8 @@ var thisNamespace = parentNode.namespaces[element.name] = { 'name': element.name, 'description': element.description || '', - 'access': element.access || '' + 'access': element.access || '', + 'virtual': !!element.virtual }; graft(thisNamespace, childNodes, element.longname, element.name); @@ -64,7 +65,8 @@ var thisMixin = parentNode.mixins[element.name] = { 'name': element.name, 'description': element.description || '', - 'access': element.access || '' + 'access': element.access || '', + 'virtual': !!element.virtual }; graft(thisMixin, childNodes, element.longname, element.name); @@ -77,6 +79,7 @@ var thisFunction = parentNode.functions[element.name] = { 'name': element.name, 'access': element.access || '', + 'virtual': !!element.virtual, 'description': element.description || '', 'parameters': [ ] }; @@ -108,6 +111,7 @@ parentNode.properties[element.name] = { 'name': element.name, 'access': element.access || '', + 'virtual': !!element.virtual, 'description': element.description || '', 'type': element.type? (element.type.length === 1? element.type[0] : element.type) : '' }; @@ -121,6 +125,7 @@ var thisEvent = parentNode.events[element.name] = { 'name': element.name, 'access': element.access || '', + 'virtual': !!element.virtual, 'description': element.description || '', 'parameters': [ ] @@ -156,6 +161,7 @@ 'description': element.classdesc || '', 'extends': element.augments || [], 'access': element.access || '', + 'virtual': !!element.virtual, 'fires': element.fires || '', 'constructor': { 'name': element.name, diff --git a/test/cases/abstracttag.js b/test/cases/abstracttag.js new file mode 100644 index 00000000..07aeb9b7 --- /dev/null +++ b/test/cases/abstracttag.js @@ -0,0 +1,17 @@ +/** @constructor */ +function Thingy() { + + /** @abstract */ + this.pez = 2; + +} + +// same as... + +/** @constructor */ +function OtherThingy() { + + /** @virtual */ + this.pez = 2; + +} \ No newline at end of file diff --git a/test/runner.js b/test/runner.js index ae341fed..b37c9cd0 100644 --- a/test/runner.js +++ b/test/runner.js @@ -103,6 +103,7 @@ testFile('test/t/cases/innerscope2.js'); testFile('test/t/cases/modules/data/mod-1.js'); testFile('test/t/cases/modules/data/mod-2.js'); +testFile('test/t/cases/abstracttag.js'); testFile('test/t/cases/accesstag.js'); testFile('test/t/cases/alias.js'); testFile('test/t/cases/alias2.js'); diff --git a/test/t/cases/abstracttag.js b/test/t/cases/abstracttag.js new file mode 100644 index 00000000..be9c66e3 --- /dev/null +++ b/test/t/cases/abstracttag.js @@ -0,0 +1,22 @@ +(function() { + var docSet = testhelpers.getDocSetFromFile('test/cases/abstracttag.js'), + type = docSet.getByLongname('Thingy')[0] + pez = docSet.getByLongname('Thingy#pez')[0]; + + test('By default symbol has virtual=undefined property.', function() { + assert.equal(!!type.virtual, false); + }); + + test('When a symbol has a @abstract tag, the doclet has a virtual=true property.', function() { + assert.equal(pez.virtual, true); + }); + + // same as... + + pez = docSet.getByLongname('OtherThingy#pez')[0]; + + test('When a symbol has a @virtual tag, the doclet has a virtual=true property.', function() { + assert.equal(pez.virtual, true); + }); + +})(); \ No newline at end of file