 85bf1341f3
			
		
	
	85bf1341f3
	
	
	
		
			
			Frontend Enhancements: - Complete React TypeScript frontend with modern UI components - Distributed workflows management interface with real-time updates - Socket.IO integration for live agent status monitoring - Agent management dashboard with cluster visualization - Project management interface with metrics and task tracking - Responsive design with proper error handling and loading states Backend Infrastructure: - Distributed coordinator for multi-agent workflow orchestration - Cluster management API with comprehensive agent operations - Enhanced database models for agents and projects - Project service for filesystem-based project discovery - Performance monitoring and metrics collection - Comprehensive API documentation and error handling Documentation: - Complete distributed development guide (README_DISTRIBUTED.md) - Comprehensive development report with architecture insights - System configuration templates and deployment guides The platform now provides a complete web interface for managing the distributed AI cluster with real-time monitoring, workflow orchestration, and agent coordination capabilities. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			899 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			899 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  * @fileoverview Main Doctrine object
 | |
|  * @author Yusuke Suzuki <utatane.tea@gmail.com>
 | |
|  * @author Dan Tao <daniel.tao@gmail.com>
 | |
|  * @author Andrew Eisenberg <andrew@eisenberg.as>
 | |
|  */
 | |
| 
 | |
| (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 : */
 |