/** * build common layout output. * @return {IceCap} layout output. * @private */ _buildLayoutDoc() { let info = this._getInfo(); let ice = new IceCap(this._readTemplate('layout.html'), {autoClose: false}); ice.text('esdocVersion', `(${this._config._esdocVersion})`); if (info.url) { ice.attr('repoURL', 'href', info.url); if (info.url.match(new RegExp('^https?://github.com/'))) { ice.attr('repoURL', 'class', 'repo-url-github'); } } else { ice.drop('repoURL'); } ice.drop('testLink', !this._config.test); // see StaticFileBuilder#exec ice.loop('userScript', this._config.scripts || [], (i, userScript, ice)=>{ let name = `user/script/${i}-${path.basename(userScript)}`; ice.attr('userScript', 'src', name); }); ice.loop('userStyle', this._config.styles || [], (i, userStyle, ice)=>{ let name = `user/css/${i}-${path.basename(userStyle)}`; ice.attr('userStyle', 'href', name); }); ice.load('nav', this._buildNavDoc()); return ice; }
/** * build summary output html by docs. * @param {DocObject[]} docs - target docs. * @param {string} title - summary title. * @param {boolean} innerLink - if true, link in summary is inner link. * @return {IceCap} summary output. * @private */ _buildSummaryDoc(docs, title, innerLink) { if (docs.length === 0) return; let ice = new IceCap(this._readTemplate('summary.html')); ice.text('title', title); ice.loop('target', docs, (i, doc, ice)=>{ ice.text('generator', doc.generator ? '*' : ''); ice.load('name', this._buildDocLinkHTML(doc.longname, null, innerLink, doc.kind)); ice.load('signature', this._buildSignatureHTML(doc)); ice.load('description', shorten(doc, true)); ice.text('abstract', doc.abstract ? 'abstract' : ''); ice.text('access', doc.access); if (['get', 'set'].includes(doc.kind)) { ice.text('kind', doc.kind); } else { ice.drop('kind'); } if (['member', 'method', 'get', 'set'].includes(doc.kind)) { ice.text('static', doc.static ? 'static' : ''); } else { ice.drop('static'); } ice.text('since', doc.since); ice.load('deprecated', this._buildDeprecatedHTML(doc)); ice.load('experimental', this._buildExperimentalHTML(doc)); ice.text('version', doc.version); }); return ice; }
/** * build test describe list html. * @param {number} [depth=0] - test depth. * @param {string} [memberof] - target test. * @returns {string} html of describe list. * @private */ _buildTestDescribeDocHTML(depth = 0, memberof = null) { let cond = {kind: 'testDescribe', testDepth: depth}; if (memberof) cond.memberof = memberof; let describeDocs = this._orderedFind('testId asec', cond); let padding; let html = ''; for (let describeDoc of describeDocs) { let ice = new IceCap(this._readTemplate('testDescribe.html')); let testCount = this._find({kind: 'testIt', longname: {regex: new RegExp(`^${describeDoc.longname}\\.`)}}).length; padding = 10 * (depth + 1); ice.attr('testDescribe', 'data-test-depth', depth); ice.into('testDescribe', describeDoc, (describeDoc, ice)=>{ let descriptionHTML = this._buildFileDocLinkHTML(describeDoc, describeDoc.description); let testTargetsHTML = []; for (let testTarget of describeDoc._custom_test_targets || []) { testTargetsHTML.push(this._buildDocLinkHTML(testTarget[0], testTarget[1])); } testTargetsHTML = testTargetsHTML.join('\n') || '-'; ice.load('testDescription', descriptionHTML); ice.attr('testDescription', 'style', `padding-left: ${padding}px`); ice.load('testTarget', testTargetsHTML); ice.text('testCount', testCount); }); padding = 10 * (depth + 2); let itDocs = this._orderedFind('testId asec', {kind: 'testIt', testDepth: depth + 1, memberof: describeDoc.longname}); ice.loop('testIt', itDocs, (i, itDoc, ice)=>{ let descriptionHTML = this._buildFileDocLinkHTML(itDoc, itDoc.description); let testTargetsHTML = []; for (let testTarget of itDoc._custom_test_targets || []) { testTargetsHTML.push(this._buildDocLinkHTML(testTarget[0], testTarget[1])); } testTargetsHTML = testTargetsHTML.join('\n') || '-'; ice.attr('testIt', 'data-test-depth', depth + 1); ice.load('testDescription', descriptionHTML); ice.attr('testDescription', 'style', `padding-left: ${padding}px`); ice.load('testTarget', testTargetsHTML); }); let innerDescribeHTML = this._buildTestDescribeDocHTML(depth + 1, describeDoc.longname); html += '\n' + ice.html + '\n' + innerDescribeHTML; } return html; }
/** * built manual index. * @param {ManualConfigItem[]} manualConfig - target manual config. * @return {IceCap} built index. * @private */ _buildManualIndex(manualConfig) { const ice = new IceCap(this._readTemplate('manualIndex.html')); ice.loop('manual', manualConfig, (i, item, ice)=>{ const toc = []; if (item.references) { const identifiers = this._findAllIdentifiersKindGrouping(); if (identifiers.class.length) toc.push({label: 'Class', link: 'identifiers.html#class', indent: 'indent-h1'}); if (identifiers.interface.length) toc.push({label: 'Interface', link: 'identifiers.html#interface', indent: 'indent-h1'}); if (identifiers.function.length) toc.push({label: 'Function', link: 'identifiers.html#function', indent: 'indent-h1'}); if (identifiers.variable.length) toc.push({label: 'Variable', link: 'identifiers.html#variable', indent: 'indent-h1'}); if (identifiers.typedef.length) toc.push({label: 'Typedef', link: 'identifiers.html#typedef', indent: 'indent-h1'}); if (identifiers.external.length) toc.push({label: 'External', link: 'identifiers.html#external', indent: 'indent-h1'}); } else { const fileName = this._getManualOutputFileName(item); const html = this._convertMDToHTML(item); const $root = cheerio.load(html).root(); const isHRise = $root.find('h1').length === 0; $root.find('h1,h2,h3,h4,h5').each((i, el)=>{ const $el = cheerio(el); const label = $el.text(); const link = `${fileName}#${$el.attr('id')}`; let indent; if (isHRise) { const tagName = `h${parseInt(el.tagName.charAt(1), 10) - 1}`; indent = `indent-${tagName}`; } else { indent = `indent-${el.tagName.toLowerCase()}`; } toc.push({label, link, indent}); }); } ice.attr('manual', 'data-toc-name', item.label.toLowerCase()); ice.text('title', item.label); ice.attr('title', 'href', this._getManualOutputFileName(item)); ice.loop('manualNav', toc, (i, item, ice)=>{ ice.attr('manualNav', 'class', item.indent); ice.text('link', item.label); ice.attr('link', 'href', item.link); }); }); return ice; }
/** * build properties output. * @param {ParsedParam[]} [properties=[]] - properties in doc object. * @param {string} title - output title. * @return {IceCap} built properties output. * @private */ _buildProperties(properties = [], title = 'Properties:') { let ice = new IceCap(this._readTemplate('properties.html')); ice.text('title', title); ice.loop('property', properties, (i, prop, ice)=>{ ice.autoDrop = false; ice.attr('property', 'data-depth', prop.name.split('.').length - 1); ice.text('name', prop.name); ice.attr('name', 'data-depth', prop.name.split('.').length - 1); ice.load('description', prop.description); let typeNames = []; for (var typeName of prop.types) { typeNames.push(this._buildTypeDocLinkHTML(typeName)); } ice.load('type', typeNames.join(' | ')); // appendix let appendix = []; if (prop.optional) { appendix.push('<li>optional</li>'); } if ('defaultValue' in prop) { appendix.push(`<li>default: ${prop.defaultValue}</li>`); } if (typeof prop.nullable === 'boolean') { appendix.push(`<li>nullable: ${prop.nullable}</li>`); } if (appendix.length) { ice.load('appendix', `<ul>${appendix.join('\n')}</ul>`); } else { ice.text('appendix', ''); } }); if (!properties || properties.length === 0) { ice.drop('properties'); } return ice; }
/** * build common navigation output. * @return {IceCap} navigation output. * @private */ _buildNavDoc() { let html = this._readTemplate('nav.html'); let ice = new IceCap(html); const kinds = ['class', 'function', 'variable', 'typedef', 'external']; const allDocs = this._find({kind: kinds}).filter(v => !v.builtinExternal); const kindOrder = {class: 0, interface: 1, function: 2, variable: 3, typedef: 4, external: 5}; allDocs.sort((a, b)=>{ const filePathA = a.longname.split('~')[0].replace('src/', ''); const filePathB = b.longname.split('~')[0].replace('src/', ''); const dirPathA = path.dirname(filePathA); const dirPathB = path.dirname(filePathB); const kindA = a.interface ? 'interface' : a.kind; const kindB = b.interface ? 'interface' : b.kind; if (dirPathA === dirPathB) { if (kindA === kindB) { return a.longname > b.longname ? 1 : -1; } else { return kindOrder[kindA] > kindOrder[kindB] ? 1 : -1; } } else { return dirPathA > dirPathB ? 1 : -1; } }); let lastDirPath = '.'; ice.loop('doc', allDocs, (i, doc, ice)=>{ const filePath = doc.longname.split('~')[0].replace(/^.*?[/]/, ''); const dirPath = path.dirname(filePath); const kind = doc.interface ? 'interface' : doc.kind; const kindText = kind.charAt(0).toUpperCase(); const kindClass = `kind-${kind}`; ice.load('name', this._buildDocLinkHTML(doc.longname)); ice.load('kind', kindText); ice.attr('kind', 'class', kindClass); ice.text('dirPath', dirPath); ice.drop('dirPath', lastDirPath === dirPath); lastDirPath = dirPath; }); return ice; }
/** * build common navigation output. * @return {IceCap} navigation output. * @private */ _buildNavDoc() { let html = this._readTemplate('nav.html'); let ice = new IceCap(html); // class let classDocs = this._find({kind: 'class', interface: false}); ice.drop('classWrap', !classDocs.length); ice.loop('classDoc', classDocs, (i, classDoc, ice)=>{ ice.load('classDoc', this._buildDocLinkHTML(classDoc.longname)); }); // interface let interfaceDocs = this._find({kind: 'class', interface: true}); ice.drop('interfaceWrap', !interfaceDocs.length); ice.loop('interfaceDoc', interfaceDocs, (i, interfaceDoc, ice)=>{ ice.load('interfaceDoc', this._buildDocLinkHTML(interfaceDoc.longname)); }); // function let functionDocs = this._find({kind: 'function'}); ice.drop('functionWrap', !functionDocs.length); ice.loop('functionDoc', functionDocs, (i, functionDoc, ice)=>{ ice.load('functionDoc', this._buildDocLinkHTML(functionDoc.longname)); }); // variable let variableDocs = this._find({kind: 'variable'}); ice.drop('variableWrap', !variableDocs.length); ice.loop('variableDoc', variableDocs, (i, variableDoc, ice)=>{ ice.load('variableDoc', this._buildDocLinkHTML(variableDoc.longname)); }); // typedef let typedefDocs = this._find({kind: 'typedef'}); ice.drop('typedefWrap', !typedefDocs.length); ice.loop('typedefDoc', typedefDocs, (i, typedefDoc, ice)=>{ ice.load('typedefDoc', this._buildDocLinkHTML(typedefDoc.longname)); }); // external let externalDocs = this._find({kind: 'external'}).filter(v => !v.builtinExternal); ice.drop('externalWrap', !externalDocs.length); ice.loop('externalDoc', externalDocs, (i, externalDoc, ice)=>{ ice.load('externalDoc', this._buildDocLinkHTML(externalDoc.longname)); }); return ice; }
/** * build detail output html by docs. * @param {DocObject[]} docs - target docs. * @param {string} title - detail title. * @return {IceCap} detail output. * @private */ _buildDetailDocs(docs, title) { let ice = new IceCap(this._readTemplate('details.html')); ice.text('title', title); ice.drop('title', !docs.length); ice.loop('detail', docs, (i, doc, ice)=>{ let scope = doc.static ? 'static' : 'instance'; ice.attr('anchor', 'id', `${scope}-${doc.kind}-${doc.name}`); ice.text('generator', doc.generator ? '*' : ''); ice.text('name', doc.name); ice.load('signature', this._buildSignatureHTML(doc)); ice.load('description', doc.description); ice.text('abstract', doc.abstract ? 'abstract' : ''); ice.text('access', doc.access); if (['get', 'set'].includes(doc.kind)) { ice.text('kind', doc.kind); } else { ice.drop('kind'); } if (doc.export && doc.importPath && doc.importStyle) { let link = this._buildFileDocLinkHTML(doc, doc.importPath); ice.into('importPath', `import ${doc.importStyle} from '${link}'`, (code, ice)=>{ ice.load('importPathCode', code); }); } else { ice.drop('importPath'); } if (['member', 'method', 'get', 'set'].includes(doc.kind)) { ice.text('static', doc.static ? 'static' : ''); } else { ice.drop('static'); } ice.load('source', this._buildFileDocLinkHTML(doc, 'source')); ice.text('since', doc.since, 'append'); ice.load('deprecated', this._buildDeprecatedHTML(doc)); ice.load('experimental', this._buildExperimentalHTML(doc)); ice.text('version', doc.version, 'append'); ice.load('see', this._buildDocsLinkHTML(doc.see), 'append'); ice.load('todo', this._buildDocsLinkHTML(doc.todo), 'append'); ice.load('override', this._buildOverrideMethod(doc)); let isFunction = false; if (['method', 'constructor', 'function'].indexOf(doc.kind) !== -1) isFunction = true; if (doc.kind === 'typedef' && doc.params && doc.type.types[0] === 'function') isFunction = true; if (isFunction) { ice.load('properties', this._buildProperties(doc.params, 'Params:')); } else { ice.load('properties', this._buildProperties(doc.properties, 'Properties:')); } // return if (doc.return) { ice.load('returnDescription', doc.return.description); let typeNames = []; for (let typeName of doc.return.types) { typeNames.push(this._buildTypeDocLinkHTML(typeName)); } if (typeof doc.return.nullable === 'boolean') { let nullable = doc.return.nullable; ice.load('returnType', typeNames.join(' | ') + ` (nullable: ${nullable})`); } else { ice.load('returnType', typeNames.join(' | ')); } ice.load('returnProperties', this._buildProperties(doc.properties, 'Return Properties:')); } else { ice.drop('returnParams'); } // throws if (doc.throws) { ice.loop('throw', doc.throws, (i, exceptionDoc, ice)=>{ ice.load('throwName', this._buildDocLinkHTML(exceptionDoc.types[0])); ice.load('throwDesc', exceptionDoc.description); }); } else { ice.drop('throwWrap'); } // fires if (doc.emits) { ice.loop('emit', doc.emits, (i, emitDoc, ice)=>{ ice.load('emitName', this._buildDocLinkHTML(emitDoc.types[0])); ice.load('emitDesc', emitDoc.description); }); } else { ice.drop('emitWrap'); } // listens if (doc.listens) { ice.loop('listen', doc.listens, (i, listenDoc, ice)=>{ ice.load('listenName', this._buildDocLinkHTML(listenDoc.types[0])); ice.load('listenDesc', listenDoc.description); }); } else { ice.drop('listenWrap'); } // example ice.into('example', doc.examples, (examples, ice)=>{ ice.loop('exampleDoc', examples, (i, exampleDoc, ice)=>{ let parsed = parseExample(exampleDoc); ice.text('exampleCode', parsed.body); ice.text('exampleCaption', parsed.caption); }); }); // tests ice.into('tests', doc._custom_tests, (tests, ice)=>{ ice.loop('test', tests, (i, test, ice)=>{ let testDoc = this._find({longname: test})[0]; ice.load('test', this._buildFileDocLinkHTML(testDoc, testDoc.testFullDescription)); }); }); }); return ice; }