{"id":30283140,"url":"https://github.com/halliwood/ts2lua","last_synced_at":"2025-10-18T02:33:31.937Z","repository":{"id":57381375,"uuid":"199566541","full_name":"Halliwood/ts2lua","owner":"Halliwood","description":"Change typescript to lua.","archived":false,"fork":false,"pushed_at":"2023-07-11T14:14:03.000Z","size":137,"stargazers_count":32,"open_issues_count":1,"forks_count":3,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-08-09T17:55:31.990Z","etag":null,"topics":["lua","typescript"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Halliwood.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-07-30T03:20:05.000Z","updated_at":"2025-03-18T08:07:15.000Z","dependencies_parsed_at":"2022-09-01T01:00:45.449Z","dependency_job_id":null,"html_url":"https://github.com/Halliwood/ts2lua","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Halliwood/ts2lua","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Halliwood%2Fts2lua","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Halliwood%2Fts2lua/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Halliwood%2Fts2lua/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Halliwood%2Fts2lua/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Halliwood","download_url":"https://codeload.github.com/Halliwood/ts2lua/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Halliwood%2Fts2lua/sbom","scorecard":{"id":60935,"data":{"date":"2025-08-11","repo":{"name":"github.com/Halliwood/ts2lua","commit":"0641581289a8980b7c982ac7fa52ba2c8f105ba0"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.7,"checks":[{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":7,"reason":"3 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-15T01:41:26.467Z","repository_id":57381375,"created_at":"2025-08-15T01:41:26.467Z","updated_at":"2025-08-15T01:41:26.467Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270742064,"owners_count":24637513,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-16T02:00:11.002Z","response_time":91,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lua","typescript"],"created_at":"2025-08-16T17:14:07.491Z","updated_at":"2025-10-18T02:33:26.894Z","avatar_url":"https://github.com/Halliwood.png","language":"JavaScript","readme":"# ts2lua\nts2lua是一个将TypeScript代码转换为lua代码的工具。在使用之前，建议您先阅读[lua-objects](https://github.com/dmccuskey/lua-objects \"lua-objects的Github\")，它是一个很不错的lua面向对象解决方案，支持多重继承、getter/setter等，ts2lua按照lua-objects的规范来处理TypeScript类。\n\n## 安装\n```\n$ npm i ts2lua\n```\n\n## 用法\n转换TypeScript语句\n\n```JavaScript\nconst ts2lua = require('ts2lua');\nconst tsCode = 'let a = \"Hello World!\";';\nconst luaCode = ts2lua.translate(tsCode);\nconsole.log(luaCode);\n```\n\nTypeScript\n```TypeScript\nimport ts2lua = require('ts2lua');\n\nlet testCode = `\nlet num = 123;\nif(num \u003e 100) {\n  console.log(num + ' is bigger than 100!');\n} else {\n  console.log(num + ' is smaller than 100!');\n}\n`\nconsole.log(ts2lua.translate(testCode));\n```\n\n批量转换TypeScript文件\n\n```JavaScript\nconst ts2lua = require('ts2lua');\nconst inputPath = 'ts_file_root';\nconse outputPath = 'lua_file_root';\nts2lua.translateFiles(inputPath, outputPath);\n// 指定生成lua文件后缀名\nts2lua.translateFiles(inputPath, outputPath, { ext: '.lua.txt' });\n```\n\n## 批量转换接口的说明\n使用`translateFiles`可以批量转换TypeScript代码。先来看看index.d.ts的声明：\n\n```TypeScript\n/**\n * Translate typescript files from the given input path and write lua files into the given output path.\n * @param inputPath input path which contains typescript files to translate.\n * @param outputPath output path where to write lua files into.\n * @param option translate option\n */\nexport declare function translateFiles(inputPath : string, outputPath : string, option ?: TranslateOption): void;\n```\n\n其中，必选参数`inputPath`和`outputPath`分别表示TypeScript文件目录和生成的lua文件目录。可选参数`option`表示转换选项，当前支持如下选项：\n\n```TypeScript\nexport interface TranslateOption {\n  /**生成lua代码文件后缀名，默认为'.lua' */\n  ext?: string, \n  /**lua代码风格，默认适配xlua */\n  style?: 'xlua' | null, \n  /**是否在生成的lua代码中，增加ts2lua认为有必要人工处理的提示，默认为true */\n  addTip?: boolean,\n  /**函数名替换配置json文件路径，默认为lib\\\\func.json */\n  funcReplConfJson?: string, \n  /**正则表达式替换配置txt文件路径，默认为lib\\\\regex.txt */\n  regexReplConfTxt?: string, \n  /**对于没有替换配置的正则表达式，是否尝试简单翻译成lua，默认false。如果为true，则将正则表达式翻译为字符串，将转义符翻译成%。 */\n  translateRegex?: boolean,\n  /**输出未识别的正则表达式的文件路径，默认不输出 */\n  traceUnknowRegex?: string\n}\n```\n\n*可选字段`ext`表示生成lua文件后缀，比如可以指定为`.lua.txt`。\n*可选字段`style`表示生成lua代码的风格，默认是xlua风格，ts2lua会按照xlua的一些规范生成对应的lua代码，详细见下方说明。如果不使用xlua风格，请设置`style`为`null`，如下所示：\n\n```JavaScript\nts2lua.translateFiles('in', 'out', { style: null });\n```\n\n* 可选字段`addTip`默认为true，当ts2lua遇到无法确定转换结果100%效果一致时，将在代码中插入必要的提示。比如数组下标访问、正则表达式处理等。\n* 可选字段`funcReplConfJson`表示用于配置函数名转换规则的json文件的存放路径。ts2lua将根据该文件的映射关系对指定的函数名进行翻译，你可以直接修改默认配置`lib\\\\func.json`。比如，`replace`函数将默认翻译为`gsub`。\n* 可选字段`regexReplConfTxt`表示用于配置正则表达式转换规则的txt文件的存放路径。ts2lua将根据该文件的映射关系对指定的正则表达式进行翻译，你可以直接修改默认配置`lib\\\\regex.txt`。\n* 可选字段`translateRegex`若为`true`，则对于正则表达式转换规则json文件中没有配置的正则表达式，ts2lua将简单的进行处理：将正则表达式翻译为字符串，将转义符翻译成%。比如`/\\w+/g`将翻译成`'%w+'`。该字段默认为`false`，即原样输出（对lua来说，通常会有语法错误）。\n* 可选字段`traceUnknowRegex`表示未识别正则表达式的输出路径。若指定了该值，则对于正则表达式转换规则json文件中没有配置的正则表达式，ts2lua将记录到一个文件中，方便集中处理后加入到转换配置中。\n* 可选字段`ignoreNoUsedExp`若为`true`，则ts2lua会忽略代码块（`BlockStatement`）中没有实际用途的表达式（包括多余的成员表达式`MemberExpression`和标识`Identifier`访问）。该字段默认为`true`。如下述代码中多余的语句将被忽略：\n\nTypeScript\n```TypeScript\ndoStr() {\n  let idx = 2;\n  this.myArr;  // 这句是多余的MemberExpression\n  idx;  // 这句是多余的Identifier\n  console.log('idx == ' + idx);\n}\n```\n\nlua\n```lua\nfunction doStr()\n  local idx = 2\n  print('idx == ' .. idx)\nend\n```\n\n\n## 关于变量名、函数名不符合lua规范的处理\n如果变量名、函数名为lua关键字，则自动添加`tsvar_`的前缀。如果包含`$`等lua不支持的字符，则自动将`$`替换为`tsvar_`。\n\n## 关于单个ts文件中存在多个类定义的处理\nTypeScript允许在单个ts文件中定义多个类，lua其实也可以这么写。但是为了避免循环引用的问题，最好的做法是将每个“类”定义在单独的文件里。ts2lua采用了这一策略。比如，在`module/something/Thing.ts`中定义了类`ThingB`，ts2lua会将`ThingB`生成到`module/something/Thing/ThingB.lua`中。\n\n## 关于数组下标访问的处理\n由于lua的下标从1开始，所以对于类似`arr[i]`这种会转化为`arr[i+1]`，而对于`arr[idx]`这种则不会进行+1处理，ts2lua会自动添加注释提醒您人工确认转换结果是否正确。\n比如，下述代码将转换为\n\nTypeScript\n```TypeScript\ndoStr() {\n  if(this.subValue \u003e 10) {\n    console.log('subValue is bigger than 10: ' + this.subValue + ', yes!');\n  } else {\n    console.log('subValue is smaller than 10: ' + this.subValue + ', no!');\n  }\n  for(let i = 0, len = this.myArr.length; i \u003c len; i++) {\n    console.log(this.myArr[i]);\n  }\n  let idx = 2;\n  console.log('this.myArr[2] == ' + this.myArr[idx]);\n}\n```\n\nlua\n```lua\nfunction doStr()\n  if self.subValue\u003e10 then\n    print('subValue is bigger than 10: '..self.subValue..', yes!')\n    \n  else\n    print('subValue is smaller than 10: '..self.subValue..', no!')\n    \n  end\n  \n  local i=0\n  local len=#self.myArr\n  repeat\n    print(self.myArr[i+1])\n    i=i+1\n  until not(i\u003clen)\n  local idx=2\n  -- [ts2lua]self.myArr下标访问可能不正确\n  print('this.myArr[2] == '..self.myArr[idx])\nend\n```\n\n## 关于数组长度length的处理\n读取数组长度`arr.length`将处理成`#arr`，而修改数组长度则不做任何处理，请搜索ts2lua提示进行手动处理。比如下述代码转化为\n\nTypeScript\n```TypeScript\nlet arr = [1, 2, 3];\nconsole.log('数组长度为' + arr.length);\narr.length = 0;\n```\n\nlua\n```lua\nlocal arr = {1, 2, 3}\nprint('数组长度为' .. #arr)\n-- [ts2lua]修改数组长度需要手动处理。\narr.length = 0\n```\n\n## 关于运算符+的处理\n由于TypeScript采用+进行字符串连接，而lua采用..运算符。ts2lua在转换时尽可能识别字符串连接，但可能存在识别失败的情况，比如下述代码转化为\n\nTypeScript\n```TypeScript\npublic log(s: string) {\n    this._log += s;\n    this._log += '\\n';\n}\n```\n\nlua\n```lua\nfunction Result.prototype:log(s)\n  self._log = self._log + s\n  self._log = self._log .. '\\n'\nend\n```\n\n## 关于数组push的处理\n所有名字为push的方法都会处理成table.concat。\n\n## 关于自增/增减的处理(UpdateExpression)\n由于lua没有自增/自减运算符，所以类似`A++`会处理成`A = A + 1`。不可避免地，由于语法之间的差异，比如TypeScript的语句`myArr[A++]`会被处理成`myArr[A = A + 1]`，这在lua中是错误的。对于类似情况，ts2lua的转化结果可能不正确，需要手动处理。比如下述代码转化为：\n\nTypeScript\n```TypeScript\nd = arr[d++] + arr[d];\n```\n\nlua\n```lua\nd = arr[d=d+1] + arr[d+1]\n```\n\n上述代码是有问题的，您需要根据实际语境进行手动修改。\n\n## 关于形如a = b = c的赋值表达式的处理\n由于lua不允许类似`a = b = c`的语法，ts2lua将处理成`b = c`和`a = b`两个语句，比如下述代码转化为：\n\nTypeScript\n```TypeScript\nlet a = 1, b = 2, c = 3;\nlet d = a = b = c;\na *= b -= c;\na = b /= c;\n```\n\nlua\n```lua\nlocal a = 1\nlocal b = 2\nlocal c = 3\nb = c\na = b\nlocal d = a\nb = b - c\na = a * b\nb = b / c\na = b\n```\n\n## 关于===和!==的处理\n`===`和`!==`将转换为`==`和`~=`，这在可以预见的大部分情况下是正确的。反而值得注意的是，TypeScript中的`==`和lua中的`==`可能在某些情况下存在不同的结果。比如下述代码：\n\nTypeScript\n```TypeScript\nlet a = 1\nif(a == true) {\n  console.log('1 equals to true in TypeScript');  // a == true 成立\n} else {\n  console.log('1 not equals to true in TypeScript!');\n}\n```\n\nlua\n```lua\nlocal a = 1\nif a == true then\n  print('1 equals to true in lua.')\nelse\n  print('1 not equals to true in lua!')  -- a == true 不成立\nend\n```\n\nts2lua仅仅将`==`和`!=`转换为lua对应的`==`和`~=`，不会进行任何特殊处理，您还需要根据具体语境进行可能的修改。\n\n## 关于try-catch的处理\nts2lua使用了[模拟实现lua try-catch](lua/trycatch.lua \"trycatch.lua定义\")来转换TypeScript的try-catch语句。\n\n## 三元表达式的处理\n`a ? b : c`将转换为`(a and {b} or {c})[1]`。\n\n## 关于正则表达式的处理\n由于lua不适用POSIX规范的正则表达式，因此写法上与TypeScript存在很多的差异和限制。部分TypeScript正则表达式的特效并无法简单地在lua中实现，比如lookahead和lookbehind。因此ts2lua不对正则表达式进行处理，在生成lua代码时插入如下注释，请搜索该注释并手动处理。\n\n## 关于接口的处理(TSInterfaceDeclaration)\n由于lua没有类型的概念，为方便，所有接口声明全部不生成对应的lua代码。\n\n## 关于类型强转的处理(TSTypeAssertion)\n由于lua没有类型的概念，为方便，所有类型强转全部不生成对应的lua代码。\n\n## for循环的处理\n对于常见的ts for循环，最直接与之对应的应该是lua的for的循环。但为了确保转换结果“总是”正确的，for循环总是转化为repeat...until结构。\n\n## in操作符的处理\n`A in B`将转换为`B[A]`。\n\n## 以下语句不生成对应lua代码\n* ExportDefaultDeclaration - 默认导出声明。\n* TSDeclareFunction - 函数声明。\n* TSTypeParameterDeclaration - 泛型参数。\n\n## 以下语句不进行处理\n* 正则表达式。\n* 使用了自增/自减的复杂语句，比如`a = b++`、`a = arr[b++]`等。\n* 使用中文作为key的Object。\n* TypeScript中一些常用的方法，比如`split`、`indexOf`等。\n\n## 关于xlua模式的说明\nxlua模式下，会针对xlua规范对生成的lua代码进行处理：\n* `UnityEngine.XXX`将会转换为`CS.UnityEngine.XXX`\n* `UnityEngine.XXX.GetType()`将会被转换为`typeof(CS.UnityEngine.XXX)`\n\n\n## 注意\nts2lua可以将TypeScipt代码转化为lua代码并尽可能保证转换完成后代码的正确性。由于语法之间的差异性，部分难以使用通用规则进行转换的语句，ts2lua将在可能有疑义的地方加上以`-[ts2lua]`标记开头的注释，以便提示您进行手动确认。建议转化完成后全局搜索`[ts2lua]`一一确认。如果你不需要生成提示，可为选项`addTip`传递`false`关闭提示。\n\nts2lua是一个正在开发中的工具，包括以下内容：\n* updateexpression\n* push(1, 2, 3)\n* new Array()\n* new Array(n)\n* [1, 2, 3, 4]","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhalliwood%2Fts2lua","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhalliwood%2Fts2lua","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhalliwood%2Fts2lua/lists"}