diff --git a/main.js b/main.js index e4c994ce..82343694 100644 --- a/main.js +++ b/main.js @@ -69,6 +69,6 @@ print('Validation: ' + validation.toSource()); } - print( jsdoc.parser.result.asString(opts.destination) ); + print( jsdoc.parser.result.toString(opts.destination) ); })(); //// \ No newline at end of file diff --git a/modules/common/fs.js b/modules/common/fs.js index 236e8100..374803eb 100644 --- a/modules/common/fs.js +++ b/modules/common/fs.js @@ -13,7 +13,7 @@ var options = options || {}, encoding = encoding || defaultEncoding, input; -print('encoding is '+encoding); + input = new java.util.Scanner( new File(path), encoding diff --git a/modules/jsdoc/doclet.js b/modules/jsdoc/doclet.js index 8449e71d..4673585d 100644 --- a/modules/jsdoc/doclet.js +++ b/modules/jsdoc/doclet.js @@ -34,11 +34,9 @@ postprocess(doclet); name.resolve(doclet); - - doclet.meta = { - line: node.getLineno(), - file: sourceName - }; + + doclet.meta = { file: sourceName }; + if (node) { doclet.meta.line = node.getLineno(); } return doclet } @@ -52,7 +50,7 @@ /** An array of Objects representing tags. @type Array. - @property Doclet#tags + @member Doclet#tags */ this.tags = tags; } @@ -109,7 +107,7 @@ } // safe to export to JSON - var exportTags = ['name', 'path', 'kind', 'desc', 'type', 'param', 'returns', 'exports', 'requires', 'memberof', 'access', 'attribute']; + var exportTags = ['name', 'path', 'denom', 'desc', 'type', 'param', 'returns', 'exports', 'requires', 'memberof', 'access', 'attribute']; /** Get a JSON-compatible object representing this Doclet. @@ -206,9 +204,9 @@ } // other tags that can provide the memberof - var memberofs = {methodof: 'method', propertyof: 'property', eventof: 'event'}; + var memberofs = {methodof: 'method', eventof: 'event'}; // other tags that can provide the symbol name - var nameables = ['constructor', 'module', 'event', 'namespace', 'method', 'property', 'function', 'variable', 'enum']; + var nameables = ['constructor', 'const', 'module', 'event', 'namespace', 'method', 'member', 'function', 'variable', 'enum']; /** Expand some shortcut tags. Modifies the tags argument in-place. @@ -220,7 +218,7 @@ function preprocess(tags) { var name = '', taggedName = '', - kind = '', + denom = '', taggedKind = '', memberof = '', taggedMemberof = ''; @@ -244,9 +242,9 @@ if (name && name !== tags[i].text) { tooManyNames(name, tags[i].text); } taggedName = name = tags[i].text; } - else if (tags[i].name === 'kind') { - if (kind && kind !== tags[i].text) { tooManyKinds(kind, tags[i].text); } - taggedKind = kind = tags[i].text; + else if (tags[i].name === 'denom') { + if (denom && denom !== tags[i].text) { tooManyKinds(denom, tags[i].text); } + taggedKind = denom = tags[i].text; } else if (tags[i].name === 'memberof') { if (memberof) { tooManyTags('memberof'); } @@ -259,12 +257,17 @@ name = tags[i].text; } + if (tags[i].pdesc) { + tags[tags.length] = tag.fromTagText('desc ' + tags[i].pdesc); + } + if (tags[i].type) { tags[tags.length] = tag.fromTagText('type ' + tags[i].type); } - if (kind && kind !== tags[i].name) { tooManyKinds(kind, tags[i].name); } - kind = tags[i].name; + if (denom && denom !== tags[i].name) { tooManyKinds(denom, tags[i].name); } + denom = tags[i].name; + if (denom === 'const') { denom = 'member'; } // an exception to the namebale rule } if ( memberofs.hasOwnProperty(tags[i].name) ) { @@ -273,8 +276,8 @@ memberof = tags[i].text; } - if (kind && kind !== memberofs[tags[i].name]) { tooManyKinds(kind, memberofs[tags[i].name]); } - kind = memberofs[tags[i].name]; + if (denom && denom !== memberofs[tags[i].name]) { tooManyKinds(denom, memberofs[tags[i].name]); } + denom = memberofs[tags[i].name]; } } @@ -282,8 +285,8 @@ tags[tags.length] = tag.fromTagText('name ' + name); } - if (kind && !taggedKind) { - tags[tags.length] = tag.fromTagText('kind ' + kind); + if (denom && !taggedKind) { + tags[tags.length] = tag.fromTagText('denom ' + denom); } if (memberof && !taggedMemberof) { @@ -293,7 +296,7 @@ function postprocess(doclet) { if ( doclet.hasTag('class') && !doclet.hasTag('constructor') ) { - doclet.tags[doclet.tags.length] = tag.fromTagText('kind constructor'); + doclet.tags[doclet.tags.length] = tag.fromTagText('denom constructor'); } if ( doclet.hasTag('enum')) { @@ -307,8 +310,8 @@ } if ( doclet.hasTag('const')) { - if (!doclet.hasTag('kind')) { - doclet.tags[doclet.tags.length] = tag.fromTagText('kind property'); + if (!doclet.hasTag('denom')) { + doclet.tags[doclet.tags.length] = tag.fromTagText('denom member'); } if (!doclet.hasTag('readonly') && !doclet.hasTag('const')) { diff --git a/modules/jsdoc/docset.js b/modules/jsdoc/docset.js index 4241007a..5dd7bc02 100644 --- a/modules/jsdoc/docset.js +++ b/modules/jsdoc/docset.js @@ -3,7 +3,7 @@ xml = require('goessner/json2xml'), doclets = exports.doclets = []; - doclets.getDocsByName = function getDocsByName(docName) { + doclets.getDocsByPath = function(docName) { var foundDocs = [], i = doclets.length; @@ -16,7 +16,7 @@ return foundDocs; } - doclets.toObject = function toObject() { + doclets.toObject = function() { var docsObjects = [], i = doclets.length; @@ -27,7 +27,7 @@ return { doc: docsObjects }; } - doclets.asString = function asString(destinationName) { + doclets.toString = function(destinationName) { if ( /xml$/i.test(destinationName) ) { return doclets.toXML(); } @@ -36,11 +36,11 @@ } } - doclets.toJSON = function toJSON() { + doclets.toJSON = function() { return dumper.jsDump.parse( doclets.toObject() ); } - doclets.toXML = function toXML() { + doclets.toXML = function() { var o = doclets.toObject(); // make `id` an attribute of the doc tag diff --git a/modules/jsdoc/name.js b/modules/jsdoc/name.js index 82582603..4b8753db 100644 --- a/modules/jsdoc/name.js +++ b/modules/jsdoc/name.js @@ -22,7 +22,7 @@ @param {Doclet} doclet */ exports.resolve = function(doclet) { - var kind = doclet.tagText('kind'), + var denom = doclet.tagText('denom'), name = doclet.tagText('name'), memberof = doclet.tagText('memberof'), path, @@ -40,9 +40,9 @@ name = name.replace(/\.prototype\.?/g, '#'); // if name doesn't already have a doc-namespace and needs one - if (!/^[a-z_$-]+:\S+/i.test(name) && supportedNamespaces.indexOf(kind) > -1) { + if (!/^[a-z_$-]+:\S+/i.test(name) && supportedNamespaces.indexOf(denom) > -1) { // add doc-namespace to path - name = kind + '(' + name + ')'; + name = denom + ':' + name; } path = shortname = name; @@ -122,7 +122,7 @@ if (memberof || !enclosing) { // `this` refers to nearest instance in the name path - if (enclosingDoc && enclosingDoc.tagText('kind') !== 'constructor') { + if (enclosingDoc && enclosingDoc.tagText('denom') !== 'constructor') { var parts = memberof.split('#'); parts.pop(); memberof = parts.join('#'); diff --git a/modules/jsdoc/parser.js b/modules/jsdoc/parser.js index 0e900f30..8fff30bd 100644 --- a/modules/jsdoc/parser.js +++ b/modules/jsdoc/parser.js @@ -20,10 +20,10 @@ commentSrc = '' + comment.toSource(); if (commentSrc) { - thisDoclet = doclet.makeDoclet(commentSrc, node, currentSourceName); + thisDoclet = doclet.makeDoclet(commentSrc, comment, currentSourceName); if ( thisDoclet.hasTag('name') ) { doclets.push(thisDoclet); - if (thisDoclet.tagText('kind') === 'module') { + if (thisDoclet.tagText('denom') === 'module') { name.setCurrentModule( thisDoclet.tagText('path') ); } } @@ -64,7 +64,7 @@ thisDoclet = doclet.makeDoclet(commentSrc, node, currentSourceName); thisDocletName = thisDoclet.tagText('name'); - nodeKind = thisDoclet.tagText('kind'); + nodeKind = thisDoclet.tagText('denom'); if (!thisDocletName) { nodeName = name.resolveThis( nodeName, node, thisDoclet ); @@ -89,7 +89,7 @@ if (commentSrc) { thisDoclet = doclet.makeDoclet('' + commentSrc, node, currentSourceName); thisDocletName = thisDoclet.tagText('path'); - nodeKind = thisDoclet.tagText('kind'); + nodeKind = thisDoclet.tagText('denom'); if ( !thisDocletName ) { thisDocletName = n.target.string; @@ -130,6 +130,12 @@ fs = require('common/fs'), source = ''; + if (arguments.length === 0) { + throw 'module:jsdoc/parser.parseFiles requires argument sourceFiles(none provided).'; + } + + if (typeof sourceFiles[0] === 'string') { sourceFiles = [sourceFiles]; } + for (i = 0, leni = sourceFiles.length; i < leni; i++) { try { source = fs.read(sourceFiles[i], encoding); diff --git a/modules/jsdoc/schema.js b/modules/jsdoc/schema.js index 85b2fa67..2cad82ea 100644 --- a/modules/jsdoc/schema.js +++ b/modules/jsdoc/schema.js @@ -23,9 +23,9 @@ jsdoc.schema.jsdocSchema = { "type": "string", "optional": true }, - "kind": { + "denom": { "type": "string", - "enum": ["constructor", "module", "event", "namespace", "method", "property", "function", "variable", "enum"] + "enum": ["constructor", "module", "event", "namespace", "method", "member", "function", "variable", "enum"] }, "meta": { "file": { diff --git a/modules/jsdoc/tag.js b/modules/jsdoc/tag.js index e30a22f2..be5a9e81 100644 --- a/modules/jsdoc/tag.js +++ b/modules/jsdoc/tag.js @@ -36,6 +36,7 @@ return new Tag(tagText); } + var longTags = ['param', 'constructor', 'const', 'module', 'event', 'namespace', 'method', 'member', 'function', 'variable', 'enum']; /** @private @constructor Tag @@ -68,7 +69,7 @@ this.text = trim(typeText.text); - if (this.name === 'param') { // is a parameter w/ long format + if (longTags.indexOf(this.name) > -1) { // is a tag that uses the long format var [pname, pdesc] = splitPname(this.text); this.pname = pname; this.pdesc = pdesc; diff --git a/modules/jsdoc/test.js b/modules/jsdoc/test.js index 08187235..57eced7e 100644 --- a/modules/jsdoc/test.js +++ b/modules/jsdoc/test.js @@ -12,23 +12,36 @@ exports.runAll = function() { load(BASEDIR + 'lib/jsunity.js'); + + testSuites = []; load(BASEDIR + 'tests/opts.js'); + load(BASEDIR + 'tests/tag_namespace.js'); + load(BASEDIR + 'tests/tag_constructor.js'); + load(BASEDIR + 'tests/tag_const.js'); + load(BASEDIR + 'tests/tag_enum.js'); jsUnity.attachAssertions(); jsUnity.log = function (s) { print(s); }; - var results = jsUnity.run(testSuite); + var results = jsUnity.run.apply(jsUnity, testSuites); summarize(results); } function summarize(results) { - var colorStart = '\033[1;37;42m', // green + var colorStart, colorEnd = '\033[m'; - print('--------'); - if (results.failed !== 0) { - colorStart = '\033[1;37;41m'; // red + print('------------------'); + print('Total: ' + results.total + ' tests'); + + if (results.failed === 0) { + colorStart = '\033[1;37;42m', // green + print(colorStart + 'ALL PASS' + colorEnd); } - print(colorStart + 'Total: ' + results.total + ', Pass: ' + results.passed + ', Fail: ' + results.failed + colorEnd); + else { + colorStart = '\033[1;37;41m'; // red + print(colorStart + results.failed + 'FAILED' + colorEnd); + } + print(''); } })(); \ No newline at end of file diff --git a/tests/opts.js b/tests/opts.js index 0e9c7a79..964e156b 100644 --- a/tests/opts.js +++ b/tests/opts.js @@ -1,7 +1,7 @@ (function() { var jsdoc = { opts: require('jsdoc/opts') }; - testSuite = { + var testSuite = { suiteName: 'jsdoc/opts', setUp: function() { @@ -30,4 +30,6 @@ assertEqual(opts.destination, 'mydestination.json'); } }; + + testSuites.push(testSuite); })(); \ No newline at end of file diff --git a/tests/tag_const.js b/tests/tag_const.js new file mode 100644 index 00000000..0011a21c --- /dev/null +++ b/tests/tag_const.js @@ -0,0 +1,80 @@ +(function() { + var jsdoc = { parser: require('jsdoc/parser') }; + + jsdoc.parser.parseFiles(BASEDIR + 'tests/tag_const.js'); + var docset = jsdoc.parser.result; + + var testSuite = { + suiteName: 'tag_const', + + setUp: function() { + }, + + tearDown: function() { + }, + + testConstDocs: function() { + assertEqual(typeof docset, 'object'); + }, + + testConstCompactTag: function() { + var doc = docset.getDocsByPath('pi'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + + doc = doc[0]; + + assertEqual(typeof doc, 'object', 'The found doclet is an object.'); + assertEqual(doc.tagText('path'), 'pi', 'The found doclet has the expected path.'); + assertEqual(doc.tagText('type'), 'number', 'The found doclet has the expected type.'); + assertEqual(doc.tagText('desc'), "The ratio of any circle's circumference to its diameter.", 'The found doclet has the expected desc.'); + }, + + testConstCompactVerbose: function() { + var doc = docset.getDocsByPath('e'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + + doc = doc[0]; + + assertEqual(typeof doc, 'object', 'The found doclet is an object.'); + assertEqual(doc.tagText('path'), 'e', 'The found doclet has the expected path.'); + assertEqual(doc.tagText('type'), 'number', 'The found doclet has the expected type.'); + assertEqual(doc.tagText('desc'), "Euler's number.", 'The found doclet has the expected desc.'); + }, + + testConstCodename: function() { + var doc = docset.getDocsByPath('c'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + + doc = doc[0]; + + assertEqual(typeof doc, 'object', 'The found doclet is an object.'); + assertEqual(doc.tagText('path'), 'c', 'The found doclet has the expected path.'); + assertEqual(doc.tagText('type'), 'number', 'The found doclet has the expected type.'); + assertEqual(doc.tagText('desc'), "Speed of light(m/s)", 'The found doclet has the expected desc.'); + } + }; + + testSuites.push(testSuite); +})(); + +function sample() { + + /** + * @const {number} pi The ratio of any circle's circumference to its diameter. + */ + + /** + * Euler's number. + * @const + * @name e + * @type number + */ + + /** + * Speed of light(m/s) + * @const {number} + * + */ + var c = 299792458; // <- name will be found here + +} \ No newline at end of file diff --git a/tests/tag_constructor.js b/tests/tag_constructor.js new file mode 100644 index 00000000..9af293d3 --- /dev/null +++ b/tests/tag_constructor.js @@ -0,0 +1,112 @@ +(function() { + var jsdoc = { parser: require('jsdoc/parser') }; + + jsdoc.parser.parseFiles(BASEDIR + 'tests/tag_constructor.js'); + var docset = jsdoc.parser.result; + + var testSuite = { + suiteName: 'tag_constructor', + + setUp: function() { + }, + + tearDown: function() { + }, + + testConstructorDocs: function() { + assertEqual(typeof docset, 'object'); + }, + + testConstructorCompactTag: function() { + var doc = docset.getDocsByPath('Triangle'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + + doc = doc[0]; + + assertEqual(typeof doc, 'object', 'The found doclet is an object.'); + assertEqual(doc.tagText('name'), 'Triangle', 'The found doclet has the expected name.'); + assertEqual(doc.tagText('path'), 'Triangle', 'The found doclet has the expected path.'); + assertEqual(doc.tagText('denom'), 'constructor', 'The found doclet has the expected denom.'); + assertEqual(doc.tagText('desc'), 'A three-sided polygon.', 'The found doclet has the expected desc.'); + }, + + testConstructorFromCode: function() { + var doc = docset.getDocsByPath('shapes.Quadrilateral'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + + doc = doc[0]; + + assertEqual(typeof doc, 'object', 'The found doclet is an object.'); + assertEqual(doc.tagText('path'), 'shapes.Quadrilateral', 'The found doclet has the expected path.'); + assertEqual(doc.tagText('name'), 'Quadrilateral', 'The found doclet has the expected name.'); + assertEqual(doc.tagText('memberof'), 'shapes', 'The found doclet has the expected memberof.'); + assertEqual(doc.tagText('desc'), '', 'The found doclet has the expected desc.'); + }, + + testConstructorBeforeVar: function() { + var doc = docset.getDocsByPath('Polygon'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + + doc = doc[0]; + + assertEqual(typeof doc, 'object', 'The found doclet is an object.'); + assertEqual(doc.tagText('path'), 'Polygon', 'The found doclet has the expected path.'); + assertEqual(doc.tagText('name'), 'Polygon', 'The found doclet has the expected name.'); + assertEqual(doc.tagText('memberof'), '', 'The found doclet has the expected memberof.'); + assertEqual(doc.tagText('desc'), 'Jsdoc is before the `var`.', 'The found doclet has the expected desc.'); + }, + + testConstructorNested: function() { + var doc = docset.getDocsByPath('Polygon#Rhombus'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + + doc = doc[0]; + + assertEqual(typeof doc, 'object', 'The found doclet is an object.'); + assertEqual(doc.tagText('path'), 'Polygon#Rhombus', 'The found doclet has the expected path.'); + assertEqual(doc.tagText('name'), 'Rhombus', 'The found doclet has the expected name.'); + assertEqual(doc.tagText('memberof'), 'Polygon#', 'The found doclet has the expected memberof.'); + assertEqual(doc.tagText('denom'), 'constructor', 'The found doclet has the expected denom.'); + }, + + testConstructorInVarList: function() { + var doc = docset.getDocsByPath('Trapezoid'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + + doc = doc[0]; + + assertEqual(typeof doc, 'object', 'The found doclet is an object.'); + } + }; + + testSuites.push(testSuite); +})(); + +function sample() { + + /**@constructor Triangle A three-sided polygon.*/ + /** + * @constructor + * @name Square + */ + someIgnoredCode = function() {} + + /** @constructor */ + shapes.Quadrilateral = new Klass("shapes", "Quadrilateral"); + + /** + Jsdoc is before the `var`. + @constructor + */ + var Polygon = function() { + /** A nested constructor + @constructor + */ + this.Rhombus = function () {} + }, + /** + In a list of vars. + @constructor + */ + Trapezoid = function() {}; +} \ No newline at end of file diff --git a/tests/tag_enum.js b/tests/tag_enum.js new file mode 100644 index 00000000..06bca27e --- /dev/null +++ b/tests/tag_enum.js @@ -0,0 +1,89 @@ +(function() { + var jsdoc = { parser: require('jsdoc/parser') }; + + jsdoc.parser.parseFiles(BASEDIR + 'tests/tag_enum.js'); + var docset = jsdoc.parser.result; + + var testSuite = { + suiteName: 'tag_enum', + + setUp: function() { + }, + + tearDown: function() { + }, + + testEnumDocs: function() { + assertEqual(typeof docset, 'object'); + }, + + testEnumCompactTag: function() { + var doc = docset.getDocsByPath('buttons'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + + doc = doc[0]; + + assertEqual(typeof doc, 'object', 'The found doclet is an object.'); + assertEqual(doc.tagText('path'), 'buttons', 'The found doclet has the expected path.'); + assertEqual(doc.tagText('type'), 'string', 'The found doclet has the expected type.'); + assertEqual(doc.tagText('desc'), 'Text equivalents for editor buttons.', 'The found doclet has the expected desc.'); + }, + + testEnumCompactMembers: function() { + var doc = docset.getDocsByPath('replies'); + assertEqual(doc.length, 1, '1 doclet by that name replies is found.'); + + doc = docset.getDocsByPath('replies.YES'); + assertEqual(doc.length, 1, '1 doclet by that name YES is found.'); + + doc = doc[0]; + + assertEqual(doc.tagText('memberof'), 'replies', 'The found doclet is a member of the enum.'); + + doc = docset.getDocsByPath('replies.NO'); + assertEqual(doc.length, 1, '1 doclet by that name NO is found.'); + }, + + testEnumThis: function() { + var doc = docset.getDocsByPath('Chart#colors'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + } + }; + + testSuites.push(testSuite); +})(); + +function sample() { + + /** @enum {string} buttons Text equivalents for editor buttons. */ + this['buttons'] = { BOLD: 'B', ITALIC: 'I', CLOSE: 'X' }; + + /** + Valid replies. + @enum + */ + var replies = { + /** A positive response. */ + YES: 1, + + /** A negative response. */ + NO: -1, + + /** An uncertain response */ + MAYBE: 0 + } + + /** @constructor */ + function Chart() { + /** + Valid colors. + @enum {string} + */ + this.colors = { + RED: '#F00', + BLUE: '#00F', + GREEN: '#0F0' + } + } + +} \ No newline at end of file diff --git a/tests/tag_namespace.js b/tests/tag_namespace.js new file mode 100644 index 00000000..ccd6ec78 --- /dev/null +++ b/tests/tag_namespace.js @@ -0,0 +1,41 @@ +(function() { + var jsdoc = { parser: require('jsdoc/parser') }; + + jsdoc.parser.parseFiles(BASEDIR + 'tests/tag_namespace.js'); + var docset = jsdoc.parser.result; + + var testSuite = { + suiteName: 'tag_namespace', + + setUp: function() { + }, + + tearDown: function() { + }, + + testNsDocs: function() { + assertEqual(typeof docset, 'object'); + }, + + testNsCompactTag: function() { + var doc = docset.getDocsByPath('polygons'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + }, + + testNsNested: function() { + var doc = docset.getDocsByPath('polygons.quadrilaterals'); + assertEqual(doc.length, 1, '1 doclet by that name is found.'); + } + }; + + testSuites.push(testSuite); +})(); + +function sample() { + + /** @namespace polygons Closed figure made by joining line segments. */ + this['polygons'] = {}; + + /** @namespace */ + polygons.quadrilaterals = {}; +} \ No newline at end of file