lib/doc_tags.coffee

Supported Doctags

This script tries to implement known doctags from jsdoc, jsdoc2 and jsdoc3. Most of them are supported. This implementation is mainly suitable for languages like Javascript, Coffeescript or even PHP, but certainly not for Ruby or Python as the later languages have their own conventions and thorough introspection capabilities.

A list of doctag-candidates:

@access
@alias
@augments
@author
@borrows
@callback
@classdesc
@constant
@constructor
@constructs
@copyright
@default
@deprecated
@desc
@enum
@event
@example
@exports
@extends
@external
@file
@fires
@global
@ignore
@inner
@instance
@kind
@lends
@license
@link
@member
@memberof
@method
@mixes
@mixin
@module
@name
@namespace
@param
@private
@property
@protected
@public
@readonly
@requires
@returns
@see
@since
@static
@summary
@this
@throws
@todo
@tutorial
@type
@typedef
@variation
@version

# imports
# imports humanize = require './utils/humanize' { collapse_space, link_type, convert_type, translate_type, convert_parameter_type, translate_parameter_type } = require './utils/doctag_helpers'

Public module DOC_TAGS is an Object

This is a sample doc tagged block comment



module.exports = DOC_TAGS = description: section: 'description' markdown: '{value}' abstract: section: 'access' constant: section: 'access' deprecated: section: 'access' internal: section: 'access' 'private': section: 'access' 'protected': section: 'access' 'public': valuePrefix: 'as' section: 'access' 'static': section: 'access' constructor: section: 'special' destructor: section: 'special' 'class': section: 'type' markdown: 'class *{type}*' event: section: 'type'

Public method markdown

renders @event-doctags

Parameters:

Returns a String
should be in markdown syntax



markdown: (value, fileInfo) -> if match = collapse_space(value).match ///^\s*(.*)#(.*)\s*$/// "event *#{link_type match[2], fileInfo} of class *#{link_type match[1], fileInfo}*" else "event *#{link_type value, fileInfo}*" method: section: 'type' markdown: 'method *{type}*' mixin: section: 'type' markdown: 'mixin *{type}*' module: section: 'type' markdown: 'module *{type}*' 'package': section: 'type' markdown: 'package *{type}*' property: section: 'type' markdown: 'property *{type}*' accessor: section: 'flag' markdown: 'is an accessor' async: section: 'flag' markdown: 'is asynchronous' asynchronous: 'async' getter: section: 'flag' markdown: 'is a getter' recursive: section: 'flag' markdown: 'is recursive' refactor: section: 'flag' markdown: 'needs to be refactored' setter: section: 'flag' markdown: 'is a setter' alias: valuePrefix: 'as' section: 'metadata' markdown: 'is aliased as *{type}*' augments: section: 'metadata' markdown: 'extends *{type}*' 'extends': section: 'metadata' markdown: 'extends *{type}*' fires: section: 'metadata'

Public method markdown

renders @fires-doctags

Parameters:

Returns a String
should be in markdown syntax



markdown: (value, fileInfo) -> if match = collapse_space(value).match ///^\s*(.+)#(.+)\s*$/// "fires #{humanize.article match[2]} *#{link_type match[2], fileInfo}* event on class *#{link_type match[1], fileInfo}*" else "fires #{humanize.article value} *#{link_type value, fileInfo}* event" memberof: section: 'metadata' markdown: 'is a member of *{type}*' mixes: section: 'metadata' markdown: 'mixes *{type}* in' namespace: section: 'metadata' markdown: 'is in namespace *{value}*' publishes: section: 'metadata' requests: section: 'metadata' markdown: 'makes an ajax request to <{value}>' since: section: 'metadata' markdown: 'is available since version {value}' subscribes: valuePrefix: 'to' section: 'metadata' markdown: 'subscribes to {type}' type: section: 'metadata'

Public method markdown

render @type-doctags Alternative: markdown: 'is of type *{value}*'

Parameters:

Returns a String



markdown: (value, fileInfo) -> value = translate_type convert_type(value, fileInfo), fileInfo if value is 'any type' "is of #{value}" else "is #{value}" version: section: 'metadata' markdown: 'has version {value}' author: section: 'authors'

Public method markdown

renders @author-doctags

Parameter:

Returns a String
Should be in markdown syntax

