784 lines
19 KiB
JavaScript
784 lines
19 KiB
JavaScript
|
var arrayify = require('array-back')
|
||
|
var util = require('util')
|
||
|
var handlebars = require('handlebars')
|
||
|
var marked = require('marked')
|
||
|
var objectGet = require('object-get')
|
||
|
var where = require('test-value').where
|
||
|
var flatten = require('reduce-flatten')
|
||
|
var state = require('../lib/state')
|
||
|
|
||
|
/**
|
||
|
* ddata is a collection of handlebars helpers for working with the documentation data output by [jsdoc-parse](https://github.com/75lb/jsdoc-parse).
|
||
|
* @module
|
||
|
* @example
|
||
|
* ```js
|
||
|
* var handlebars = require("handlebars")
|
||
|
* var ddata = require("ddata")
|
||
|
* var docs = require("./docs.json") // jsdoc-parse output
|
||
|
*
|
||
|
* handlebars.registerHelper(ddata)
|
||
|
* var template =
|
||
|
* "{{#module name='yeah-module'}}\
|
||
|
* The author of the module is: {{author}}.\
|
||
|
* {{/module}}"
|
||
|
* console.log(handlebars.compile(template)(docs))
|
||
|
* ```
|
||
|
*/
|
||
|
|
||
|
/* utility block helpers */
|
||
|
exports.link = link
|
||
|
exports.returnSig2 = returnSig2
|
||
|
exports.sig = sig
|
||
|
exports.children = children
|
||
|
exports.indexChildren = indexChildren
|
||
|
|
||
|
/* helpers which return objects */
|
||
|
exports._link = _link
|
||
|
|
||
|
/* helpers which return booleans */
|
||
|
exports.isClass = isClass
|
||
|
exports.isClassMember = isClassMember
|
||
|
exports.isConstructor = isConstructor
|
||
|
exports.isFunction = isFunction
|
||
|
exports.isConstant = isConstant
|
||
|
exports.isEvent = isEvent
|
||
|
exports.isEnum = isEnum
|
||
|
exports.isTypedef = isTypedef
|
||
|
exports.isCallback = isCallback
|
||
|
exports.isModule = isModule
|
||
|
exports.isMixin = isMixin
|
||
|
exports.isExternal = isExternal
|
||
|
exports.isPrivate = isPrivate
|
||
|
exports.isProtected = isProtected
|
||
|
exports.showMainIndex = showMainIndex
|
||
|
|
||
|
/* helpers which return lists */
|
||
|
exports._orphans = _orphans
|
||
|
exports._identifiers = _identifiers
|
||
|
exports._children = _children
|
||
|
exports._globals = _globals
|
||
|
exports.descendants = descendants
|
||
|
|
||
|
/* helpers which return single identifiers */
|
||
|
exports.exported = exported
|
||
|
exports.parentObject = parentObject
|
||
|
exports._identifier = _identifier
|
||
|
|
||
|
/* helpers which return strings */
|
||
|
exports.anchorName = anchorName
|
||
|
exports.md = md
|
||
|
exports.md2 = md2
|
||
|
exports.methodSig = methodSig
|
||
|
exports.parseLink = parseLink
|
||
|
exports.parentName = parentName
|
||
|
exports.option = option
|
||
|
exports.optionEquals = optionEquals
|
||
|
exports.optionSet = optionSet
|
||
|
exports.optionIsSet = optionIsSet
|
||
|
exports.stripNewlines = stripNewlines
|
||
|
|
||
|
/* helpers which keep state */
|
||
|
exports.headingDepth = headingDepth
|
||
|
exports.depth = depth
|
||
|
exports.depthIncrement = depthIncrement
|
||
|
exports.depthDecrement = depthDecrement
|
||
|
exports.indexDepth = indexDepth
|
||
|
exports.indexDepthIncrement = indexDepthIncrement
|
||
|
exports.indexDepthDecrement = indexDepthDecrement
|
||
|
|
||
|
/**
|
||
|
* omits externals without a description
|
||
|
* @static
|
||
|
*/
|
||
|
function _globals (options) {
|
||
|
options.hash.scope = 'global'
|
||
|
return _identifiers(options).filter(function (identifier) {
|
||
|
if (identifier.kind === 'external') {
|
||
|
return identifier.description && identifier.description.length > 0
|
||
|
} else {
|
||
|
return true
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This helper is a duplicate of the handlebars `each` helper with the one exception that `depthIncrement` is called on each iteration.
|
||
|
* @category Block helper: selector
|
||
|
*/
|
||
|
function children (options) {
|
||
|
var context = _children.call(this, options)
|
||
|
var fn = options.fn
|
||
|
var inverse = options.inverse
|
||
|
var i = 0
|
||
|
var ret = ''
|
||
|
var data
|
||
|
|
||
|
var contextPath
|
||
|
|
||
|
if (options.data) {
|
||
|
data = handlebars.createFrame(options.data)
|
||
|
}
|
||
|
|
||
|
for (var j = context.length; i < j; i++) {
|
||
|
depthIncrement(options)
|
||
|
if (data) {
|
||
|
data.index = i
|
||
|
data.first = (i === 0)
|
||
|
data.last = (i === (context.length - 1))
|
||
|
|
||
|
if (contextPath) {
|
||
|
data.contextPath = contextPath + i
|
||
|
}
|
||
|
}
|
||
|
ret = ret + fn(context[i], { data: data })
|
||
|
depthDecrement(options)
|
||
|
}
|
||
|
|
||
|
if (i === 0) {
|
||
|
ret = inverse(this)
|
||
|
}
|
||
|
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* This helper is a duplicate of the handlebars `each` helper with the one exception that `indexDepthIncrement` is called on each iteration.
|
||
|
* @static
|
||
|
* @category Block helper: selector
|
||
|
*/
|
||
|
function indexChildren (options) {
|
||
|
var context = _children.call(this, options)
|
||
|
var fn = options.fn
|
||
|
var inverse = options.inverse
|
||
|
var i = 0
|
||
|
var ret = ''
|
||
|
var data
|
||
|
|
||
|
var contextPath
|
||
|
|
||
|
if (options.data) {
|
||
|
data = handlebars.createFrame(options.data)
|
||
|
}
|
||
|
|
||
|
for (var j = context.length; i < j; i++) {
|
||
|
indexDepthIncrement(options)
|
||
|
if (data) {
|
||
|
data.index = i
|
||
|
data.first = (i === 0)
|
||
|
data.last = (i === (context.length - 1))
|
||
|
|
||
|
if (contextPath) {
|
||
|
data.contextPath = contextPath + i
|
||
|
}
|
||
|
}
|
||
|
ret = ret + fn(context[i], { data: data })
|
||
|
indexDepthDecrement(options)
|
||
|
}
|
||
|
|
||
|
if (i === 0) {
|
||
|
ret = inverse(this)
|
||
|
}
|
||
|
|
||
|
return ret
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param id {string} - the ID to link to, e.g. `external:XMLHttpRequest`, `GlobalClass#propOne` etc.
|
||
|
* @static
|
||
|
* @category Block helper: util
|
||
|
* @example
|
||
|
* {{#link "module:someModule.property"~}}
|
||
|
* {{name}} {{!-- prints 'property' --}}
|
||
|
* {{url}} {{!-- prints 'module-someModule-property' --}}
|
||
|
* {{/link}}
|
||
|
*/
|
||
|
function link (longname, options) {
|
||
|
return options.fn(_link(longname, options))
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* e.g. namepaths `module:Something` or type expression `Array.<module:Something>`
|
||
|
* @static
|
||
|
* @param {string} - namepath or type expression
|
||
|
* @param {object} - the handlebars helper options object
|
||
|
*/
|
||
|
function _link (input, options) {
|
||
|
if (typeof input !== 'string') return null
|
||
|
|
||
|
var linked, matches, namepath
|
||
|
var output = {}
|
||
|
|
||
|
/*
|
||
|
test input for
|
||
|
1. A type expression containing a namepath, e.g. Array.<module:Something>
|
||
|
2. a namepath referencing an `id`
|
||
|
3. a namepath referencing a `longname`
|
||
|
*/
|
||
|
if ((matches = input.match(/.*?<(.*?)>/))) {
|
||
|
namepath = matches[1]
|
||
|
} else {
|
||
|
namepath = input
|
||
|
}
|
||
|
|
||
|
options.hash = { id: namepath }
|
||
|
linked = _identifier(options)
|
||
|
if (!linked) {
|
||
|
options.hash = { longname: namepath }
|
||
|
linked = _identifier(options)
|
||
|
}
|
||
|
if (!linked) {
|
||
|
output = { name: input, url: null }
|
||
|
} else {
|
||
|
output.name = input.replace(namepath, linked.name)
|
||
|
if (isExternal.call(linked)) {
|
||
|
if (linked.description) {
|
||
|
output.url = '#' + anchorName.call(linked, options)
|
||
|
} else {
|
||
|
if (linked.see && linked.see.length) {
|
||
|
var firstLink = parseLink(linked.see[0])[0]
|
||
|
output.url = firstLink ? firstLink.url : linked.see[0]
|
||
|
} else {
|
||
|
output.url = null
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
output.url = '#' + anchorName.call(linked, options)
|
||
|
}
|
||
|
}
|
||
|
return output
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
@returns {{symbol: string, types: array}}
|
||
|
@category Block helper: util
|
||
|
*/
|
||
|
function returnSig2 (options) {
|
||
|
if (!isConstructor.call(this)) {
|
||
|
if (this.returns) {
|
||
|
var typeNames = arrayify(this.returns).map(function (ret) {
|
||
|
return ret.type && ret.type.names
|
||
|
})
|
||
|
typeNames = typeNames.filter(function (name) {
|
||
|
return name
|
||
|
})
|
||
|
if (typeNames.length) {
|
||
|
return options.fn({
|
||
|
symbol: '⇒',
|
||
|
types: typeNames.reduce(flatten, [])
|
||
|
})
|
||
|
} else {
|
||
|
return options.fn({
|
||
|
symbol: null,
|
||
|
types: null
|
||
|
})
|
||
|
}
|
||
|
} else if ((this.type || this.kind === 'namespace') && this.kind !== 'event') {
|
||
|
if (this.kind === 'namespace') {
|
||
|
return options.fn({
|
||
|
symbol: ':',
|
||
|
types: ['object']
|
||
|
})
|
||
|
} else {
|
||
|
return options.fn({
|
||
|
symbol: ':',
|
||
|
types: this.type.names
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@category Block helper: util
|
||
|
*/
|
||
|
function sig (options) {
|
||
|
var data
|
||
|
|
||
|
if (options.data) {
|
||
|
data = handlebars.createFrame(options.data || {})
|
||
|
}
|
||
|
|
||
|
data.prefix = this.kind === 'constructor' ? 'new' : ''
|
||
|
data.parent = null
|
||
|
data.accessSymbol = null
|
||
|
data.name = isEvent.call(this) ? '"' + this.name + '"' : this.name
|
||
|
data.methodSign = null
|
||
|
data.returnSymbol = null
|
||
|
data.returnTypes = null
|
||
|
data.suffix = this.isExported ? '⏏' : isPrivate.call(this) ? '℗' : ''
|
||
|
data.depOpen = null
|
||
|
data.depClose = null
|
||
|
data.codeOpen = null
|
||
|
data.codeClose = null
|
||
|
|
||
|
var mSig = methodSig.call(this)
|
||
|
if (isConstructor.call(this) || isFunction.call(this)) {
|
||
|
data.methodSign = '(' + mSig + ')'
|
||
|
} else if (isEvent.call(this)) {
|
||
|
if (mSig) data.methodSign = '(' + mSig + ')'
|
||
|
}
|
||
|
|
||
|
if (!isEvent.call(this)) {
|
||
|
data.parent = parentName.call(this, options)
|
||
|
data.accessSymbol = (this.scope === 'static' || this.scope === 'instance') ? '.' : this.scope === 'inner' ? '~' : ''
|
||
|
}
|
||
|
|
||
|
if (!isConstructor.call(this)) {
|
||
|
if (this.returns) {
|
||
|
data.returnSymbol = '⇒'
|
||
|
var typeNames = arrayify(this.returns)
|
||
|
.map(function (ret) {
|
||
|
return ret.type && ret.type.names
|
||
|
})
|
||
|
.filter(function (name) {
|
||
|
return name
|
||
|
})
|
||
|
if (typeNames.length) {
|
||
|
data.returnTypes = typeNames.reduce(flatten, [])
|
||
|
}
|
||
|
} else if ((this.type || this.kind === 'namespace') && this.kind !== 'event') {
|
||
|
data.returnSymbol = ':'
|
||
|
|
||
|
if (isEnum.call(this)) {
|
||
|
data.returnTypes = ['enum']
|
||
|
} else if (this.kind === 'namespace') {
|
||
|
data.returnTypes = ['object']
|
||
|
} else {
|
||
|
data.returnTypes = this.type.names
|
||
|
}
|
||
|
} else if (this.chainable) {
|
||
|
data.returnSymbol = '↩︎'
|
||
|
} else if (this.augments) {
|
||
|
data.returnSymbol = '⇐'
|
||
|
data.returnTypes = [this.augments[0]]
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (this.deprecated) {
|
||
|
if (optionEquals('no-gfm', true, options) || options.hash['no-gfm']) {
|
||
|
data.depOpen = '<del>'
|
||
|
data.depClose = '</del>'
|
||
|
} else {
|
||
|
data.depOpen = '~~'
|
||
|
data.depClose = '~~'
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (option('name-format', options) && !isClass.call(this) && !isModule.call(this)) {
|
||
|
data.codeOpen = '`'
|
||
|
data.codeClose = '`'
|
||
|
}
|
||
|
|
||
|
return options.fn(this, { data: data })
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@this {identifier}
|
||
|
@returns {boolean}
|
||
|
@alias module:ddata.isClass
|
||
|
*/
|
||
|
function isClass () { return this.kind === 'class' }
|
||
|
|
||
|
/**
|
||
|
returns true if the parent of the current identifier is a class
|
||
|
@returns {boolean}
|
||
|
@static
|
||
|
*/
|
||
|
function isClassMember (options) {
|
||
|
var parent = arrayify(options.data.root).find(where({ id: this.memberof }))
|
||
|
if (parent) {
|
||
|
return parent.kind === 'class'
|
||
|
}
|
||
|
}
|
||
|
function isConstructor () { return this.kind === 'constructor' }
|
||
|
function isFunction () { return this.kind === 'function' }
|
||
|
function isConstant () { return this.kind === 'constant' }
|
||
|
/**
|
||
|
returns true if this is an event
|
||
|
@returns {boolean}
|
||
|
@static
|
||
|
*/
|
||
|
function isEvent () { return this.kind === 'event' }
|
||
|
function isEnum () { return this.isEnum || this.kind === 'enum' }
|
||
|
function isExternal () { return this.kind === 'external' }
|
||
|
function isTypedef () {
|
||
|
return this.kind === 'typedef' && this.type.names[0] !== 'function'
|
||
|
}
|
||
|
function isCallback () {
|
||
|
return this.kind === 'typedef' && this.type.names[0] === 'function'
|
||
|
}
|
||
|
function isModule () { return this.kind === 'module' }
|
||
|
function isMixin () { return this.kind === 'mixin' }
|
||
|
function isPrivate () { return this.access === 'private' }
|
||
|
function isProtected () { return this.access === 'protected' }
|
||
|
|
||
|
/**
|
||
|
True if there at least two top-level identifiers (i.e. globals or modules)
|
||
|
@category returns boolean
|
||
|
@returns {boolean}
|
||
|
@static
|
||
|
*/
|
||
|
function showMainIndex (options) {
|
||
|
return _orphans(options).length > 1
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns an array of the top-level elements which have no parents. Output only includes externals which have a description.
|
||
|
* @returns {array}
|
||
|
* @static
|
||
|
* @category Returns list
|
||
|
*/
|
||
|
function _orphans (options) {
|
||
|
options.hash.memberof = undefined
|
||
|
return _identifiers(options).filter(function (identifier) {
|
||
|
if (identifier.kind === 'external') {
|
||
|
return identifier.description && identifier.description.length > 0
|
||
|
} else {
|
||
|
return true
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns an array of identifiers matching the query
|
||
|
* @returns {array}
|
||
|
* @static
|
||
|
*/
|
||
|
function _identifiers (options) {
|
||
|
var query = {}
|
||
|
|
||
|
for (var prop in options.hash) {
|
||
|
if (/^-/.test(prop)) {
|
||
|
query[prop.replace(/^-/, '!')] = options.hash[prop]
|
||
|
} else if (/^_/.test(prop)) {
|
||
|
query[prop.replace(/^_/, '')] = new RegExp(options.hash[prop])
|
||
|
} else {
|
||
|
query[prop] = options.hash[prop]
|
||
|
}
|
||
|
}
|
||
|
return arrayify(options.data.root).filter(where(query)).filter(function (doclet) {
|
||
|
return !doclet.ignore && (state.options.private ? true : doclet.access !== 'private')
|
||
|
})
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
return the identifiers which are a `memberof` this one. Exclude externals without descriptions.
|
||
|
@param [sortBy] {string} - "kind"
|
||
|
@param [min] {number} - only returns if there are `min` children
|
||
|
@this {identifier}
|
||
|
@returns {identifier[]}
|
||
|
@static
|
||
|
*/
|
||
|
function _children (options) {
|
||
|
if (!this.id) return []
|
||
|
var min = options.hash.min
|
||
|
delete options.hash.min
|
||
|
options.hash.memberof = this.id
|
||
|
var output = _identifiers(options)
|
||
|
output = output.filter(function (identifier) {
|
||
|
if (identifier.kind === 'external') {
|
||
|
return identifier.description && identifier.description.length > 0
|
||
|
} else {
|
||
|
return true
|
||
|
}
|
||
|
})
|
||
|
if (output.length >= (min || 0)) return output
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
return a flat list containing all decendants
|
||
|
@param [sortBy] {string} - "kind"
|
||
|
@param [min] {number} - only returns if there are `min` children
|
||
|
@this {identifier}
|
||
|
@returns {identifier[]}
|
||
|
@static
|
||
|
*/
|
||
|
function descendants (options) {
|
||
|
var min = typeof options.hash.min !== 'undefined' ? options.hash.min : 2
|
||
|
delete options.hash.min
|
||
|
options.hash.memberof = this.id
|
||
|
var output = []
|
||
|
function iterate (childrenList) {
|
||
|
if (childrenList.length) {
|
||
|
childrenList.forEach(function (child) {
|
||
|
output.push(child)
|
||
|
iterate(_children.call(child, options))
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
iterate(_children.call(this, options))
|
||
|
if (output.length >= (min || 0)) return output
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
returns the exported identifier of this module
|
||
|
@this {identifier} - only works on a module
|
||
|
@returns {identifier}
|
||
|
@static
|
||
|
*/
|
||
|
function exported (options) {
|
||
|
var exp = arrayify(options.data.root).find(where({ '!kind': 'module', id: this.id }))
|
||
|
return exp || this
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Returns an identifier matching the query
|
||
|
@static
|
||
|
*/
|
||
|
function _identifier (options) {
|
||
|
return _identifiers(options)[0]
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Returns the parent
|
||
|
@static
|
||
|
*/
|
||
|
function parentObject (options) {
|
||
|
return arrayify(options.data.root).find(where({ id: this.memberof }))
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
returns a unique ID string suitable for use as an `href`.
|
||
|
@this {identifier}
|
||
|
@returns {string}
|
||
|
@static
|
||
|
@category Returns string
|
||
|
@example
|
||
|
```js
|
||
|
> ddata.anchorName.call({ id: "module:yeah--Yeah()" })
|
||
|
'module_yeah--Yeah_new'
|
||
|
```
|
||
|
*/
|
||
|
function anchorName (options) {
|
||
|
if (!this.id) throw new Error('[anchorName helper] cannot create a link without a id: ' + JSON.stringify(this))
|
||
|
if (this.inherited) {
|
||
|
options.hash.id = this.inherits
|
||
|
var inherits = _identifier(options)
|
||
|
if (inherits) {
|
||
|
return anchorName.call(inherits, options)
|
||
|
} else {
|
||
|
return ''
|
||
|
}
|
||
|
}
|
||
|
return util.format(
|
||
|
'%s%s%s',
|
||
|
this.isExported ? 'exp_' : '',
|
||
|
this.kind === 'constructor' ? 'new_' : '',
|
||
|
this.id
|
||
|
.replace(/:/g, '_')
|
||
|
.replace(/~/g, '..')
|
||
|
.replace(/\(\)/g, '_new')
|
||
|
.replace(/#/g, '+')
|
||
|
)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
converts the supplied text to markdown
|
||
|
@static
|
||
|
@category Returns string
|
||
|
*/
|
||
|
function md (string, options) {
|
||
|
if (string) {
|
||
|
var result = marked(string).replace('lang-js', 'language-javascript')
|
||
|
return result
|
||
|
}
|
||
|
}
|
||
|
function md2 (options) {
|
||
|
return marked.inlineLexer(options.fn(this).toString(), [])
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Returns the method signature, e.g. `(options, [onComplete])`
|
||
|
@this {identifier}
|
||
|
@returns {string}
|
||
|
@category Returns string
|
||
|
@static
|
||
|
*/
|
||
|
function methodSig () {
|
||
|
return arrayify(this.params).filter(function (param) {
|
||
|
return param.name && !/\./.test(param.name)
|
||
|
}).map(function (param) {
|
||
|
if (param.variable) {
|
||
|
return param.optional ? '[...' + param.name + ']' : '...' + param.name
|
||
|
} else {
|
||
|
return param.optional ? '[' + param.name + ']' : param.name
|
||
|
}
|
||
|
}).join(', ')
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* extracts url and caption data from @link tags
|
||
|
* @param {string} - a string containing one or more {@link} tags
|
||
|
* @returns {Array.<{original: string, caption: string, url: string}>}
|
||
|
* @static
|
||
|
*/
|
||
|
function parseLink (text) {
|
||
|
if (!text) return ''
|
||
|
var results = []
|
||
|
var matches = null
|
||
|
var link1 = /{@link\s+([^\s}|]+?)\s*}/g // {@link someSymbol}
|
||
|
var link2 = /\[([^\]]+?)\]{@link\s+([^\s}|]+?)\s*}/g // [caption here]{@link someSymbol}
|
||
|
var link3 = /{@link\s+([^\s}|]+?)\s*\|([^}]+?)}/g // {@link someSymbol|caption here}
|
||
|
var link4 = /{@link\s+([^\s}|]+?)\s+([^}|]+?)}/g // {@link someSymbol Caption Here}
|
||
|
|
||
|
while ((matches = link4.exec(text)) !== null) {
|
||
|
results.push({
|
||
|
original: matches[0],
|
||
|
caption: matches[2],
|
||
|
url: matches[1]
|
||
|
})
|
||
|
text = text.replace(matches[0], ' '.repeat(matches[0].length))
|
||
|
}
|
||
|
|
||
|
while ((matches = link3.exec(text)) !== null) {
|
||
|
results.push({
|
||
|
original: matches[0],
|
||
|
caption: matches[2],
|
||
|
url: matches[1]
|
||
|
})
|
||
|
text = text.replace(matches[0], ' '.repeat(matches[0].length))
|
||
|
}
|
||
|
|
||
|
while ((matches = link2.exec(text)) !== null) {
|
||
|
results.push({
|
||
|
original: matches[0],
|
||
|
caption: matches[1],
|
||
|
url: matches[2]
|
||
|
})
|
||
|
text = text.replace(matches[0], ' '.repeat(matches[0].length))
|
||
|
}
|
||
|
|
||
|
while ((matches = link1.exec(text)) !== null) {
|
||
|
results.push({
|
||
|
original: matches[0],
|
||
|
caption: matches[1],
|
||
|
url: matches[1]
|
||
|
})
|
||
|
text = text.replace(matches[0], ' '.repeat(matches[0].length))
|
||
|
}
|
||
|
return results
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
returns the parent name, instantiated if necessary
|
||
|
@this {identifier}
|
||
|
@returns {string}
|
||
|
@static
|
||
|
*/
|
||
|
function parentName (options) {
|
||
|
function instantiate (input) {
|
||
|
if (/^[A-Z]{3}/.test(input)) {
|
||
|
return input.replace(/^([A-Z]+)([A-Z])/, function (str, p1, p2) {
|
||
|
return p1.toLowerCase() + p2
|
||
|
})
|
||
|
} else {
|
||
|
return input.charAt(0).toLowerCase() + input.slice(1)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* don't bother with a parentName for exported identifiers */
|
||
|
if (this.isExported) return ''
|
||
|
|
||
|
if (this.memberof && this.kind !== 'constructor') {
|
||
|
var parent = arrayify(options.data.root).find(where({ id: this.memberof }))
|
||
|
if (parent) {
|
||
|
if (this.scope === 'instance') {
|
||
|
var name = parent.typicalname || parent.name
|
||
|
return instantiate(name)
|
||
|
} else if (this.scope === 'static' && !(parent.kind === 'class' || parent.kind === 'constructor')) {
|
||
|
return parent.typicalname || parent.name
|
||
|
} else {
|
||
|
return parent.name
|
||
|
}
|
||
|
} else {
|
||
|
return this.memberof
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
returns a dmd option, e.g. "sort-by", "heading-depth" etc.
|
||
|
@static
|
||
|
*/
|
||
|
function option (name, options) {
|
||
|
return objectGet(options.data.root.options, name)
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function optionEquals (name, value, options) {
|
||
|
return options.data.root.options[name] === value
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function optionSet (name, value, options) {
|
||
|
options.data.root.options[name] = value
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function optionIsSet (name, options) {
|
||
|
return options.data.root.options[name] !== undefined
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function stripNewlines (input) {
|
||
|
if (input) return input.replace(/[\r\n]+/g, ' ')
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function headingDepth (options) {
|
||
|
return options.data.root.options._depth + (options.data.root.options['heading-depth'])
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function depth (options) {
|
||
|
return options.data.root.options._depth
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function depthIncrement (options) {
|
||
|
options.data.root.options._depth++
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function depthDecrement (options) {
|
||
|
options.data.root.options._depth--
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function indexDepth (options) {
|
||
|
return options.data.root.options._indexDepth
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function indexDepthIncrement (options) {
|
||
|
options.data.root.options._indexDepth++
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
@static
|
||
|
*/
|
||
|
function indexDepthDecrement (options) {
|
||
|
options.data.root.options._indexDepth--
|
||
|
}
|