Skip to content

Commit 783b632

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 2183c59 + 1ed3b4d commit 783b632

54 files changed

Lines changed: 965 additions & 301 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,36 @@
11
# Changelog
22

3+
## 1.32.0
4+
5+
- Fixed a broken `@customName` interation with import statements
6+
- Use `(table.)unpack(expression, from, to)` when using array destructing syntax `const [a,b] = array;` to avoid having to unpack the entire array
7+
- Fixed compiler annotations also considering the next line as part of any possible arguments
8+
- Fixed a bug with unicode classnames not being properly escaped in static initializer blocks
9+
- Fixed a bug where `@noSelf` still was not respected for index signature methods
10+
- Fixed a case where loop variables were incorrectly missing `local`
11+
- Removed dead code that was sometimes generated using `continue` in a loop
12+
- Fixed a bug with tagged template literals when the tag is a function call
13+
- Fixed a bug with class decorators leading to invalid Lua code being generated
14+
- A `-` or `+` prefix now converts expressions to numbers with `Number()`
15+
- Fixed a bug with root level `using` statements not properly disposing objects
16+
17+
## 1.31.0
18+
19+
- Upgraded TypeScript to 5.8.2
20+
- Changed `currentIndent` from private to protected in the `LuaPrinter` to allow custom printers with alternate indentation
21+
- Added `bit` and `bit32` as reserved Lua keywords to avoid accidental naming clashes.
22+
23+
## 1.30.0
24+
25+
- Allow passing in-memory plugins when using the tstl API, for more flexible integration into scripts
26+
- Changed how stacktraces are handled for `Error` in Lua 5.1 and LuaJIT
27+
28+
## 1.29.0
29+
30+
- Added support for the `Luau` luaTarget. This will use Luau's `continue` statement and ternary conditional expression `if ... then ... else ...` where appropriate.
31+
- Added support for `new Array<T>()` syntax to construct arrays (constructing with a length argument is not allowed).
32+
- Fixed a bug causing arrays to sometimes be indexed with a wrong index.
33+
334
## 1.28.0
435

536
- Upgraded TypeScript to 5.7.2

package-lock.json

Lines changed: 195 additions & 220 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@jackmacwindows/typescript-to-lua",
3-
"version": "1.28.1",
3+
"version": "1.32.0",
44
"description": "A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua! (With ComputerCraft support)",
55
"repository": "https://github.com/MCJack123/TypeScriptToLua",
66
"homepage": "https://typescripttolua.github.io/",
@@ -42,7 +42,7 @@
4242
"node": ">=16.10.0"
4343
},
4444
"peerDependencies": {
45-
"typescript": "5.7.2"
45+
"typescript": "5.8.2"
4646
},
4747
"dependencies": {
4848
"@typescript-to-lua/language-extensions": "1.19.0",
@@ -58,7 +58,7 @@
5858
"@types/node": "^22.10.0",
5959
"@types/picomatch": "^2.3.0",
6060
"@types/resolve": "1.14.0",
61-
"eslint": "^9.11.0",
61+
"eslint": "^9.22.0",
6262
"eslint-plugin-jest": "^28.8.3",
6363
"fs-extra": "^8.1.0",
6464
"javascript-stringify": "^2.0.1",
@@ -69,7 +69,7 @@
6969
"prettier": "^2.8.8",
7070
"ts-jest": "^29.2.5",
7171
"ts-node": "^10.9.2",
72-
"typescript": "5.7.2",
73-
"typescript-eslint": "^8.16.0"
72+
"typescript": "5.8.2",
73+
"typescript-eslint": "^8.26.0"
7474
}
7575
}

src/CompilerOptions.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as ts from "typescript";
22
import { JsxEmit } from "typescript";
33
import * as diagnosticFactories from "./transpilation/diagnostics";
4+
import { Plugin } from "./transpilation/plugins";
45