Author:



markdown: (value) -> value = collapse_space value # the other alternatives, as [text](link) do not (yet) encode email # addresses - that sucks, so we leave it as it is, for now … if author = value.match /^\s*(.*)<([^>]+)>\s*$/ "* #{author[1]} (<#{author[2]}>)" else "* #{value}" see: section: 'references'

Public method markdown

renders @see-doctags as hyperlink references

Parameter:

Returns a String
Should be in markdown syntax

Reference:



markdown: (value) -> value = collapse_space value if /^\s*(\[[^\]]+\]\([^\)]+\)|<[^>]+>|\`[^\`]+\`)\s*$/.test value "* #{value}" else "* <#{value}>" todo: section: 'todo' markdown: 'TODO: {value}' example: section: 'example' markdown: '{value}' examples: 'example' usage: 'example' howto: section: 'howto' markdown: '{value}'

A comment that does not have doc tags in it

note: section: 'discard' notes: 'note' param: section: 'params'

Public method parseValue

parses function parameters

Parameter:

  • value must be a String
    Text that follows @param

Returns an Object



parseValue: (value) -> parts = collapse_space(value).match /^\{([^\}]+)\}\s+(\[?)([\w\.\$]+)(?:=([^\s\]]+))?(\]?)\s*(.*)$/ types : (parts[1]?.split /\|{1,2}/g) isOptional : (parts[2] == '[' and parts[5] == ']') varName : parts[3] defaultValue : parts[4] description : parts[6]

Public method markdown

converts parsed values to markdown text

Parameters:

  • value must be an Object
    Result of parseValue from above

    • […].types must be an Array of Strings
      A list of all types the parameter allows

    • […].isOptional must be a Boolean and has a default value of false
      A flag indicating if the parameter is optional

    • […].varName must be a String
      The parameter's name

    • […].defaultValue is optional and must be a String
      The parameter's default value

    • […].description is optional and must be a String
      The parameter's default value

  • fileInfo must be an Object
    A fileInfo-instance created by the rendering process

Returns a String
Should be in markdown syntax



markdown: (value, fileInfo) -> types = (convert_parameter_type(type, fileInfo) for type in value.types) fragments = [] fragments.push 'is optional' if value.isOptional verb = 'must' if types.length > 1 verb = 'can' else type = translate_parameter_type types[0], fileInfo if type isnt types[0] verb = 'can' types[0] = if type is 'any type' then "of #{type}" else type fragments.push "#{verb} be #{humanize.joinSentence types, 'or'}" fragments.push "has a default value of #{value.defaultValue}" if value.defaultValue? # we assume that : # 1. parameters always appear before their sub-parameters # 2. sub-parameters always have a parent parameter # 3. the dot always divides sub-parameters into its parts # 4. parameter descriptions always ran through `collapse_space` parts = value.varName.split '.' varName = parts[parts.length - 1] indent = Array(parts.length).join(' ') prefix = if 1 < parts.length then '[…].' else '' description = if value.description.length then " \n#{indent} #{value.description}" else "" "#{indent}* #{prefix}***#{varName}* #{humanize.joinSentence fragments}**#{description}" params: 'param' parameters: 'param' 'return': section: 'returns' parseValue: (value) -> parts = collapse_space(value).match /^\{([^\}]+)\}\s*(.*)$/ types : parts[1].split /\|{1,2}/g description: parts[2] markdown: (value, fileInfo) -> types = (convert_type(type, fileInfo) for type in value.types) if types.length is 1 type = translate_type types[0] if type isnt types[0] types[0] = type description = if value.description.length then "<br/>#{value.description}<br/>" else "" "**returns #{humanize.joinSentence types, 'or'}**#{description}" returns: 'return' throw: section: 'throws' parseValue: (value) -> parts = collapse_space(value).match /^\{([^\}]+)\}\s*(.*)$/ types : parts[1].split /\|{1,2}/g description: parts[2] markdown: (value, fileInfo) -> types = ("#{humanize.article type} *#{link_type type, fileInfo}*" for type in value.types) description = if value.description.length then "<br/>#{value.description}<br/>" else "" "**can throw #{humanize.joinSentence types, 'or'}**#{description}" throws: 'throw' defaultNoValue: section: 'flag' defaultHasValue: section: 'metadata'