From ff84493fac65cdcdf836400b844b42b8b2b7e1e1 Mon Sep 17 00:00:00 2001 From: "Jill \"oatmealine\" Monoids" Date: Wed, 3 Nov 2021 11:24:05 +0300 Subject: [PATCH] better type transpiling --- index.js | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index d39bb71..faf4467 100644 --- a/index.js +++ b/index.js @@ -8,6 +8,51 @@ const outPath = path.resolve(__dirname, './out/'); let classes = {}; +let tsToLuaTypes = { + undefined: 'nil', + unknown: 'any', +} + +function transpileType(type) { + type = type.trim(); + + if (type.startsWith('(') && type.endsWith(')')) type = type.slice(1, -1); + + if (tsToLuaTypes[type]) { + return tsToLuaTypes[type]; + } + + if (type.endsWith('[]')) { + return transpileType(type.slice(0, -2)) + '[]'; + } + + if (type.includes('|')) { + return type.split('|').map(t => transpileType(t)).join(' | '); + } + + if (type.startsWith('Record<')) { + return 'table<' + transpileType(type.split(',')[0].replace('Record<','')) + ', ' + transpileType(type.split(',')[1].replace('>','')) + '>'; + } + if (type.startsWith('LuaTable<')) { + return 'table<' + transpileType(type.split(',')[0].replace('LuaTable<','')) + ', ' + transpileType(type.split(',')[1].replace('>','')) + '>'; + } + + let match; + + if (match = /\((.*?)\) ?=> ?(.*)/.exec(type)) { // functions + return `fun(${match[1] !== '' ? match[1].split(',').map(c => c.split(':')[0] + ':' + transpileType(c.split(':')[1])).join(',') : ''}): ${transpileType(match[2])}`; + } + + if (match = /(?:Array)|(?:Map)<(.*?)>/.exec(type)) { + return transpileType(match[1]) + '[]'; + } + + if (match = /(.*?)<(.*?)>/.exec(type)) { // any other weird type we just discard + return transpileType(match[2]); + } + return type; +} + function transpile(parsed, indent, prefix) { let global = false; indent = indent || 0; @@ -29,11 +74,11 @@ function transpile(parsed, indent, prefix) { } classes[d.name] = contents; - return `---@class ${d.name}${n}${contents.filter(e => e[0] === 'const').map(c => `---@field public ${c[1].name} ${c[1].type}${n}`).join('')}${global ? '' : '__class_'}${d.name} = {}${n}${contents.filter(e => e[0] !== 'const').map(c => transpile(c, indent, `${global ? '' : '__class_'}${d.name}`)).join(n)}\n`; + return `---@class ${d.name}${n}${contents.filter(e => e[0] === 'const').map(c => `---@field public ${c[1].name} ${transpileType(c[1].type)}${n}`).join('')}${global ? '' : '__class_'}${d.name} = {}${n}${contents.filter(e => e[0] !== 'const').map(c => transpile(c, indent, `${global ? '' : '__class_'}${d.name}`)).join(n)}\n`; case 'function': - return `${d.arguments.map(p => `---@param ${p.name.replace('?', '')} ${p.type}${n}`).join('')}---@return ${d.returns}${n}function ${prefix ? prefix + ':' : ''}${d.name}(${d.arguments.map(a => a.name.replace('?', '')).join(', ')}) end`; + return `${d.arguments.map(p => `---@param ${p.name.replace('?', '')} ${transpileType(p.type)}${n}`).join('')}---@return ${transpileType(d.returns)}${n}function ${prefix ? prefix + ':' : ''}${d.name}(${d.arguments.map(a => a.name.replace('?', '')).join(', ')}) end`; case 'const': - return `---@type ${d.type}${n}${prefix ? prefix + '.' : ''}${d.name} = nil`; + return `---@type ${transpileType(d.type)}${n}${prefix ? prefix + '.' : ''}${d.name} = nil`; case 'enum': return `${prefix ? prefix + '.' : ''}${d.name} = {${n} ${d.contents.map(c => `${c.name} = ${c.value}`).join(`,${n} `)}${n}}`; } @@ -61,6 +106,7 @@ function parse(code) { // sanitize stuff code = removeComments(code); + let match; const elements = []; // look for interfaces @@ -83,7 +129,7 @@ function parse(code) { // look for functions let functionFreeCode = code; - const functions = /(function)?\s(\w+)\s*\(([^;]*)\)(\s*:\s*([\w\[\]]+))?/g; // wow this sucks + const functions = /(function)?\s(\w+)\s*\(([^;]*)\)(\s*:\s*([\w\[\]\s|<>,]+))?/g; // wow this sucks while ((match = functions.exec(code)) !== null) { functionFreeCode = functionFreeCode.replace(match[0], ''); let arguments = match[3].split(',').map(s => {