From e687ad1a2d7e64dd214971c7eeb7caf9a893317d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Miernik?= Date: Mon, 21 Oct 2019 19:21:06 +0200 Subject: [PATCH 1/5] Fixed array.flat[Map] on [[]] (fixes #719). --- src/lualib/ArrayFlat.ts | 2 +- src/lualib/ArrayFlatMap.ts | 2 +- test/unit/builtins/array.spec.ts | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lualib/ArrayFlat.ts b/src/lualib/ArrayFlat.ts index 4006b51d5..938ebfa03 100644 --- a/src/lualib/ArrayFlat.ts +++ b/src/lualib/ArrayFlat.ts @@ -1,7 +1,7 @@ function __TS__ArrayFlat(this: void, array: any[], depth = 1): any[] { let result: any[] = []; for (const value of array) { - if (depth > 0 && type(value) === "table" && 1 in value) { + if (depth > 0 && type(value) === "table") { result = result.concat(__TS__ArrayFlat(value, depth - 1)); } else { result[result.length] = value; diff --git a/src/lualib/ArrayFlatMap.ts b/src/lualib/ArrayFlatMap.ts index 7bd7a8a22..3e9440209 100644 --- a/src/lualib/ArrayFlatMap.ts +++ b/src/lualib/ArrayFlatMap.ts @@ -6,7 +6,7 @@ function __TS__ArrayFlatMap( let result: U[] = []; for (let i = 0; i < array.length; i++) { const value = callback(array[i], i, array); - if (type(value) === "table" && 1 in value) { + if (type(value) === "table") { result = result.concat(value); } else { result[result.length] = value as U; diff --git a/test/unit/builtins/array.spec.ts b/test/unit/builtins/array.spec.ts index 51aac9cc3..aa21d85ed 100644 --- a/test/unit/builtins/array.spec.ts +++ b/test/unit/builtins/array.spec.ts @@ -487,6 +487,7 @@ test.each([ }); test.each([ + { array: [[]], expected: [] }, { array: [1, [2, 3], 4], expected: [1, 2, 3, 4] }, { array: [1, [2, 3], 4], depth: 0, expected: [1, [2, 3], 4] }, { array: [1, [[2], [3]], 4], expected: [1, [2], [3], 4] }, @@ -497,6 +498,7 @@ test.each([ }); test.each([ + { array: [[]], map: (v: T) => v, expected: [] }, { array: [1, [2, 3], [4]], map: (value: T) => value, expected: [1, 2, 3, 4] }, { array: [1, 2, 3], map: (v: number) => v * 2, expected: [2, 4, 6] }, { array: [1, 2, 3], map: (v: number) => [v, v * 2], expected: [1, 2, 2, 4, 3, 6] }, From ee474ba720b2e27c96012a6e29a80999f5e904cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Miernik?= Date: Mon, 21 Oct 2019 23:03:31 +0200 Subject: [PATCH 2/5] Added failing flat[Map] tests. --- test/unit/builtins/array.spec.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/unit/builtins/array.spec.ts b/test/unit/builtins/array.spec.ts index aa21d85ed..56d144e02 100644 --- a/test/unit/builtins/array.spec.ts +++ b/test/unit/builtins/array.spec.ts @@ -488,6 +488,7 @@ test.each([ test.each([ { array: [[]], expected: [] }, + { array: [{ a: 1 }, { a: 2 }, { a: 3 }], expected: [{ a: 1 }, { a: 2 }, { a: 3 }] }, { array: [1, [2, 3], 4], expected: [1, 2, 3, 4] }, { array: [1, [2, 3], 4], depth: 0, expected: [1, [2, 3], 4] }, { array: [1, [[2], [3]], 4], expected: [1, [2], [3], 4] }, @@ -499,6 +500,7 @@ test.each([ test.each([ { array: [[]], map: (v: T) => v, expected: [] }, + { array: [1, 2, 3], map: (v: number) => ({ a: v * 2 }), expected: [{ a: 2 }, { a: 4 }, { a: 6 }] }, { array: [1, [2, 3], [4]], map: (value: T) => value, expected: [1, 2, 3, 4] }, { array: [1, 2, 3], map: (v: number) => v * 2, expected: [2, 4, 6] }, { array: [1, 2, 3], map: (v: number) => [v, v * 2], expected: [1, 2, 2, 4, 3, 6] }, From 26500713e8bba95aff9bffaf42f4adb0d5bb4c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Miernik?= Date: Tue, 22 Oct 2019 20:21:14 +0200 Subject: [PATCH 3/5] Added empty table checks. --- src/lualib/ArrayFlat.ts | 3 ++- src/lualib/ArrayFlatMap.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lualib/ArrayFlat.ts b/src/lualib/ArrayFlat.ts index 938ebfa03..fe582f639 100644 --- a/src/lualib/ArrayFlat.ts +++ b/src/lualib/ArrayFlat.ts @@ -1,7 +1,8 @@ function __TS__ArrayFlat(this: void, array: any[], depth = 1): any[] { let result: any[] = []; for (const value of array) { - if (depth > 0 && type(value) === "table") { + // A hack to concat only true "arrays" and empty tables. + if (depth > 0 && type(value) === "table" && (1 in value || next(value, undefined) === undefined)) { result = result.concat(__TS__ArrayFlat(value, depth - 1)); } else { result[result.length] = value; diff --git a/src/lualib/ArrayFlatMap.ts b/src/lualib/ArrayFlatMap.ts index 3e9440209..05f2cbbd4 100644 --- a/src/lualib/ArrayFlatMap.ts +++ b/src/lualib/ArrayFlatMap.ts @@ -6,7 +6,8 @@ function __TS__ArrayFlatMap( let result: U[] = []; for (let i = 0; i < array.length; i++) { const value = callback(array[i], i, array); - if (type(value) === "table") { + // A hack to concat only true "arrays" and empty tables. + if (type(value) === "table" && (1 in value || next(value as any, undefined) === undefined)) { result = result.concat(value); } else { result[result.length] = value as U; From 50190982b1f10a03e1836a4504c9a5b8b3c24961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Miernik?= Date: Tue, 22 Oct 2019 21:03:07 +0200 Subject: [PATCH 4/5] Added a clean workaround for next. --- src/lualib/ArrayFlat.ts | 7 +++++-- src/lualib/ArrayFlatMap.ts | 6 ++++-- src/lualib/declarations/global.d.ts | 3 +++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lualib/ArrayFlat.ts b/src/lualib/ArrayFlat.ts index fe582f639..30731521d 100644 --- a/src/lualib/ArrayFlat.ts +++ b/src/lualib/ArrayFlat.ts @@ -1,8 +1,11 @@ function __TS__ArrayFlat(this: void, array: any[], depth = 1): any[] { let result: any[] = []; for (const value of array) { - // A hack to concat only true "arrays" and empty tables. - if (depth > 0 && type(value) === "table" && (1 in value || next(value, undefined) === undefined)) { + if ( + depth > 0 && + type(value) === "table" && + (1 in value || (next as NextEmptyCheck)(value, undefined) === undefined) + ) { result = result.concat(__TS__ArrayFlat(value, depth - 1)); } else { result[result.length] = value; diff --git a/src/lualib/ArrayFlatMap.ts b/src/lualib/ArrayFlatMap.ts index 05f2cbbd4..fe2a3608a 100644 --- a/src/lualib/ArrayFlatMap.ts +++ b/src/lualib/ArrayFlatMap.ts @@ -6,8 +6,10 @@ function __TS__ArrayFlatMap( let result: U[] = []; for (let i = 0; i < array.length; i++) { const value = callback(array[i], i, array); - // A hack to concat only true "arrays" and empty tables. - if (type(value) === "table" && (1 in value || next(value as any, undefined) === undefined)) { + if ( + type(value) === "table" && + (1 in value || (next as NextEmptyCheck)(value as any, undefined) === undefined) + ) { result = result.concat(value); } else { result[result.length] = value as U; diff --git a/src/lualib/declarations/global.d.ts b/src/lualib/declarations/global.d.ts index 77a88b694..4a86d2542 100644 --- a/src/lualib/declarations/global.d.ts +++ b/src/lualib/declarations/global.d.ts @@ -5,6 +5,9 @@ declare var __TS__originalTraceback: | ((this: void, thread?: any, message?: string, level?: number) => string) | undefined; +// Override next declaration so we can omit extra return values +declare type NextEmptyCheck = (this: void, table: any, index: undefined) => unknown | undefined; + declare function tonumber(value: any, base?: number): number | undefined; declare function type( value: any From 139169274f5d36a59deb1f6110482545359e9da6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rados=C5=82aw=20Miernik?= Date: Tue, 22 Oct 2019 21:03:28 +0200 Subject: [PATCH 5/5] Documented workaround. --- src/lualib/ArrayFlat.ts | 2 ++ src/lualib/ArrayFlatMap.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/lualib/ArrayFlat.ts b/src/lualib/ArrayFlat.ts index 30731521d..54120e69a 100644 --- a/src/lualib/ArrayFlat.ts +++ b/src/lualib/ArrayFlat.ts @@ -4,6 +4,8 @@ function __TS__ArrayFlat(this: void, array: any[], depth = 1): any[] { if ( depth > 0 && type(value) === "table" && + // Workaround to determine if value is an array or not (fails in case of objects without keys) + // See discussion in: https://github.com/TypeScriptToLua/TypeScriptToLua/pull/737 (1 in value || (next as NextEmptyCheck)(value, undefined) === undefined) ) { result = result.concat(__TS__ArrayFlat(value, depth - 1)); diff --git a/src/lualib/ArrayFlatMap.ts b/src/lualib/ArrayFlatMap.ts index fe2a3608a..02d58329b 100644 --- a/src/lualib/ArrayFlatMap.ts +++ b/src/lualib/ArrayFlatMap.ts @@ -8,6 +8,8 @@ function __TS__ArrayFlatMap( const value = callback(array[i], i, array); if ( type(value) === "table" && + // Workaround to determine if value is an array or not (fails in case of objects without keys) + // See discussion in: https://github.com/TypeScriptToLua/TypeScriptToLua/pull/737 (1 in value || (next as NextEmptyCheck)(value as any, undefined) === undefined) ) { result = result.concat(value);