mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
Merge branch 'master' into parsimony
Conflicts: lib/jsdoc/name.js lib/jsdoc/src/handlers.js lib/jsdoc/src/parser.js lib/jsdoc/tag/dictionary/definitions.js lib/jsdoc/util/templateHelper.js package.json test/specs/documentation/alias.js test/specs/documentation/modules.js test/specs/tags/augmentstag.js test/specs/tags/overviewtag.js
This commit is contained in:
commit
e7752cde18
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ jsdoc.jar
|
||||
test/tutorials/out
|
||||
conf.json
|
||||
out/
|
||||
.tern-port
|
||||
|
||||
@ -10,15 +10,13 @@
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0"
|
||||
}
|
||||
],
|
||||
"repositories": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/jsdoc3/jsdoc"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jsdoc3/jsdoc"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "0.1.22",
|
||||
"catharsis": "0.5.6",
|
||||
"catharsis": "0.7.0",
|
||||
"crypto-browserify": "git+https://github.com/dominictarr/crypto-browserify.git#95c5d505",
|
||||
"esprima": "1.0.4",
|
||||
"js2xmlparser": "0.1.0",
|
||||
|
||||
@ -15,7 +15,7 @@ task('default', [], function(params) {
|
||||
|
||||
var metadata = {
|
||||
appname : 'jsdoc',
|
||||
appversion : '3.2.0-dev',
|
||||
appversion : '3.3.0-dev',
|
||||
timestamp : '' + new Date().getTime()
|
||||
};
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ Installation
|
||||
|
||||
Use git to clone the [official JSDoc repository](https://github.com/jsdoc3/jsdoc):
|
||||
|
||||
git clone git@github.com:jsdoc3/jsdoc.git
|
||||
git clone https://github.com/jsdoc3/jsdoc.git
|
||||
|
||||
Alternatively, you can download a .zip file for the
|
||||
[latest development version](https://github.com/jsdoc3/jsdoc/archive/master.zip)
|
||||
|
||||
32
changes.md
32
changes.md
@ -3,6 +3,38 @@
|
||||
This file describes notable changes in each version of JSDoc 3. To download a specific version of JSDoc 3, see [GitHub's tags page](https://github.com/jsdoc3/jsdoc/tags).
|
||||
|
||||
|
||||
## 3.2.1 (October 2013)
|
||||
|
||||
### Enhancements
|
||||
+ JSDoc's parser now fires a `processingComplete` event after JSDoc has completed all post-processing of the parse results. This event has a `doclets` property containing an array of doclets. (#421)
|
||||
+ When JSDoc's parser fires a `parseComplete` event, the event now includes a `doclets` property containing an array of doclets. (#431)
|
||||
+ You can now use relative paths in the JSDoc configuration file's `source.exclude` option. Relative paths will be resolved relative to the current working directory. (#405)
|
||||
+ If a symbol uses the `@default` tag, and its default value is an object literal, this value is now stored as a string, and the doclet will have a `defaultvaluetype` property containing the string `object`. This change enables templates to show the default value with appropriate syntax highlighting. (#419)
|
||||
+ Inline `{@link}` tags can now contain newlines. (#441)
|
||||
|
||||
### Bug fixes
|
||||
+ Inherited symbols now indicate that they were inherited from the ancestor that defined the symbol, rather than the direct parent. (#422)
|
||||
+ If the first line of a JavaScript file contains a hashbang (for example, `#!/usr/bin/env node`), the hashbang is now ignored when the file is parsed. (#499)
|
||||
+ Resolved a crash when a JavaScript file contains a [JavaScript 1.8](https://developer.mozilla.org/en-US/docs/Web/JavaScript/New_in_JavaScript/1.8) keyword, such as `let`. (#477)
|
||||
+ The type expression `function[]` is now parsed correctly. (#493)
|
||||
+ If a module is tagged incorrectly, the module's output file now has a valid filename. (#440, #458)
|
||||
+ For tags that accept names, such as `@module` and `@param`, if a hyphen is used to separate the name and description, the hyphen must appear on the same line as the name. This change prevents a Markdown bullet on the followng line from being interpreted as a separator. (#459)
|
||||
+ When lenient mode is enabled, a `@param` tag with an invalid type expression no longer causes a crash. (#448)
|
||||
+ The `@requires` tag can now contain an inline tag in its tag text. (#486)
|
||||
+ The `@returns` tag can now contain inline tags even if a type is not specified. (#444)
|
||||
+ When lenient mode is enabled, a `@returns` tag with no value no longer causes a crash. (#451)
|
||||
+ The `@type` tag now works correctly with type expressions that span multiple lines. (#427)
|
||||
+ If a string contains inline `{@link}` tags preceded by bracketed link text (for example, `[test]{@link Test#test}`), HTML links are now generated correctly even if the string contains other bracketed text. (#470)
|
||||
+ On POSIX systems, if you run JSDoc using a symlink to the startup script, JSDoc now works correctly. (#492)
|
||||
|
||||
### Default template
|
||||
+ Pretty-printed source files are now generated by default. To disable this feature, add the property `templates.default.outputSourceFiles: false` to your `conf.json` file. (#454)
|
||||
+ Links to a specific line in a source file now work correctly. (#475)
|
||||
+ Pretty-printed source files are now generated using the encoding specified in the `-e/--encoding` option. (#496)
|
||||
+ If a `@default` tag is added to a symbol whose default value is an object, the value is now displayed in the output file. (#419)
|
||||
+ Output files now identify symbols as "abstract" rather than "virtual." (#432)
|
||||
|
||||
|
||||
## 3.2.0 (May 2013)
|
||||
|
||||
### Major changes
|
||||
|
||||
12
jsdoc
12
jsdoc
@ -2,7 +2,15 @@
|
||||
|
||||
# rhino discards the path to the current script file, so we must add it back
|
||||
SOURCE="$0"
|
||||
while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done
|
||||
while [ -h "$SOURCE" ] ; do
|
||||
NEXTSOURCE="$(readlink "$SOURCE")"
|
||||
echo $NEXTSOURCE | grep -q -e "^/"
|
||||
if [ $? = 0 ]; then
|
||||
SOURCE="$NEXTSOURCE"
|
||||
else
|
||||
SOURCE="$(dirname $SOURCE)/$NEXTSOURCE"
|
||||
fi
|
||||
done
|
||||
# Get a Windows path under MinGW or Cygwin
|
||||
BASEPATH="$( cd -P "$( dirname "$SOURCE" )" && (pwd -W 2>/dev/null || cygpath -w $(pwd) 2>/dev/null || pwd))"
|
||||
if [ "${BASEPATH%${BASEPATH#?}}" != "/" ] ; then
|
||||
@ -21,7 +29,7 @@ ENCODEDBASEPATH=`echo "$BASEPATH" | sed -e 's/ /%20/g'`
|
||||
if test "$1" = "--debug"
|
||||
then
|
||||
echo "Running Debug"
|
||||
CMD="org.mozilla.javascript.tools.debugger.Main -debug"
|
||||
CMD="org.mozilla.javascript.tools.debugger.Main -debug -opt -1"
|
||||
# strip --debug argument
|
||||
shift
|
||||
else
|
||||
|
||||
@ -20,7 +20,7 @@ IF NOT "%_URLPATH%"=="%_URLPATH: =%" GOTO ESCAPE_SPACE
|
||||
|
||||
IF [%1]==[--debug] (
|
||||
ECHO Running Debug
|
||||
SET CMD=org.mozilla.javascript.tools.debugger.Main -debug
|
||||
SET CMD=org.mozilla.javascript.tools.debugger.Main -debug -opt -1
|
||||
|
||||
REM `SHIFT` doesn't affect %*
|
||||
:COLLECT_ARGS
|
||||
|
||||
10
jsdoc.js
10
jsdoc.js
@ -61,6 +61,13 @@ require('lib/jsdoc/util/global').env = {
|
||||
*/
|
||||
opts: {},
|
||||
|
||||
/**
|
||||
* The source files that JSDoc will parse.
|
||||
* @type Array
|
||||
* @memberof env
|
||||
*/
|
||||
sourceFiles: [],
|
||||
|
||||
/**
|
||||
* The JSDoc version number and revision date.
|
||||
*
|
||||
@ -222,7 +229,8 @@ function main() {
|
||||
if (env.conf.source && env.opts._.length > 0) { // are there any files to scan and parse?
|
||||
filter = new jsdoc.src.filter.Filter(env.conf.source);
|
||||
|
||||
sourceFiles = app.jsdoc.scanner.scan(env.opts._, (env.opts.recurse? 10 : undefined), filter);
|
||||
env.sourceFiles = sourceFiles = app.jsdoc.scanner.scan(env.opts._,
|
||||
(env.opts.recurse? 10 : undefined), filter);
|
||||
|
||||
jsdoc.src.handlers.attachTo(app.jsdoc.parser);
|
||||
|
||||
|
||||
@ -120,7 +120,8 @@ exports.addInherited = function(docs) {
|
||||
// only build the list of longnames if we'll actually need it
|
||||
if (sorted.length) {
|
||||
longnames = docs.map(function(doc) {
|
||||
if (doc.longname) {
|
||||
// keep the ancestor's docs for a symbol if a local override is not documented
|
||||
if (doc.longname && !doc.undocumented) {
|
||||
return doc.longname;
|
||||
}
|
||||
});
|
||||
|
||||
@ -33,7 +33,7 @@ const defaults = {
|
||||
},
|
||||
"source": {
|
||||
"includePattern": ".+\\.js(doc)?$",
|
||||
"excludePattern": "(^|\\/)_"
|
||||
"excludePattern": "(^|\\/|\\\\)_"
|
||||
},
|
||||
"plugins": []
|
||||
};
|
||||
|
||||
@ -32,7 +32,7 @@ var DEFAULT_SCOPE = 'static';
|
||||
@param {module:jsdoc/doclet.Doclet} doclet
|
||||
*/
|
||||
exports.resolve = function(doclet) {
|
||||
var name = doclet.name,
|
||||
var name = doclet.name ? String(doclet.name) : '',
|
||||
memberof = doclet.memberof || '',
|
||||
about = {},
|
||||
scopePunc = '([' + INNER + INSTANCE + STATIC + '])',
|
||||
@ -40,8 +40,13 @@ exports.resolve = function(doclet) {
|
||||
trailingScope = new RegExp(scopePunc + '$'),
|
||||
parentDoc;
|
||||
|
||||
doclet.name = name = name? ('' + name).replace(/(^|\.)prototype\.?/g, INSTANCE) : '';
|
||||
|
||||
// change MyClass.prototype.instanceMethod to MyClass#instanceMethod
|
||||
// (but not in function params, which lack doclet.kind)
|
||||
if (name && doclet.kind) {
|
||||
name = name.replace(/(?:^|\.)prototype\.?/g, INSTANCE);
|
||||
}
|
||||
doclet.name = name;
|
||||
|
||||
// member of a var in an outer scope?
|
||||
if (name && !memberof && doclet.meta.code && doclet.meta.code.funcscope) {
|
||||
name = doclet.longname = doclet.meta.code.funcscope + INNER + name;
|
||||
@ -138,6 +143,7 @@ function quoteUnsafe(name, kind) { // docspaced names may have unsafe characters
|
||||
return name;
|
||||
}
|
||||
|
||||
// TODO: make this a private method, or remove it if possible
|
||||
RegExp.escape = RegExp.escape || function(str) {
|
||||
var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g"); // .*+?|()[]{}\
|
||||
return str.replace(specials, "\\$&");
|
||||
@ -213,7 +219,8 @@ exports.shorten = function(longname, forcedMemberof) {
|
||||
|
||||
// like /** @name foo.bar(2) */
|
||||
if ( /(.+)\(([^)]+)\)$/.test(name) ) {
|
||||
name = RegExp.$1, variation = RegExp.$2;
|
||||
name = RegExp.$1;
|
||||
variation = RegExp.$2;
|
||||
}
|
||||
|
||||
//// restore quoted strings back again
|
||||
@ -230,44 +237,17 @@ exports.shorten = function(longname, forcedMemberof) {
|
||||
};
|
||||
|
||||
/**
|
||||
Split a string that starts with a name and ends with a description, into its parts.
|
||||
Split a string that starts with a name and ends with a description into its parts.
|
||||
@param {string} nameDesc
|
||||
@returns {object} Hash with "name" and "description" properties.
|
||||
*/
|
||||
exports.splitName = function(nameDesc) {
|
||||
var name = '',
|
||||
desc = '',
|
||||
thisChar = '',
|
||||
inQuote = false;
|
||||
|
||||
for (var i = 0, len = nameDesc.length; i < len; i++) {
|
||||
thisChar = nameDesc.charAt(i);
|
||||
|
||||
if (thisChar === '\\') {
|
||||
name += thisChar + nameDesc.charAt(++i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (thisChar === '"') {
|
||||
inQuote = !inQuote;
|
||||
}
|
||||
|
||||
if (inQuote) {
|
||||
name += thisChar;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inQuote) {
|
||||
if ( /\s/.test(thisChar) ) {
|
||||
desc = nameDesc.substr(i);
|
||||
desc = desc.replace(/^[\s\-\s]+/, '').trim();
|
||||
break;
|
||||
}
|
||||
else {
|
||||
name += thisChar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { name: name, description: desc };
|
||||
// like: name, [name], name text, [name] text, name - text, or [name] - text
|
||||
// the hyphen must be on the same line as the name; this prevents us from treating a Markdown
|
||||
// dash as a separator
|
||||
nameDesc.match(/^(\[[^\]]+\]|\S+)((?:[ \t]*\-\s*|\s+)(\S[\s\S]*))?$/);
|
||||
return {
|
||||
name: RegExp.$1,
|
||||
description: RegExp.$3
|
||||
};
|
||||
};
|
||||
|
||||
@ -63,8 +63,8 @@ function parseQuery(str) {
|
||||
return result;
|
||||
}
|
||||
|
||||
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('t', 'template', true, 'The path to the template to use. Default: path/to/jsdoc/templates/default');
|
||||
argParser.addOption('c', 'configure', true, 'The path to the configuration file. Default: path/to/jsdoc/conf.json');
|
||||
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/');
|
||||
|
||||
@ -51,7 +51,10 @@ function prefixReducer(previousPath, current) {
|
||||
* @return {string} The common prefix, or an empty string if there is no common prefix.
|
||||
*/
|
||||
exports.commonPrefix = function(paths) {
|
||||
var common = paths.reduce(prefixReducer, undefined);
|
||||
var common;
|
||||
|
||||
paths = paths || [];
|
||||
common = paths.reduce(prefixReducer, undefined) || [];
|
||||
|
||||
// if there's anything left (other than a placeholder for a leading slash), add a placeholder
|
||||
// for a trailing slash
|
||||
|
||||
@ -19,7 +19,7 @@ function getNewDoclet(comment, e) {
|
||||
err = new Error( util.format('cannot create a doclet for the comment "%s": %s',
|
||||
comment.replace(/[\r\n]/g, ''), error.message) );
|
||||
require('jsdoc/util/error').handle(err);
|
||||
doclet = new Doclet('', {});
|
||||
doclet = new Doclet('', e);
|
||||
}
|
||||
|
||||
return doclet;
|
||||
|
||||
@ -151,7 +151,8 @@ Parser.prototype.parse = function(sourceFiles, encoding) {
|
||||
}
|
||||
|
||||
this.emit('parseComplete', {
|
||||
sourcefiles: parsedFiles
|
||||
sourcefiles: parsedFiles,
|
||||
doclets: this._resultBuffer
|
||||
});
|
||||
|
||||
return this._resultBuffer;
|
||||
@ -188,6 +189,9 @@ Parser.prototype.getAstNodeVisitors = function() {
|
||||
// TODO: docs
|
||||
function pretreat(code) {
|
||||
return code
|
||||
// comment out hashbang at the top of the file, like: #!/usr/bin/env node
|
||||
.replace(/^(\#\![\S \t]+\n)/, '// $1')
|
||||
|
||||
// to support code minifiers that preserve /*! comments, treat /*!* as equivalent to /**
|
||||
.replace(/\/\*\!\*/g, '/**')
|
||||
// merge adjacent doclets
|
||||
|
||||
@ -10,6 +10,18 @@
|
||||
var path = require('jsdoc/path');
|
||||
var Syntax = require('jsdoc/src/syntax').Syntax;
|
||||
|
||||
function filepathMinusPrefix(filepath) {
|
||||
var sourceFiles = env.sourceFiles || [];
|
||||
var commonPrefix = path.commonPrefix( sourceFiles.concat(env.opts._ || []) );
|
||||
var result = (filepath + '/').replace(commonPrefix, '');
|
||||
|
||||
if (result.length > 0 && result[result.length - 1] !== '/') {
|
||||
result += '/';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @private */
|
||||
function setDocletKindToTitle(doclet, tag) {
|
||||
doclet.addTag( 'kind', tag.title );
|
||||
@ -35,12 +47,11 @@ function setDocletDescriptionToValue(doclet, tag) {
|
||||
}
|
||||
|
||||
function setNameToFile(doclet, tag) {
|
||||
var name = '';
|
||||
var name;
|
||||
|
||||
if (doclet.meta.filename) {
|
||||
// TODO: find the shortest path shared by all input files, and remove that from
|
||||
// doclet.meta.path
|
||||
name += path.basename(doclet.meta.path) + '/';
|
||||
doclet.addTag( 'name', name + doclet.meta.filename );
|
||||
name = filepathMinusPrefix(doclet.meta.path) + doclet.meta.filename;
|
||||
doclet.addTag('name', name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,17 +76,13 @@ function applyNamespace(docletOrNs, tag) {
|
||||
}
|
||||
|
||||
function setDocletNameToFilename(doclet, tag) {
|
||||
// TODO: find the shortest path shared by all input files, and remove that from doclet.meta.path
|
||||
var name = doclet.meta.path ? path.basename(doclet.meta.path) + '/' : '';
|
||||
name += doclet.meta.filename;
|
||||
name = name.replace(/\.js$/i, '');
|
||||
|
||||
for (var i = 0, len = env.opts._.length; i < len; i++) {
|
||||
if (name.indexOf(env.opts._[i]) === 0) {
|
||||
name = name.replace(env.opts._[0], '');
|
||||
break;
|
||||
}
|
||||
var name = '';
|
||||
|
||||
if (doclet.meta.path) {
|
||||
name = filepathMinusPrefix(doclet.meta.path);
|
||||
}
|
||||
name += doclet.meta.filename.replace(/\.js$/i, '');
|
||||
|
||||
doclet.name = name;
|
||||
}
|
||||
|
||||
@ -541,15 +548,24 @@ exports.defineTags = function(dictionary) {
|
||||
dictionary.defineTag('requires', {
|
||||
mustHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
var MODULE_PREFIX = require('jsdoc/name').MODULE_PREFIX;
|
||||
var modName = firstWordOf(tag.value);
|
||||
var requiresName;
|
||||
|
||||
if (modName.indexOf(MODULE_PREFIX) !== 0) {
|
||||
modName = MODULE_PREFIX + modName;
|
||||
var MODULE_PREFIX = require('jsdoc/name').MODULE_PREFIX;
|
||||
|
||||
// inline link tags are passed through as-is so that `@requires {@link foo}` works
|
||||
if ( require('jsdoc/tag/inline').isInlineTag(tag.value, 'link\\S*') ) {
|
||||
requiresName = tag.value;
|
||||
}
|
||||
|
||||
// otherwise, assume it's a module
|
||||
else {
|
||||
requiresName = firstWordOf(tag.value);
|
||||
if (requiresName.indexOf(MODULE_PREFIX) !== 0) {
|
||||
requiresName = MODULE_PREFIX + requiresName;
|
||||
}
|
||||
}
|
||||
|
||||
if (!doclet.requires) { doclet.requires = []; }
|
||||
doclet.requires.push(modName);
|
||||
doclet.requires.push(requiresName);
|
||||
}
|
||||
});
|
||||
|
||||
@ -619,17 +635,21 @@ exports.defineTags = function(dictionary) {
|
||||
mustHaveValue: true,
|
||||
canHaveType: true,
|
||||
onTagText: function(text) {
|
||||
// remove line breaks so we can parse the type expression correctly
|
||||
text = text.replace(/[\n\r]/g, '');
|
||||
// any text must be formatted as a type, but for back compat braces are optional
|
||||
if ( ! /^\{.+\}$/.test(text) ) {
|
||||
text = '{ '+text+' }';
|
||||
if ( !/^\{[\s\S]+\}$/.test(text) ) {
|
||||
text = '{' + text + '}';
|
||||
}
|
||||
return text;
|
||||
},
|
||||
onTagged: function(doclet, tag) {
|
||||
if (tag.value && tag.value.type) {
|
||||
doclet.type = tag.value.type;
|
||||
|
||||
// for backwards compatibility, we allow @type for functions to imply return type
|
||||
if (doclet.kind === 'function') {
|
||||
doclet.addTag('returns', tag.text); // for backwards compatibility we allow @type for functions to imply return type
|
||||
doclet.addTag('returns', tag.text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +35,44 @@
|
||||
* @return {string} An updated version of the complete string.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Create a regexp that matches a specific inline tag, or all inline tags.
|
||||
*
|
||||
* @private
|
||||
* @memberof module:jsdoc/tag/inline
|
||||
* @param {?string} tagName - The inline tag that the regexp will match. May contain regexp
|
||||
* characters. If omitted, matches any string.
|
||||
* @param {?string} prefix - A prefix for the regexp. Defaults to an empty string.
|
||||
* @param {?string} suffix - A suffix for the regexp. Defaults to an empty string.
|
||||
* @returns {RegExp} A regular expression that matches the requested inline tag.
|
||||
*/
|
||||
function regExpFactory(tagName, prefix, suffix) {
|
||||
tagName = tagName || '\\S+';
|
||||
prefix = prefix || '';
|
||||
suffix = suffix || '';
|
||||
|
||||
return new RegExp(prefix + '\\{@' + tagName + '\\s+((?:.|\n)+?)\\}' + suffix, 'gi');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a string is an inline tag. You can check for a specific inline tag or for any valid
|
||||
* inline tag.
|
||||
*
|
||||
* @param {string} string - The string to check.
|
||||
* @param {?string} tagName - The inline tag to match. May contain regexp characters. If this
|
||||
* parameter is omitted, this method returns `true` for any valid inline tag.
|
||||
* @returns {boolean} Set to `true` if the string is a valid inline tag or `false` in all other
|
||||
* cases.
|
||||
*/
|
||||
exports.isInlineTag = function(string, tagName) {
|
||||
try {
|
||||
return regExpFactory(tagName, '^', '$').test(string);
|
||||
}
|
||||
catch(e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Replace all instances of multiple inline tags with other text.
|
||||
*
|
||||
@ -61,7 +99,7 @@ exports.replaceInlineTags = function(string, replacers) {
|
||||
|
||||
string = string || '';
|
||||
Object.keys(replacers).forEach(function(replacer) {
|
||||
var tagRegExp = new RegExp('\\{@' + replacer + '\\s+((?:.|\n)+?)\\}', 'gi');
|
||||
var tagRegExp = regExpFactory(replacer);
|
||||
var matches;
|
||||
// call the replacer once for each match
|
||||
while ( (matches = tagRegExp.exec(string)) !== null ) {
|
||||
@ -69,7 +107,7 @@ exports.replaceInlineTags = function(string, replacers) {
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
return {
|
||||
tags: tagInfo,
|
||||
newString: string.trim()
|
||||
};
|
||||
|
||||
@ -6,6 +6,13 @@
|
||||
* @license Apache License 2.0 - See file 'LICENSE.md' in this project.
|
||||
*/
|
||||
|
||||
var jsdoc = {
|
||||
name: require('jsdoc/name'),
|
||||
tag: {
|
||||
inline: require('jsdoc/tag/inline')
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Information about a type expression extracted from tag text.
|
||||
*
|
||||
@ -35,7 +42,7 @@ function unescapeBraces(text) {
|
||||
var count = 0;
|
||||
var position = 0;
|
||||
var expression = '';
|
||||
var startIndex = string.indexOf('{');
|
||||
var startIndex = string.search(/\{[^@]/);
|
||||
var textStartIndex;
|
||||
|
||||
if (startIndex !== -1) {
|
||||
@ -83,6 +90,7 @@ function getTagInfo(tagValue, canHaveName, canHaveType) {
|
||||
var typeExpression = '';
|
||||
var text = tagValue;
|
||||
var expressionAndText;
|
||||
var nameAndDescription;
|
||||
var typeOverride;
|
||||
|
||||
if (canHaveType) {
|
||||
@ -92,15 +100,14 @@ function getTagInfo(tagValue, canHaveName, canHaveType) {
|
||||
}
|
||||
|
||||
if (canHaveName) {
|
||||
// like: name, [name], name text, [name] text, name - text, or [name] - text
|
||||
text.match(/^(\[[^\]]+\]|\S+)((?:\s*\-\s*|\s+)(\S[\s\S]*))?$/);
|
||||
name = RegExp.$1;
|
||||
text = RegExp.$3;
|
||||
nameAndDescription = jsdoc.name.splitName(text);
|
||||
name = nameAndDescription.name;
|
||||
text = nameAndDescription.description;
|
||||
}
|
||||
|
||||
// an inline @type tag, like {@type Foo}, overrides the type expression
|
||||
if (canHaveType) {
|
||||
typeOverride = require('jsdoc/tag/inline').extractInlineTag(text, 'type');
|
||||
typeOverride = jsdoc.tag.inline.extractInlineTag(text, 'type');
|
||||
if (typeOverride.tags && typeOverride.tags[0]) {
|
||||
typeExpression = typeOverride.tags[0].text || typeExpression;
|
||||
}
|
||||
@ -134,6 +141,7 @@ function getTagInfo(tagValue, canHaveName, canHaveType) {
|
||||
* can vary (for example, in a function that accepts any number of parameters).
|
||||
*/
|
||||
|
||||
// TODO: move to module:jsdoc/name?
|
||||
/**
|
||||
* Extract JSDoc-style type information from the name specified in the tag info, including the
|
||||
* member name; whether the member is optional; and the default value of the member.
|
||||
|
||||
@ -51,8 +51,19 @@ function makeFilenameUnique(filename, str) {
|
||||
return filename;
|
||||
}
|
||||
|
||||
// compute it here just once
|
||||
var nsprefix = /^(event|module|external):/;
|
||||
function cleanseFilename(str) {
|
||||
str = str || '';
|
||||
|
||||
// allow for namespace prefix
|
||||
// TODO: use prefixes in jsdoc/doclet
|
||||
return str.replace(/^(event|module|external|package):/, '$1-')
|
||||
// use - instead of ~ to denote 'inner'
|
||||
.replace(/~/g, '-')
|
||||
// use _ instead of # to denote 'instance'
|
||||
.replace(/\#/g, '_')
|
||||
// remove the variation, if any
|
||||
.replace(/\([\s\S]*\)$/, '');
|
||||
}
|
||||
|
||||
var htmlsafe = exports.htmlsafe = function(str) {
|
||||
return str.replace(/</g, '<');
|
||||
@ -71,11 +82,7 @@ var htmlsafe = exports.htmlsafe = function(str) {
|
||||
*/
|
||||
var getUniqueFilename = exports.getUniqueFilename = function(str) {
|
||||
// allow for namespace prefix
|
||||
var basename = str.replace(nsprefix, '$1-')
|
||||
// use - instead of ~ to denote 'inner'
|
||||
.replace(/~/g, '-')
|
||||
// remove the variation, if any
|
||||
.replace(/\([\s\S]*\)$/, '');
|
||||
var basename = cleanseFilename(str);
|
||||
|
||||
// if the basename includes characters that we can't use in a filepath, remove everything up to
|
||||
// and including the last bad character
|
||||
@ -342,13 +349,18 @@ exports.resolveLinks = function(str) {
|
||||
function extractLeadingText(string, completeTag) {
|
||||
var tagIndex = string.indexOf(completeTag);
|
||||
var leadingText = null;
|
||||
var leadingTextInfo = /\[(.+?)\]/.exec(string);
|
||||
var leadingTextRegExp = /\[(.+?)\]/g;
|
||||
var leadingTextInfo = leadingTextRegExp.exec(string);
|
||||
|
||||
// did we find leading text, and if so, does it immediately precede the tag?
|
||||
if ( leadingTextInfo && leadingTextInfo.index &&
|
||||
(leadingTextInfo.index + leadingTextInfo[0].length === tagIndex) ) {
|
||||
string = string.replace(leadingTextInfo[0], '');
|
||||
leadingText = leadingTextInfo[1];
|
||||
while (leadingTextInfo && leadingTextInfo.length) {
|
||||
if (leadingTextInfo.index + leadingTextInfo[0].length === tagIndex) {
|
||||
string = string.replace(leadingTextInfo[0], '');
|
||||
leadingText = leadingTextInfo[1];
|
||||
break;
|
||||
}
|
||||
|
||||
leadingTextInfo = leadingTextRegExp.exec(string);
|
||||
}
|
||||
|
||||
return {
|
||||
@ -466,11 +478,7 @@ exports.getMembers = function(data) {
|
||||
|
||||
// functions that are also modules (as in "module.exports = function() {};") are not globals
|
||||
members.globals = members.globals.filter(function(doclet) {
|
||||
if ( isModuleFunction(doclet) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return !isModuleFunction(doclet);
|
||||
});
|
||||
|
||||
return members;
|
||||
@ -576,7 +584,7 @@ exports.getSignatureReturns = function(d, cssClass) {
|
||||
|
||||
if (d.returns) {
|
||||
d.returns.forEach(function(r) {
|
||||
if (r.type && r.type.names) {
|
||||
if (r && r.type && r.type.names) {
|
||||
if (!returnTypes.length) {
|
||||
returnTypes = r.type.names;
|
||||
}
|
||||
@ -699,18 +707,47 @@ function getFilename(longname) {
|
||||
|
||||
/** Turn a doclet into a URL. */
|
||||
exports.createLink = function(doclet) {
|
||||
var filename;
|
||||
var fragment;
|
||||
var match;
|
||||
var fakeContainer;
|
||||
|
||||
var url = '';
|
||||
var INSTANCE = exports.scopeToPunc.instance;
|
||||
var longname = doclet.longname;
|
||||
var filename;
|
||||
|
||||
if ( containers.indexOf(doclet.kind) !== -1 || isModuleFunction(doclet) ) {
|
||||
url = getFilename(longname);
|
||||
// handle doclets in which doclet.longname implies that the doclet gets its own HTML file, but
|
||||
// doclet.kind says otherwise. this happens due to mistagged JSDoc (for example, a module that
|
||||
// somehow has doclet.kind set to `member`).
|
||||
// TODO: generate a warning (ideally during parsing!)
|
||||
if (containers.indexOf(doclet.kind) === -1) {
|
||||
match = /(\S+):/.exec(longname);
|
||||
if (match && containers.indexOf(match[1]) !== -1) {
|
||||
fakeContainer = match[1];
|
||||
}
|
||||
}
|
||||
|
||||
// the doclet gets its own HTML file
|
||||
if ( containers.indexOf(doclet.kind) !== -1 || isModuleFunction(doclet) ) {
|
||||
filename = getFilename(longname);
|
||||
}
|
||||
// mistagged version of a doclet that gets its own HTML file
|
||||
else if ( containers.indexOf(doclet.kind) === -1 && fakeContainer ) {
|
||||
filename = getFilename(doclet.memberof || longname);
|
||||
if (doclet.name === doclet.longname) {
|
||||
fragment = '';
|
||||
}
|
||||
else {
|
||||
fragment = doclet.name || '';
|
||||
}
|
||||
}
|
||||
// the doclet is within another HTML file
|
||||
else {
|
||||
filename = getFilename(doclet.memberof || exports.globalName);
|
||||
url = filename + INSTANCE + getNamespace(doclet.kind) + doclet.name;
|
||||
fragment = getNamespace(doclet.kind) + (doclet.name || '');
|
||||
}
|
||||
|
||||
url = fragment ? (filename + INSTANCE + fragment) : filename;
|
||||
|
||||
return url;
|
||||
};
|
||||
|
||||
2
node_modules/catharsis/catharsis.js
generated
vendored
2
node_modules/catharsis/catharsis.js
generated
vendored
@ -56,7 +56,7 @@ function cachedParse(expr, options) {
|
||||
var cache = getTypeExpressionCache(options);
|
||||
var parsedType;
|
||||
|
||||
if (cache && cache[expr]) {
|
||||
if (cache && Object.prototype.hasOwnProperty.call(cache, expr)) {
|
||||
return cache[expr];
|
||||
} else {
|
||||
parsedType = parse(expr, options);
|
||||
|
||||
6
node_modules/catharsis/lib/parser.js
generated
vendored
6
node_modules/catharsis/lib/parser.js
generated
vendored
File diff suppressed because one or more lines are too long
57
node_modules/catharsis/lib/stringify.js
generated
vendored
57
node_modules/catharsis/lib/stringify.js
generated
vendored
@ -66,7 +66,6 @@ Stringifier.prototype.nullable = function(nullable) {
|
||||
};
|
||||
|
||||
Stringifier.prototype.optional = function(optional) {
|
||||
/*jshint boss: true */ // TODO: remove after JSHint releases the fix for jshint/jshint#878
|
||||
if (optional === true) {
|
||||
return '=';
|
||||
} else {
|
||||
@ -111,43 +110,46 @@ Stringifier.prototype['this'] = function(funcThis) {
|
||||
return funcThis ? 'this:' + this.type(funcThis) : '';
|
||||
};
|
||||
|
||||
// TODO: refactor for clarity
|
||||
Stringifier.prototype.type = function(type) {
|
||||
var result = '';
|
||||
|
||||
if (!type) {
|
||||
return '';
|
||||
return result;
|
||||
}
|
||||
|
||||
// nullable comes first
|
||||
var result = this.nullable(type.nullable);
|
||||
|
||||
// next portion varies by type
|
||||
switch(type.type) {
|
||||
case Types.AllLiteral:
|
||||
result += this._formatNameAndType(type, '*');
|
||||
result += this._formatRepeatableAndNullable(type, '',
|
||||
this._formatNameAndType(type, '*'));
|
||||
break;
|
||||
case Types.FunctionType:
|
||||
result += this._signature(type);
|
||||
break;
|
||||
case Types.NullLiteral:
|
||||
result += this._formatNameAndType(type, 'null');
|
||||
result += this._formatRepeatableAndNullable(type, '',
|
||||
this._formatNameAndType(type, 'null'));
|
||||
break;
|
||||
case Types.RecordType:
|
||||
result += this._record(type);
|
||||
result += this._formatRepeatableAndNullable(type, '', this._record(type));
|
||||
break;
|
||||
case Types.TypeApplication:
|
||||
result += this.type(type.expression);
|
||||
result += this._formatRepeatableAndNullable(type, '', this.type(type.expression));
|
||||
result += this.applications(type.applications);
|
||||
break;
|
||||
case Types.UndefinedLiteral:
|
||||
result += this._formatNameAndType(type, 'undefined');
|
||||
result += this._formatRepeatableAndNullable(type, '',
|
||||
this._formatNameAndType(type, 'undefined'));
|
||||
break;
|
||||
case Types.TypeUnion:
|
||||
result += this.elements(type.elements);
|
||||
result += this._formatRepeatableAndNullable(type, '', this.elements(type.elements));
|
||||
break;
|
||||
case Types.UnknownLiteral:
|
||||
result += this._formatNameAndType(type, '?');
|
||||
result += this._formatRepeatableAndNullable(type, '',
|
||||
this._formatNameAndType(type, '?'));
|
||||
break;
|
||||
default:
|
||||
result += this._formatNameAndType(type);
|
||||
result += this._formatRepeatableAndNullable(type, '', this._formatNameAndType(type));
|
||||
}
|
||||
|
||||
// finally, optionality
|
||||
@ -190,14 +192,23 @@ Stringifier.prototype._recordFields = function(fields) {
|
||||
|
||||
function combineNameAndType(nameString, typeString) {
|
||||
var separator = (nameString && typeString) ? ':' : '';
|
||||
|
||||
return nameString + separator + typeString;
|
||||
}
|
||||
|
||||
Stringifier.prototype._formatRepeatable = function(nameString, typeString) {
|
||||
var open = this._inFunctionSignatureParams ? '...[' : '...';
|
||||
var close = this._inFunctionSignatureParams ? ']' : '';
|
||||
Stringifier.prototype._formatRepeatableAndNullable = function(type, nameString, typeString) {
|
||||
var open = '';
|
||||
var close = '';
|
||||
var combined;
|
||||
|
||||
return open + combineNameAndType(nameString, typeString) + close;
|
||||
if (type.repeatable) {
|
||||
open = this._inFunctionSignatureParams ? '...[' : '...';
|
||||
close = this._inFunctionSignatureParams ? ']' : '';
|
||||
}
|
||||
|
||||
combined = this.nullable(type.nullable) + combineNameAndType(nameString, typeString);
|
||||
|
||||
return open + combined + close;
|
||||
};
|
||||
|
||||
Stringifier.prototype._formatNameAndType = function(type, literal) {
|
||||
@ -215,17 +226,14 @@ Stringifier.prototype._formatNameAndType = function(type, literal) {
|
||||
nameString = openTag + nameString + '</a>';
|
||||
}
|
||||
|
||||
if (type.repeatable === true) {
|
||||
return this._formatRepeatable(nameString, typeString);
|
||||
} else {
|
||||
return combineNameAndType(nameString, typeString);
|
||||
}
|
||||
return combineNameAndType(nameString, typeString);
|
||||
};
|
||||
|
||||
Stringifier.prototype._signature = function(type) {
|
||||
var params = [];
|
||||
var param;
|
||||
var result;
|
||||
var signatureBase;
|
||||
|
||||
// these go within the signature's parens, in this order
|
||||
var props = [
|
||||
@ -245,7 +253,8 @@ Stringifier.prototype._signature = function(type) {
|
||||
}
|
||||
this._inFunctionSignatureParams = false;
|
||||
|
||||
result = 'function(' + params.join(', ') + ')';
|
||||
signatureBase = 'function(' + params.join(', ') + ')';
|
||||
result = this._formatRepeatableAndNullable(type, '', signatureBase);
|
||||
result += this.result(type.result);
|
||||
|
||||
return result;
|
||||
|
||||
29
node_modules/catharsis/package.json
generated
vendored
29
node_modules/catharsis/package.json
generated
vendored
File diff suppressed because one or more lines are too long
17
package.json
17
package.json
@ -1,7 +1,12 @@
|
||||
{
|
||||
"name": "jsdoc",
|
||||
<<<<<<< HEAD
|
||||
"version": "3.2.0-dev",
|
||||
"revision": "1382363021327",
|
||||
=======
|
||||
"version": "3.3.0-dev",
|
||||
"revision": "1381768141793",
|
||||
>>>>>>> master
|
||||
"description": "An API documentation generator for JavaScript.",
|
||||
"keywords": [ "documentation", "javascript" ],
|
||||
"licenses": [
|
||||
@ -10,15 +15,13 @@
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0"
|
||||
}
|
||||
],
|
||||
"repositories": [
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/jsdoc3/jsdoc"
|
||||
}
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/jsdoc3/jsdoc"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "0.1.22",
|
||||
"catharsis": "0.5.6",
|
||||
"catharsis": "0.7.0",
|
||||
"crypto-browserify": "git+https://github.com/dominictarr/crypto-browserify.git#95c5d505",
|
||||
"esprima": "1.0.4",
|
||||
"js2xmlparser": "0.1.0",
|
||||
|
||||
@ -4,6 +4,9 @@
|
||||
* to get JSDoc to run.
|
||||
*/
|
||||
|
||||
// Set the JS version that the Rhino interpreter will use.
|
||||
version(180);
|
||||
|
||||
/**
|
||||
* Emulate DOM timeout/interval functions.
|
||||
* @see https://developer.mozilla.org/en-US/docs/DOM/window#Methods
|
||||
|
||||
@ -1,20 +1,27 @@
|
||||
To create or use your own template, create a folder, and give it the name of your template, for example "mycooltemplate". Within this folder create a file named "publish.js". That file must define a global method named "publish". For example:
|
||||
To create or use your own template:
|
||||
|
||||
1. Create a folder with the same name as your template (for example, `mycooltemplate`).
|
||||
2. Within the template folder, create a file named `publish.js`. This file must be a CommonJS module that exports a method named `publish`.
|
||||
|
||||
For example:
|
||||
|
||||
````javascript
|
||||
/** @module publish */
|
||||
|
||||
/**
|
||||
* Turn the data about your docs into file output.
|
||||
* @global
|
||||
* Generate documentation output.
|
||||
*
|
||||
* @param {TAFFY} data - A TaffyDB collection representing
|
||||
* all the symbols documented in your code.
|
||||
* @param {object} opts - An object with options information.
|
||||
*/
|
||||
function publish(data, opts) {
|
||||
exports.publish = function(data, opts) {
|
||||
// do stuff here to generate your output files
|
||||
}
|
||||
};
|
||||
````
|
||||
|
||||
To invoke JSDoc 3 with your own template, use the `-t` command line option, giving it the path to your template folder.
|
||||
To invoke JSDoc 3 with your own template, use the `-t` command line option, and specify the path to your template folder:
|
||||
|
||||
````
|
||||
./jsdoc mycode.js -t /path/to/mycooltemplate
|
||||
````
|
||||
````
|
||||
|
||||
@ -66,7 +66,10 @@ function addSignatureParams(f) {
|
||||
function addSignatureReturns(f) {
|
||||
var returnTypes = helper.getSignatureReturns(f);
|
||||
|
||||
f.signature = '<span class="signature">'+(f.signature || '') + '</span>' + '<span class="type-signature">'+(returnTypes.length? ' → {'+returnTypes.join('|')+'}' : '')+'</span>';
|
||||
f.signature = '<span class="signature">' + (f.signature || '') + '</span>' +
|
||||
'<span class="type-signature">' +
|
||||
(returnTypes && returnTypes.length ? ' → {' + returnTypes.join('|') + '}' : '') +
|
||||
'</span>';
|
||||
}
|
||||
|
||||
function addSignatureTypes(f) {
|
||||
@ -78,7 +81,9 @@ function addSignatureTypes(f) {
|
||||
function addAttribs(f) {
|
||||
var attribs = helper.getAttribs(f);
|
||||
|
||||
f.attribs = '<span class="type-signature">'+htmlsafe(attribs.length? '<'+attribs.join(', ')+'> ' : '')+'</span>';
|
||||
f.attribs = '<span class="type-signature">' + htmlsafe(attribs.length ?
|
||||
// we want the template output to say 'abstract', not 'virtual'
|
||||
'<' + attribs.join(', ').replace('virtual', 'abstract') + '> ' : '') + '</span>';
|
||||
}
|
||||
|
||||
function shortenPaths(files, commonPrefix) {
|
||||
@ -127,7 +132,8 @@ function generate(title, docs, filename, resolveLinks) {
|
||||
fs.writeFileSync(outpath, html, 'utf8');
|
||||
}
|
||||
|
||||
function generateSourceFiles(sourceFiles) {
|
||||
function generateSourceFiles(sourceFiles, encoding) {
|
||||
encoding = encoding || 'utf8';
|
||||
Object.keys(sourceFiles).forEach(function(file) {
|
||||
var source;
|
||||
// links are keyed to the shortened path in each doclet's `meta.filename` property
|
||||
@ -137,7 +143,7 @@ function generateSourceFiles(sourceFiles) {
|
||||
try {
|
||||
source = {
|
||||
kind: 'source',
|
||||
code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, 'utf8') )
|
||||
code: helper.htmlsafe( fs.readFileSync(sourceFiles[file].resolved, encoding) )
|
||||
};
|
||||
}
|
||||
catch(e) {
|
||||
@ -478,10 +484,10 @@ exports.publish = function(taffyData, opts, tutorials) {
|
||||
attachModuleSymbols( find({ kind: ['class', 'function'], longname: {left: 'module:'} }),
|
||||
members.modules );
|
||||
|
||||
// only output pretty-printed source files if requested; do this before generating any other
|
||||
// pages, so the other pages can link to the source files
|
||||
if (conf['default'].outputSourceFiles) {
|
||||
generateSourceFiles(sourceFiles);
|
||||
// output pretty-printed source files by default; do this before generating any other pages, so
|
||||
// that the other pages can link to the source files
|
||||
if (!conf['default'] || conf['default'].outputSourceFiles !== false) {
|
||||
generateSourceFiles(sourceFiles, opts.encoding);
|
||||
}
|
||||
|
||||
if (members.globals.length) { generate('Global', [{kind: 'globalobj'}], globalUrl); }
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
numbered = source.innerHTML.split('\n');
|
||||
numbered = numbered.map(function(item) {
|
||||
counter++;
|
||||
return '<span id="line' + counter + '"></span>' + item;
|
||||
return '<span id="line' + counter + '" class="line"></span>' + item;
|
||||
});
|
||||
|
||||
source.innerHTML = numbered.join('\n');
|
||||
|
||||
@ -242,6 +242,11 @@ h6
|
||||
border-left: 3px #ddd solid;
|
||||
}
|
||||
|
||||
.prettyprint code span.line
|
||||
{
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.params, .props
|
||||
{
|
||||
border-spacing: 0;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<?js
|
||||
var data = obj;
|
||||
var data = obj || {};
|
||||
if (data.description) {
|
||||
?>
|
||||
<div class="param-desc">
|
||||
|
||||
21
test/fixtures/augmentstag4.js
vendored
Normal file
21
test/fixtures/augmentstag4.js
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
// used to test jsdoc/augments module directly
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @classdesc Base class
|
||||
*/
|
||||
var Base = function() {
|
||||
/** member */
|
||||
this.test1 = "base";
|
||||
/** another member */
|
||||
this.test2 = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @extends Base
|
||||
* @classdesc Extension of Base
|
||||
*/
|
||||
var Derived = function() {
|
||||
this.test1 = "derived";
|
||||
};
|
||||
17
test/fixtures/letkeyword.js
vendored
Normal file
17
test/fixtures/letkeyword.js
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
/*global define: true */
|
||||
define( [], function() {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* My example module.
|
||||
* @exports exampleModule
|
||||
*/
|
||||
let myModule = {
|
||||
/**
|
||||
* My example method.
|
||||
*/
|
||||
exampleMethod: function() {}
|
||||
};
|
||||
|
||||
return myModule;
|
||||
} );
|
||||
9
test/fixtures/paramtaginvalidtype.js
vendored
Normal file
9
test/fixtures/paramtaginvalidtype.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
var Test = function () {};
|
||||
|
||||
/**
|
||||
* @param {string, number} a
|
||||
*/
|
||||
Test.prototype.test = function (a) {};
|
||||
18
test/fixtures/requirestag.js
vendored
18
test/fixtures/requirestag.js
vendored
@ -1,12 +1,20 @@
|
||||
/**
|
||||
* @requires module:foo/helper
|
||||
*/
|
||||
* @requires module:foo/helper
|
||||
*/
|
||||
function foo() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires foo
|
||||
* @requires Pez#blat this text is ignored
|
||||
*/
|
||||
* @requires foo
|
||||
* @requires Pez#blat this text is ignored
|
||||
*/
|
||||
function bar() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires {@link module:zest}
|
||||
* @requires {@linkplain module:zing}
|
||||
* @requires {@linkstupid module:pizzazz}
|
||||
*/
|
||||
function baz() {
|
||||
}
|
||||
|
||||
8
test/fixtures/returnstag.js
vendored
8
test/fixtures/returnstag.js
vendored
@ -9,3 +9,11 @@ function find(targetName) {
|
||||
*/
|
||||
function bind(callback) {
|
||||
}
|
||||
|
||||
// This test exists because there used to be a bug in jsdoc which
|
||||
// would cause it to fail parsing.
|
||||
/**
|
||||
* @return An object to be passed to {@link find}.
|
||||
*/
|
||||
function convert(name) {
|
||||
}
|
||||
|
||||
14
test/fixtures/typetagwithnewline.js
vendored
Normal file
14
test/fixtures/typetagwithnewline.js
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
/** @class Matryoshka */
|
||||
function Matryoshka() {}
|
||||
|
||||
/**
|
||||
* @type {(!Array.<number>|
|
||||
* !Array.<!Array.<number>>)}
|
||||
*/
|
||||
Matryoshka.mini;
|
||||
|
||||
/**
|
||||
* @type (!Array.<number>|!Array.<!Array.<number>>|
|
||||
* !Array.<!Array.<!Array.<number>>>)
|
||||
*/
|
||||
Matryoshka.mega;
|
||||
@ -27,7 +27,7 @@ describe("aliases", function() {
|
||||
expect(foundMember[0].scope).toEqual('instance');
|
||||
});
|
||||
|
||||
it('When a symbol is a member of an aliased class, a this-variables is documented as if it were a member that class.', function() {
|
||||
it('When a symbol is a member of an aliased class, a this-variable is documented as if it were a member that class.', function() {
|
||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/alias3.js');
|
||||
var tcm = docSet.getByLongname('trackr.CookieManager')[0];
|
||||
var tcmValue = docSet.getByLongname('trackr.CookieManager#value')[0];
|
||||
|
||||
28
test/specs/documentation/letkeyword.js
Normal file
28
test/specs/documentation/letkeyword.js
Normal file
@ -0,0 +1,28 @@
|
||||
/*global describe: true, expect: true, it: true, jasmine: true */
|
||||
describe('let keyword', function() {
|
||||
var docSet;
|
||||
var exampleModule;
|
||||
var exampleMethod;
|
||||
|
||||
function getDocSet() {
|
||||
docSet = jasmine.getDocSetFromFile('test/fixtures/letkeyword.js');
|
||||
exampleModule = docSet.getByLongname('module:exampleModule');
|
||||
exampleMethod = docSet.getByLongname('module:exampleModule.exampleMethod');
|
||||
}
|
||||
|
||||
it('should be able to compile JS files that contain the "let" keyword', function() {
|
||||
expect(getDocSet).not.toThrow();
|
||||
});
|
||||
|
||||
it('should correctly recognize a module defined with the "let" keyword', function() {
|
||||
expect(exampleModule).toBeDefined();
|
||||
expect( Array.isArray(exampleModule) ).toBe(true);
|
||||
expect(exampleModule.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should correctly recognize members of a module defined with the "let" keyword', function() {
|
||||
expect(exampleMethod).toBeDefined();
|
||||
expect( Array.isArray(exampleMethod) ).toBe(true);
|
||||
expect(exampleMethod.length).toBe(1);
|
||||
});
|
||||
});
|
||||
@ -1,16 +1,23 @@
|
||||
/*global beforeEach: true, describe: true, env: true, expect: true, it: true */
|
||||
/*global afterEach: true, beforeEach: true, describe: true, env: true, expect: true, it: true */
|
||||
describe("module names", function() {
|
||||
var runtime = require('jsdoc/util/runtime');
|
||||
var parser = require( runtime.getModulePath('jsdoc/src/parser') );
|
||||
var srcParser = null;
|
||||
|
||||
var doclets;
|
||||
|
||||
var parser = require( runtime.getModulePath('jsdoc/src/parser') );
|
||||
var srcParser = null;
|
||||
var sourcePaths = env.opts._.slice(0);
|
||||
|
||||
beforeEach(function() {
|
||||
env.opts._ = [__dirname + '/test/fixtures/modules/'];
|
||||
env.opts._ = [__dirname + '/test/fixtures/modules/data/'];
|
||||
srcParser = new parser.Parser();
|
||||
require('jsdoc/src/handlers').attachTo(srcParser);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
env.opts._ = sourcePaths;
|
||||
});
|
||||
|
||||
it("should create a name from the file path when no documented module name exists", function() {
|
||||
doclets = srcParser.parse(__dirname + '/test/fixtures/modules/data/mod-1.js');
|
||||
expect(doclets.length).toBeGreaterThan(1);
|
||||
|
||||
28
test/specs/documentation/typetagwithnewline.js
Normal file
28
test/specs/documentation/typetagwithnewline.js
Normal file
@ -0,0 +1,28 @@
|
||||
/*global describe: true, expect: true, it: true, jasmine: true */
|
||||
|
||||
describe('@type tag containing a newline character', function() {
|
||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/typetagwithnewline.js');
|
||||
var mini = docSet.getByLongname('Matryoshka.mini')[0];
|
||||
var mega = docSet.getByLongname('Matryoshka.mega')[0];
|
||||
|
||||
it('When the type expression for a @type tag contains a newline character and is not ' +
|
||||
'enclosed in braces, the type expression is parsed correctly.', function() {
|
||||
expect(mini).toBeDefined();
|
||||
expect(mini.type).toBeDefined();
|
||||
expect(mini.type.names).toBeDefined();
|
||||
expect(mini.type.names.length).toBe(2);
|
||||
expect(mini.type.names[0]).toBe('!Array.<number>');
|
||||
expect(mini.type.names[1]).toBe('!Array.<!Array.<number>>');
|
||||
});
|
||||
|
||||
it('When the type expression for a @type tag contains a newline character and is enclosed ' +
|
||||
'in braces, the type expression is parsed correctly.', function() {
|
||||
expect(mega).toBeDefined();
|
||||
expect(mega.type).toBeDefined();
|
||||
expect(mega.type.names).toBeDefined();
|
||||
expect(mega.type.names.length).toBe(3);
|
||||
expect(mega.type.names[0]).toBe('!Array.<number>');
|
||||
expect(mega.type.names[1]).toBe('!Array.<!Array.<number>>');
|
||||
expect(mega.type.names[2]).toBe('!Array.<!Array.<!Array.<number>>>');
|
||||
});
|
||||
});
|
||||
@ -85,7 +85,7 @@ describe("jsdoc/name", function() {
|
||||
expect(parts.memberof).toEqual('channels."#ops"');
|
||||
expect(parts.scope).toEqual('#');
|
||||
|
||||
startName = 'channels["#bots"]["log.max"]',
|
||||
startName = 'channels["#bots"]["log.max"]';
|
||||
parts = jsdoc.name.shorten(startName);
|
||||
|
||||
expect(parts.name).toEqual('"log.max"');
|
||||
@ -174,20 +174,37 @@ describe("jsdoc/name", function() {
|
||||
expect(parts.name, 'ns.Page#"last \\"sentence\\"".words~sort(2)');
|
||||
expect(parts.description, 'This is a description.');
|
||||
});
|
||||
|
||||
it('should strip the separator when the separator starts on the same line as the name', function() {
|
||||
var startName = 'socket - The networking kind, not the wrench.';
|
||||
var parts = jsdoc.name.splitName(startName);
|
||||
|
||||
expect(parts.name).toBe('socket');
|
||||
expect(parts.description).toBe('The networking kind, not the wrench.');
|
||||
});
|
||||
|
||||
it('should not strip a separator that is preceded by a line break', function() {
|
||||
var startName = 'socket\n - The networking kind, not the wrench.';
|
||||
var parts = jsdoc.name.splitName(startName);
|
||||
|
||||
expect(parts.name).toBe('socket');
|
||||
expect(parts.description).toBe('- The networking kind, not the wrench.');
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolve", function() {
|
||||
// TODO: further tests (namespaces, modules, ...)
|
||||
|
||||
// @event testing.
|
||||
var event = '@event';
|
||||
var memberOf = '@memberof MyClass';
|
||||
var name = '@name A';
|
||||
function makeDoclet(bits) {
|
||||
var comment = '/**\n' + bits.join('\n') + '\n*/';
|
||||
return new jsdoc.doclet.Doclet(comment, {});
|
||||
}
|
||||
|
||||
// @event testing.
|
||||
var event = '@event';
|
||||
var memberOf = '@memberof MyClass';
|
||||
var name = '@name A';
|
||||
|
||||
// Test the basic @event that is not nested.
|
||||
it('unnested @event gets resolved correctly', function() {
|
||||
var doclet = makeDoclet([event, name]),
|
||||
@ -274,12 +291,23 @@ describe("jsdoc/name", function() {
|
||||
});
|
||||
|
||||
// a double-nested one just in case
|
||||
it('@event @name MyClass.EventName @memberof somethingelse workse', function() {
|
||||
it('@event @name MyClass.EventName @memberof somethingelse works', function() {
|
||||
var doclet = makeDoclet([event, '@name MyClass.A', '@memberof MyNamespace']),
|
||||
out = jsdoc.name.resolve(doclet);
|
||||
expect(doclet.name).toEqual('A');
|
||||
expect(doclet.memberof).toEqual('MyNamespace.MyClass');
|
||||
expect(doclet.longname).toEqual('MyNamespace.MyClass.event:A');
|
||||
});
|
||||
|
||||
// other cases
|
||||
it('correctly handles a function parameter named "prototype"', function() {
|
||||
var doclet = makeDoclet(['@name Bar.prototype.baz', '@function', '@memberof module:foo',
|
||||
'@param {string} qux']);
|
||||
var out = jsdoc.name.resolve(doclet);
|
||||
|
||||
expect(doclet.name).toBe('baz');
|
||||
expect(doclet.memberof).toBe('module:foo.Bar');
|
||||
expect(doclet.longname).toBe('module:foo.Bar#baz');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -191,11 +191,25 @@ describe("jsdoc/src/parser", function() {
|
||||
});
|
||||
|
||||
it("should fire 'parseComplete' events after it finishes parsing files", function() {
|
||||
var eventObject;
|
||||
|
||||
var spy = jasmine.createSpy(),
|
||||
sourceCode = ['javascript:var bar = false;'];
|
||||
sourceCode = ['javascript:/** @class */function Foo() {}'];
|
||||
|
||||
require('jsdoc/src/handlers').attachTo(parser);
|
||||
parser.on('parseComplete', spy).parse(sourceCode);
|
||||
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(spy.mostRecentCall.args[0].sourcefiles).toEqual(["[[string0]]"]);
|
||||
|
||||
eventObject = spy.mostRecentCall.args[0];
|
||||
expect(eventObject).toBeDefined();
|
||||
expect( Array.isArray(eventObject.sourcefiles) ).toBe(true);
|
||||
expect(eventObject.sourcefiles.length).toBe(1);
|
||||
expect(eventObject.sourcefiles[0]).toBe('[[string0]]');
|
||||
expect( Array.isArray(eventObject.doclets) ).toBe(true);
|
||||
expect(eventObject.doclets.length).toBe(1);
|
||||
expect(eventObject.doclets[0].kind).toBe('class');
|
||||
expect(eventObject.doclets[0].longname).toBe('Foo');
|
||||
});
|
||||
|
||||
it("should fire processingComplete when fireProcessingComplete is called", function() {
|
||||
@ -219,6 +233,16 @@ describe("jsdoc/src/parser", function() {
|
||||
|
||||
expect(parse).not.toThrow();
|
||||
});
|
||||
|
||||
it("should comment out a POSIX hashbang at the start of the file", function() {
|
||||
function parse() {
|
||||
parser.parse(parserSrc);
|
||||
}
|
||||
|
||||
var parserSrc = 'javascript:#!/usr/bin/env node\n/** class */function Foo() {}';
|
||||
|
||||
expect(parse).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('results', function() {
|
||||
|
||||
@ -12,6 +12,11 @@ describe('jsdoc/tag/inline', function() {
|
||||
expect(typeof jsdoc.tag.inline).toBe('object');
|
||||
});
|
||||
|
||||
it('should export an isInlineTag function', function() {
|
||||
expect(jsdoc.tag.inline.isInlineTag).toBeDefined();
|
||||
expect(typeof jsdoc.tag.inline.isInlineTag).toBe('function');
|
||||
});
|
||||
|
||||
it('should export a replaceInlineTag function', function() {
|
||||
expect(jsdoc.tag.inline.replaceInlineTag).toBeDefined();
|
||||
expect(typeof jsdoc.tag.inline.replaceInlineTag).toBe('function');
|
||||
@ -22,6 +27,43 @@ describe('jsdoc/tag/inline', function() {
|
||||
expect(typeof jsdoc.tag.inline.replaceInlineTag).toBe('function');
|
||||
});
|
||||
|
||||
describe('isInlineTag', function() {
|
||||
var isInlineTag = jsdoc.tag.inline.isInlineTag;
|
||||
|
||||
it('should correctly identify an inline tag', function() {
|
||||
expect( isInlineTag('{@mytag hooray}', 'mytag') ).toBe(true);
|
||||
});
|
||||
|
||||
it('should correctly identify a non-inline tag', function() {
|
||||
expect( isInlineTag('mytag hooray', 'mytag') ).toBe(false);
|
||||
});
|
||||
|
||||
it('should report that a string containing an inline tag is not an inline tag', function() {
|
||||
expect( isInlineTag('this is {@mytag hooray}', 'mytag') ).toBe(false);
|
||||
});
|
||||
|
||||
it('should default to allowing any inline tag', function() {
|
||||
expect( isInlineTag('{@anyoldtag will do}') ).toBe(true);
|
||||
});
|
||||
|
||||
it('should still identify non-inline tags when a tag name is not provided', function() {
|
||||
expect( isInlineTag('mytag hooray') ).toBe(false);
|
||||
});
|
||||
|
||||
it('should allow regexp characters in the tag name', function() {
|
||||
expect( isInlineTag('{@mytags hooray}', 'mytag\\S') ).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false (rather than throwing) with invalid input', function() {
|
||||
function badInput() {
|
||||
return isInlineTag({});
|
||||
}
|
||||
|
||||
expect(badInput).not.toThrow();
|
||||
expect( badInput() ).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('replaceInlineTag', function() {
|
||||
it('should throw if the tag is matched and the replacer is invalid', function() {
|
||||
function badReplacerUndefined() {
|
||||
|
||||
@ -737,6 +737,23 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
|
||||
delete helper.longnameToUrl.MyClass;
|
||||
});
|
||||
|
||||
it("doesn't throw an error in lenient mode if a 'returns' item has no value", function() {
|
||||
function getReturns() {
|
||||
return helper.getSignatureReturns(doc);
|
||||
}
|
||||
|
||||
var doc;
|
||||
var lenient = !!env.opts.lenient;
|
||||
|
||||
env.opts.lenient = true;
|
||||
spyOn(console, 'log');
|
||||
doc = new doclet.Doclet('/** @function myFunction\n@returns */', {});
|
||||
|
||||
expect(getReturns).not.toThrow();
|
||||
|
||||
env.opts.lenient = lenient;
|
||||
});
|
||||
});
|
||||
|
||||
describe("getAncestorLinks", function() {
|
||||
@ -1094,6 +1111,20 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
expect(output).toBe('This is a <a href="path/to/test.html">hello there</a>.');
|
||||
});
|
||||
|
||||
it('should translate [dummy text] and [hello there]{@link test} into an HTML link with the custom content.', function() {
|
||||
var input = 'This is [dummy text] and [hello there]{@link test}.',
|
||||
output = helper.resolveLinks(input);
|
||||
|
||||
expect(output).toBe('This is [dummy text] and <a href="path/to/test.html">hello there</a>.');
|
||||
});
|
||||
|
||||
it('should translate [dummy text] and [more] and [hello there]{@link test} into an HTML link with the custom content.', function() {
|
||||
var input = 'This is [dummy text] and [more] and [hello there]{@link test}.',
|
||||
output = helper.resolveLinks(input);
|
||||
|
||||
expect(output).toBe('This is [dummy text] and [more] and <a href="path/to/test.html">hello there</a>.');
|
||||
});
|
||||
|
||||
it('should ignore [hello there].', function() {
|
||||
var input = 'This is a [hello there].',
|
||||
output = helper.resolveLinks(input);
|
||||
@ -1342,6 +1373,58 @@ describe("jsdoc/util/templateHelper", function() {
|
||||
|
||||
expect(url).toEqual('module-bar.html');
|
||||
});
|
||||
|
||||
it('should create a url for a doclet with the wrong kind (caused by incorrect JSDoc tags', function() {
|
||||
var moduleDoclet = {
|
||||
kind: 'module',
|
||||
longname: 'module:baz',
|
||||
name: 'module:baz'
|
||||
};
|
||||
var badDoclet = {
|
||||
kind: 'member',
|
||||
longname: 'module:baz',
|
||||
name: 'module:baz'
|
||||
};
|
||||
|
||||
var moduleDocletUrl = helper.createLink(moduleDoclet);
|
||||
var badDocletUrl = helper.createLink(badDoclet);
|
||||
|
||||
expect(moduleDocletUrl).toBe('module-baz.html');
|
||||
expect(badDocletUrl).toBe('module-baz.html');
|
||||
});
|
||||
|
||||
it('should create a url for a function that is a member of a doclet with the wrong kind', function() {
|
||||
var badModuleDoclet = {
|
||||
kind: 'member',
|
||||
longname: 'module:qux',
|
||||
name: 'module:qux'
|
||||
};
|
||||
var memberDoclet = {
|
||||
kind: 'function',
|
||||
name: 'frozzle',
|
||||
memberof: 'module:qux',
|
||||
scope: 'instance',
|
||||
longname: 'module:qux#frozzle'
|
||||
};
|
||||
|
||||
var badModuleDocletUrl = helper.createLink(badModuleDoclet);
|
||||
var memberDocletUrl = helper.createLink(memberDoclet);
|
||||
|
||||
expect(badModuleDocletUrl).toBe('module-qux.html');
|
||||
expect(memberDocletUrl).toBe('module-qux.html#frozzle');
|
||||
});
|
||||
|
||||
it('should create a url for an empty package definition', function() {
|
||||
var packageDoclet = {
|
||||
kind: 'package',
|
||||
name: undefined,
|
||||
longname: 'package:undefined'
|
||||
};
|
||||
|
||||
var packageDocletUrl = helper.createLink(packageDoclet);
|
||||
|
||||
expect(packageDocletUrl).toBe('global.html');
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveAuthorLinks", function() {
|
||||
|
||||
@ -1,65 +1,54 @@
|
||||
/*global describe: true, expect: true, it: true, jasmine: true */
|
||||
describe("@augments tag", function() {
|
||||
/*jshint unused: false */
|
||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/augmentstag.js');
|
||||
var foo = docSet.getByLongname('Foo')[0];
|
||||
var fooProp1 = docSet.getByLongname('Foo#prop1')[0];
|
||||
var fooProp2 = docSet.getByLongname('Foo#prop2')[0];
|
||||
var fooProp3 = docSet.getByLongname('Foo#prop3')[0];
|
||||
var fooMethod1 = docSet.getByLongname('Foo#method1')[0];
|
||||
var fooMethod2 = docSet.getByLongname('Foo#method2')[0];
|
||||
var bar = docSet.getByLongname('Bar')[0];
|
||||
var barProp1 = docSet.getByLongname('Bar#prop1')[0];
|
||||
var barProp2 = docSet.getByLongname('Bar#prop2')[0];
|
||||
var barProp3 = docSet.getByLongname('Bar#prop3')[0];
|
||||
var barMethod1 = docSet.getByLongname('Bar#method1')[0];
|
||||
var barMethod2 = docSet.getByLongname('Bar#method2')[0];
|
||||
var barMethod2All = docSet.getByLongname('Bar#method2');
|
||||
var bazProp1 = docSet.getByLongname('Baz#prop1')[0];
|
||||
var bazProp1All = docSet.getByLongname('Baz#prop1');
|
||||
var bazProp2 = docSet.getByLongname('Baz#prop2')[0];
|
||||
var bazProp3 = docSet.getByLongname('Baz#prop3')[0];
|
||||
var bazMethod1 = docSet.getByLongname('Baz#method1')[0];
|
||||
var bazMethod2 = docSet.getByLongname('Baz#method2')[0];
|
||||
var bazMethod3 = docSet.getByLongname('Baz#method3')[0];
|
||||
|
||||
var docSet2 = jasmine.getDocSetFromFile('test/fixtures/augmentstag2.js');
|
||||
var qux = docSet2.getByLongname('Qux')[0];
|
||||
|
||||
var docSet3 = jasmine.getDocSetFromFile('test/fixtures/augmentstag3.js');
|
||||
var FooMethod1 = docSet3.getByLongname('Foo#method1')[0];
|
||||
var BarMethod2 = docSet3.getByLongname('Bar#method2')[0];
|
||||
var FooBarMethod1 = docSet3.getByLongname('FooBar#method1')[0];
|
||||
var FooBarMethod2 = docSet3.getByLongname('FooBar#method2')[0];
|
||||
var docSet4 = jasmine.getDocSetFromFile('test/fixtures/augmentstag4.js');
|
||||
|
||||
it('When a symbol has an @augments tag, the doclet has a augments property that includes that value.', function() {
|
||||
var bar = docSet.getByLongname('Bar')[0];
|
||||
|
||||
expect(typeof bar.augments).toBe('object');
|
||||
expect(bar.augments[0]).toBe('Foo');
|
||||
});
|
||||
|
||||
it('When an object is extended, the original is not modified', function() {
|
||||
var fooProp3 = docSet.getByLongname('Foo#prop3')[0];
|
||||
|
||||
expect(fooProp3).toBeUndefined();
|
||||
});
|
||||
|
||||
it('When an object is extended, it inherits properties set in parent constructor', function() {
|
||||
var fooProp1 = docSet.getByLongname('Foo#prop1')[0];
|
||||
var barProp1 = docSet.getByLongname('Bar#prop1')[0];
|
||||
|
||||
expect(fooProp1.memberof).toBe("Foo");
|
||||
expect(barProp1.memberof).toBe("Bar");
|
||||
expect(barProp1.description).toBe(fooProp1.description);
|
||||
});
|
||||
|
||||
it('When an object is extended, it inherits properties set on parent prototype', function() {
|
||||
var fooProp2 = docSet.getByLongname('Foo#prop2')[0];
|
||||
var barProp2 = docSet.getByLongname('Bar#prop2')[0];
|
||||
|
||||
expect(fooProp2.memberof).toBe("Foo");
|
||||
expect(barProp2.memberof).toBe("Bar");
|
||||
expect(barProp2.description).toBe(fooProp2.description);
|
||||
});
|
||||
|
||||
it('When an object is extended, it inherits methods set on parent prototype', function() {
|
||||
var fooMethod1 = docSet.getByLongname('Foo#method1')[0];
|
||||
var barMethod1 = docSet.getByLongname('Bar#method1')[0];
|
||||
|
||||
expect(fooMethod1.memberof).toBe("Foo");
|
||||
expect(barMethod1.memberof).toBe("Bar");
|
||||
expect(barMethod1.description).toBe(fooMethod1.description);
|
||||
});
|
||||
|
||||
it('When an object is extended, it may override methods set on parent prototype', function() {
|
||||
var fooMethod2 = docSet.getByLongname('Foo#method2')[0];
|
||||
var barMethod2 = docSet.getByLongname('Bar#method2')[0];
|
||||
|
||||
expect(fooMethod2.memberof).toBe("Foo");
|
||||
expect(fooMethod2.description).toBe("Second parent method.");
|
||||
expect(barMethod2.memberof).toBe("Bar");
|
||||
@ -67,10 +56,19 @@
|
||||
});
|
||||
|
||||
it('When an object is extended, and it overrides an ancestor method, the child does not include docs for the ancestor method.', function() {
|
||||
var barMethod2All = docSet.getByLongname('Bar#method2');
|
||||
|
||||
expect(barMethod2All.length).toBe(1);
|
||||
});
|
||||
|
||||
it('When an object is extended, it inherits properties set on grandparent prototype', function() {
|
||||
var fooProp1 = docSet.getByLongname('Foo#prop1')[0];
|
||||
var barProp1 = docSet.getByLongname('Bar#prop1')[0];
|
||||
var bazProp1 = docSet.getByLongname('Baz#prop1')[0];
|
||||
var bazMethod1 = docSet.getByLongname('Baz#method1')[0];
|
||||
var bazMethod2 = docSet.getByLongname('Baz#method2')[0];
|
||||
var bazMethod3 = docSet.getByLongname('Baz#method3')[0];
|
||||
|
||||
expect(fooProp1.memberof).toBe("Foo");
|
||||
expect(barProp1.memberof).toBe("Bar");
|
||||
expect(bazProp1.memberof).toBe("Baz");
|
||||
@ -81,28 +79,54 @@
|
||||
});
|
||||
|
||||
it('(Grand)children correctly identify the original source of inherited members', function(){
|
||||
expect(fooProp1.inherits).not.toBeDefined();
|
||||
expect(barProp3.inherits).not.toBeDefined();
|
||||
expect(barProp1.inherits).toBe("Foo#prop1");
|
||||
expect(bazProp2.inherits).toBe("Foo#prop2");
|
||||
expect(bazProp3.inherits).toBe("Bar#prop3");
|
||||
expect(bazMethod1.inherits).toBe("Foo#method1");
|
||||
var fooProp1 = docSet.getByLongname('Foo#prop1')[0];
|
||||
var barProp1 = docSet.getByLongname('Bar#prop1')[0];
|
||||
var barProp3 = docSet.getByLongname('Bar#prop3')[0];
|
||||
var bazProp2 = docSet.getByLongname('Baz#prop2')[0];
|
||||
var bazProp3 = docSet.getByLongname('Baz#prop3')[0];
|
||||
var bazMethod1 = docSet.getByLongname('Baz#method1')[0];
|
||||
|
||||
expect(fooProp1.inherits).not.toBeDefined();
|
||||
expect(barProp3.inherits).not.toBeDefined();
|
||||
expect(barProp1.inherits).toBe("Foo#prop1");
|
||||
expect(bazProp2.inherits).toBe("Foo#prop2");
|
||||
expect(bazProp3.inherits).toBe("Bar#prop3");
|
||||
expect(bazMethod1.inherits).toBe("Foo#method1");
|
||||
});
|
||||
|
||||
it('When an object is extended, and it overrides an ancestor property, the child does not include docs for the ancestor property.', function() {
|
||||
var bazProp1All = docSet.getByLongname('Baz#prop1');
|
||||
|
||||
expect(bazProp1All.length).toBe(1);
|
||||
});
|
||||
|
||||
it('When a symbol has an @augments tag, and the parent is not documented, the doclet still has an augments property', function() {
|
||||
var qux = docSet2.getByLongname('Qux')[0];
|
||||
|
||||
expect(typeof qux.augments).toBe('object');
|
||||
expect(qux.augments[0]).toBe('UndocumentedThing');
|
||||
});
|
||||
|
||||
|
||||
it('When a symbol @augments multiple parents, it inherits methods from all parents', function() {
|
||||
expect(FooBarMethod1).toBeDefined();
|
||||
expect(FooBarMethod2).toBeDefined();
|
||||
expect(FooBarMethod1.description).toBe(FooMethod1.description);
|
||||
expect(FooBarMethod2.description).toBe(BarMethod2.description);
|
||||
var fooMethod1 = docSet3.getByLongname('Foo#method1')[0];
|
||||
var barMethod2 = docSet3.getByLongname('Bar#method2')[0];
|
||||
var fooBarMethod1 = docSet3.getByLongname('FooBar#method1')[0];
|
||||
var fooBarMethod2 = docSet3.getByLongname('FooBar#method2')[0];
|
||||
|
||||
expect(fooBarMethod1).toBeDefined();
|
||||
expect(fooBarMethod2).toBeDefined();
|
||||
expect(fooBarMethod1.description).toBe(fooMethod1.description);
|
||||
expect(fooBarMethod2.description).toBe(barMethod2.description);
|
||||
});
|
||||
|
||||
it('When a symbol overrides an inherited method without documenting the method, it uses the parent\'s docs', function() {
|
||||
var baseMethod1 = docSet4.getByLongname('Base#test1')[0];
|
||||
var derivedMethod1All = docSet4.getByLongname('Derived#test1');
|
||||
var derivedMethod1 = derivedMethod1All[1];
|
||||
|
||||
expect(derivedMethod1All.length).toBe(2);
|
||||
expect(derivedMethod1.undocumented).not.toBe(true);
|
||||
expect(derivedMethod1.description).toBe(baseMethod1.description);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,19 +1,32 @@
|
||||
/*global describe: true, env: true, expect: true, it: true */
|
||||
/*global beforeEach: true, afterEach: true, describe: true, env: true, expect: true, it: true */
|
||||
|
||||
describe("@overview tag", function() {
|
||||
var parser = require('jsdoc/src/parser');
|
||||
var runtime = require('jsdoc/util/runtime');
|
||||
var parser = require( runtime.getModulePath('jsdoc/src/parser') );
|
||||
var srcParser = new parser.Parser();
|
||||
|
||||
var doclets;
|
||||
|
||||
require('jsdoc/src/handlers').attachTo(srcParser);
|
||||
doclets = srcParser.parse(__dirname + '/test/fixtures/file.js');
|
||||
var parser = require( runtime.getModulePath('jsdoc/src/parser') );
|
||||
var srcParser = null;
|
||||
var sourcePaths = env.opts._.slice(0);
|
||||
|
||||
beforeEach(function() {
|
||||
env.opts._ = [__dirname + '/test/fixtures/'];
|
||||
srcParser = new parser.Parser();
|
||||
require('jsdoc/src/handlers').attachTo(srcParser);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
env.opts._ = sourcePaths;
|
||||
});
|
||||
|
||||
it('When a file overview tag appears in a doclet, the name of the doclet should contain the path to the file.', function() {
|
||||
doclets = srcParser.parse(__dirname + '/test/fixtures/file.js');
|
||||
expect(doclets[0].name).toMatch(/^(fixtures[\/\\]file\.js)$/);
|
||||
});
|
||||
|
||||
it("The name and longname should be equal", function() {
|
||||
doclets = srcParser.parse(__dirname + '/test/fixtures/file.js');
|
||||
expect(doclets[0].name).toBe(doclets[0].longname);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
/*global describe: true, env: true, expect: true, it: true, jasmine: true, spyOn: true */
|
||||
describe("@param tag", function() {
|
||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/paramtag.js'),
|
||||
find = docSet.getByLongname('find')[0],
|
||||
@ -77,4 +78,28 @@ describe("@param tag", function() {
|
||||
expect(commit.params[0].name).toBe('atomic');
|
||||
});
|
||||
|
||||
it('When a symbol has a @param tag with an invalid type expression, the doclet is generated in lenient mode, and the JSDoc comment is ignored.', function() {
|
||||
var badDocSet;
|
||||
var test;
|
||||
var lenient = !!env.opts.lenient;
|
||||
|
||||
env.opts.lenient = true;
|
||||
spyOn(console, 'log');
|
||||
|
||||
badDocSet = jasmine.getDocSetFromFile('test/fixtures/paramtaginvalidtype.js');
|
||||
test = badDocSet.getByLongname('Test#test')[0];
|
||||
|
||||
expect(test).toBeDefined();
|
||||
expect(typeof test).toBe('object');
|
||||
|
||||
expect(test.meta).toBeDefined();
|
||||
expect(typeof test.meta).toBe('object');
|
||||
|
||||
expect(test.meta.filename).toBeDefined();
|
||||
expect(test.meta.filename).toBe('[[string0]]');
|
||||
|
||||
expect(test.description).not.toBeDefined();
|
||||
|
||||
env.opts.lenient = lenient;
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,14 +1,24 @@
|
||||
/*global describe: true, expect: true, it: true, jasmine: true */
|
||||
describe("@requires tag", function() {
|
||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/requirestag.js'),
|
||||
foo = docSet.getByLongname('foo')[0],
|
||||
bar = docSet.getByLongname('bar')[0];
|
||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/requirestag.js');
|
||||
var foo = docSet.getByLongname('foo')[0];
|
||||
var bar = docSet.getByLongname('bar')[0];
|
||||
var baz = docSet.getByLongname('baz')[0];
|
||||
|
||||
it('When a symbol has an @requires tag, the doclet has a requires property that includes that value, with the "module:" namespace added.', function() {
|
||||
expect(typeof foo.requires).toBe('object');
|
||||
it('When a symbol has a @requires tag, the doclet has a requires property that includes that value, with the "module:" namespace added.', function() {
|
||||
expect( Array.isArray(foo.requires) ).toBe(true);
|
||||
expect(foo.requires[0]).toBe('module:foo/helper');
|
||||
|
||||
expect(typeof bar.requires).toBe('object');
|
||||
expect( Array.isArray(bar.requires) ).toBe(true);
|
||||
expect(bar.requires[0]).toBe('module:foo');
|
||||
expect(bar.requires[1]).toBe('module:Pez#blat');
|
||||
});
|
||||
});
|
||||
|
||||
it('When a symbol has a @requires tag whose value is an inline {@link} tag, the doclet has a requires property that includes that tag without modification.', function() {
|
||||
expect( Array.isArray(baz.requires) ).toBe(true);
|
||||
expect(baz.requires[0]).toBe('{@link module:zest}');
|
||||
expect(baz.requires[1]).toBe('{@linkplain module:zing}');
|
||||
// by design, we don't validate the tag name, as long as it starts with @link
|
||||
expect(baz.requires[2]).toBe('{@linkstupid module:pizzazz}');
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
describe("@returns tag", function() {
|
||||
var docSet = jasmine.getDocSetFromFile('test/fixtures/returnstag.js'),
|
||||
find = docSet.getByLongname('find')[0],
|
||||
bind = docSet.getByLongname('bind')[0];
|
||||
bind = docSet.getByLongname('bind')[0],
|
||||
convert = docSet.getByLongname('convert')[0];
|
||||
|
||||
it('When a symbol has an @returns tag with a type and description, the doclet has a returns array that includes that return.', function() {
|
||||
expect(typeof find.returns).toBe('object');
|
||||
@ -15,4 +16,10 @@ describe("@returns tag", function() {
|
||||
expect(bind.returns.length).toBe(1);
|
||||
expect(bind.returns[0].description).toBe('The binding id.');
|
||||
});
|
||||
|
||||
it('When a symbol has an @returns tag without a type but with an inline tag, the doclet does not confuse the inline tag for a type.', function() {
|
||||
expect(typeof convert.returns).toBe('object');
|
||||
expect(convert.returns.length).toBe(1);
|
||||
expect(convert.returns[0].description).toBe('An object to be passed to {@link find}.');
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user