routesToSwagger.mjs

import JSON5 from 'json5'
import map from 'lodash-es/map.js'
import join from 'lodash-es/join.js'
import replace from 'wsemi/src/replace.mjs'


let itemGet = `
'get': {
    'tags': [
        '{tag}'
    ],
    'summary': 'select {tag} by {col}',
    'description': 'select {tag} by {col}',
    'parameters': [
        {
            'in': 'query',
            'name': 'token',
            'type': 'string',
            'default': '{token}'
        },
        {
            'name': '{col}',
            'in': 'path',
            'description': '{colDescription}',
            'required': true,
            'type': '{colType}',
        }
    ],
    'responses': {
        '200': {
            'description': 'success'
        },
        'default': {
            'description': 'error'
        }
    }
},
`


let itemPost = `
'post': {
    'tags': [
        '{tag}'
    ],
    'summary': 'add or modify {tag} by {col}',
    'description': 'add or modify {tag} by {col}',
    'consumes': [
        'application/json',
    ],
    'parameters': [
        {
            'in': 'query',
            'name': 'token',
            'type': 'string',
            'default': '{token}'
        },
        {
            'name': '{col}',
            'in': 'path',
            'description': '{colDescription}',
            'required': true,
            'type': '{colType}',
        },
        {
            'name': 'body',
            'in': 'body',
            'description': '{tag} object in JSON string format',
            'required': true,
            'schema': {
                'type': 'string',
                'properties': {props}
            }
        }
    ],
    'responses': {
        '200': {
            'description': 'success'
        },
        'default': {
            'description': 'error'
        }
    }
},
`


let itemPut = itemPost.replace(`'post':`, `'put':`)


let itemDelete = `
'delete': {
    'tags': [
        '{tag}'
    ],
    'summary': 'delete {tag} by {col}',
    'description': 'delete {tag} by {col}',
    'parameters': [
        {
            'in': 'query',
            'name': 'token',
            'type': 'string',
            'default': '{token}'
        },
        {
            'name': '{col}',
            'in': 'path',
            'description': '{colDescription}',
            'required': true,
            'type': '{colType}',
        }
    ],
    'responses': {
        '200': {
            'description': 'success'
        },
        'default': {
            'description': 'error'
        }
    }
},
`


let itemsGet = `
'get': {
    'tags': [
        '{tag}'
    ],
    'summary': 'select all {tag}(s)',
    'description': 'select all {tag}(s)',
    'parameters': [
        {
            'in': 'query',
            'name': 'token',
            'type': 'string',
            'default': '{token}'
        }
    ],
    'security': [],
    'responses': {
        '200': {
            'description': 'success'
        },
        'default': {
            'description': 'error'
        }
    }
},
`


let itemsPost = `
'post': {
    'tags': [
        '{tag}'
    ],
    'summary': 'add or modify one or multiple {tag}(s)',
    'description': 'add or modify one or multiple {tag}(s)',
    'consumes': [
        'application/json',
    ],
    'parameters': [
        {
            'in': 'query',
            'name': 'token',
            'type': 'string',
            'default': '{token}'
        },
        {
            'name': 'body',
            'in': 'body',
            'description': '{tag} object or array of objects in JSON string format',
            'required': true,
            'schema': {
                'type': 'string',
                'properties': {props}
            }
        }
    ],
    'responses': {
        '200': {
            'description': 'success'
        },
        'default': {
            'description': 'error'
        }
    }
},
`


let itemsPut = itemsPost.replace(`'post':`, `'put':`)


let tagPath = `
'/{tag}': {
    {itemsGet}
    {itemsPost}
    {itemsPut}
},
`


let tagColPath = `
'/{tag}/{col}/{{col}}': {
    {itemGet}
    {itemPost}
    {itemPut}
    {itemDelete}
},
`

let swJSON = `
{
    'swagger': '2.0',
    'info': {
        'description': 'Server API(s) is generated by hapi.',
        'version': '1.0.0',
        'title': 'API Documents'
    },
    'host': '{host}',
    'basePath': '/{basePath}',
    'schemes': [
        'http'
    ],
    'paths': {
        {paths}
    },
}
`


function addPathFromItemProp(col, colDescription, colType) {
    let c = tagColPath
    c = replace(c, `{itemGet}`, itemGet)
    c = replace(c, `{itemPost}`, itemPost)
    c = replace(c, `{itemPut}`, itemPut)
    c = replace(c, `{itemDelete}`, itemDelete)
    c = replace(c, `{col}`, col)
    c = replace(c, `{colDescription}`, colDescription)
    c = replace(c, `{colType}`, colType)
    return c
}


function addPathFromItemProps(props) {
    let c = map(props, (p, col) => {
        return addPathFromItemProp(col, p.description, p.type)
    })
    return join(c, '')
}


function addPathFromItems() {
    let c = tagPath
    c = replace(c, `{itemsGet}`, itemsGet)
    c = replace(c, `{itemsPost}`, itemsPost)
    c = replace(c, `{itemsPut}`, itemsPut)
    return c
}


function addPath(tag, props) {
    let c = ''
    c += addPathFromItems()
    c += addPathFromItemProps(props)
    c = replace(c, `{tag}`, tag)
    c = replace(c, `{props}`, JSON.stringify(props))
    return c
}


function genPathsFromRoutes(routes) {
    let c = map(routes, (v) => {
        let tag = v.apiName
        let props = v.props
        return addPath(tag, props)
    })
    return join(c, '')
}


function genSWJson(host, basePath, routes, token) {
    let paths = genPathsFromRoutes(routes)
    let c = swJSON
    c = replace(c, `{host}`, host)
    c = replace(c, `{basePath}`, basePath)
    c = replace(c, `{paths}`, paths)
    c = replace(c, `{token}`, token)
    return JSON5.parse(c)
}


/**
 * 由Routes陣列資料轉Swagger的設定物件
 *
 * @param {String} [host='localhost:8080'] 輸入伺服器所在host字串,預設'localhost:8080'
 * @param {String} [apiParent='api'] 輸入api上層路徑字串,預設'api'
 * @param {Array} [routes=[]] 輸入Routes陣列,每個物件皆需要有表名字串'apiName'、主鍵名字串'pk'、物件所屬欄位物件'props',預設[]
 * @returns {Object} 回傳Swagger的設定物件
 */
function routesToSwagger(host = 'localhost:8080', apiParent = 'api', routes = [], token = '') {
    return genSWJson(host, apiParent, routes, token)
}


export default routesToSwagger