-
-
Notifications
You must be signed in to change notification settings - Fork 847
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a370f46
commit f1533bf
Showing
12 changed files
with
741 additions
and
260 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,46 @@ | ||
# always ignore files | ||
*.DS_Store | ||
.idea | ||
.vscode/* | ||
!.vscode/settings.json | ||
!.vscode/tasks.json | ||
# include common debug launch configs | ||
!.vscode/launch.json | ||
!.vscode/extensions.json | ||
!.vscode/launch.sample.json | ||
*.sublime-* | ||
.settings/ | ||
|
||
# test related, or directories generated by tests | ||
test/actual | ||
actual | ||
coverage | ||
.nyc* | ||
debug.log | ||
/luacov.* | ||
/lcov* | ||
/site | ||
/output.txt | ||
cachegrind.out.* | ||
callgrind.out.* | ||
|
||
# npm | ||
node_modules | ||
npm-debug.log | ||
|
||
# yarn | ||
yarn.lock | ||
coverage | ||
.nyc_output | ||
yarn-error.log | ||
|
||
# misc | ||
_gh_pages | ||
_draft | ||
_drafts | ||
bower_components | ||
vendor | ||
temp | ||
tmp | ||
TODO.md | ||
package-lock.json | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"name": "chalk", | ||
"tree": { | ||
"$path": "source" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
[tools] | ||
luau-lsp = { source = "JohnnyMorganz/luau-lsp", version = "1.18.1" } | ||
rojo = { source = "rojo-rbx/rojo", version = "7.2.1" } | ||
selene = { source = "Kampfkarren/selene", version = "0.25.0" } | ||
stylua = { source = "JohnnyMorganz/StyLua", version = "0.17.1" } | ||
wally = { source = "UpliftGames/wally", version = "=0.3.1" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
std="roblox+testez" | ||
[config] | ||
empty_if = { comments_count = true } | ||
|
||
[rules] | ||
incorrect_standard_library_use = "allow" | ||
shadowing = "allow" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
--[[ | ||
derived from documentation and reference implementation at: | ||
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf | ||
Attributions and copyright licensing by Mozilla Contributors is licensed under CC-BY-SA 2.5 | ||
These are heuristcs tested across 300+KLOC of JS translated to Lua | ||
It isn't perfect, but it works for dozens of packages in the React, Jest, and GraphQL ecosystem | ||
In those dozens of packages, hundreds and hundreds of tests were ported to Lua and passing | ||
Additionally, the packages were integrated into a 500+KLOC 60fps product and shipped to 150+M global users | ||
Reimplemented by Matt Hargett, 2023 | ||
]] | ||
--!strict | ||
local exports = {} | ||
export type Array<T> = { [number]: T } | ||
type Object = { [string]: any } | ||
exports.indexOf = function<T>(haystack: Array<T>, needle: T, startIndex_: number?): number | ||
local length = #haystack | ||
local startIndex = if startIndex_ == nil | ||
then 1 | ||
else if startIndex_ < 1 then math.max(1, length - math.abs(startIndex_)) else startIndex_ | ||
|
||
for i = startIndex, length, 1 do | ||
if haystack[i] == needle then | ||
return i | ||
end | ||
end | ||
|
||
-- we maintain the JS not found value, as it's often checked for explicitly and as < 0 | ||
return -1 | ||
end | ||
|
||
-- we pulled a few refinement ideas from this stackoverflow article, but found: | ||
-- 1. no single one answer worked enough of the time in terms of transliterated JS expectations | ||
-- 2. most had very poor accuracy versus performance tradeoffs | ||
-- https://stackoverflow.com/questions/7526223/how-do-i-know-if-a-table-is-an-array/20958869#20958869 | ||
exports.isArray = function(val: any): boolean | ||
if type(val) ~= "table" then | ||
return false | ||
end | ||
|
||
if next(val) == nil then | ||
-- it's table with nothing in it, which we express is an array | ||
-- this works 99% of the time for transliterated Lua | ||
return true | ||
end | ||
|
||
local tableLength = #val | ||
if tableLength == 0 then | ||
-- getting past the preceding clause says the table isn't an empty iterable | ||
-- if the length of the table is reported as 0, that means it has non-numeric indices | ||
return false | ||
end | ||
|
||
-- the slow part, verifying each index is a positive, whole number. a Lua VM built-in would be nice. | ||
for key, _ in pairs(val) do | ||
if type(key) ~= "number" then | ||
return false | ||
end | ||
if key < 1 then | ||
-- Lua arrays start at 1, a 0 index means it's not a pure Lua array | ||
return false | ||
end | ||
-- Lua TODO: would math.floor be faster? needs a benchmark | ||
if (key % 1) ~= 0 then | ||
-- if the number key isn't a whole number, it's not a pure Lua array | ||
return false | ||
end | ||
|
||
if key > tableLength then | ||
-- if we get a numeric key larger than the length operator reports, this isn't a contiguous array | ||
return false | ||
end | ||
|
||
if key ~= tableLength then | ||
-- if we're not at the end of a contiguous array, the value in the index slot should be non-nil | ||
if nil == val[key + 1] then | ||
return false | ||
end | ||
end | ||
end | ||
|
||
return true | ||
end | ||
|
||
-- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join | ||
exports.join = function<T>(array: Array<T>, separator: string?): string | ||
-- this behavior is relied on by GraphQL and jest | ||
return if 0 == #array | ||
then "" | ||
-- some lua implementations of concat don't behave when passed nil | ||
else table.concat(array, separator or ",") | ||
end | ||
|
||
-- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | ||
exports.reverse = function(array: Array<any>): Array<any> | ||
local end_ = #array | ||
local start = 1 | ||
while start < end_ do | ||
-- this one-liner is a Lua idiom for swapping two values | ||
array[start], array[end_] = array[end_], array[start] | ||
end_ -= 1 | ||
start += 1 | ||
end | ||
|
||
return array | ||
end | ||
|
||
-- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | ||
exports.slice = function<T>(array: Array<T>, startIndex_: number?, endIndex_: number?): Array<T> | ||
local length = #array | ||
|
||
-- JS translates indices > length to be length; in Lua, we translate to length + 1 | ||
local endIndex = if (nil == endIndex_ or endIndex_ > length + 1) | ||
then length + 1 | ||
else if endIndex_ < 1 then math.max(1, length - math.abs(endIndex_)) else endIndex_ | ||
|
||
-- JS translates negative indices to 0; in Lua, we translate it to 1 | ||
local startIndex = if startIndex_ == nil | ||
then 1 | ||
else if startIndex_ < 1 then math.max(1, length - math.abs(startIndex_)) else startIndex_ | ||
|
||
local i = 1 | ||
local index = startIndex | ||
local result = {} | ||
while index < endIndex do | ||
result[i] = array[index] | ||
i += 1 | ||
index += 1 | ||
end | ||
|
||
return result | ||
end | ||
|
||
-- this replicates the behavior that mixed Arrays of numbers and strings containing numbers | ||
-- sort the *number* 6 before the *string* 6, and before *userdata* 6, which is relied upon by jest and GraphQL | ||
local function builtinSort<T>(one: T, another: T): boolean | ||
return type(another) .. tostring(another) > type(one) .. tostring(one) | ||
end | ||
|
||
-- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort | ||
type Comparator = (one: any, another: any) -> number | ||
exports.sort = function<T>(array: Array<T>, compare: Comparator?): Array<T> | ||
-- Lua BUG: this is a workaround for a typr solver bug where it says template types aren't compatible with `any` | ||
local translateJsSortReturnToLuaSortReturn: (any, any) -> boolean = if compare == nil | ||
then builtinSort | ||
else function<T>(x: T, y: T): boolean | ||
return 0 > compare(x, y) | ||
end | ||
|
||
table.sort(array, translateJsSortReturnToLuaSortReturn) | ||
return array | ||
end | ||
|
||
type callbackFunction<T, U> = (value: T, index: number, array: Array<T>) -> U | ||
type callbackFunctionWithSelfArgument<T, U> = (self: Object, value: T, index: number, array: Array<T>) -> U | ||
-- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map | ||
exports.map = function<T, U>( | ||
arr: Array<T>, | ||
callback: callbackFunction<T, U> | callbackFunctionWithSelfArgument<T, U>, | ||
selfArgument: Object? | ||
): Array<U> | ||
local i = 1 | ||
local length = #arr | ||
local result = {} | ||
|
||
if selfArgument == nil then | ||
while i <= length do | ||
local inputValue = arr[i] | ||
-- Lua BUG: type solver says callback isn't callable, but it is | ||
result[i] = (callback :: callbackFunction<T, U>)(inputValue, i, arr) | ||
i += 1 | ||
end | ||
else | ||
while i <= length do | ||
local inputValue = arr[i] | ||
-- Lua BUG: type solver says callback isn't callable, but it is | ||
result[i] = (callback :: callbackFunctionWithSelfArgument<T, U>)(selfArgument, inputValue, i, arr) | ||
i += 1 | ||
end | ||
end | ||
|
||
return result | ||
end | ||
|
||
return exports |
Oops, something went wrong.