doc: generator code health (3) (#4850)

This commit is contained in:
Pavel Feldman 2020-12-29 12:12:46 -08:00 committed by GitHub
parent 6697dadca2
commit 9817d1095a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 2115 additions and 718 deletions

2730
types/types.d.ts vendored

File diff suppressed because it is too large Load Diff

View File

@ -91,9 +91,9 @@ class MDOutline {
clazz.visit(item => patchLinks(item, item.spec, classesMap, membersMap, linkRenderer));
}
renderComments() {
generateSourceCodeComments() {
for (const clazz of this.classesArray)
clazz.visit(item => item.comment = renderLinksForSourceCode(item.spec));
clazz.visit(item => item.comment = generateSourceCodeComment(item.spec));
}
}
@ -127,13 +127,13 @@ function extractComments(item) {
/**
* @param {MarkdownNode[]} spec
*/
function renderLinksForSourceCode(spec) {
function generateSourceCodeComment(spec) {
const comments = (spec || []).filter(n => n.type !== 'gen' && !n.type.startsWith('h') && (n.type !== 'li' || n.liType !== 'default')).map(c => md.clone(c));
md.visitAll(comments, node => {
if (node.liType === 'bullet')
node.liType = 'default';
});
return md.render(comments);
return md.render(comments, 120);
}
/**
@ -149,24 +149,24 @@ function patchLinks(item, spec, classesMap, membersMap, linkRenderer) {
md.visitAll(spec, node => {
if (!node.text)
return;
node.text = node.text.replace(/\[`((?:event|method|property): [^\]]+)`\]/g, (_, p1) => {
node.text = node.text.replace(/\[`((?:event|method|property): [^\]]+)`\]/g, (match, p1) => {
const member = membersMap.get(p1);
return linkRenderer({ member });
return linkRenderer({ member }) || match;
});
node.text = node.text.replace(/\[`(param|option): ([^\]]+)`\]/g, (_, p1, p2) => {
node.text = node.text.replace(/\[`(param|option): ([^\]]+)`\]/g, (match, p1, p2) => {
const context = {
clazz: item instanceof Documentation.Class ? item : undefined,
member: item instanceof Documentation.Member ? item : undefined,
};
if (p1 === 'param')
return linkRenderer({ ...context, param: p2 });
return linkRenderer({ ...context, param: p2 }) || match;
if (p1 === 'option')
return linkRenderer({ ...context, option: p2 });
return linkRenderer({ ...context, option: p2 }) || match;
});
node.text = node.text.replace(/\[([\w]+)\]/, (match, p1) => {
const clazz = classesMap.get(p1);
if (clazz)
return linkRenderer({ clazz });
return linkRenderer({ clazz }) || match;
return match;
});
});

View File

@ -17,15 +17,29 @@
// @ts-check
const path = require('path');
const Documentation = require('./Documentation');
const { MDOutline } = require('./MDBuilder');
const PROJECT_DIR = path.join(__dirname, '..', '..');
{
const { documentation } = new MDOutline(path.join(PROJECT_DIR, 'docs-src', 'api-body.md'), path.join(PROJECT_DIR, 'docs-src', 'api-params.md'));
const result = serialize(documentation);
const outline = new MDOutline(path.join(PROJECT_DIR, 'docs-src', 'api-body.md'), path.join(PROJECT_DIR, 'docs-src', 'api-params.md'));
outline.renderLinks(item => {
const { clazz, member, param, option } = item;
if (param)
return `\`${param}\``;
if (option)
return `\`${option}\``;
if (clazz)
return `\`${clazz.name}\``;
});
outline.generateSourceCodeComments();
const result = serialize(outline);
console.log(JSON.stringify(result));
}
/**
* @param {Documentation} documentation
*/
function serialize(documentation) {
const result = {};
for (const clazz of documentation.classesArray)
@ -33,6 +47,9 @@ function serialize(documentation) {
return result;
}
/**
* @param {Documentation.Class} clazz
*/
function serializeClass(clazz) {
const result = { name: clazz.name };
if (clazz.extends)
@ -58,11 +75,13 @@ function serializeClass(clazz) {
return result;
}
/**
* @param {Documentation.Member} member
*/
function serializeMember(member) {
const result = { ...member };
const result = /** @type {any} */ ({ ...member });
sanitize(result);
result.args = {};
delete member.clazz;
for (const arg of member.argsArray)
result.args[arg.name] = serializeProperty(arg);
if (member.type)
@ -83,6 +102,7 @@ function sanitize(result) {
delete result.args;
delete result.argsArray;
delete result.templates;
delete result.clazz;
if (result.properties && !Object.keys(result.properties).length)
delete result.properties;
if (result.comment === '')

View File

@ -58,7 +58,7 @@ let hadChanges = false;
return createMemberLink(`${member.clazz.varName}.${member.name}`);
throw new Error('Unknown member kind ' + member.kind);
});
outline.renderComments();
outline.generateSourceCodeComments();
documentation = outline.documentation;
// Root module types are overridden.

View File

@ -156,12 +156,13 @@ function parse(content) {
/**
* @param {MarkdownNode[]} nodes
* @param {number=} maxColumns
*/
function render(nodes) {
function render(nodes, maxColumns) {
const result = [];
let lastNode;
for (let node of nodes) {
innerRenderMdNode(node, lastNode, result);
innerRenderMdNode(node, lastNode, result, maxColumns);
lastNode = node;
}
return result.join('\n');
@ -170,9 +171,10 @@ function render(nodes) {
/**
* @param {MarkdownNode} node
* @param {MarkdownNode} lastNode
* @param {number=} maxColumns
* @param {string[]} result
*/
function innerRenderMdNode(node, lastNode, result) {
function innerRenderMdNode(node, lastNode, result, maxColumns) {
const newLine = () => {
if (result[result.length - 1] !== '')
result.push('');
@ -184,7 +186,7 @@ function innerRenderMdNode(node, lastNode, result) {
result.push(`${'#'.repeat(depth)} ${node.text}`);
let lastNode = node;
for (const child of node.children || []) {
innerRenderMdNode(child, lastNode, result);
innerRenderMdNode(child, lastNode, result, maxColumns);
lastNode = child;
}
}
@ -193,7 +195,7 @@ function innerRenderMdNode(node, lastNode, result) {
const bothComments = node.text.startsWith('>') && lastNode && lastNode.type === 'text' && lastNode.text.startsWith('>');
if (!bothComments && lastNode && lastNode.text)
newLine();
result.push(node.text);
result.push(wrapText(node.text, maxColumns));
}
if (node.type === 'code') {
@ -220,7 +222,7 @@ function innerRenderMdNode(node, lastNode, result) {
case 'default': char = '-'; break;
case 'ordinal': char = '1.'; break;
}
result.push(`${indent}${char} ${node.text}`);
result.push(`${indent}${char} ${wrapText(node.text, maxColumns, indent + ' '.repeat(char.length + 1))}`);
for (const child of node.children || [])
visit(child, indent + ' ');
};
@ -228,6 +230,45 @@ function innerRenderMdNode(node, lastNode, result) {
}
}
/**
* @param {string} text
*/
function tokenizeText(text) {
const links = [];
// Don't wrap simple links with spaces.
text = text.replace(/\[[^\]]+\]/g, match => {
links.push(match);
return `[${links.length - 1}]`;
});
return text.split(' ').map(c => c.replace(/\[(\d+)\]/g, (_, p1) => links[+p1]));
}
/**
* @param {string} text
* @param {number=} maxColumns
* @param {string=} indent
*/
function wrapText(text, maxColumns = 0, indent = '') {
if (!maxColumns)
return text;
const lines = [];
maxColumns -= indent.length;
const words = tokenizeText(text);
let line = '';
for (const word of words) {
if (line.length && line.length + word.length < maxColumns) {
line += ' ' + word;
} else {
if (line)
lines.push(line);
line = (lines.length ? indent : '') + word;
}
}
if (line)
lines.push(line);
return lines.join('\n');
}
/**
* @param {MarkdownNode} node
*/