Skip to content

Commit 40e4c22

Browse files
Z3rioPerryvw
andauthored
Setup custom name support (#1505)
* Setup basic POC for customName param * remove & ignore lock files * Add CustomName annotation * Add customNames to tsconfig * Fix customNames in tsconfig schema * Setup functionality for customNames in tsconfig * Revert "remove & ignore lock files" This reverts commit 2a8e998. * fix linting / run prettier lint fix * Setup tests for customName * Remove customNames from tsconfig * Change throw new error into expect in tests * Add more specific test name * Add further jest tests for customName * Add customName test for declared function * Fix namespace customName renaming * Make customName check more universal * Improve customName handling in call visitor * Move customname logic to `transformContextualCallExpression` * Use left instead of passing calledMethod * remove unneeded type specification Co-authored-by: Perry van Wesel <Perryvw@users.noreply.github.com> --------- Co-authored-by: Perry van Wesel <Perryvw@users.noreply.github.com>
1 parent e697c6e commit 40e4c22

File tree

4 files changed

+169
-9
lines changed

4 files changed

+169
-9
lines changed

src/transformation/utils/annotations.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export enum AnnotationKind {
55
CompileMembersOnly = "compileMembersOnly",
66
NoResolution = "noResolution",
77
NoSelf = "noSelf",
8+
CustomName = "customName",
89
NoSelfInFile = "noSelfInFile",
910
}
1011

src/transformation/visitors/call.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { transformInPrecedingStatementScope } from "../utils/preceding-statement
1515
import { getOptionalContinuationData, transformOptionalChain } from "./optional-chaining";
1616
import { transformImportExpression } from "./modules/import";
1717
import { transformLanguageExtensionCallExpression } from "./language-extensions/call-extension";
18+
import { getCustomNameFromSymbol } from "./identifier";
1819

1920
export function validateArguments(
2021
context: TransformationContext,
@@ -135,12 +136,16 @@ export function transformContextualCallExpression(
135136
) {
136137
// table:name()
137138
const table = context.transformExpression(left.expression);
138-
return lua.createMethodCallExpression(
139-
table,
140-
lua.createIdentifier(left.name.text, left.name),
141-
transformedArguments,
142-
node
143-
);
139+
let name = left.name.text;
140+
141+
const symbol = context.checker.getSymbolAtLocation(left);
142+
const customName = getCustomNameFromSymbol(symbol);
143+
144+
if (customName) {
145+
name = customName;
146+
}
147+
148+
return lua.createMethodCallExpression(table, lua.createIdentifier(name, left.name), transformedArguments, node);
144149
} else if (ts.isElementAccessExpression(left) || ts.isPropertyAccessExpression(left)) {
145150
if (isExpressionWithEvaluationEffect(left.expression)) {
146151
return transformElementAccessCall(context, left, transformedArguments, argPrecedingStatements);

src/transformation/visitors/identifier.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,38 @@ import { isStandardLibraryType } from "../utils/typescript";
1212
import { getExtensionKindForNode, getExtensionKindForSymbol } from "../utils/language-extensions";
1313
import { callExtensions } from "./language-extensions/call-extension";
1414
import { isIdentifierExtensionValue, reportInvalidExtensionValue } from "./language-extensions/identifier";
15+
import { Annotation, AnnotationKind, getNodeAnnotations } from "../utils/annotations";
1516

1617
export function transformIdentifier(context: TransformationContext, identifier: ts.Identifier): lua.Identifier {
1718
return transformNonValueIdentifier(context, identifier, context.checker.getSymbolAtLocation(identifier));
1819
}
1920

21+
export function getCustomNameFromSymbol(symbol?: ts.Symbol): undefined | string {
22+
let retVal: undefined | string;
23+
24+
if (symbol) {
25+
const declarations = symbol.getDeclarations();
26+
if (declarations) {
27+
let customNameAnnotation: undefined | Annotation = undefined;
28+
for (const declaration of declarations) {
29+
const nodeAnnotations = getNodeAnnotations(declaration);
30+
const foundAnnotation = nodeAnnotations.get(AnnotationKind.CustomName);
31+
32+
if (foundAnnotation) {
33+
customNameAnnotation = foundAnnotation;
34+
break;
35+
}
36+
}
37+
38+
if (customNameAnnotation) {
39+
retVal = customNameAnnotation.args[0];
40+
}
41+
}
42+
}
43+
44+
return retVal;
45+
}
46+
2047
function transformNonValueIdentifier(
2148
context: TransformationContext,
2249
identifier: ts.Identifier,
@@ -53,9 +80,10 @@ function transformNonValueIdentifier(
5380
}
5481
}
5582

56-
const text = hasUnsafeIdentifierName(context, identifier, symbol)
57-
? createSafeName(identifier.text)
58-
: identifier.text;
83+
let text = hasUnsafeIdentifierName(context, identifier, symbol) ? createSafeName(identifier.text) : identifier.text;
84+
85+
const customName = getCustomNameFromSymbol(symbol);
86+
if (customName) text = customName;
5987

6088
const symbolId = getIdentifierSymbolId(context, identifier, symbol);
6189
return lua.createIdentifier(text, identifier, symbolId, identifier.text);

test/unit/identifiers.spec.ts

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,3 +845,129 @@ test("lua built-in as in constructor assignment", () => {
845845
export const result = new A("42").error;
846846
`.expectToMatchJsResult();
847847
});
848+
849+
test("customName rename function", () => {
850+
const result = util.testModule`
851+
/** @customName test2 **/
852+
function test(this: void): number { return 3; }
853+
export const result: number = test();
854+
`
855+
.expectToEqual({ result: 3 })
856+
.getLuaResult();
857+
858+
expect(result.transpiledFiles).not.toHaveLength(0);
859+
860+
const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua");
861+
expect(mainFile).toBeDefined();
862+
863+
// avoid ts error "not defined", even though toBeDefined is being checked above
864+
if (!mainFile) return;
865+
866+
expect(mainFile.lua).toBeDefined();
867+
expect(mainFile.lua).toContain("function test2()");
868+
expect(mainFile.lua).not.toContain("test()");
869+
});
870+
871+
test("customName rename variable", () => {
872+
const result = util.testModule`
873+
/** @customName result2 **/
874+
export const result: number = 3;
875+
`
876+
.expectToEqual({ result2: 3 })
877+
.getLuaResult();
878+
879+
const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua");
880+
expect(mainFile).toBeDefined();
881+
882+
// avoid ts error "not defined", even though toBeDefined is being checked above
883+
if (!mainFile) return;
884+
885+
expect(mainFile.lua).toBeDefined();
886+
expect(mainFile.lua).toContain("result2 =");
887+
expect(mainFile.lua).not.toContain("result =");
888+
});
889+
890+
test("customName rename classes", () => {
891+
const testModule = util.testModule`
892+
/** @customName Class2 **/
893+
class Class {
894+
test: string;
895+
896+
constructor(test: string) {
897+
this.test = test;
898+
}
899+
}
900+
901+
export const result = new Class("hello world");
902+
`;
903+
904+
const executionResult = testModule.getLuaExecutionResult();
905+
expect(executionResult.result).toBeDefined();
906+
expect(executionResult.result).toMatchObject({ test: "hello world" });
907+
908+
const result = testModule.getLuaResult();
909+
expect(result.transpiledFiles).not.toHaveLength(0);
910+
911+
const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua");
912+
expect(mainFile).toBeDefined();
913+
914+
// avoid ts error "not defined", even though toBeDefined is being checked above
915+
if (!mainFile) return;
916+
917+
expect(mainFile.lua).toBeDefined();
918+
expect(mainFile.lua).toContain("local Class2 =");
919+
expect(mainFile.lua).not.toContain("local Class =");
920+
});
921+
922+
test("customName rename namespace", () => {
923+
const testModule = util.testModule`
924+
/** @customName Test2 **/
925+
namespace Test {
926+
/** @customName Func2 **/
927+
export function Func(): string {
928+
return "hi";
929+
}
930+
}
931+
932+
export const result = Test.Func();
933+
`;
934+
935+
testModule.expectToEqual({ result: "hi" });
936+
937+
const result = testModule.getLuaResult();
938+
expect(result.transpiledFiles).not.toHaveLength(0);
939+
940+
const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua");
941+
expect(mainFile).toBeDefined();
942+
943+
// avoid ts error "not defined", even though toBeDefined is being checked above
944+
if (!mainFile) return;
945+
946+
expect(mainFile.lua).toBeDefined();
947+
expect(mainFile.lua).toContain("Test2 =");
948+
expect(mainFile.lua).toContain("Test2.Func2");
949+
expect(mainFile.lua).not.toContain("Test =");
950+
expect(mainFile.lua).not.toContain("Func(");
951+
});
952+
953+
test("customName rename declared function", () => {
954+
const testModule = util.testModule`
955+
/** @customName Test2 **/
956+
declare function Test(this: void): void;
957+
958+
Test();
959+
`;
960+
961+
const result = testModule.getLuaResult();
962+
expect(result.transpiledFiles).not.toHaveLength(0);
963+
964+
const mainFile = result.transpiledFiles.find(f => f.outPath === "main.lua");
965+
expect(mainFile).toBeDefined();
966+
967+
// avoid ts error "not defined", even though toBeDefined is being checked above
968+
if (!mainFile) return;
969+
970+
expect(mainFile.lua).toBeDefined();
971+
expect(mainFile.lua).toContain("Test2(");
972+
expect(mainFile.lua).not.toContain("Test(");
973+
});

0 commit comments

Comments
 (0)