Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "typescript-to-lua",
"version": "1.33.2",
"name": "its-typescript-to-lua",
"version": "1.33.2-7",
"description": "A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!",
"repository": "https://github.com/TypeScriptToLua/TypeScriptToLua",
"homepage": "https://typescripttolua.github.io/",
Expand Down
9 changes: 9 additions & 0 deletions src/CompilerOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export interface TypeScriptToLuaOptions {
tstlVerbose?: boolean;
lua51AllowTryCatchInAsyncAwait?: boolean;
measurePerformance?: boolean;
arrayIndexModification?: ArrayIndexModification;
}

export type CompilerOptions = OmitIndexSignature<ts.CompilerOptions> &
Expand Down Expand Up @@ -76,9 +77,17 @@ export enum BuildMode {
Library = "library",
}

export enum ArrayIndexModification {
Never = "never",
Always = "always",
}

export const isBundleEnabled = (options: CompilerOptions) =>
options.luaBundle !== undefined && options.luaBundleEntry !== undefined;

export const arrayIndexModificationEnabled = (options: CompilerOptions) =>
options.arrayIndexModification !== ArrayIndexModification.Never;

export function validateOptions(options: CompilerOptions): ts.Diagnostic[] {
const diagnostics: ts.Diagnostic[] = [];

Expand Down
55 changes: 31 additions & 24 deletions src/LuaPrinter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -664,26 +664,27 @@ export class LuaPrinter {
public printFunctionExpression(expression: lua.FunctionExpression): SourceNode {
const chunks: SourceChunk[] = [];

chunks.push("\n");
chunks.push("function(");
chunks.push(...this.printFunctionParameters(expression));
chunks.push(")");

if (lua.isInlineFunctionExpression(expression)) {
const returnStatement = expression.body.statements[0];
chunks.push(" ");
const returnNode: SourceChunk[] = [
"return ",
...this.joinChunksWithComma(returnStatement.expressions.map(e => this.printExpression(e))),
];
chunks.push(this.createSourceNode(returnStatement, returnNode));
chunks.push(this.createSourceNode(expression, " end"));
} else {
chunks.push("\n");
this.pushIndent();
chunks.push(this.printBlock(expression.body));
this.popIndent();
chunks.push(this.indent(this.createSourceNode(expression, "end")));
}
// if (lua.isInlineFunctionExpression(expression)) {
// const returnStatement = expression.body.statements[0];
// chunks.push(" ");
// const returnNode: SourceChunk[] = [
// "return ",
// ...this.joinChunksWithComma(returnStatement.expressions.map(e => this.printExpression(e))),
// ];
// chunks.push(this.createSourceNode(returnStatement, returnNode));
// chunks.push(this.createSourceNode(expression, " end"));
// } else {
chunks.push("\n");
this.pushIndent();
chunks.push(this.printBlock(expression.body));
this.popIndent();
chunks.push(this.indent(this.createSourceNode(expression, "end")));
// }

return this.createSourceNode(expression, chunks);
}
Expand Down Expand Up @@ -867,17 +868,23 @@ export class LuaPrinter {
protected printExpressionList(expressions: lua.Expression[]): SourceChunk[] {
const chunks: SourceChunk[] = [];

if (this.isSimpleExpressionList(expressions)) {
chunks.push(...this.joinChunksWithComma(expressions.map(e => this.printExpression(e))));
} else {
chunks.push("\n");
this.pushIndent();
for (const [index, expression] of expressions.entries()) {
for (const [index, expression] of expressions.entries()) {
if (lua.isCallExpression(expression)) {
if (index === 0) {
chunks.push("\n");
} else {
chunks.pop();
chunks.push(",\n");
}
this.pushIndent();
const tail = index < expressions.length - 1 ? ",\n" : "\n";
chunks.push(this.indent(), this.printExpression(expression), tail);
this.popIndent();
chunks.push(this.indent());
} else {
const tail = index < expressions.length - 1 ? ", " : "";
chunks.push(this.printExpression(expression), tail);
}
this.popIndent();
chunks.push(this.indent());
}

return chunks;
Expand Down
36 changes: 36 additions & 0 deletions src/cli/parse.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import * as ts from "typescript";
import { BuildMode, CompilerOptions, LuaLibImportKind, LuaTarget } from "../CompilerOptions";
import * as cliDiagnostics from "./diagnostics";
import * as fs from "fs";
import * as path from "path";

export interface ParsedCommandLine extends ts.ParsedCommandLine {
options: CompilerOptions;
Expand Down Expand Up @@ -104,8 +106,38 @@ export const optionDeclarations: CommandLineOption[] = [
description: "Measure performance of the tstl compiler.",
type: "boolean",
},
{
name: "arrayIndexModification",
description: "If array indexing operations should be modified (0 based to 1 based).",
type: "string",
},
];

function substituteFirmwareLocation(config: ts.ParsedCommandLine) {
if (config.options.outDir?.includes("${firmwareLocation}")) {
let substitution = "";
const baseDir = process.cwd();
const paths = fs.readdirSync(baseDir, { recursive: true });
const filtered = paths.filter(dir => dir.toString().endsWith("sharedscripts_default"));
if (filtered.length === 1) {
substitution = path.dirname(filtered[0].toString());
}
if (substitution && substitution !== "") {
config.options.outDir = path.normalize(config.options.outDir?.replace("${firmwareLocation}", substitution));
} else {
config.errors.push({
file: undefined,
start: undefined,
length: undefined,
category: ts.DiagnosticCategory.Error,
code: 42,
source: "typescript-to-lua",
messageText: "Cannot find firmware location (sharedscripts_default)"
});
}
}
}

export function updateParsedConfigFile(parsedConfigFile: ts.ParsedCommandLine): ParsedCommandLine {
let hasRootLevelOptions = false;
for (const [name, rawValue] of Object.entries(parsedConfigFile.raw)) {
Expand Down Expand Up @@ -135,6 +167,8 @@ export function updateParsedConfigFile(parsedConfigFile: ts.ParsedCommandLine):
}
}

substituteFirmwareLocation(parsedConfigFile);

return parsedConfigFile;
}

Expand Down Expand Up @@ -176,6 +210,8 @@ function updateParsedCommandLine(parsedCommandLine: ts.ParsedCommandLine, args:
}
}

substituteFirmwareLocation(parsedCommandLine);

return parsedCommandLine;
}

Expand Down
6 changes: 5 additions & 1 deletion src/transformation/visitors/access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
import { SyntaxKind } from "typescript";
import { getCustomNameFromSymbol } from "./identifier";
import { getSymbolExportScope, isSymbolExported } from "../utils/export";
import { arrayIndexModificationEnabled } from "../../CompilerOptions";

function addOneToArrayAccessArgument(
context: TransformationContext,
Expand All @@ -34,7 +35,10 @@ function addOneToArrayAccessArgument(
const type = context.checker.getTypeAtLocation(node.expression);
const argumentType = context.checker.getTypeAtLocation(node.argumentExpression);
if (isArrayType(context, type) && isNumberType(context, argumentType)) {
return addToNumericExpression(index, 1);
const options = context.program.getCompilerOptions();
if (arrayIndexModificationEnabled(options)) {
return addToNumericExpression(index, 1);
}
}
return index;
}
Expand Down
6 changes: 5 additions & 1 deletion src/transformation/visitors/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { unsupportedProperty } from "../utils/diagnostics";
import { isArrayType, isNumberType } from "../utils/typescript";
import { addToNumericExpression } from "../utils/lua-ast";
import { transformOptionalDeleteExpression } from "./optional-chaining";
import { arrayIndexModificationEnabled } from "../../CompilerOptions";

export const transformDeleteExpression: FunctionVisitor<ts.DeleteExpression> = (node, context) => {
if (ts.isOptionalChain(node.expression)) {
Expand All @@ -27,7 +28,10 @@ export const transformDeleteExpression: FunctionVisitor<ts.DeleteExpression> = (
const argumentType = context.checker.getTypeAtLocation(node.expression.argumentExpression);

if (isArrayType(context, type) && isNumberType(context, argumentType)) {
propertyExpression = addToNumericExpression(propertyExpression, 1);
const options = context.program.getCompilerOptions();
if (arrayIndexModificationEnabled(options)) {
propertyExpression = addToNumericExpression(propertyExpression, 1);
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/transformation/visitors/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as ts from "typescript";
import * as lua from "../../LuaAST";
import { FunctionVisitor, TransformationContext } from "../context";
import { AnnotationKind, getTypeAnnotations } from "../utils/annotations";
import { getSymbolExportScope } from "../utils/export";
import { addExportToIdentifier, getSymbolExportScope } from "../utils/export";
import { createLocalOrExportedOrGlobalDeclaration } from "../utils/lua-ast";
import { isFirstDeclaration } from "../utils/typescript";
import { transformIdentifier } from "./identifier";
Expand Down Expand Up @@ -32,7 +32,7 @@ export const transformEnumDeclaration: FunctionVisitor<ts.EnumDeclaration> = (no
if (!membersOnly && isFirstDeclaration(context, node)) {
const name = transformIdentifier(context, node.name);
const table = lua.createBinaryExpression(
lua.cloneIdentifier(name),
addExportToIdentifier(context, name),
lua.createTableExpression(),
lua.SyntaxKind.OrOperator
);
Expand Down
16 changes: 16 additions & 0 deletions test/unit/enum.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,19 @@ test("enum merging multiple files", () => {
)
.expectToMatchJsResult();
});

test("enum nested in namespace", () => {
util.testModule`
namespace A {
export enum TestEnum {
C,
D
}
}
`.tap(builder => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just use expectToMatchSnapshot() instead if you want to check the entire content

const lua = builder.getMainLuaCodeChunk();
expect(lua).toMatch(
'A = A or ({})\ndo\n A.TestEnum = A.TestEnum or ({})\n A.TestEnum.C = 0\n A.TestEnum[A.TestEnum.C] = "C"\n A.TestEnum.D = 1\n A.TestEnum[A.TestEnum.D] = "D"\nend'
);
});
});
1 change: 1 addition & 0 deletions test/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ export abstract class TestBuilder {
moduleResolution: ts.ModuleResolutionKind.Node10,
resolveJsonModule: true,
sourceMap: true,
arrayIndexModification: tstl.ArrayIndexModification.Never,
};
public setOptions(options: tstl.CompilerOptions = {}): this {
this.throwIfProgramExists("setOptions");
Expand Down
5 changes: 5 additions & 0 deletions tsconfig-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,11 @@
"measurePerformance": {
"description": "Measure and report performance of the tstl compiler.",
"type": "boolean"
},
"arrayIndexModification": {
"description": "If array indexing operations should be modified (0 based to 1 based).",
"type": "string",
"enum": ["never", "always"]
}
},
"dependencies": {
Expand Down