Spaces:
Runtime error
Runtime error
/* | |
* @fileoverview Main Doctrine object | |
* @author Yusuke Suzuki <[email protected]> | |
* @author Dan Tao <[email protected]> | |
* @author Andrew Eisenberg <[email protected]> | |
*/ | |
(function () { | |
'use strict'; | |
var typed, | |
utility, | |
jsdoc, | |
esutils, | |
hasOwnProperty; | |
esutils = require('esutils'); | |
typed = require('./typed'); | |
utility = require('./utility'); | |
function sliceSource(source, index, last) { | |
return source.slice(index, last); | |
} | |
hasOwnProperty = (function () { | |
var func = Object.prototype.hasOwnProperty; | |
return function hasOwnProperty(obj, name) { | |
return func.call(obj, name); | |
}; | |
}()); | |
function shallowCopy(obj) { | |
var ret = {}, key; | |
for (key in obj) { | |
if (obj.hasOwnProperty(key)) { | |
ret[key] = obj[key]; | |
} | |
} | |
return ret; | |
} | |
function isASCIIAlphanumeric(ch) { | |
return (ch >= 0x61 /* 'a' */ && ch <= 0x7A /* 'z' */) || | |
(ch >= 0x41 /* 'A' */ && ch <= 0x5A /* 'Z' */) || | |
(ch >= 0x30 /* '0' */ && ch <= 0x39 /* '9' */); | |
} | |
function isParamTitle(title) { | |
return title === 'param' || title === 'argument' || title === 'arg'; | |
} | |
function isReturnTitle(title) { | |
return title === 'return' || title === 'returns'; | |
} | |
function isProperty(title) { | |
return title === 'property' || title === 'prop'; | |
} | |
function isNameParameterRequired(title) { | |
return isParamTitle(title) || isProperty(title) || | |
title === 'alias' || title === 'this' || title === 'mixes' || title === 'requires'; | |
} | |
function isAllowedName(title) { | |
return isNameParameterRequired(title) || title === 'const' || title === 'constant'; | |
} | |
function isAllowedNested(title) { | |
return isProperty(title) || isParamTitle(title); | |
} | |
function isAllowedOptional(title) { | |
return isProperty(title) || isParamTitle(title); | |
} | |
function isTypeParameterRequired(title) { | |
return isParamTitle(title) || isReturnTitle(title) || | |
title === 'define' || title === 'enum' || | |
title === 'implements' || title === 'this' || | |
title === 'type' || title === 'typedef' || isProperty(title); | |
} | |
// Consider deprecation instead using 'isTypeParameterRequired' and 'Rules' declaration to pick when a type is optional/required | |
// This would require changes to 'parseType' | |
function isAllowedType(title) { | |
return isTypeParameterRequired(title) || title === 'throws' || title === 'const' || title === 'constant' || | |
title === 'namespace' || title === 'member' || title === 'var' || title === 'module' || | |
title === 'constructor' || title === 'class' || title === 'extends' || title === 'augments' || | |
title === 'public' || title === 'private' || title === 'protected'; | |
} | |
// A regex character class that contains all whitespace except linebreak characters (\r, \n, \u2028, \u2029) | |
var WHITESPACE = '[ \\f\\t\\v\\u00a0\\u1680\\u180e\\u2000-\\u200a\\u202f\\u205f\\u3000\\ufeff]'; | |
var STAR_MATCHER = '(' + WHITESPACE + '*(?:\\*' + WHITESPACE + '?)?)(.+|[\r\n\u2028\u2029])'; | |
function unwrapComment(doc) { | |
// JSDoc comment is following form | |
// /** | |
// * ....... | |
// */ | |
return doc. | |
// remove /** | |
replace(/^\/\*\*?/, ''). | |
// remove */ | |
replace(/\*\/$/, ''). | |
// remove ' * ' at the beginning of a line | |
replace(new RegExp(STAR_MATCHER, 'g'), '$2'). | |
// remove trailing whitespace | |
replace(/\s*$/, ''); | |
} | |
/** | |
* Converts an index in an "unwrapped" JSDoc comment to the corresponding index in the original "wrapped" version | |
* @param {string} originalSource The original wrapped comment | |
* @param {number} unwrappedIndex The index of a character in the unwrapped string | |
* @returns {number} The index of the corresponding character in the original wrapped string | |
*/ | |
function convertUnwrappedCommentIndex(originalSource, unwrappedIndex) { | |
var replacedSource = originalSource.replace(/^\/\*\*?/, ''); | |
var numSkippedChars = 0; | |
var matcher = new RegExp(STAR_MATCHER, 'g'); | |
var match; | |
while ((match = matcher.exec(replacedSource))) { | |
numSkippedChars += match[1].length; | |
if (match.index + match[0].length > unwrappedIndex + numSkippedChars) { | |
return unwrappedIndex + numSkippedChars + originalSource.length - replacedSource.length; | |
} | |
} | |
return originalSource.replace(/\*\/$/, '').replace(/\s*$/, '').length; | |
} | |
// JSDoc Tag Parser | |
(function (exports) { | |
var Rules, | |
index, | |
lineNumber, | |
length, | |
source, | |
originalSource, | |
recoverable, | |
sloppy, | |
strict; | |
function advance() { | |
var ch = source.charCodeAt(index); | |
index += 1; | |
if (esutils.code.isLineTerminator(ch) && !(ch === 0x0D /* '\r' */ && source.charCodeAt(index) === 0x0A /* '\n' */)) { | |
lineNumber += 1; | |
} | |
return String.fromCharCode(ch); | |
} | |
function scanTitle() { | |
var title = ''; | |
// waste '@' | |
advance(); | |
while (index < length && isASCIIAlphanumeric(source.charCodeAt(index))) { | |
title += advance(); | |
} | |
return title; | |
} | |
function seekContent() { | |
var ch, waiting, last = index; | |
waiting = false; | |
while (last < length) { | |
ch = source.charCodeAt(last); | |
if (esutils.code.isLineTerminator(ch) && !(ch === 0x0D /* '\r' */ && source.charCodeAt(last + 1) === 0x0A /* '\n' */)) { | |
waiting = true; | |
} else if (waiting) { | |
if (ch === 0x40 /* '@' */) { | |
break; | |
} | |
if (!esutils.code.isWhiteSpace(ch)) { | |
waiting = false; | |
} | |
} | |
last += 1; | |
} | |
return last; | |
} | |
// type expression may have nest brace, such as, | |
// { { ok: string } } | |
// | |
// therefore, scanning type expression with balancing braces. | |
function parseType(title, last, addRange) { | |
var ch, brace, type, startIndex, direct = false; | |
// search '{' | |
while (index < last) { | |
ch = source.charCodeAt(index); | |
if (esutils.code.isWhiteSpace(ch)) { | |
advance(); | |
} else if (ch === 0x7B /* '{' */) { | |
advance(); | |
break; | |
} else { | |
// this is direct pattern | |
direct = true; | |
break; | |
} | |
} | |
if (direct) { | |
return null; | |
} | |
// type expression { is found | |
brace = 1; | |
type = ''; | |
while (index < last) { | |
ch = source.charCodeAt(index); | |
if (esutils.code.isLineTerminator(ch)) { | |
advance(); | |
} else { | |
if (ch === 0x7D /* '}' */) { | |
brace -= 1; | |
if (brace === 0) { | |
advance(); | |
break; | |
} | |
} else if (ch === 0x7B /* '{' */) { | |
brace += 1; | |
} | |
if (type === '') { | |
startIndex = index; | |
} | |
type += advance(); | |
} | |
} | |
if (brace !== 0) { | |
// braces is not balanced | |
return utility.throwError('Braces are not balanced'); | |
} | |
if (isAllowedOptional(title)) { | |
return typed.parseParamType(type, {startIndex: convertIndex(startIndex), range: addRange}); | |
} | |
return typed.parseType(type, {startIndex: convertIndex(startIndex), range: addRange}); | |
} | |
function scanIdentifier(last) { | |
var identifier; | |
if (!esutils.code.isIdentifierStartES5(source.charCodeAt(index)) && !source[index].match(/[0-9]/)) { | |
return null; | |
} | |
identifier = advance(); | |
while (index < last && esutils.code.isIdentifierPartES5(source.charCodeAt(index))) { | |
identifier += advance(); | |
} | |
return identifier; | |
} | |
function skipWhiteSpace(last) { | |
while (index < last && (esutils.code.isWhiteSpace(source.charCodeAt(index)) || esutils.code.isLineTerminator(source.charCodeAt(index)))) { | |
advance(); | |
} | |
} | |
function parseName(last, allowBrackets, allowNestedParams) { | |
var name = '', | |
useBrackets, | |
insideString; | |
skipWhiteSpace(last); | |
if (index >= last) { | |
return null; | |
} | |
if (source.charCodeAt(index) === 0x5B /* '[' */) { | |
if (allowBrackets) { | |
useBrackets = true; | |
name = advance(); | |
} else { | |
return null; | |
} | |
} | |
name += scanIdentifier(last); | |
if (allowNestedParams) { | |
if (source.charCodeAt(index) === 0x3A /* ':' */ && ( | |
name === 'module' || | |
name === 'external' || | |
name === 'event')) { | |
name += advance(); | |
name += scanIdentifier(last); | |
} | |
if(source.charCodeAt(index) === 0x5B /* '[' */ && source.charCodeAt(index + 1) === 0x5D /* ']' */){ | |
name += advance(); | |
name += advance(); | |
} | |
while (source.charCodeAt(index) === 0x2E /* '.' */ || | |
source.charCodeAt(index) === 0x2F /* '/' */ || | |
source.charCodeAt(index) === 0x23 /* '#' */ || | |
source.charCodeAt(index) === 0x2D /* '-' */ || | |
source.charCodeAt(index) === 0x7E /* '~' */) { | |
name += advance(); | |
name += scanIdentifier(last); | |
} | |
} | |
if (useBrackets) { | |
skipWhiteSpace(last); | |
// do we have a default value for this? | |
if (source.charCodeAt(index) === 0x3D /* '=' */) { | |
// consume the '='' symbol | |
name += advance(); | |
skipWhiteSpace(last); | |
var ch; | |
var bracketDepth = 1; | |
// scan in the default value | |
while (index < last) { | |
ch = source.charCodeAt(index); | |
if (esutils.code.isWhiteSpace(ch)) { | |
if (!insideString) { | |
skipWhiteSpace(last); | |
ch = source.charCodeAt(index); | |
} | |
} | |
if (ch === 0x27 /* ''' */) { | |
if (!insideString) { | |
insideString = '\''; | |
} else { | |
if (insideString === '\'') { | |
insideString = ''; | |
} | |
} | |
} | |
if (ch === 0x22 /* '"' */) { | |
if (!insideString) { | |
insideString = '"'; | |
} else { | |
if (insideString === '"') { | |
insideString = ''; | |
} | |
} | |
} | |
if (ch === 0x5B /* '[' */) { | |
bracketDepth++; | |
} else if (ch === 0x5D /* ']' */ && | |
--bracketDepth === 0) { | |
break; | |
} | |
name += advance(); | |
} | |
} | |
skipWhiteSpace(last); | |
if (index >= last || source.charCodeAt(index) !== 0x5D /* ']' */) { | |
// we never found a closing ']' | |
return null; | |
} | |
// collect the last ']' | |
name += advance(); | |
} | |
return name; | |
} | |
function skipToTag() { | |
while (index < length && source.charCodeAt(index) !== 0x40 /* '@' */) { | |
advance(); | |
} | |
if (index >= length) { | |
return false; | |
} | |
utility.assert(source.charCodeAt(index) === 0x40 /* '@' */); | |
return true; | |
} | |
function convertIndex(rangeIndex) { | |
if (source === originalSource) { | |
return rangeIndex; | |
} | |
return convertUnwrappedCommentIndex(originalSource, rangeIndex); | |
} | |
function TagParser(options, title) { | |
this._options = options; | |
this._title = title.toLowerCase(); | |
this._tag = { | |
title: title, | |
description: null | |
}; | |
if (this._options.lineNumbers) { | |
this._tag.lineNumber = lineNumber; | |
} | |
this._first = index - title.length - 1; | |
this._last = 0; | |
// space to save special information for title parsers. | |
this._extra = { }; | |
} | |
// addError(err, ...) | |
TagParser.prototype.addError = function addError(errorText) { | |
var args = Array.prototype.slice.call(arguments, 1), | |
msg = errorText.replace( | |
/%(\d)/g, | |
function (whole, index) { | |
utility.assert(index < args.length, 'Message reference must be in range'); | |
return args[index]; | |
} | |
); | |
if (!this._tag.errors) { | |
this._tag.errors = []; | |
} | |
if (strict) { | |
utility.throwError(msg); | |
} | |
this._tag.errors.push(msg); | |
return recoverable; | |
}; | |
TagParser.prototype.parseType = function () { | |
// type required titles | |
if (isTypeParameterRequired(this._title)) { | |
try { | |
this._tag.type = parseType(this._title, this._last, this._options.range); | |
if (!this._tag.type) { | |
if (!isParamTitle(this._title) && !isReturnTitle(this._title)) { | |
if (!this.addError('Missing or invalid tag type')) { | |
return false; | |
} | |
} | |
} | |
} catch (error) { | |
this._tag.type = null; | |
if (!this.addError(error.message)) { | |
return false; | |
} | |
} | |
} else if (isAllowedType(this._title)) { | |
// optional types | |
try { | |
this._tag.type = parseType(this._title, this._last, this._options.range); | |
} catch (e) { | |
//For optional types, lets drop the thrown error when we hit the end of the file | |
} | |
} | |
return true; | |
}; | |
TagParser.prototype._parseNamePath = function (optional) { | |
var name; | |
name = parseName(this._last, sloppy && isAllowedOptional(this._title), true); | |
if (!name) { | |
if (!optional) { | |
if (!this.addError('Missing or invalid tag name')) { | |
return false; | |
} | |
} | |
} | |
this._tag.name = name; | |
return true; | |
}; | |
TagParser.prototype.parseNamePath = function () { | |
return this._parseNamePath(false); | |
}; | |
TagParser.prototype.parseNamePathOptional = function () { | |
return this._parseNamePath(true); | |
}; | |
TagParser.prototype.parseName = function () { | |
var assign, name; | |
// param, property requires name | |
if (isAllowedName(this._title)) { | |
this._tag.name = parseName(this._last, sloppy && isAllowedOptional(this._title), isAllowedNested(this._title)); | |
if (!this._tag.name) { | |
if (!isNameParameterRequired(this._title)) { | |
return true; | |
} | |
// it's possible the name has already been parsed but interpreted as a type | |
// it's also possible this is a sloppy declaration, in which case it will be | |
// fixed at the end | |
if (isParamTitle(this._title) && this._tag.type && this._tag.type.name) { | |
this._extra.name = this._tag.type; | |
this._tag.name = this._tag.type.name; | |
this._tag.type = null; | |
} else { | |
if (!this.addError('Missing or invalid tag name')) { | |
return false; | |
} | |
} | |
} else { | |
name = this._tag.name; | |
if (name.charAt(0) === '[' && name.charAt(name.length - 1) === ']') { | |
// extract the default value if there is one | |
// example: @param {string} [somebody=John Doe] description | |
assign = name.substring(1, name.length - 1).split('='); | |
if (assign.length > 1) { | |
this._tag['default'] = assign.slice(1).join('='); | |
} | |
this._tag.name = assign[0]; | |
// convert to an optional type | |
if (this._tag.type && this._tag.type.type !== 'OptionalType') { | |
this._tag.type = { | |
type: 'OptionalType', | |
expression: this._tag.type | |
}; | |
} | |
} | |
} | |
} | |
return true; | |
}; | |
TagParser.prototype.parseDescription = function parseDescription() { | |
var description = sliceSource(source, index, this._last).trim(); | |
if (description) { | |
if ((/^-\s+/).test(description)) { | |
description = description.substring(2); | |
} | |
this._tag.description = description; | |
} | |
return true; | |
}; | |
TagParser.prototype.parseCaption = function parseDescription() { | |
var description = sliceSource(source, index, this._last).trim(); | |
var captionStartTag = '<caption>'; | |
var captionEndTag = '</caption>'; | |
var captionStart = description.indexOf(captionStartTag); | |
var captionEnd = description.indexOf(captionEndTag); | |
if (captionStart >= 0 && captionEnd >= 0) { | |
this._tag.caption = description.substring( | |
captionStart + captionStartTag.length, captionEnd).trim(); | |
this._tag.description = description.substring(captionEnd + captionEndTag.length).trim(); | |
} else { | |
this._tag.description = description; | |
} | |
return true; | |
}; | |
TagParser.prototype.parseKind = function parseKind() { | |
var kind, kinds; | |
kinds = { | |
'class': true, | |
'constant': true, | |
'event': true, | |
'external': true, | |
'file': true, | |
'function': true, | |
'member': true, | |
'mixin': true, | |
'module': true, | |
'namespace': true, | |
'typedef': true | |
}; | |
kind = sliceSource(source, index, this._last).trim(); | |
this._tag.kind = kind; | |
if (!hasOwnProperty(kinds, kind)) { | |
if (!this.addError('Invalid kind name \'%0\'', kind)) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
TagParser.prototype.parseAccess = function parseAccess() { | |
var access; | |
access = sliceSource(source, index, this._last).trim(); | |
this._tag.access = access; | |
if (access !== 'private' && access !== 'protected' && access !== 'public') { | |
if (!this.addError('Invalid access name \'%0\'', access)) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
TagParser.prototype.parseThis = function parseThis() { | |
// this name may be a name expression (e.g. {foo.bar}), | |
// an union (e.g. {foo.bar|foo.baz}) or a name path (e.g. foo.bar) | |
var value = sliceSource(source, index, this._last).trim(); | |
if (value && value.charAt(0) === '{') { | |
var gotType = this.parseType(); | |
if (gotType && this._tag.type.type === 'NameExpression' || this._tag.type.type === 'UnionType') { | |
this._tag.name = this._tag.type.name; | |
return true; | |
} else { | |
return this.addError('Invalid name for this'); | |
} | |
} else { | |
return this.parseNamePath(); | |
} | |
}; | |
TagParser.prototype.parseVariation = function parseVariation() { | |
var variation, text; | |
text = sliceSource(source, index, this._last).trim(); | |
variation = parseFloat(text, 10); | |
this._tag.variation = variation; | |
if (isNaN(variation)) { | |
if (!this.addError('Invalid variation \'%0\'', text)) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
TagParser.prototype.ensureEnd = function () { | |
var shouldBeEmpty = sliceSource(source, index, this._last).trim(); | |
if (shouldBeEmpty) { | |
if (!this.addError('Unknown content \'%0\'', shouldBeEmpty)) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
TagParser.prototype.epilogue = function epilogue() { | |
var description; | |
description = this._tag.description; | |
// un-fix potentially sloppy declaration | |
if (isAllowedOptional(this._title) && !this._tag.type && description && description.charAt(0) === '[') { | |
this._tag.type = this._extra.name; | |
if (!this._tag.name) { | |
this._tag.name = undefined; | |
} | |
if (!sloppy) { | |
if (!this.addError('Missing or invalid tag name')) { | |
return false; | |
} | |
} | |
} | |
return true; | |
}; | |
Rules = { | |
// http://usejsdoc.org/tags-access.html | |
'access': ['parseAccess'], | |
// http://usejsdoc.org/tags-alias.html | |
'alias': ['parseNamePath', 'ensureEnd'], | |
// http://usejsdoc.org/tags-augments.html | |
'augments': ['parseType', 'parseNamePathOptional', 'ensureEnd'], | |
// http://usejsdoc.org/tags-constructor.html | |
'constructor': ['parseType', 'parseNamePathOptional', 'ensureEnd'], | |
// Synonym: http://usejsdoc.org/tags-constructor.html | |
'class': ['parseType', 'parseNamePathOptional', 'ensureEnd'], | |
// Synonym: http://usejsdoc.org/tags-extends.html | |
'extends': ['parseType', 'parseNamePathOptional', 'ensureEnd'], | |
// http://usejsdoc.org/tags-example.html | |
'example': ['parseCaption'], | |
// http://usejsdoc.org/tags-deprecated.html | |
'deprecated': ['parseDescription'], | |
// http://usejsdoc.org/tags-global.html | |
'global': ['ensureEnd'], | |
// http://usejsdoc.org/tags-inner.html | |
'inner': ['ensureEnd'], | |
// http://usejsdoc.org/tags-instance.html | |
'instance': ['ensureEnd'], | |
// http://usejsdoc.org/tags-kind.html | |
'kind': ['parseKind'], | |
// http://usejsdoc.org/tags-mixes.html | |
'mixes': ['parseNamePath', 'ensureEnd'], | |
// http://usejsdoc.org/tags-mixin.html | |
'mixin': ['parseNamePathOptional', 'ensureEnd'], | |
// http://usejsdoc.org/tags-member.html | |
'member': ['parseType', 'parseNamePathOptional', 'ensureEnd'], | |
// http://usejsdoc.org/tags-method.html | |
'method': ['parseNamePathOptional', 'ensureEnd'], | |
// http://usejsdoc.org/tags-module.html | |
'module': ['parseType', 'parseNamePathOptional', 'ensureEnd'], | |
// Synonym: http://usejsdoc.org/tags-method.html | |
'func': ['parseNamePathOptional', 'ensureEnd'], | |
// Synonym: http://usejsdoc.org/tags-method.html | |
'function': ['parseNamePathOptional', 'ensureEnd'], | |
// Synonym: http://usejsdoc.org/tags-member.html | |
'var': ['parseType', 'parseNamePathOptional', 'ensureEnd'], | |
// http://usejsdoc.org/tags-name.html | |
'name': ['parseNamePath', 'ensureEnd'], | |
// http://usejsdoc.org/tags-namespace.html | |
'namespace': ['parseType', 'parseNamePathOptional', 'ensureEnd'], | |
// http://usejsdoc.org/tags-private.html | |
'private': ['parseType', 'parseDescription'], | |
// http://usejsdoc.org/tags-protected.html | |
'protected': ['parseType', 'parseDescription'], | |
// http://usejsdoc.org/tags-public.html | |
'public': ['parseType', 'parseDescription'], | |
// http://usejsdoc.org/tags-readonly.html | |
'readonly': ['ensureEnd'], | |
// http://usejsdoc.org/tags-requires.html | |
'requires': ['parseNamePath', 'ensureEnd'], | |
// http://usejsdoc.org/tags-since.html | |
'since': ['parseDescription'], | |
// http://usejsdoc.org/tags-static.html | |
'static': ['ensureEnd'], | |
// http://usejsdoc.org/tags-summary.html | |
'summary': ['parseDescription'], | |
// http://usejsdoc.org/tags-this.html | |
'this': ['parseThis', 'ensureEnd'], | |
// http://usejsdoc.org/tags-todo.html | |
'todo': ['parseDescription'], | |
// http://usejsdoc.org/tags-typedef.html | |
'typedef': ['parseType', 'parseNamePathOptional'], | |
// http://usejsdoc.org/tags-variation.html | |
'variation': ['parseVariation'], | |
// http://usejsdoc.org/tags-version.html | |
'version': ['parseDescription'] | |
}; | |
TagParser.prototype.parse = function parse() { | |
var i, iz, sequences, method; | |
// empty title | |
if (!this._title) { | |
if (!this.addError('Missing or invalid title')) { | |
return null; | |
} | |
} | |
// Seek to content last index. | |
this._last = seekContent(this._title); | |
if (this._options.range) { | |
this._tag.range = [this._first, source.slice(0, this._last).replace(/\s*$/, '').length].map(convertIndex); | |
} | |
if (hasOwnProperty(Rules, this._title)) { | |
sequences = Rules[this._title]; | |
} else { | |
// default sequences | |
sequences = ['parseType', 'parseName', 'parseDescription', 'epilogue']; | |
} | |
for (i = 0, iz = sequences.length; i < iz; ++i) { | |
method = sequences[i]; | |
if (!this[method]()) { | |
return null; | |
} | |
} | |
return this._tag; | |
}; | |
function parseTag(options) { | |
var title, parser, tag; | |
// skip to tag | |
if (!skipToTag()) { | |
return null; | |
} | |
// scan title | |
title = scanTitle(); | |
// construct tag parser | |
parser = new TagParser(options, title); | |
tag = parser.parse(); | |
// Seek global index to end of this tag. | |
while (index < parser._last) { | |
advance(); | |
} | |
return tag; | |
} | |
// | |
// Parse JSDoc | |
// | |
function scanJSDocDescription(preserveWhitespace) { | |
var description = '', ch, atAllowed; | |
atAllowed = true; | |
while (index < length) { | |
ch = source.charCodeAt(index); | |
if (atAllowed && ch === 0x40 /* '@' */) { | |
break; | |
} | |
if (esutils.code.isLineTerminator(ch)) { | |
atAllowed = true; | |
} else if (atAllowed && !esutils.code.isWhiteSpace(ch)) { | |
atAllowed = false; | |
} | |
description += advance(); | |
} | |
return preserveWhitespace ? description : description.trim(); | |
} | |
function parse(comment, options) { | |
var tags = [], tag, description, interestingTags, i, iz; | |
if (options === undefined) { | |
options = {}; | |
} | |
if (typeof options.unwrap === 'boolean' && options.unwrap) { | |
source = unwrapComment(comment); | |
} else { | |
source = comment; | |
} | |
originalSource = comment; | |
// array of relevant tags | |
if (options.tags) { | |
if (Array.isArray(options.tags)) { | |
interestingTags = { }; | |
for (i = 0, iz = options.tags.length; i < iz; i++) { | |
if (typeof options.tags[i] === 'string') { | |
interestingTags[options.tags[i]] = true; | |
} else { | |
utility.throwError('Invalid "tags" parameter: ' + options.tags); | |
} | |
} | |
} else { | |
utility.throwError('Invalid "tags" parameter: ' + options.tags); | |
} | |
} | |
length = source.length; | |
index = 0; | |
lineNumber = 0; | |
recoverable = options.recoverable; | |
sloppy = options.sloppy; | |
strict = options.strict; | |
description = scanJSDocDescription(options.preserveWhitespace); | |
while (true) { | |
tag = parseTag(options); | |
if (!tag) { | |
break; | |
} | |
if (!interestingTags || interestingTags.hasOwnProperty(tag.title)) { | |
tags.push(tag); | |
} | |
} | |
return { | |
description: description, | |
tags: tags | |
}; | |
} | |
exports.parse = parse; | |
}(jsdoc = {})); | |
exports.version = utility.VERSION; | |
exports.parse = jsdoc.parse; | |
exports.parseType = typed.parseType; | |
exports.parseParamType = typed.parseParamType; | |
exports.unwrapComment = unwrapComment; | |
exports.Syntax = shallowCopy(typed.Syntax); | |
exports.Error = utility.DoctrineError; | |
exports.type = { | |
Syntax: exports.Syntax, | |
parseType: typed.parseType, | |
parseParamType: typed.parseParamType, | |
stringify: typed.stringify | |
}; | |
}()); | |
/* vim: set sw=4 ts=4 et tw=80 : */ | |