UNPKG

nebulab-dropbox

Version:
315 lines (266 loc) 10.8 kB
fs = require 'fs' mustache = require 'mustache' path = require 'path' S = require 'string' yaml = require 'js-yaml' # Converts codo YAML docs to the Dropbox site JSON format. jsonDoc = (yamlDir, toc) -> classIndexPath = path.join yamlDir, 'class_index.yaml' index = yaml.load fs.readFileSync(classIndexPath, 'utf8') classes = index.classes classIndex = {} for klass in classes classPath = path.join yamlDir, klass.href klass.data = yaml.load fs.readFileSync(classPath, 'utf8') classIndex[klass.namespace + '.' + klass.name] = klass tocIndex = 0 for section in toc.sections for entry in section.entries unless classIndex[entry.class] throw new Error "TOC entry not found: #{entry.class}" tocIndex += 1 classIndex[entry.class].tocIndex = tocIndex inf = classes.length + 1 classes.sort (a, b) -> if a.tocIndex or b.tocIndex (a.tocIndex or inf) - (b.tocIndex or inf) else if a.namespace is b.namespace a.name.localeCompare b.name else a.namespace.localeCompare b.namespace # Expand mixins. for klass in classes continue unless klass.data.includes for included in klass.data.includes includedMixin = classIndex[included.name] for method in includedMixin.data.methods continue if method.private methodClone = JSON.parse(JSON.stringify(method)) methodClone.type = 'instance' klass.data.instanceMethods.push methodClone nameIndex = makeNameIndex classes json = { classes: [] } for klass in classes continue if klass.type is 'Mixin' jsonCMethods = [] jsonIMethods = [] jsonClass = name: klass.namespace + '.' + klass.name desc: xref(klass.data.doc.comment, nameIndex) sections: [] json.classes.push jsonClass methodSections = [ { methods: klass.data.classMethods, name: 'Class Methods', type: 'class' }, { methods: klass.data.instanceMethods, name: 'Instance Methods', type: 'instance' } ] for section in methodSections continue unless section.methods and section.methods.length isnt 0 jsonMethods = [] jsonClass.sections.push( section_name: section.name, methods: jsonMethods) for method in section.methods jsonMethod = desc: '' method_name: method.name method_type: section.type discussion: xref(method.comment, nameIndex) formattedComponents: methodSignature(method, nameIndex) params: [] option_hashes: [] throws: [] see: [] jsonMethods.push jsonMethod if method.params and method.params.length isnt 0 jsonMethod.has_params = true for param in method.params jsonParam = param_name: param.name formattedType: typeSignature(param.type, nameIndex) desc: xref(param.desc, nameIndex) jsonMethod.params.push jsonParam if method.options and method.options.length isnt 0 for optionHash in method.options jsonOptions = [] jsonHash = param_name: S(optionHash.hash).capitalize() options: jsonOptions jsonMethod.option_hashes.push jsonHash for option in optionHash.options jsonOption = option_name: option.name option_type: option.type desc: xref(option.desc, nameIndex) jsonOptions.push jsonOption if method.returns jsonMethod.returns = xref(method.returns.desc, nameIndex) if method.throws and method.throws.length isnt 0 jsonMethod.has_throws = true for thrown in method.throws jsonThrown = formattedType: bareTypeSignature(thrown.type, nameIndex) desc: xref(thrown.desc, nameIndex) jsonMethod.throws.push jsonThrown if method.see and method.see.length isnt 0 jsonMethod.has_see = true for see in method.see jsonSee = formattedType: seeAlsoReference(see, nameIndex) desc: '' jsonMethod.see.push jsonSee if klass.data.properties and klass.data.properties.length isnt 0 jsonProperties = [] jsonClass.sections.push( section_name: 'Properties', methods: jsonProperties) for property in klass.data.properties jsonProperty = desc: '' method_name: property.name method_type: 'property' discussion: xref(property.comment, nameIndex) formattedComponents: propertySignature(property, nameIndex) see: [] jsonProperties.push jsonProperty if property.see and property.see.length isnt 0 jsonProperty.has_see = true for see in property.see jsonSee = formattedType: seeAlsoReference(see, nameIndex) desc: '' jsonProperty.see.push jsonSee if klass.data.constants and klass.data.constants.length isnt 0 jsonConstants = [] jsonClass.sections.push( section_name: 'Constants', methods: jsonConstants) for constant in klass.data.constants jsonConstant = desc: '' method_name: constant.name method_type: 'constant' discussion: xref(constant.doc.comment, nameIndex) formattedComponents: constantSignature(constant, nameIndex) see: [] jsonConstants.push jsonConstant if property.see and property.see.length isnt 0 jsonConstant.has_see = true for see in property.see jsonSee = formattedType: seeAlsoReference(see, nameIndex) desc: '' jsonConstant.see.push jsonSee json # Map from Codo references to href objects. makeNameIndex = (classes) -> nameIndex = {} for klass in classes className = klass.namespace + '.' + klass.name nameIndex[className] = "##{className}" attrs = (klass.data?.instanceMethods or []).concat( klass.data?.properties or []) for attr in attrs nameIndex["#{className}##{attr.name}"] = "##{className}.#{attr.name}" cattrs = (klass.data?.classMethods or []).concat( klass.data?.constants or []) for attr in cattrs nameIndex["#{className}.#{attr.name}"] = "##{className}.#{attr.name}" nameIndex # A method's signature, in the formattedComponents format used for iOS. methodSignature = (method, nameIndex) -> formattedComponents = [] if method.name isnt 'constructor' returnType = method.doc?.returns?.type or method.returns?.type or 'void' addTypeSignature returnType, nameIndex, formattedComponents formattedComponents.push value: ' ' formattedComponents.push value: method.name, emphasized: true formattedComponents.push value: '(' firstParam = true for param in method.params or [] if firstParam firstParam = false else formattedComponents.push value: ', ' formattedComponents.push value: param.name formattedComponents.push value: ')' formattedComponents # A property's signature, in the formattedComponents format used for iOS. propertySignature = (property, nameIndex) -> match = /\([^)]*\)/.exec property.signature if match propertyType = S(match[0]).unescapeHTML(). replace(/(^\()|(\)$)/g, '').toString() else propertyType = null formattedComponents = [] formattedComponents.push value: property.name, emphasized: true if propertyType formattedComponents.push value: ' ' formattedComponents.push value: '(' addTypeSignature propertyType, nameIndex, formattedComponents formattedComponents.push value: ')' formattedComponents # A type's signature, in the formattedComponents format used for iOS. typeSignature = (typeString, nameIndex) -> if typeString.length is 0 null else formattedComponents = [{ value: '(' }] addTypeSignature typeString, nameIndex, formattedComponents formattedComponents.push value: ')' formattedComponents # A type's signature, in the formattedComponents format, without parenthesis. bareTypeSignature = (typeString, nameIndex) -> if typeString.length is 0 null else addTypeSignature typeString, nameIndex, [] # Adds a type's signature to an in-construction formattedComponents array. addTypeSignature = (typeString, nameIndex, formattedComponents) -> parts = typeString.split(/([\w\.\#]+)/) for part in parts continue if part.length is 0 if nameIndex[part] formattedComponents.push value: part, href: nameIndex[part] else formattedComponents.push value: part formattedComponents # A "See Also" reference, in the formattedComponents format used for iOS. seeAlsoReference = (see, nameIndex) -> return null unless see.label if nameIndex[see.label] [{value: see.label, href: nameIndex[see.label]}] else [{value: see.label, href: see.reference}] # Fixes <a> links in description text. xref = (string, nameIndex) -> return string unless string string.replace /(<a [^>]*>)([^>]*)<\/a>/g, (match, tag, innerHtml) -> newHref = nameIndex[innerHtml.trim()] return match unless newHref newTag = tag.replace(/href='[^']+'/, "href='#{newHref}'") newTag = newTag.replace(/href="[^"]+"/, "href=\"#{newHref}\"") "#{newTag}#{innerHtml}</a>" # A constant's signature, in the formattedComponents format used for iOS. constantSignature = (constant) -> [{ value: constant.name }] # Outputs siteDoc = (siteDir) -> tocPath = path.join siteDir, 'templates', 'toc.json' toc = JSON.parse fs.readFileSync(tocPath, 'utf8') json = jsonDoc path.join(siteDir, 'yaml'), toc fs.writeFileSync path.join(siteDir, 'all.json'), JSON.stringify(json) htmlPath = path.join(siteDir, 'html') fs.mkdirSync htmlPath unless fs.existsSync htmlPath docsTemplatePath = path.join siteDir, 'templates', 'docs-template.html' docsTemplate = fs.readFileSync docsTemplatePath, 'utf8' docs = mustache.render docsTemplate, json, {} fs.writeFileSync path.join(htmlPath, 'docs_js_ds.html'), docs tocTemplatePath = path.join siteDir, 'templates', 'toc-template.html' tocTemplate = fs.readFileSync tocTemplatePath, 'utf8' toc = mustache.render tocTemplate, toc, {} fs.writeFileSync path.join(htmlPath, 'docs_js_ds_toc.html'), toc module.exports = siteDoc