@vuese/markdown-render
Version:
Render raw markdown string according to AST
464 lines (458 loc) • 16.9 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
function genMarkdownTpl (parserRes) {
const desc = parserRes.componentDesc;
let templateStr = '# [name]\n\n';
if (desc && desc.default.length) {
templateStr += `${desc.default.join(' ')}\n\n`;
}
const forceGenerate = desc && desc.vuese && parserRes.name;
const original = templateStr;
templateStr += parserRes.props ? genBaseTemplate('props') : '';
templateStr += parserRes.events ? genBaseTemplate('events') : '';
templateStr += parserRes.slots ? genBaseTemplate('slots') : '';
templateStr += parserRes.methods ? genBaseTemplate('methods') : '';
templateStr += parserRes.computed ? genBaseTemplate('computed') : '';
templateStr += parserRes.mixIns ? genBaseTemplate('mixIns') : '';
templateStr += parserRes.data ? genBaseTemplate('data') : '';
templateStr += parserRes.watch ? genBaseTemplate('watch') : '';
return !forceGenerate && original === templateStr ? '' : templateStr;
}
function genBaseTemplate(label) {
let str = `## ${upper(label)}\n\n`;
str += `<!-- :[name]:${label}:start -->\n`;
str += `<!-- :[name]:${label}:end -->\n\n`;
return str;
}
function upper(word) {
return word[0].toUpperCase() + word.slice(1);
}
const nameRE = /\[name\]/g;
const htmlCommentRE = /<!--\s*:([a-zA-Z_][\w\-\.]*|\[name\]):(\w+):start\s*-->[^]*<!--\s*:\1:\2:end\s*-->/;
function renderMarkdown (renderRes, parserRes) {
const mdTemplate = genMarkdownTpl(parserRes);
// Indicates that this component has no documentable content
if (!mdTemplate)
return null;
let str = mdTemplate;
const compName = parserRes.name;
const groupName = parserRes.componentDesc && parserRes.componentDesc.group
? parserRes.componentDesc.group[0]
: undefined;
if (compName) {
str = mdTemplate.replace(nameRE, compName);
}
let index = 0, stream = str;
while (stream) {
const res = stream.match(htmlCommentRE);
if (res) {
const matchText = res[0];
const type = res[2];
const i = stream.indexOf(matchText);
const currentHtmlCommentRE = new RegExp(`<!--\\s*:(${compName ? compName : '\\[name\\]'}):(${type}):start\\s*-->[^]*<!--\\s*:\\1:\\2:end\\s*-->`);
str = str.replace(currentHtmlCommentRE, (s, c1, c2) => {
if (renderRes[type]) {
let code = `<!-- :${c1}:${c2}:start -->\n`;
code += renderRes[type];
code += `\n<!-- :${c1}:${c2}:end -->\n`;
return code;
}
return s;
});
index = i + matchText.length;
}
else {
index = stream.length;
}
stream = stream.slice(index);
}
return {
content: str,
componentName: compName || '',
groupName: groupName || 'BASIC'
};
}
class Render {
constructor(parserResult, options) {
this.parserResult = parserResult;
this.options = options;
this.options = Object.assign({}, {
props: ['Name', 'Description', 'Type', 'Required', 'Default'],
events: ['Event Name', 'Description', 'Parameters'],
slots: ['Name', 'Description', 'Default Slot Content'],
methods: ['Method', 'Description', 'Parameters'],
computed: ['Computed', 'Type', 'Description', 'From Store'],
mixIns: ['MixIn'],
data: ['Name', 'Type', 'Description', 'Default'],
watch: ['Name', 'Description', 'Parameters']
}, this.options);
}
render() {
const { props, slots, events, methods, mixIns, data, computed, watch } = this.parserResult;
const md = {};
if (props) {
md.props = this.propRender(props);
}
if (slots) {
md.slots = this.slotRender(slots);
}
if (events) {
md.events = this.eventRender(events);
}
if (methods) {
md.methods = this.methodRender(methods);
}
if (computed) {
md.computed = this.computedRender(computed);
}
if (mixIns) {
md.mixIns = this.mixInRender(mixIns);
}
if (data) {
md.data = this.dataRender(data);
}
if (watch) {
md.watch = this.watchRender(watch);
}
return md;
}
propRender(propsRes) {
const propConfig = this.options.props;
let code = this.renderTabelHeader(propConfig);
propsRes.forEach((prop) => {
const row = [];
for (let i = 0; i < propConfig.length; i++) {
if (propConfig[i] === 'Name') {
row.push(prop.name);
}
else if (propConfig[i] === 'Description') {
let desc = ['-'];
if (prop.describe && prop.describe.length) {
desc = prop.describe;
if (prop.validatorDesc) {
desc = prop.describe.concat(prop.validatorDesc);
}
}
row.push(desc.join(' '));
}
else if (propConfig[i] === 'Type') {
if (prop.typeDesc) {
row.push(prop.typeDesc.join(' '));
}
else if (!prop.type) {
row.push('—');
}
else if (typeof prop.type === 'string') {
row.push(`\`${prop.type}\``);
}
else if (Array.isArray(prop.type)) {
row.push(prop.type
.map(t => `\`${t}\` / `)
.join(' ')
.slice(0, -3));
}
else {
row.push('-');
}
}
else if (propConfig[i] === 'Required') {
if (typeof prop.required === 'undefined') {
row.push('`false`');
}
else if (typeof prop.required === 'boolean') {
row.push(`\`${String(prop.required)}\``);
}
else {
row.push('-');
}
}
else if (propConfig[i] === 'Default') {
if (prop.defaultDesc) {
row.push(prop.defaultDesc.join(' '));
}
else if (prop.default) {
row.push(typeof prop.default === 'object'
? JSON.stringify(prop.default)
: prop.default);
}
else {
row.push('-');
}
}
else {
row.push('-');
}
}
code += this.renderTabelRow(row);
});
return code;
}
slotRender(slotsRes) {
const slotConfig = this.options.slots;
let code = this.renderTabelHeader(slotConfig);
// If the template and script contain slots with the same name,
// only the slots in the template are rendered
const slotInTemplate = [];
const slotInScript = [];
slotsRes.forEach((slot) => {
slot.target === 'template'
? slotInTemplate.push(slot)
: slotInScript.push(slot);
});
slotsRes = slotInTemplate.concat(slotInScript.filter(ss => {
for (let i = 0; i < slotInTemplate.length; i++) {
if (ss.name === slotInTemplate[i].name)
return false;
}
return true;
}));
slotsRes.forEach((slot) => {
const row = [];
for (let i = 0; i < slotConfig.length; i++) {
if (slotConfig[i] === 'Name') {
row.push(slot.name);
}
else if (slotConfig[i] === 'Description') {
if (slot.describe) {
row.push(slot.describe);
}
else {
row.push('-');
}
}
else if (slotConfig[i] === 'Default Slot Content') {
if (slot.backerDesc) {
row.push(slot.backerDesc);
}
else {
row.push('-');
}
}
else {
row.push('-');
}
}
code += this.renderTabelRow(row);
});
return code;
}
eventRender(propsRes) {
const eventConfig = this.options.events;
let code = this.renderTabelHeader(eventConfig);
propsRes.forEach((event) => {
const row = [];
for (let i = 0; i < eventConfig.length; i++) {
if (eventConfig[i] === 'Event Name') {
row.push(event.name);
}
else if (eventConfig[i] === 'Description') {
if (event.describe && event.describe.length) {
row.push(event.describe.join(' '));
}
else {
row.push('-');
}
}
else if (eventConfig[i] === 'Parameters') {
if (event.argumentsDesc) {
row.push(event.argumentsDesc.join(' '));
}
else {
row.push('-');
}
}
else {
row.push('-');
}
}
code += this.renderTabelRow(row);
});
return code;
}
methodRender(methodsRes) {
const methodConfig = this.options.methods;
let code = this.renderTabelHeader(methodConfig);
methodsRes.forEach((method) => {
const row = [];
for (let i = 0; i < methodConfig.length; i++) {
if (methodConfig[i] === 'Method') {
row.push(method.name);
}
else if (methodConfig[i] === 'Description') {
if (method.describe) {
row.push(method.describe.join(' '));
}
else {
row.push('-');
}
}
else if (methodConfig[i] === 'Parameters') {
if (method.argumentsDesc) {
row.push(method.argumentsDesc.join(' '));
}
else {
row.push('-');
}
}
else {
row.push('-');
}
}
code += this.renderTabelRow(row);
});
return code;
}
computedRender(computedRes) {
const computedConfig = this.options.computed;
let code = this.renderTabelHeader(computedConfig);
computedRes.forEach((computed) => {
const row = [];
for (let i = 0; i < computedConfig.length; i++) {
if (computedConfig[i] === 'Computed') {
row.push(computed.name);
}
else if (computedConfig[i] === 'Type') {
if (computed.type) {
row.push(`\`${computed.type.join(' ')}\``);
row.push();
}
else {
row.push('-');
}
}
else if (computedConfig[i] === 'Description') {
if (computed.describe) {
row.push(computed.describe.join(' '));
}
else {
row.push('-');
}
}
else if (computedConfig[i] === 'From Store') {
if (computed.isFromStore) {
row.push('Yes');
}
else {
row.push('No');
}
}
else {
row.push('-');
}
}
code += this.renderTabelRow(row);
});
return code;
}
mixInRender(mixInsRes) {
const mixInsConfig = this.options.mixIns;
let code = this.renderTabelHeader(mixInsConfig);
mixInsRes.forEach((mixIn) => {
const row = [];
for (let i = 0; i < mixInsConfig.length; i++) {
if (mixInsConfig[i] === 'MixIn') {
row.push(mixIn.mixIn);
}
else {
row.push('-');
}
}
code += this.renderTabelRow(row);
});
return code;
}
dataRender(dataRes) {
const dataConfig = this.options.data;
let code = this.renderTabelHeader(dataConfig);
dataRes.forEach((data) => {
const row = [];
for (let i = 0; i < dataConfig.length; i++) {
if (dataConfig[i] === 'Name') {
row.push(data.name);
}
else if (dataConfig[i] === 'Description') {
if (data.describe) {
row.push(data.describe.join(' '));
}
else {
row.push('-');
}
}
else if (dataConfig[i] === 'Type') {
if (data.type.length > 0) {
row.push(`\`${data.type}\``);
}
else {
row.push('—');
}
}
else if (dataConfig[i] === 'Default') {
if (data.default) {
row.push(data.default);
}
else {
row.push('-');
}
}
else {
row.push('-');
}
}
code += this.renderTabelRow(row);
});
return code;
}
watchRender(watchRes) {
const watchConfig = this.options.watch;
let code = this.renderTabelHeader(watchConfig);
watchRes.forEach((watch) => {
const row = [];
for (let i = 0; i < watchConfig.length; i++) {
if (watchConfig[i] === 'Name') {
row.push(watch.name);
}
else if (watchConfig[i] === 'Description') {
if (watch.describe) {
row.push(watch.describe.join(' '));
}
else {
row.push('-');
}
}
else if (watchConfig[i] === 'Parameters') {
if (watch.argumentsDesc) {
row.push(watch.argumentsDesc.join(' '));
}
else {
row.push('-');
}
}
else {
row.push('-');
}
}
code += this.renderTabelRow(row);
});
return code;
}
renderTabelHeader(header) {
const headerString = this.renderTabelRow(header);
const splitLine = this.renderSplitLine(header.length);
return headerString + splitLine + '\n';
}
renderTabelRow(row) {
return row.map(n => `|${n}`).join('') + '|\n';
}
renderSplitLine(num) {
let line = '';
for (let i = 0; i < num; i++) {
line += '|---';
}
return line + '|';
}
renderMarkdown() {
return renderMarkdown(this.render(), this.parserResult);
}
}
exports.Render = Render;
exports.default = Render;