X Tutup
Skip to content

Commit 39c7420

Browse files
authored
Feature/arrayisarray (#970)
* Added Array.IsArray to lualib * Fix bug in string.split lualib dependencies * Fix isArray test for empty object actually testing an object * Used Array.isArray in array.prototype.concat
1 parent 0158732 commit 39c7420

File tree

10 files changed

+62
-20
lines changed

10 files changed

+62
-20
lines changed

src/LuaLib.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export enum LuaLibFeature {
1010
ArrayFindIndex = "ArrayFindIndex",
1111
ArrayIncludes = "ArrayIncludes",
1212
ArrayIndexOf = "ArrayIndexOf",
13+
ArrayIsArray = "ArrayIsArray",
1314
ArrayJoin = "ArrayJoin",
1415
ArrayMap = "ArrayMap",
1516
ArrayPush = "ArrayPush",
@@ -86,8 +87,9 @@ export enum LuaLibFeature {
8687
}
8788

8889
const luaLibDependencies: Partial<Record<LuaLibFeature, LuaLibFeature[]>> = {
89-
ArrayFlat: [LuaLibFeature.ArrayConcat],
90-
ArrayFlatMap: [LuaLibFeature.ArrayConcat],
90+
ArrayConcat: [LuaLibFeature.ArrayIsArray],
91+
ArrayFlat: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray],
92+
ArrayFlatMap: [LuaLibFeature.ArrayConcat, LuaLibFeature.ArrayIsArray],
9193
Decorate: [LuaLibFeature.CloneDescriptor],
9294
Delete: [LuaLibFeature.ObjectGetOwnPropertyDescriptors],
9395
Error: [LuaLibFeature.New, LuaLibFeature.Class],
@@ -102,6 +104,7 @@ const luaLibDependencies: Partial<Record<LuaLibFeature, LuaLibFeature[]>> = {
102104
WeakMap: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
103105
WeakSet: [LuaLibFeature.InstanceOf, LuaLibFeature.Iterator, LuaLibFeature.Symbol, LuaLibFeature.Class],
104106
Spread: [LuaLibFeature.Iterator, LuaLibFeature.Unpack],
107+
StringSplit: [LuaLibFeature.StringSubstring],
105108
SymbolRegistry: [LuaLibFeature.Symbol],
106109
};
107110

src/lualib/ArrayConcat.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ function __TS__ArrayConcat(this: void, arr1: any[], ...args: any[]): any[] {
44
out[out.length] = val;
55
}
66
for (const arg of args) {
7-
// Hack because we don't have an isArray function
8-
if (pcall(() => (arg as any[]).length) && type(arg) !== "string") {
9-
const argAsArray = arg as any[];
7+
if (Array.isArray(arg)) {
8+
const argAsArray = arg;
109
for (const val of argAsArray) {
1110
out[out.length] = val;
1211
}

src/lualib/ArrayFlat.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
function __TS__ArrayFlat(this: void, array: any[], depth = 1): any[] {
22
let result: any[] = [];
33
for (const value of array) {
4-
if (
5-
depth > 0 &&
6-
type(value) === "table" &&
7-
// Workaround to determine if value is an array or not (fails in case of objects without keys)
8-
// See discussion in: https://github.com/TypeScriptToLua/TypeScriptToLua/pull/737
9-
(1 in value || (next as NextEmptyCheck)(value, undefined) === undefined)
10-
) {
4+
if (depth > 0 && Array.isArray(value)) {
115
result = result.concat(__TS__ArrayFlat(value, depth - 1));
126
} else {
137
result[result.length] = value;

src/lualib/ArrayFlatMap.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,7 @@ function __TS__ArrayFlatMap<T, U>(
66
let result: U[] = [];
77
for (let i = 0; i < array.length; i++) {
88
const value = callback(array[i], i, array);
9-
if (
10-
type(value) === "table" &&
11-
// Workaround to determine if value is an array or not (fails in case of objects without keys)
12-
// See discussion in: https://github.com/TypeScriptToLua/TypeScriptToLua/pull/737
13-
(1 in value || (next as NextEmptyCheck)(value as any, undefined) === undefined)
14-
) {
9+
if (type(value) === "table" && Array.isArray(value)) {
1510
result = result.concat(value);
1611
} else {
1712
result[result.length] = value as U;

src/lualib/ArrayIsArray.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function __TS__ArrayIsArray(this: void, value: any): value is any[] {
2+
// Workaround to determine if value is an array or not (fails in case of objects without keys)
3+
// See discussion in: https://github.com/TypeScriptToLua/TypeScriptToLua/pull/7
4+
return type(value) === "table" && (1 in value || (next as NextEmptyCheck)(value, undefined) === undefined);
5+
}

src/transformation/builtins/array.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,23 @@ import { LuaLibFeature, transformLuaLibFunction } from "../utils/lualib";
66
import { PropertyCallExpression, transformArguments } from "../visitors/call";
77
import { isStringType, isNumberType } from "../utils/typescript";
88

9+
export function transformArrayConstructorCall(
10+
context: TransformationContext,
11+
node: PropertyCallExpression
12+
): lua.CallExpression | undefined {
13+
const expression = node.expression;
14+
const signature = context.checker.getResolvedSignature(node);
15+
const params = transformArguments(context, node.arguments, signature);
16+
17+
const expressionName = expression.name.text;
18+
switch (expressionName) {
19+
case "isArray":
20+
return transformLuaLibFunction(context, LuaLibFeature.ArrayIsArray, node, ...params);
21+
default:
22+
context.diagnostics.push(unsupportedProperty(expression.name, "Array", expressionName));
23+
}
24+
}
25+
926
export function transformArrayPrototypeCall(
1027
context: TransformationContext,
1128
node: PropertyCallExpression

src/transformation/builtins/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import {
1515
} from "../utils/typescript";
1616
import { PropertyCallExpression } from "../visitors/call";
1717
import { checkForLuaLibType } from "../visitors/class/new";
18-
import { transformArrayProperty, transformArrayPrototypeCall } from "./array";
18+
import { transformArrayConstructorCall, transformArrayProperty, transformArrayPrototypeCall } from "./array";
1919
import { transformConsoleCall } from "./console";
2020
import { transformFunctionPrototypeCall, transformFunctionProperty } from "./function";
2121
import { transformGlobalCall } from "./global";
@@ -79,6 +79,8 @@ export function transformBuiltinCallExpression(
7979
if (isStandardLibraryType(context, ownerType, undefined)) {
8080
const symbol = ownerType.getSymbol();
8181
switch (symbol?.name) {
82+
case "ArrayConstructor":
83+
return transformArrayConstructorCall(context, node);
8284
case "Console":
8385
return transformConsoleCall(context, node);
8486
case "Math":

test/unit/builtins/array.spec.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,3 +618,23 @@ test.each(genericChecks)("array constrained generic length (%p)", signature => {
618618
`;
619619
expect(util.transpileAndExecute(code)).toBe(3);
620620
});
621+
622+
test.each(["[]", '"hello"', "42", "[1, 2, 3]", '{ a: "foo", b: "bar" }'])(
623+
"Array.isArray matches JavaScript (%p)",
624+
valueString => {
625+
util.testExpression`Array.isArray(${valueString})`.expectToMatchJsResult();
626+
}
627+
);
628+
629+
test("Array.isArray returns true for empty objects", () => {
630+
// Important edge case we cannot handle correctly due to [] and {}
631+
// being identical in Lua. We assume [] is more common than Array.isArray({}),
632+
// so it is more important to handle [] right, sacrificing the result for {}.
633+
// See discussion: https://github.com/TypeScriptToLua/TypeScriptToLua/pull/737
634+
util.testExpression`Array.isArray({})`.expectToEqual(true);
635+
});
636+
637+
// Test fix for https://github.com/TypeScriptToLua/TypeScriptToLua/issues/738
638+
test("array.prototype.concat issue #738", () => {
639+
util.testExpression`([] as any[]).concat(13, 323, {x: 3}, [2, 3])`.expectToMatchJsResult();
640+
});

test/unit/builtins/string.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { LuaLibImportKind } from "../../../src";
12
import * as util from "../../util";
23

34
test("Supported lua string function", () => {
@@ -193,6 +194,12 @@ test.each([
193194
util.testExpressionTemplate`${inp}.split(${separator})`.expectToMatchJsResult();
194195
});
195196

197+
test("string.split inline", () => {
198+
util.testExpression`"a, b, c".split(",")`
199+
.setOptions({ luaLibImport: LuaLibImportKind.Inline })
200+
.expectToMatchJsResult();
201+
});
202+
196203
test.each([
197204
{ inp: "hello test", index: 0 },
198205
{ inp: "hello test", index: 1 },

test/unit/spread.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ describe("in array literal", () => {
9393

9494
test("of array literal /w OmittedExpression", () => {
9595
util.testFunction`
96-
const array = [1, 2, ...[3], , 5];
96+
const array = [1, 2, ...[3], 5, , 6];
9797
return { a: array[0], b: array[1], c: array[2], d: array[3] };
9898
`.expectToMatchJsResult();
9999
});

0 commit comments

Comments
 (0)
X Tutup