287 lines
9.0 KiB
JavaScript
287 lines
9.0 KiB
JavaScript
var ret = {}
|
|
|
|
var io = use('io')
|
|
|
|
// Helper: Given an object `obj`, return either:
|
|
// - If there's no prosperon.DOC, return ''.
|
|
// - If obj[prosperon.DOC] is a string, return that (unless a sub-property was requested).
|
|
// - If obj[prosperon.DOC] is an object, return its .doc field if no prop, or doc for that prop if provided.
|
|
var docOf = function(obj, prop) {
|
|
var block = obj[prosperon.DOC]
|
|
if (typeof block === 'string') {
|
|
if (prop) return ''
|
|
return block
|
|
}
|
|
if (!block || typeof block !== 'object') return ''
|
|
if (!prop) return block.doc || ''
|
|
return block[prop] || ''
|
|
}
|
|
|
|
// Reusable doc parsing logic for rewriting :param and :return.
|
|
function parseDocStr(docStr) {
|
|
var out = []
|
|
if (!docStr) return out
|
|
|
|
var docLines = docStr.split('\n')
|
|
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
|
var returnRe = /^:return:\s*(.*)$/
|
|
|
|
for (var j = 0; j < docLines.length; j++) {
|
|
var line = docLines[j]
|
|
var pm = paramRe.exec(line)
|
|
var rm = returnRe.exec(line)
|
|
|
|
if (pm) {
|
|
out.push('**' + pm[1] + '**: ' + pm[2])
|
|
out.push('')
|
|
} else if (rm) {
|
|
out.push('**Returns**: ' + rm[1])
|
|
out.push('')
|
|
} else {
|
|
out.push(line)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Recursively write docs for an object and its sub-objects.
|
|
// level -> how many '#' in our markdown heading
|
|
// name -> the name of this object in the heading
|
|
function writeDocsForObject(obj, lines, level, name) {
|
|
var docStr = docOf(obj)
|
|
if (docStr) {
|
|
// Print heading for the object itself
|
|
var headingLine = Array(level + 1).join('#') + ' ' + name + '\n'
|
|
lines.push(headingLine)
|
|
var docOut = parseDocStr(docStr)
|
|
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
|
}
|
|
|
|
// Enumerate properties
|
|
for (var prop in obj) {
|
|
if (!obj.hasOwnProperty(prop)) continue
|
|
var val = obj[prop]
|
|
var valDoc = val && (val[prosperon.DOC] || docOf(obj, prop)) || ''
|
|
|
|
// If it's a function, print a heading like "## area(r)"
|
|
if (typeof val === 'function') {
|
|
var paramMatches = []
|
|
var docLines = valDoc.split('\n')
|
|
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
|
for (var j = 0; j < docLines.length; j++) {
|
|
var pm = paramRe.exec(docLines[j])
|
|
if (pm) paramMatches.push(pm[1])
|
|
}
|
|
|
|
var fnHeading = Array(level + 2).join('#') + ' ' + prop
|
|
// If paramMatches is not empty, list them in the heading
|
|
if (paramMatches.length > 0) fnHeading += '(' + paramMatches.join(', ') + ')\n'
|
|
else {
|
|
// fallback: parse from function signature
|
|
var m = val.toString().match(/\(([^)]*)\)/)
|
|
if (m) fnHeading += '(' + m[1].trim() + ')\n'
|
|
else fnHeading += '\n'
|
|
}
|
|
|
|
lines.push(fnHeading)
|
|
var parsed = parseDocStr(valDoc)
|
|
if (parsed.length > 0) lines.push(parsed.join('\n') + '\n')
|
|
}
|
|
|
|
// If it's a nested object, recursively write docs for it
|
|
else if (val && typeof val === 'object') {
|
|
// We only bother if the sub-object has any doc
|
|
// or if there's a good reason to drill deeper.
|
|
// If we want to always print sub-objects, remove the doc check.
|
|
var subObjDoc = docOf(val)
|
|
if (subObjDoc) {
|
|
writeDocsForObject(val, lines, level + 1, prop)
|
|
}
|
|
// If subObjDoc is empty but the object might contain sub-doc for
|
|
// its methods, you may want to call writeDocsForObject anyway.
|
|
else {
|
|
// We can still check if any child function has a doc:
|
|
var hasChildWithDoc = false
|
|
for (var sp in val) {
|
|
if (!val.hasOwnProperty(sp)) continue
|
|
var subVal = val[sp]
|
|
if (subVal && typeof subVal === 'function' && (subVal[prosperon.DOC] || docOf(val, sp))) {
|
|
hasChildWithDoc = true
|
|
break
|
|
}
|
|
}
|
|
if (hasChildWithDoc) writeDocsForObject(val, lines, level + 1, prop)
|
|
}
|
|
}
|
|
// else (if it's something else, e.g. number/string) you might skip it or do something special
|
|
}
|
|
}
|
|
|
|
var docs = io.enumerate("scripts/modules", 0)
|
|
docs = docs.filter(x => io.match("**/*.js", x)).map(x => x.name())
|
|
|
|
var APIPATH = '.src/docs/api/'
|
|
|
|
ret.print_api = function(obj) {
|
|
// Old console-based printing. We'll leave as-is or minimal changes if desired.
|
|
var topDoc = docOf(obj)
|
|
if (topDoc) console.log(' doc: ' + topDoc)
|
|
|
|
for (var prop in obj) {
|
|
if (!obj.hasOwnProperty(prop)) continue
|
|
var val = obj[prop]
|
|
console.log(prop)
|
|
|
|
var docStr = val[prosperon.DOC] || docOf(obj, prop)
|
|
if (docStr) console.log(' doc: ' + docStr)
|
|
|
|
if (typeof val === 'function') {
|
|
var m = val.toString().match(/\(([^)]*)\)/)
|
|
if (m) console.log(' function: ' + prop + '(' + m[1].trim() + ')')
|
|
}
|
|
}
|
|
}
|
|
|
|
ret.print_modules = function() {
|
|
for (var i = 0; i < docs.length; i++) {
|
|
var name = docs[i]
|
|
var mod = use(name)
|
|
console.log('MODULE: ' + name)
|
|
var modDoc = docOf(mod)
|
|
if (modDoc) console.log(' doc: ' + modDoc)
|
|
ret.print_api(mod)
|
|
console.log('')
|
|
}
|
|
}
|
|
|
|
// Writes each module's docs to .src/docs/api/<moduleName>.md
|
|
ret.write_modules = function() {
|
|
// rm all in APIPATH
|
|
var old = io.enumerate(APIPATH, 0)
|
|
old = old.filter(x => !io.match("**/index.md", x))
|
|
old = old.filter(x => !io.match("**/c_types", x))
|
|
old.forEach(x => io.rm(x))
|
|
if (!io.exists(APIPATH)) io.mkdir(APIPATH)
|
|
|
|
for (var i = 0; i < docs.length; i++) {
|
|
var name = docs[i]
|
|
var mod = use(name)
|
|
var lines = []
|
|
|
|
// Top-level heading for module
|
|
lines.push('# ' + name + '\n')
|
|
|
|
// Recursively write docs for the module at heading level 1
|
|
writeDocsForObject(mod, lines, 1, name)
|
|
|
|
var out = lines.join('\n')
|
|
io.slurpwrite(APIPATH + '/' + name + '.md', out)
|
|
}
|
|
}
|
|
|
|
ret.write_c_types = function() {
|
|
var CTYPEPATH = '.src/docs/api/c_types'
|
|
|
|
// Remove old ctype docs except index.md
|
|
var old = io.enumerate(CTYPEPATH, 0)
|
|
old = old.filter(x => !io.match("**/index.md", x))
|
|
old.forEach(x => io.rm(x))
|
|
if (!io.exists(CTYPEPATH)) io.mkdir(CTYPEPATH)
|
|
|
|
var cTypeNames = Object.keys(prosperon.c_types)
|
|
for (var i = 0; i < cTypeNames.length; i++) {
|
|
var name = cTypeNames[i]
|
|
var ctype = prosperon.c_types[name]
|
|
var lines = []
|
|
|
|
// Title
|
|
lines.push('# ' + name + '\n')
|
|
|
|
// If the ctype itself has a docstring (string or object.doc), include it
|
|
var ctypeDoc = docOf(ctype)
|
|
if (ctypeDoc) lines.push(ctypeDoc + '\n')
|
|
|
|
// Enumerate all own properties on the prototype (so we don't trigger getters)
|
|
var props = Object.getOwnPropertyNames(ctype)
|
|
|
|
for (var p = 0; p < props.length; p++) {
|
|
var propName = props[p]
|
|
if (propName === 'constructor') continue
|
|
|
|
var desc = Object.getOwnPropertyDescriptor(ctype, propName)
|
|
if (!desc) continue
|
|
|
|
if (typeof desc.value === 'function') writeMethod(lines, propName, desc.value, ctype)
|
|
if (typeof desc.get === 'function') writeGetter(lines, propName, desc.get, ctype)
|
|
if (typeof desc.set === 'function') writeSetter(lines, propName, desc.set, ctype)
|
|
}
|
|
|
|
var out = lines.join('\n')
|
|
io.slurpwrite(CTYPEPATH + '/' + name + '.md', out)
|
|
}
|
|
|
|
function writeMethod(lines, prop, fn, parent) {
|
|
var docStr = fn[prosperon.DOC] || docOf(parent, prop) || ''
|
|
var paramMatches = []
|
|
|
|
if (typeof fn === 'function') {
|
|
var docLines = docStr.split('\n')
|
|
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
|
for (var j = 0; j < docLines.length; j++) {
|
|
var pm = paramRe.exec(docLines[j])
|
|
if (pm) paramMatches.push(pm[1])
|
|
}
|
|
}
|
|
|
|
var heading = '## ' + prop
|
|
if (paramMatches.length > 0) heading += '(' + paramMatches.join(', ') + ')\n'
|
|
else {
|
|
var m = fn.toString().match(/\(([^)]*)\)/)
|
|
if (m) heading += '(' + m[1].trim() + ')\n'
|
|
else heading += '\n'
|
|
}
|
|
|
|
lines.push(heading)
|
|
var docOut = parseDocStr(docStr)
|
|
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
|
lines.push('')
|
|
}
|
|
|
|
function writeGetter(lines, prop, getterFn, parent) {
|
|
lines.push('## get ' + prop + '\n')
|
|
var docStr = getterFn[prosperon.DOC] || docOf(parent, prop) || ''
|
|
var docOut = parseDocStr(docStr)
|
|
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
|
lines.push('')
|
|
}
|
|
|
|
function writeSetter(lines, prop, setterFn, parent) {
|
|
var docStr = setterFn[prosperon.DOC] || docOf(parent, prop) || ''
|
|
var paramMatches = []
|
|
|
|
if (typeof setterFn === 'function') {
|
|
var docLines = docStr.split('\n')
|
|
var paramRe = /^:param\s+([A-Za-z0-9_]+)\s*:\s*(.*)$/
|
|
for (var j = 0; j < docLines.length; j++) {
|
|
var pm = paramRe.exec(docLines[j])
|
|
if (pm) paramMatches.push(pm[1])
|
|
}
|
|
}
|
|
|
|
var heading = '## set ' + prop
|
|
if (paramMatches.length > 0) heading += '(' + paramMatches.join(', ') + ')\n'
|
|
else {
|
|
var m = setterFn.toString().match(/\(([^)]*)\)/)
|
|
if (m) heading += '(' + m[1].trim() + ')\n'
|
|
else heading += '\n'
|
|
}
|
|
|
|
lines.push(heading)
|
|
var docOut = parseDocStr(docStr)
|
|
if (docOut.length > 0) lines.push(docOut.join('\n') + '\n')
|
|
lines.push('')
|
|
}
|
|
}
|
|
|
|
return ret
|