feat: 增加导出schema table

This commit is contained in:
gaoxiaolin.gao 2018-03-06 11:35:09 +08:00
parent aabe214613
commit 73ed3b6463
6 changed files with 328 additions and 87 deletions

76
a.markdown Normal file
View File

@ -0,0 +1,76 @@
<h1 class="curproject-name"> swagger_test </h1>
# eeeeeee
[TOC]
## 13%0A%3Ca%20id%3D13%3E%20%3C/a%3E
[TOC]
### 基本信息
**Path** /api/13
**Method** GET
**接口描述:**
### Request
**Query**
| 参数名称 | 是否必须 | 示例 | 备注 |
| ------------ | ------------ | ------------ | ------------ |
| qqq | 是 | | |
| wwww | 是 | | |
| wwwww | 是 | | |
### Reponse
<table>
<thead class="ant-table-thead">
<tr>
<th key=name>名称</th><th key=type>类型</th><th key=required>是否必须</th><th key=default>默认值</th><th key=desc>备注</th><th key=sub>其他信息</th>
</tr>
</thead><tbody className="ant-table-tbody"><tr key=00><td key=0>id</td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span>The unique identifier for a product</span></td><td key=5>false,false</td></tr><tr key=01><td key=0>name</td><td key=1><span>string</span></td><td key=2>必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false,false</td></tr><tr key=02><td key=0>price</td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,<p key=1><span style={{ fontWeight: '700'}}>最小值: </span><span>0</span></p></td></tr><tr key=03><td key=0>arr</td><td key=1><span>string []</span></td><td key=2>非必须</td><td key=3></td><td key=4><span>bbbbb</span></td><td key=5>false,false,false,<p key=3><span style={{ fontWeight: '700'}}>item 类型: </span><span>string</span></p></td></tr><tr key=04><td key=0>tags</td><td key=1><span>object []</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5><p key=0><span style={{ fontWeight: '700'}}>最小数量: </span><span>1</span></p>,<p key=1><span style={{ fontWeight: '700'}}>元素是否都不同: </span><span>true</span></p>,false,<p key=3><span style={{ fontWeight: '700'}}>item 类型: </span><span>object</span></p></td></tr><tr key=040><td key=0>length</td><td key=1><span>number</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false</td></tr><tr key=041><td key=0>width</td><td key=1><span>number</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false</td></tr><tr key=042><td key=0>height</td><td key=1><span>number</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false</td></tr><tr key=05><td key=0>dimensions</td><td key=1><span>object</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5></td></tr><tr key=050><td key=0>length</td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false</td></tr><tr key=051><td key=0>width</td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false</td></tr><tr key=052><td key=0>height</td><td key=1><span>number</span></td><td key=2>必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false</td></tr>
</tbody>
</table>
## 16%0A%3Ca%20id%3D16%3E%20%3C/a%3E
[TOC]
### 基本信息
**Path** /api/16
**Method** GET
**接口描述:**
### Request
### Reponse
<table>
<thead class="ant-table-thead">
<tr>
<th key=name>名称</th><th key=type>类型</th><th key=required>是否必须</th><th key=default>默认值</th><th key=desc>备注</th><th key=sub>其他信息</th>
</tr>
</thead><tbody className="ant-table-tbody"><tr key=00><td key=0>success</td><td key=1><span>boolean</span></td><td key=2>必须</td><td key=3></td><td key=4><span></span></td><td key=5><p key=0><span style={{ fontWeight: '700'}}>枚举: </span><span>true,false</span></p></td></tr><tr key=01><td key=0>data</td><td key=1><span>object</span></td><td key=2>必须</td><td key=3></td><td key=4><span></span></td><td key=5></td></tr><tr key=010><td key=0>success</td><td key=1><span>boolean</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5><p key=0><span style={{ fontWeight: '700'}}>枚举: </span><span>true</span></p></td></tr><tr key=011><td key=0>data</td><td key=1><span>object</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5></td></tr><tr key=0110><td key=0>count</td><td key=1><span>number</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false</td></tr><tr key=0111><td key=0>rows</td><td key=1><span>object []</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false,false,<p key=3><span style={{ fontWeight: '700'}}>item 类型: </span><span>object</span></p></td></tr><tr key=01110><td key=0>name</td><td key=1><span>string</span></td><td key=2>必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false,false</td></tr><tr key=01111><td key=0>id</td><td key=1><span>string</span></td><td key=2>非必须</td><td key=3></td><td key=4><span></span></td><td key=5>false,false,false</td></tr>
</tbody>
</table>
# ee
[TOC]
# tag
[TOC]
# %u545C%u545C%u545C
[TOC]