56
type OmitIndexSignature<T> = {
67
[K in keyof T as string extends K ? never : number extends K ? never : K]: T[K];
@@ -23,14 +24,19 @@ export interface LuaPluginImport {
2324
[option: string]: any;
2425
}
2526

27+
export interface InMemoryLuaPlugin {
28+
plugin: Plugin | ((options: Record<string, any>) => Plugin);
29+
[option: string]: any;
30+
}
31+
2632
export interface TypeScriptToLuaOptions {
2733
buildMode?: BuildMode;
2834
extension?: string;
2935
luaBundle?: string;
3036
luaBundleEntry?: string;
3137
luaTarget?: LuaTarget;
3238
luaLibImport?: LuaLibImportKind;
33-
luaPlugins?: LuaPluginImport[];
39+
luaPlugins?: Array<LuaPluginImport | InMemoryLuaPlugin>;
3440
noImplicitGlobalVariables?: boolean;
3541
noImplicitSelf?: boolean;
3642
noHeader?: boolean;
@@ -63,6 +69,7 @@ export enum LuaTarget {
6369
Lua53 = "5.3",
6470
Lua54 = "5.4",
6571
LuaJIT = "JIT",
72+
Luau = "Luau",
6673
Cobalt = "CC",
6774
Cobalt52 = "CC-5.2"
6875
}

src/LuaAST.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export enum SyntaxKind {
2525
LabelStatement,
2626
ReturnStatement,
2727
BreakStatement,
28+
ContinueStatement, // Luau only.
2829
ExpressionStatement,
2930

3031
// Expression
@@ -45,6 +46,7 @@ export enum SyntaxKind {
4546
Identifier,
4647
TableIndexExpression,
4748
ParenthesizedExpression,
49+
ConditionalExpression, // Luau only
4850

4951
// Operators
5052

@@ -488,6 +490,18 @@ export function createBreakStatement(tsOriginal?: ts.Node): BreakStatement {
488490
return createNode(SyntaxKind.BreakStatement, tsOriginal) as BreakStatement;
489491
}
490492

493+
export interface ContinueStatement extends Statement {
494+
kind: SyntaxKind.ContinueStatement;
495+
}
496+
497+
export function isContinueStatement(node: Node): node is ContinueStatement {
498+
return node.kind === SyntaxKind.ContinueStatement;
499+
}
500+
501+
export function createContinueStatement(tsOriginal?: ts.Node): ContinueStatement {
502+
return createNode(SyntaxKind.ContinueStatement, tsOriginal) as ContinueStatement;
503+
}
504+
491505
export interface ExpressionStatement extends Statement {
492506
kind: SyntaxKind.ExpressionStatement;
493507
expression: Expression;
@@ -861,3 +875,26 @@ export function createParenthesizedExpression(expression: Expression, tsOriginal
861875
parenthesizedExpression.expression = expression;
862876
return parenthesizedExpression;
863877
}
878+
879+
export type ConditionalExpression = Expression & {
880+
condition: Expression;
881+
whenTrue: Expression;
882+
whenFalse: Expression;
883+
};
884+
885+
export function isConditionalExpression(node: Node): node is ConditionalExpression {
886+
return node.kind === SyntaxKind.ConditionalExpression;
887+
}
888+
889+
export function createConditionalExpression(
890+
condition: Expression,
891+
whenTrue: Expression,
892+
whenFalse: Expression,
893+
tsOriginal?: ts.Node
894+
): ConditionalExpression {
895+
const conditionalExpression = createNode(SyntaxKind.ConditionalExpression, tsOriginal) as ConditionalExpression;
896+
conditionalExpression.condition = condition;
897+
conditionalExpression.whenTrue = whenTrue;
898+
conditionalExpression.whenFalse = whenFalse;
899+
return conditionalExpression;
900+
}

src/LuaPrinter.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ export class LuaPrinter {
157157
};
158158
private static rightAssociativeOperators = new Set([lua.SyntaxKind.ConcatOperator, lua.SyntaxKind.PowerOperator]);
159159

160-
private currentIndent = "";
160+
protected currentIndent = "";
161161
protected luaFile: string;
162162
protected relativeSourcePath: string;
163163
protected options: CompilerOptions;
@@ -397,6 +397,8 @@ export class LuaPrinter {
397397
return this.printReturnStatement(statement as lua.ReturnStatement);
398398
case lua.SyntaxKind.BreakStatement:
399399
return this.printBreakStatement(statement as lua.BreakStatement);
400+
case lua.SyntaxKind.ContinueStatement:
401+
return this.printContinueStatement(statement as lua.ContinueStatement);
400402
case lua.SyntaxKind.ExpressionStatement:
401403
return this.printExpressionStatement(statement as lua.ExpressionStatement);
402404
default:
@@ -575,6 +577,10 @@ export class LuaPrinter {
575577
return this.createSourceNode(statement, this.indent("break"));
576578
}
577579

580+
public printContinueStatement(statement: lua.ContinueStatement): SourceNode {
581+
return this.createSourceNode(statement, this.indent("continue"));
582+
}
583+
578584
public printExpressionStatement(statement: lua.ExpressionStatement): SourceNode {
579585
return this.createSourceNode(statement, [this.indent(), this.printExpression(statement.expression)]);
580586
}
@@ -615,6 +621,8 @@ export class LuaPrinter {
615621
return this.printTableIndexExpression(expression as lua.TableIndexExpression);
616622
case lua.SyntaxKind.ParenthesizedExpression:
617623
return this.printParenthesizedExpression(expression as lua.ParenthesizedExpression);
624+
case lua.SyntaxKind.ConditionalExpression:
625+
return this.printConditionalExpression(expression as lua.ConditionalExpression);
618626
default:
619627
throw new Error(`Tried to print unknown statement kind: ${lua.SyntaxKind[expression.kind]}`);
620628
}
@@ -829,6 +837,17 @@ export class LuaPrinter {
829837
return this.createSourceNode(expression, ["(", this.printExpression(expression.expression), ")"]);
830838
}
831839

840+
public printConditionalExpression(expression: lua.ConditionalExpression): SourceNode {
841+
return this.createSourceNode(expression, [
842+
"if ",
843+
this.printExpression(expression.condition),
844+
" then ",
845+
this.printExpression(expression.whenTrue),
846+
" else ",
847+
this.printExpression(expression.whenFalse),
848+
]);
849+
}
850+
832851
public printOperator(kind: lua.Operator): SourceNode {
833852
return new SourceNode(null, null, this.relativeSourcePath, LuaPrinter.operatorMap[kind]);
834853
}

src/lualib/Error.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { __TS__New } from "./New";
2+
13
interface ErrorType {
24
name: string;
35
new (...args: any[]): Error;
@@ -22,6 +24,11 @@ function getErrorStack(constructor: () => any): string | undefined {
2224

2325
if (_VERSION.includes("Lua 5.0")) {
2426
return debug.traceback(`[Level ${level}]`);
27+
// @ts-ignore Fails when compiled with Lua 5.0 types
28+
} else if (_VERSION === "Lua 5.1") {
29+
// Lua 5.1 and LuaJIT have a bug where it's not possible to specify the level without a message.
30+
// @ts-ignore Fails when compiled with Lua 5.0 types
31+
return string.sub(debug.traceback("", level), 2);
2532
} else {
2633
// @ts-ignore Fails when compiled with Lua 5.0 types
2734
return debug.traceback(undefined, level);
@@ -33,7 +40,7 @@ function wrapErrorToString<T extends Error>(getDescription: (this: T) => string)
3340
const description = getDescription.call(this as T);
3441
const caller = debug.getinfo(3, "f");
3542
// @ts-ignore Fails when compiled with Lua 5.0 types
36-
const isClassicLua = _VERSION.includes("Lua 5.0") || _VERSION === "Lua 5.1";
43+
const isClassicLua = _VERSION.includes("Lua 5.0");
3744
if (isClassicLua || (caller && caller.func !== error)) {
3845
return description;
3946
} else {
@@ -55,7 +62,7 @@ export const Error: ErrorConstructor = initErrorClass(
5562
public stack?: string;
5663

5764
constructor(public message = "") {
58-
this.stack = getErrorStack((this.constructor as any).new);
65+
this.stack = getErrorStack(__TS__New as any);
5966
const metatable = getmetatable(this);
6067
if (metatable && !metatable.__errorToStringPatched) {
6168
metatable.__errorToStringPatched = true;

src/transformation/builtins/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,10 @@ export function checkForLuaLibType(context: TransformationContext, type: ts.Type
221221
}
222222
}
223223

224-
function tryGetStandardLibrarySymbolOfType(context: TransformationContext, type: ts.Type): ts.Symbol | undefined {
224+
export function tryGetStandardLibrarySymbolOfType(
225+
context: TransformationContext,
226+
type: ts.Type
227+
): ts.Symbol | undefined {
225228
if (type.isUnionOrIntersection()) {
226229
for (const subType of type.types) {
227230
const symbol = tryGetStandardLibrarySymbolOfType(context, subType);

src/transformation/pre-transformers/using-transformer.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ import { LuaLibFeature, importLuaLibFeature } from "../utils/lualib";
55
export function usingTransformer(context: TransformationContext): ts.TransformerFactory<ts.SourceFile> {
66
return ctx => sourceFile => {
77
function visit(node: ts.Node): ts.Node {
8-
if (ts.isBlock(node)) {
8+
if (ts.isBlock(node) || ts.isSourceFile(node)) {
99
const [hasUsings, newStatements] = transformBlockWithUsing(context, node.statements, node);
1010
if (hasUsings) {
1111
// Recurse visitor into updated block to find further usings
12-
const updatedBlock = ts.factory.updateBlock(node, newStatements);
12+
const updatedBlock = ts.isBlock(node)
13+
? ts.factory.updateBlock(node, newStatements)
14+
: ts.factory.updateSourceFile(node, newStatements);
1315
const result = ts.visitEachChild(updatedBlock, visit, ctx);
1416

1517
// Set all the synthetic node parents to something that makes sense
@@ -29,7 +31,8 @@ export function usingTransformer(context: TransformationContext): ts.Transformer
2931
}
3032
return ts.visitEachChild(node, visit, ctx);
3133
}
32-
return ts.visitEachChild(sourceFile, visit, ctx);
34+
const transformedSourceFile = ts.visitEachChild(sourceFile, visit, ctx);
35+
return visit(transformedSourceFile) as ts.SourceFile;
3336
};
3437
}
3538

@@ -40,7 +43,7 @@ function isUsingDeclarationList(node: ts.Node): node is ts.VariableStatement {
4043
function transformBlockWithUsing(
4144
context: TransformationContext,
4245
statements: ts.NodeArray<ts.Statement> | ts.Statement[],
43-
block: ts.Block
46+
block: ts.Block | ts.SourceFile
4447
): [true, ts.Statement[]] | [false] {
4548
const newStatements: ts.Statement[] = [];
4649

@@ -102,7 +105,14 @@ function transformBlockWithUsing(
102105
call = ts.factory.createAwaitExpression(call);
103106
}
104107

105-
if (ts.isBlock(block.parent) && block.parent.statements[block.parent.statements.length - 1] !== block) {
108+
if (ts.isSourceFile(block)) {
109+
// If block is a sourcefile, don't insert a return statement into root code
110+
newStatements.push(ts.factory.createExpressionStatement(call));
111+
} else if (
112+
block.parent &&
113+
ts.isBlock(block.parent) &&
114+
block.parent.statements[block.parent.statements.length - 1] !== block
115+
) {
106116
// If this is a free-standing block in a function (not the last statement), dont return the value
107117
newStatements.push(ts.factory.createExpressionStatement(call));
108118
} else {

src/transformation/utils/annotations.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ export function getFileAnnotations(sourceFile: ts.SourceFile): AnnotationsMap {
105105
function getTagArgsFromComment(tag: ts.JSDocTag): string[] {
106106
if (tag.comment) {
107107
if (typeof tag.comment === "string") {
108-
return tag.comment.split(" ");
108+
const firstLine = tag.comment.split("\n")[0];
109+
return firstLine.trim().split(" ");
109110
} else {
110111
return tag.comment.map(part => part.text);
111112
}

0 commit comments

Comments
 (0)