UNPKG

js-checker

Version:
298 lines (283 loc) 11.7 kB
/** * Created by zhangdianpeng on 2018/11/5. */ let ejs = require('ejs'); let fs = require('fs'); let path = require('path'); function innerHTML(s) { let start = s.indexOf('>'); let end = s.lastIndexOf('<'); return s.substring(start+1, end); } function FoldedMark(message) { return `<span class="foldedMark">${message}</span>`; } function Mark(mark) { return `<span class="mark">${mark}</span>`; } let FOLDID = 0; let createTree = function (name, data) { let { name: type, attribute = [], description = '' } = data; let res; // logContext 过滤不显示 if (name == 'logContext') { return {}; } if (['Obj', 'Or', 'Default', 'Value', 'Optional', 'Arr', 'OrVal', 'Map', 'Extend', 'OrValType', 'CFn'].includes(type)) { let keys, defaultVal, valType, valAttribute; switch(type) { case 'Obj': keys = Object.keys(attribute); res = keys.reduce((res, key) => { return res.concat([createTree(key, attribute[key])]); }, []); if (res.length == 0) { return { name, type, attribute: [] }; } return { name, type, description, attribute: res }; case 'Default': [valType, defaultVal] = attribute; attribute = createTree('', valType); return { name, type, description, attribute: [attribute, defaultVal] }; case 'Value': type = ''; switch (Object.prototype.toString.call(attribute)) { case '[object Number]': type = 'Num'; break; case '[object String]': type = 'Str'; break; case '[object Boolean]': type = 'Bool'; break; case '[object Null]': type = 'Null'; break; } return { name, type, attribute }; case 'Map': attribute = [{ key: createTree('', attribute[0]), value: createTree('', attribute[1]) }]; return { name, type, description, attribute }; case 'Optional': attribute = [attribute]; case 'Or': case 'OrVal': case 'Arr': attribute = attribute.reduce((res, attr) => { let tree = createTree(void 0, attr); return res.concat([tree]); }, []); return { name, type, description, attribute }; case 'OrValType': valType = attribute.type; valAttribute = attribute.values; attribute = valAttribute.reduce((res, attr) => { return res.concat([{ type: valType.name, description: valType.description, attribute: [attr] }]); }, []); return { name, type, description, attribute }; case 'CFn': attribute = [ { name: 'input', type: 'fnInput', description: '输入参数检查', attribute: attribute.input.map(attr => createTree(void 0, attr)) }, Object.assign(createTree(void 0, attribute.output), {name: 'output'}) ]; return { name, type: 'Obj', description, attribute } } } else { return { name, type, attribute, description }; } }; let getRenderData = function (type, name, description, attribute, isRoot = true) { let template, hasComplex, attributeTemplate; if (isRoot) FOLDID = 0; let complexTypes = ['Obj', 'Extend', 'Or', 'OrVal', 'OrValType', 'Map']; switch (type) { case 'Obj': template = ` <div class="obj ${ isRoot ? 'unfold':'fold' }" fold-id=${FOLDID++}> ${ name ? `<span class="field-name">${name}:</span>`: '' } ${ type == 'Extend' ? `${ type ? `<span class="C-type">${type}</span>`:'' }`: `<span style="display: none;">${type}</span>` } ${ description ? `<span class="description">${description}</span>`: '' } ${Mark`{`} ${ attribute.length > 0 ? ` <div class="attribute"> ${attribute.map(a => getRenderData(a.type, a.name, a.description, a.attribute, false) ).join('\n')} </div> ` : '' } ${Mark`}`} ${FoldedMark`{ ... }`} </div> `; return template; case 'Map': if (attribute.length > 0) attribute = attribute[0]; let mapAttributeTemplate = ''; let mapKey = attribute.key; let mapValue = attribute.value; if (attribute) { let keyTemp = getRenderData(mapKey.type, mapKey.name, mapKey.description, mapKey.attribute, false); let valueTemp = getRenderData(mapValue.type, mapValue.name, mapValue.description, mapValue.attribute, false); keyHasComplex = complexTypes.includes(mapKey.type) || complexTypes.some(type => (keyTemp.indexOf(type) > -1)); valueHasComplex = complexTypes.includes(mapValue.type) || complexTypes.some(type => (valueTemp.indexOf(type) > -1)); mapAttributeTemplate = ` <div class="attribute"> <div class="basic ${keyHasComplex ? 'fold':''}" fold-id=${FOLDID++}> key: ${innerHTML(keyTemp)} </div> <div class="basic ${valueHasComplex ? 'fold':''}" fold-id=${FOLDID++}> value: ${innerHTML(valueTemp)} </div> </div> `; } else { mapAttributeTemplate = ''; } template = ` <div class="map fold" fold-id=${FOLDID++}> ${ name ? `<span class="field-name">${name}:</span>`:'' } <span class="C-type">${type}</span> ${ description ? `<span class="description">${description}</span>`:'' } ${Mark`{`} ${ mapAttributeTemplate } ${Mark`}`} ${FoldedMark`{ ... }`} </div> `; return template; case 'Default': attributeTemplate = ''; if (attribute[0]) { attributeTemplate = innerHTML(getRenderData(attribute[0].type, attribute[0].name, attribute[0].description, attribute[0].attribute, false)); } else { attributeTemplate = ''; } hasComplex = complexTypes.some(type => (attributeTemplate.indexOf(type) > -1)); template = ` <div class="default ${hasComplex ? 'fold':''}" fold-id=${FOLDID++}> ${ name ? `<span class="field-name">${name}</span>` : '' } 默认值: ${attribute[1]} ${ attributeTemplate } ${ description ? `<span class="description">${description}</span>`:'' } </div> `; return template; case 'Or': case 'OrVal': case 'OrValType': case 'fnInput': if (type == 'OrValType') type = 'OrVal'; template = ` <div class="or ${isRoot ? 'unfold': 'fold'}" fold-id=${FOLDID++}> ${ name ? `<span class="field-name">${name}:</span>` : '' } ${ type != 'fnInput' ? `<span class="C-type">${type}</span>`: ''} ${ description ? `<span class="description">${description}</span>`:'' } ${Mark`[`} ${ attribute ? ` <div class="attribute"> ${ attribute.map((a, idx) => { hasComplex = complexTypes.includes(a.type); return ` <div class="basic ${hasComplex ? 'fold':''}" fold-id=${FOLDID++}> ${idx}: ${ innerHTML(getRenderData(a.type, a.name, a.description, a.attribute, false)) } </div> `; }).join('\n') } </div> `: `${attribute}` } ${Mark`]`} ${FoldedMark`[ ... ]`} </div> `; return template; case 'Arr': case 'Optional': attributeTemplate = attribute.map(a => { return innerHTML(getRenderData(a.type, '', a.description, a.attribute, false)); }).join('\n'); hasComplex = complexTypes.some(type => (attributeTemplate.indexOf(type) > -1)); template = ` <div class="optional ${hasComplex ? 'fold':''}" fold-id=${FOLDID++}> ${ name ? `<span class="field-name">${name}:</span>`: '' } <span class="C-type">${type}</span> ${ description ? `<span class="description">${description}</span>` : '' } ${attributeTemplate} </div> `; return template; case 'Null': case 'Any': case 'Bool': case 'Num': case 'Str': case 'Date': case 'TObj': case 'TArr': if (type == 'Str') { Array.isArray(attribute) && (attribute = attribute.join()); attribute = attribute ? `<span>"${attribute}"</span>` : ''; } else if (type == 'TObj') { attribute = `<span>{ }</span>`; } else if (type == 'TArr'){ attribute = `<span>[ ]</span>`; } else { attribute = `<span>${attribute}</span>`; } template = ` <div class="basic"> ${ name ? `<span class="field-name">${name}:</span>`:'' } <span class="T-type">${type}</span> ${ description ? `<span class="description">${description}</span>` : ''} ${ attribute } </div> `; return template; } }; let renderHtml = function (showData, title = 'test') { let { type, attribute, description } = createTree(title, showData); let renderData = getRenderData(type, title, description, attribute); return ejs.render(fs.readFileSync(path.join(__dirname, './type.ejs')).toString(), {renderData, title: 'test'}); }; let getHtml = (showData, htmlPath) => { htmlPath = htmlPath || path.resolve(__dirname, './test.html'); let renderStr = renderHtml(showData); fs.writeFileSync(htmlPath, renderStr); }; module.exports = { createTree, getHtml, renderHtml };