View File

@ -1,5 +1,6 @@
import React, { Component } from 'react';
import { Table } from 'antd';
import PropTypes from 'prop-types'
import { schemaTransformToTable } from '../../../common/shema-transformTo-table.js';
import _ from 'underscore';
@ -81,57 +82,13 @@ const columns = [
}
];
const product = {
title: 'Product',
type: 'object',
properties: {
id: {
description: 'The unique identifier for a product',
type: 'number'
},
name: {
type: 'string'
},
price: {
type: 'number',
minimum: 0,
exclusiveMinimum: true
},
arr: {
type: 'array',
items: {
type: 'string',
description: 'bbbbb'
},
description: 'sdfsdf'
},
tags: {
type: 'array',
items: {
type: 'object',
properties: {
length: { type: 'number' },
width: { type: 'number' },
height: { type: 'number' }
}
},
minItems: 1,
uniqueItems: true
},
dimensions: {
type: 'object',
properties: {
length: { type: 'number' },
width: { type: 'number' },
height: { type: 'number' }
},
required: ['length', 'width', 'height']
}
},
required: ['id', 'name', 'price']
};
export default class SchemaTable extends Component {
class SchemaTable extends Component {
static propTypes = {
dataSource: PropTypes.string
}
constructor(props) {
super(props);
this.state = {
@ -140,13 +97,16 @@ export default class SchemaTable extends Component {
}
componentDidMount() {
let product = JSON.parse(this.props.dataSource)
this.setState({
data: schemaTransformToTable(product)
});
}
render() {
console.log('data', this.state.data);
return <Table dataSource={this.state.data} columns={columns} />;
return <Table bordered size="small" pagination={false} dataSource={this.state.data} columns={columns} />;
}
}
export default SchemaTable;

View File

@ -10,6 +10,7 @@ import ErrMsg from '../../../../components/ErrMsg/ErrMsg.js';
import variable from '../../../../constants/variable';
import constants from '../../../../constants/variable.js'
import copy from 'copy-to-clipboard';
import SchemaTable from '../../../../components/SchemaTable/SchemaTable.js'
const HTTP_METHOD = constants.HTTP_METHOD;
@ -95,12 +96,17 @@ class View extends Component {
}
}
res_body(res_body_type, res_body) {
res_body(res_body_type, res_body, res_body_is_json_schema) {
if (res_body_type === 'json') {
return <div className="colBody">
{/* <div id="vres_body_json" style={{ minHeight: h * 16 + 100 }}></div> */}
<AceEditor data={res_body} readOnly={true} style={{ minHeight: 600 }} />
</div>
if(res_body_is_json_schema) {
console.log('schema')
return <SchemaTable dataSource={res_body}/>
} else {
return <div className="colBody">
{/* <div id="vres_body_json" style={{ minHeight: h * 16 + 100 }}></div> */}
<AceEditor data={res_body} readOnly={true} style={{ minHeight: 600 }} />
</div>
}
} else if (res_body_type === 'raw') {
return <div className="colBody">
<AceEditor data={res_body} readOnly={true} mode="text" style={{ minHeight: 300 }} />
@ -108,6 +114,23 @@ class View extends Component {
}
}
req_body(req_body_type, req_body_other, req_body_is_json_schema) {
if(req_body_is_json_schema) {
return <SchemaTable dataSource={req_body_other}/>
} else {
return (
<div className="colBody">
<AceEditor
data={req_body_other}
readOnly={true} style={{ minHeight: 300 }}
mode={req_body_type === 'json' ? 'javascript' : 'text'} />
</div>
)
}
}
req_query(query) {
const columns = [{
title: '参数名称',
@ -275,9 +298,9 @@ class View extends Component {
// statusColor = statusColor[this.props.curData.status?this.props.curData.status.toLowerCase():"undone"];
const aceEditor = <div style={{ display: this.props.curData.req_body_other && (this.props.curData.req_body_type !== "form") ? "block" : "none" }} className="colBody">
<AceEditor data={this.props.curData.req_body_other} readOnly={true} style={{ minHeight: 300 }} mode={this.props.curData.req_body_type === 'json' ? 'javascript' : 'text'} />
</div>
// const aceEditor = <div style={{ display: this.props.curData.req_body_other && (this.props.curData.req_body_type !== "form") ? "block" : "none" }} className="colBody">
// <AceEditor data={this.props.curData.req_body_other} readOnly={true} style={{ minHeight: 300 }} mode={this.props.curData.req_body_type === 'json' ? 'javascript' : 'text'} />
// </div>
if (!methodColor) methodColor = "get";
let res = <div className="caseContainer">
@ -337,14 +360,19 @@ class View extends Component {
<div style={{ display: this.props.curData.method && HTTP_METHOD[this.props.curData.method.toUpperCase()].request_body ? '' : 'none' }}>
<h3 style={{ display: bodyShow ? '' : 'none' }} className="col-title">Body:</h3>
{aceEditor}
{/* {aceEditor}
{
} */}
{
this.props.curData.req_body_type ==='form' ?
this.req_body_form(this.props.curData.req_body_type, this.props.curData.req_body_form)
: this.req_body(this.props.curData.req_body_type, this.props.curData.req_body_other, this.props.curData.req_body_is_json_schema)
}
</div>
<h2 className="interface-title">Response</h2>
{this.res_body(this.props.curData.res_body_type, this.props.curData.res_body)}
{this.res_body(this.props.curData.res_body_type, this.props.curData.res_body, this.props.curData.res_body_is_json_schema)}
<h2 className="interface-title">备注</h2>
{this.props.curData.desc && <div className="tui-editor-contents" style={{margin: '0px', padding:'0px 20px', float: 'none'}} dangerouslySetInnerHTML={{ __html: this.props.curData.desc }}></div>}

View File

@ -1,3 +1,52 @@
const schema = require('./shema-transformTo-table.js')
const _ = require('underscore');
const messageMap = {
desc: '备注',
default: '实例',
maximum: '最大值',
minimum: '最小值',
maxItems: '最大数量',
minItems: '最小数量',
maxLength: '最大长度',
minLength: '最小长度',
uniqueItems: '元素是否都不同',
itemType: 'item 类型',
format: '版本',
enum: '枚举'
}
const columns = [
{
title: '名称',
dataIndex: 'name',
key: 'name'
}, {
title: '类型',
dataIndex: 'type',
key: 'type'
}, {
title: '是否必须',
dataIndex: 'required',
key: 'required'
},
{
title: '默认值',
dataIndex: 'default',
key: 'default'
},
{
title: '备注',
dataIndex: 'desc',
key: 'desc'
},
{
title: '其他信息',
dataIndex: 'sub',
key: 'sub'
}
];
function escapeStr(str, isToc) {
return isToc ? escape(str) : str;
@ -62,11 +111,112 @@ function createReqBody(req_body_type, req_body_form, req_body_other) {
return "";
}
function createResponse(res_body) {
function tableHeader(columns) {
let header = ``;
columns.map(item => {
header += `<th key=${item.key}>${item.title}</th>`
})
return header
}
function handleObject (text) {
if(!_.isObject(text)) {
return text
}
return Object.keys(text || {}).map((item, index) => {
let name = messageMap[item]
let value = text[item]
return(
!_.isUndefined(text[item]) && `<p key=${index}><span style={{ fontWeight: '700'}}>${name}: </span><span>${value.toString()}</span></p>`
)
})
}
function tableCol(col, columns) {
let tpl = ``;
columns.map( (item ,index)=> {
let dataIndex = item.dataIndex;
let value = col[dataIndex]
value = _.isUndefined(value) ? '': value
let text = ``;
switch (dataIndex){
case 'sub':
text = handleObject(value);
break;
case 'type':
text = ( value === 'array' ? `<span>${ col.sub.itemType || ''} []</span>` : `<span>${value}</span>`)
break;
case 'required':
text = value ? '必须': '非必须';
break;
case 'desc':
text = _.isUndefined(col.childrenDesc)? `<span>${value}</span>` : `<span>${col.childrenDesc}</span>`
break;
default:
text = value
}
// let text =
tpl += `<td key=${index}>${text}</td>`
})
return tpl;
}
function tableBody(dataSource, columns) {
// 按照columns的顺序排列数据
let tpl = ``;
dataSource.map(col => {
let child = null;
if(!_.isUndefined(col.children)&& _.isArray(col.children)) {
child = tableBody(col.children, columns)
}
tpl +=`<tr key=${col.key}>${tableCol(col,columns)}</tr>`
tpl += child ? `${child}`: ``
})
return tpl;
}
function createSchemaTable(body){
let template = ``;
let dataSource = schema.schemaTransformToTable(JSON.parse(body));
template += `<table>
<thead class="ant-table-thead">
<tr>
${
tableHeader(columns)
}
</tr>
</thead>`
template += `<tbody className="ant-table-tbody">${tableBody(dataSource, columns)}
</tbody>
</table>
`
return template
}
function createResponse(res_body, res_body_is_json_schema) {
let resTitle = `\n### Reponse\n\n`;
if (res_body) {
let resBody = "```javascript" + `\n${res_body || ""}\n` + "```";
return resTitle + resBody;
if(res_body_is_json_schema) {
let resBody = createSchemaTable(res_body)
return resTitle + resBody;
} else {
let resBody = "```javascript" + `\n${res_body || ""}\n` + "```";
return resTitle + resBody;
}
}
return "";
}
@ -91,7 +241,7 @@ function createInterMarkdown(basepath, listItem, isToc){
mdTemplate += createReqBody(listItem.req_body_type, listItem.req_body_form, listItem.req_body_other);
// Response
// Response-body
mdTemplate += createResponse(listItem.res_body);
mdTemplate += createResponse(listItem.res_body, listItem.res_body_is_json_schema);
return mdTemplate;
}

View File

@ -1,4 +1,4 @@
import _ from 'underscore';
const _ = require('underscore');
exports.schemaTransformToTable = (schema) =>{
try{
@ -10,18 +10,36 @@ exports.schemaTransformToTable = (schema) =>{
}
}
// 自动添加type
function checkJsonSchema(json) {
let newJson = Object.assign({}, json)
if (_.isUndefined(json.type) && _.isObject(json.properties) ){
newJson.type = 'object'
}
// console.log('newJson', newJson)
return newJson;
}
const mapping = function(data, index) {
switch(data.type){
case 'string':
return SchemaString(data);
case 'number':
return SchemaNumber(data);
case 'array':
return SchemaArray(data, index);
case 'object':
return SchemaObject(data, index);
case 'boolean':
return SchemaBoolean(data);
case 'integer':
return SchemaInt(data)
default:
@ -38,8 +56,9 @@ const SchemaObject = (data, key) => {
let result =[];
Object.keys(properties).map((name, index) => {
let value = properties[name];
let copiedState = JSON.parse(JSON.stringify(value));
let optionForm = mapping(copiedState, index);
let copiedState = checkJsonSchema(JSON.parse(JSON.stringify(value)));
let optionForm = mapping(copiedState, key+''+index);
let desc = optionForm.desc;
let d = optionForm.default;
let children = optionForm.children;
@ -49,31 +68,33 @@ const SchemaObject = (data, key) => {
delete optionForm.children;
let item = {
name,
type: value.type,
type: value.type || 'object',
required: required.indexOf(name) != -1,
sub: optionForm,
desc,
default: d,
key: key+''+index
}
if(value.type === 'array' && !_.isUndefined(children) ){
if( _.isArray(children)){
item.children = children
}
item = {
...item,
childrenDesc: children.desc
}
// item = {
// ...item,
// childrenDesc: children.desc
// }
item.childrenDesc = children.desc
}
if(value.type === 'object' ){
item = {
...item,
children: optionForm
}
if(value.type === 'object'|| _.isUndefined(value.type)){
// item = {
// ...item,
// children: optionForm
// }
item.children = optionForm
delete item.sub
}
@ -81,6 +102,8 @@ const SchemaObject = (data, key) => {
})
return result
@ -100,8 +123,9 @@ const SchemaString = (data) => {
const SchemaArray =(data, index) => {
data.items = data.items || {type: 'string'};
let items = checkJsonSchema(data.items)
let optionForm = mapping(items, index);
let optionForm = mapping(data.items, index);
let item = {
desc: data.description,
@ -109,11 +133,11 @@ const SchemaArray =(data, index) => {
minItems: data.minItems,
uniqueItems: data.uniqueItems,
maxItems: data.maxItems,
itemType: data.items.type,
itemType: items.type,
children: optionForm
}
return {...item}
return item
}
const SchemaNumber =(data) => {
@ -142,7 +166,8 @@ const SchemaBoolean = (data) =>{
let item = {
desc: data.description,
default: data.default
default: data.default,
enum: data.enum
}
return item
}

View File

@ -69,13 +69,15 @@ class exportController extends baseController {
async function createHtml(list) {
let md = await createMarkdown.bind(this)(list, true);
let markdown = new markdownIt({ html: true, breaks: true });
let markdown = markdownIt({ html: true, breaks: true });
markdown.use(markdownItAnchor); // Optional, but makes sense as you really want to link to something
markdown.use(markdownItTableOfContents, {
markerPattern: /^\[toc\]/im
});
require('fs').writeFileSync('./a.markdown', md)
let tp = unescape(markdown.render(md));
let left;
// console.log('tp',tp);
let content = tp.replace(/<div\s+?class="table-of-contents"\s*>[\s\S]*?<\/ul>\s*<\/div>/gi, function (match) {