donna
Version:
A CoffeeScript documentation generator.
216 lines (173 loc) • 6.1 kB
text/coffeescript
Node = require './node'
Parameter = require './parameter'
Doc = require './doc'
_ = require 'underscore'
_.str = require 'underscore.string'
# Public: The Node representation of a CoffeeScript method.
module.exports = class Method extends Node
# Public: Constructs the documentation node.
#
# entity - The method's {Class}
# node - The method node (a {Object})
# fileName - The filename (a {String})
# lineMapping - An object mapping the actual position of a member to its Donna one
# options - The parser options (a {Object})
# comment - The comment node (a {Object})
constructor: (@entity, @node, @lineMapping, @options, comment) ->
try
@parameters = []
@doc = new Doc(comment, @options)
for param in @node.value.params
if param.name.properties? and param.name.properties[0].base?
for property in param.name.properties
@parameters.push new Parameter(param, @options, true)
else
@parameters.push new Parameter(param, @options)
@getName()
catch error
console.warn('Create method error:', @node, error) if @options.verbose
# Get the method type, either `class` or `instance`
#
# @return {String} the method type
#
getType: ->
unless @type
switch @entity.constructor.name
when 'Class'
@type = 'instance'
when 'Mixin'
@type = 'mixin'
when 'File'
@type = 'file'
@type
# Gets the original location of a method. This is only used for prototypical methods defined in Files
getOriginalFilename: ->
unless @originalFilename
@originalFilename = @getDoc().originalFilename
@originalFilename
# Gets the original name of a method. This is only used for prototypical methods defined in Files
getOriginalName: ->
unless @originalName
@originalName = @getDoc().originalName
@originalName
# Gets the original type of a method. This is only used for prototypical methods defined in Files
getOriginalType: ->
unless @originalType
@originalType = @getDoc().originalType
@originalType
# Get the class doc
#
# @return [Doc] the class doc
#
getDoc: -> @doc
# Get the full method signature.
#
# @return {String} the signature
#
getSignature: ->
try
unless @signature
@signature = switch @getType()
when 'class'
'.'
when 'instance'
'::'
else
if @getOriginalFilename()? then "::" else '? '
doc = @getDoc()
# this adds a superfluous space if there's no type defined
if doc.returnValue && doc.returnValue[0].type
retVals = []
for retVal in doc.returnValue
retVals.push "#{ _.str.escapeHTML retVal.type }"
@signature = retVals.join("|") + " #{@signature}"
@signature += "<strong>#{ @getOriginalName() || @getName() }</strong>"
@signature += '('
params = []
paramOptionized = []
for param, i in @getParameters()
if param.optionized
@inParamOption = true
optionizedDefaults = param.getOptionizedDefaults()
paramOptionized.push param.getName(i)
else
if @inParamOption
@inParamOption = false
paramValue = "{#{paramOptionized.join(', ')}}"
paramValue += "=#{optionizedDefaults}" if optionizedDefaults
params.push(paramValue)
paramOptionized = []
else
params.push param.getSignature()
# that means there was only one argument, a param'ed one
if paramOptionized.length > 0
paramValue = "{#{paramOptionized.join(', ')}}"
paramValue += "=#{optionizedDefaults}" if optionizedDefaults
params.push(paramValue)
@signature += params.join(', ')
@signature += ')'
@signature
catch error
console.warn('Get method signature error:', @node, error) if @options.verbose
# Get the short method signature.
#
# @return {String} the short signature
#
getShortSignature: ->
try
unless @shortSignature
@shortSignature = switch @getType()
when 'class'
'@'
when 'instance'
'.'
else
''
@shortSignature += @getName()
@shortSignature
catch error
console.warn('Get method short signature error:', @node, error) if @options.verbose
# Get the method name
#
# @return {String} the method name
#
getName: ->
try
unless @name
@name = @node.variable.base.value
# Reserved names will result in a name with a reserved: true property. No Bueno.
@name = @name.slice(0) if @name.reserved is true
for prop in @node.variable.properties
@name += ".#{ prop.name.value }"
if /^this\./.test @name
@name = @name.substring(5)
@type = 'class'
if /^module.exports\./.test @name
@name = @name.substring(15)
@type = 'class'
if /^exports\./.test @name
@name = @name.substring(8)
@type = 'class'
@name
catch error
console.warn('Get method name error:', @node, error) if @options.verbose
# Public: Get the source line number
#
# Returns a {Number}
#
getLocation: ->
try
unless @location
{locationData} = @node.variable
firstLine = locationData.first_line + 1
if !@lineMapping[firstLine]?
@lineMapping[firstLine] = @lineMapping[firstLine - 1]
@location = { line: @lineMapping[firstLine] }
@location
catch error
console.warn("Get location error at #{@fileName}:", @node, error) if @options.verbose
# Get the method parameters
#
# @param [Array<Parameter>] the method parameters
#
getParameters: -> @parameters