Skip to content

Commit

Permalink
feat: add test page
Browse files Browse the repository at this point in the history
  • Loading branch information
anotherso1a committed Jul 15, 2021
1 parent e043d68 commit 611937e
Showing 1 changed file with 177 additions and 0 deletions.
177 changes: 177 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>json2ts</title>
<style>
html,
body {
width: 100%;
height: 100%;
}

textarea {
width: 40%;
height: 70%;
}
</style>
</head>

<body>
<textarea id="input"></textarea>
<textarea id="output"></textarea>
<br>
<button id='convert'>Convert</button>
<script>

const simpleTypes = ['string', 'number', 'boolean']

/**
* 生成tscode
* @param { object | any[] } obj 对象或者数组
* @param {string} name 模块名
* @returns
*/
function convert(obj, name) {

if (obj instanceof Array) {
// array
let keys = [...new Set(obj.reduce((c, v) => c.concat(Object.keys(v)), []))] // every key been used
// descibe keys
let keysDesc = keys.reduce((res, k) => {
res[k] = {
types: new Set([]),
optional: false
}
return res
}, {})
// process optional && types
obj.forEach(item => {
if (typeof item !== 'object' || !item) return // ignore every simple type & arrays
// once any item not includes some keys in all, make them optional
keys.filter(k => !Object.keys(item).includes(k)).forEach(k => keysDesc[k].optional = true)
// generate types
Object.keys(item).forEach(k => {
let t = convertSingle(item[k], name, k)
keysDesc[k].types.add(t)
})
})
genCode(`interface ${name} {`) // start code
Object.keys(keysDesc).forEach(k => {
let key = keysDesc[k].optional ? `${k}?` : k // get key with optional
let type = [...keysDesc[k].types].join(' | ') // get types
genCode(` ${key}: ${type};`)
})
genCode(`}`) // end code

} else {
// object
genCode(`interface ${name} {`) // start
Object.keys(obj).forEach(k => {
let t = convertSingle(obj[k], name, k)
genCode(` ${k}: ${t};`) // every key types
})
genCode('}\n') // end
}
}

/**
*
* @param {any[]} arr 数组
* @param {string} k 键名,只在array中有对象时会使用
* @param {string} name 模块名
* @returns 类型
*/
function convertArray(arr, name, k = '') {
let item = arr[0]
// string number boolean
if (simpleTypes.includes(typeof item)) return typeof item
// null | undefined
if (!item) return 'any'
// array
if (item instanceof Array) {
return convertArray(item, name, k) + '[]'
}
// object
let objName = name + toCamalCase(k)
// 去重
stack.every(e => e.name !== objName) && stack.push({ // process by convert
name: objName,
value: arr
})
return objName
}

function convertSingle(item, name, k = '') {
let t = typeof item
// string number boolean
if (simpleTypes.includes(t)) return t
// undefined
if (t === 'undefined') return 'undefined'
// null
if (t === 'object' && !item) return 'null'
// array
if (item instanceof Array) {
let type = convertArray(item, name, k)
return `${type}[]`
}
// object
if (t === 'object') {
let objName = name + toCamalCase(k)
stack.every(e => e.name !== objName) && stack.push({ // process by convert
name: objName,
value: item
})
return objName
}
}

function toCamalCase(str) {
return str.replace(/(^|[-_])+(\w)/g, (...args) => {
return args[2].toUpperCase()
})
}

let stack = []
let res = '\n\n'
function genCode(code) {
res += code + '\n'
}


const input = document.getElementById('input')
const output = document.getElementById('output')
document.getElementById('convert').addEventListener('click', () => {
let json = input.value
stack = []
res = '\n\n'

try {
try {
json = JSON.parse(json)
} catch (err) {
json = new Function(`return ${json}`)()
}
} catch (err) {
alert(err)
}
stack.push({
name: 'tsModule',
value: json
})
try {
for (let i = 0; i < stack.length; i++) {
convert(stack[i].value, stack[i].name)
}
} catch (err) {
alert('解析失败:', err)
}
output.value = res
})
</script>
</body>

</html>

0 comments on commit 611937e

Please sign in to comment.