@tilua-types/roblox 7.1.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lowering.mjs CHANGED
@@ -1,79 +1,88 @@
1
- // @ts-check
2
- /**
3
- * What tilua lowers for Roblox: callbacks that Roblox runs later, on a thread
4
- * of their own.
5
- *
6
- * The entry of a bundle runs under `xpcall`, which is what reports an error
7
- * in the project's files instead of in the bundle's lines. A callback given
8
- * to `task.spawn` or to `signal:Connect` is not under it when it runs, so its
9
- * callback is wrapped in the same handler first (see runtime/roblox.luau):
10
- *
11
- * part.Touched:Connect(onTouched) -> tilua_roblox.Connect(part.Touched, onTouched)
12
- * task.spawn(work, 1) -> tilua_roblox.task.spawn(work, 1)
13
- *
14
- * Only where Roblox starts a thread. A callback run synchronously — a
15
- * `table.sort` comparator, `names:map(f)` — has its caller's `xpcall` already.
16
- *
17
- * And where Luau answers several values, tilua has one — an array. A method
18
- * whose type returns a tuple (`workspace:FindPartOnRay(ray)`, `signal:Wait()`)
19
- * is called through the runtime's `values`, which gathers them, and so are the
20
- * Luau globals that answer several (`string.unpack`, `utf8.codepoint`,
21
- * `coroutine.close`).
22
- *
23
- * `print`, `error` and the console are the compiler's own: Lua's standard
24
- * library is built into tilua.
25
- */
26
- import { readFileSync } from "node:fs"
27
- import { dirname, join } from "node:path"
28
- import { fileURLToPath } from "node:url"
29
- import { hasMembers, isInstanceOf, luauString, returnsTuple } from "@tilua/parser"
30
-
31
- /** @typedef {import("@tilua/parser").LoweringPlugin} LoweringPlugin */
32
-
33
- const here = dirname(fileURLToPath(import.meta.url))
34
- const roblox = readFileSync(join(here, "runtime", "roblox.luau"), "utf8")
35
-
36
- const SIGNAL_METHODS = new Set(["Connect", "Once", "ConnectParallel"])
37
-
38
- /** A service's methods that keep a callback, by the class that has them. */
39
- const SERVICE_METHODS = new Map([
40
- ["BindToRenderStep", "RunService"],
41
- ["BindToClose", "DataModel"],
42
- ["BindAction", "ContextActionService"],
43
- ["BindActionAtPriority", "ContextActionService"],
44
- ])
45
-
46
- /** `RBXScriptSignal<T...>` is structural once it is resolved: an object that
47
- * can be connected to and waited on. */
48
- const SIGNAL_MEMBERS = ["Connect", "Once", "Wait"]
49
-
50
- /** Luau globals answering several values, which the runtime gathers. */
51
- const GATHERED_GLOBALS = new Set(["string.unpack", "coroutine.close", "utf8.codepoint", "utf8.codes", "utf8.graphemes"])
52
-
53
- /** @type {LoweringPlugin} */
54
- const plugin = {
55
- runtime: { roblox },
56
-
57
- methodCall({ method, receiver, use }) {
58
- if (SIGNAL_METHODS.has(method) && hasMembers(receiver, SIGNAL_MEMBERS)) return { callee: `${use("roblox")}.${method}` }
59
- const service = SERVICE_METHODS.get(method)
60
- if (service !== undefined && isInstanceOf(receiver, service)) return { callee: `${use("roblox")}.${method}` }
61
- if (returnsTuple(receiver, method)) {
62
- return { callee: `${use("roblox")}.values`, prepend: [luauString(method)] }
63
- }
64
- return undefined
65
- },
66
-
67
- globalCall({ name, use }) {
68
- if (GATHERED_GLOBALS.has(name)) return { callee: `${use("roblox")}.globals.${name.replace(".", "_")}` }
69
- return undefined
70
- },
71
-
72
- globalValue({ name, use }) {
73
- if (name === "task") return `${use("roblox")}.task`
74
- if (GATHERED_GLOBALS.has(name)) return `${use("roblox")}.globals.${name.replace(".", "_")}`
75
- return undefined
76
- },
77
- }
78
-
79
- export default plugin
1
+ // @ts-check
2
+ /**
3
+ * What tilua lowers for Roblox: callbacks that Roblox runs later, on a thread
4
+ * of their own.
5
+ *
6
+ * The entry of a bundle runs under `xpcall`, which is what reports an error
7
+ * in the project's files instead of in the bundle's lines. A callback given
8
+ * to `task.spawn` or to `signal:Connect` is not under it when it runs, so its
9
+ * callback is wrapped in the same handler first (see runtime/roblox.luau):
10
+ *
11
+ * part.Touched:Connect(onTouched) -> tilua_roblox.Connect(part.Touched, onTouched)
12
+ * task.spawn(work, 1) -> tilua_roblox.task.spawn(work, 1)
13
+ *
14
+ * Only where Roblox starts a thread. A callback run synchronously — a
15
+ * `table.sort` comparator, `names:map(f)` — has its caller's `xpcall` already.
16
+ *
17
+ * `HttpService:JSONEncode(value)` is the language's JSON (the runtime's
18
+ * `JSONEncode`), which knows `[]` from `{}` where Roblox's sees two empty
19
+ * tables; `JSONDecode` reads back the same.
20
+ *
21
+ * And where Luau answers several values, tilua has one — an array. A method
22
+ * whose type returns a tuple (`workspace:FindPartOnRay(ray)`, `signal:Wait()`)
23
+ * is called through the runtime's `values`, which gathers them, and so are the
24
+ * Luau globals that answer several (`string.unpack`, `utf8.codepoint`,
25
+ * `coroutine.close`).
26
+ *
27
+ * `print`, `error` and the console are the compiler's own: Lua's standard
28
+ * library is built into tilua.
29
+ */
30
+ import { readFileSync } from "node:fs"
31
+ import { dirname, join } from "node:path"
32
+ import { fileURLToPath } from "node:url"
33
+ import { hasMembers, isInstanceOf, luauString, returnsTuple } from "@tilua/parser"
34
+
35
+ /** @typedef {import("@tilua/parser").LoweringPlugin} LoweringPlugin */
36
+
37
+ const here = dirname(fileURLToPath(import.meta.url))
38
+ const roblox = readFileSync(join(here, "runtime", "roblox.luau"), "utf8")
39
+
40
+ const SIGNAL_METHODS = new Set(["Connect", "Once", "ConnectParallel"])
41
+
42
+ /** A service's methods that keep a callback, by the class that has them. */
43
+ const SERVICE_METHODS = new Map([
44
+ ["BindToRenderStep", "RunService"],
45
+ ["BindToClose", "DataModel"],
46
+ ["BindAction", "ContextActionService"],
47
+ ["BindActionAtPriority", "ContextActionService"],
48
+ ])
49
+
50
+ /** HttpService's JSON, which the runtime writes and reads as tilua's values
51
+ * are: `[]` an array and `{}` an object, empty or not. */
52
+ const JSON_METHODS = new Set(["JSONEncode", "JSONDecode", "JSONEncodeAsync", "JSONDecodeAsync"])
53
+
54
+ /** `RBXScriptSignal<T...>` is structural once it is resolved: an object that
55
+ * can be connected to and waited on. */
56
+ const SIGNAL_MEMBERS = ["Connect", "Once", "Wait"]
57
+
58
+ /** Luau globals answering several values, which the runtime gathers. */
59
+ const GATHERED_GLOBALS = new Set(["string.unpack", "coroutine.close", "utf8.codepoint", "utf8.codes", "utf8.graphemes"])
60
+
61
+ /** @type {LoweringPlugin} */
62
+ const plugin = {
63
+ runtime: { roblox },
64
+
65
+ methodCall({ method, receiver, use }) {
66
+ if (SIGNAL_METHODS.has(method) && hasMembers(receiver, SIGNAL_MEMBERS)) return { callee: `${use("roblox")}.${method}` }
67
+ if (JSON_METHODS.has(method) && isInstanceOf(receiver, "HttpService")) return { callee: `${use("roblox")}.${method}` }
68
+ const service = SERVICE_METHODS.get(method)
69
+ if (service !== undefined && isInstanceOf(receiver, service)) return { callee: `${use("roblox")}.${method}` }
70
+ if (returnsTuple(receiver, method)) {
71
+ return { callee: `${use("roblox")}.values`, prepend: [luauString(method)] }
72
+ }
73
+ return undefined
74
+ },
75
+
76
+ globalCall({ name, use }) {
77
+ if (GATHERED_GLOBALS.has(name)) return { callee: `${use("roblox")}.globals.${name.replace(".", "_")}` }
78
+ return undefined
79
+ },
80
+
81
+ globalValue({ name, use }) {
82
+ if (name === "task") return `${use("roblox")}.task`
83
+ if (GATHERED_GLOBALS.has(name)) return `${use("roblox")}.globals.${name.replace(".", "_")}`
84
+ return undefined
85
+ },
86
+ }
87
+
88
+ export default plugin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tilua-types/roblox",
3
- "version": "7.1.0",
3
+ "version": "9.0.0",
4
4
  "description": "Luau and the whole Roblox API as tilua types: every class, enum, data type, service and global",
5
5
  "license": "ISC",
6
6
  "files": [
@@ -14,8 +14,11 @@
14
14
  "types": "index.d.tilua",
15
15
  "lowering": "lowering.mjs"
16
16
  },
17
+ "dependencies": {
18
+ "@tilua-types/luau": "^8.0.0"
19
+ },
17
20
  "peerDependencies": {
18
- "@tilua/parser": "^6.0.0"
21
+ "@tilua/parser": "^8.0.0"
19
22
  },
20
23
  "keywords": [
21
24
  "tilua",
@@ -1,124 +1,139 @@
1
- -- Callbacks Roblox runs on a thread of their own, reported in the project's
2
- -- files.
3
- --
4
- -- A bundle's entry runs under `xpcall`, so an error nothing caught names the
5
- -- file and line the author wrote. A callback handed to `task.spawn` or to
6
- -- `signal:Connect` runs later, on a new thread, where that `xpcall` is not on
7
- -- the stack: its errors would name lines of the bundle. `guard` gives such a
8
- -- callback the same handler — `__FAIL__`, the bundle's own — and raises what
9
- -- it returns on the callback's thread, where Roblox reports it as before.
10
- --
11
- -- The error is raised again, never swallowed: code that relied on it
12
- -- stopping the callback still sees it stop. Outside a bundle there is nothing
13
- -- to map, and callbacks are passed through untouched.
14
-
15
- local __NAME__ = {}
16
- local fail = __FAIL__
17
-
18
- local function guard(callback)
19
- if type(callback) ~= "function" or fail == nil then
20
- return callback
21
- end
22
- return function(...)
23
- local results = table.pack(xpcall(callback, fail, ...))
24
- if not results[1] then
25
- error(results[2], 0)
26
- end
27
- return table.unpack(results, 2, results.n)
28
- end
29
- end
30
-
31
- __NAME__.guard = guard
32
-
33
- -- `signal:Connect(f)` and its siblings.
34
- function __NAME__.Connect(signal, callback)
35
- return signal:Connect(guard(callback))
36
- end
37
-
38
- function __NAME__.Once(signal, callback)
39
- return signal:Once(guard(callback))
40
- end
41
-
42
- function __NAME__.ConnectParallel(signal, callback)
43
- return signal:ConnectParallel(guard(callback))
44
- end
45
-
46
- -- Services that keep a callback and run it later.
47
- function __NAME__.BindToRenderStep(service, name, priority, callback)
48
- return service:BindToRenderStep(name, priority, guard(callback))
49
- end
50
-
51
- function __NAME__.BindToClose(game, callback)
52
- return game:BindToClose(guard(callback))
53
- end
54
-
55
- function __NAME__.BindAction(service, name, callback, ...)
56
- return service:BindAction(name, guard(callback), ...)
57
- end
58
-
59
- function __NAME__.BindActionAtPriority(service, name, callback, ...)
60
- return service:BindActionAtPriority(name, guard(callback), ...)
61
- end
62
-
63
- -- `task`, with the functions that start a thread guarding what they start.
64
- -- A thread passed instead of a function is left as it is. Everything else is
65
- -- `task`'s own. Standing in for the global, rather than rewriting calls,
66
- -- covers `local spawn = task.spawn` too.
67
- __NAME__.task = setmetatable({
68
- spawn = function(target, ...)
69
- return task.spawn(guard(target), ...)
70
- end,
71
- defer = function(target, ...)
72
- return task.defer(guard(target), ...)
73
- end,
74
- delay = function(duration, target, ...)
75
- return task.delay(duration, guard(target), ...)
76
- end,
77
- }, { __index = task })
78
-
79
- -- Where Luau answers several values, tilua has one: an array. A Roblox method
80
- -- whose type says it returns several — `workspace:FindPartOnRay(ray)`,
81
- -- `signal:Wait()`, `cf:ToOrientation()` — is called through this, which
82
- -- hands its values back as that array.
83
- function __NAME__.values(name, receiver, ...)
84
- return { receiver[name](receiver, ...) }
85
- end
86
-
87
- -- The same for Luau's own globals that answer several values.
88
- __NAME__.globals = {
89
- string_unpack = function(...)
90
- return { string.unpack(...) }
91
- end,
92
- coroutine_close = function(co)
93
- return { coroutine.close(co) }
94
- end,
95
- utf8_codepoint = function(...)
96
- return { utf8.codepoint(...) }
97
- end,
98
- -- An iteration — `{ step, state, first }` — whose steps answer one
99
- -- `{ position, code }` each, as a loop walks them.
100
- utf8_codes = function(s)
101
- local step, state, first = utf8.codes(s)
102
- return {
103
- function(_, previous)
104
- local position, code = step(state, previous ~= nil and previous[1] or first)
105
- if position == nil then
106
- return nil
107
- end
108
- return { position, code }
109
- end,
110
- s,
111
- nil,
112
- }
113
- end,
114
- utf8_graphemes = function(s, i, j)
115
- local step = utf8.graphemes(s, i, j)
116
- return function()
117
- local first, last = step()
118
- if first == nil then
119
- return nil
120
- end
121
- return { first, last }
122
- end
123
- end,
124
- }
1
+ -- Callbacks Roblox runs on a thread of their own, reported in the project's
2
+ -- files.
3
+ --
4
+ -- A bundle's entry runs under `xpcall`, so an error nothing caught names the
5
+ -- file and line the author wrote. A callback handed to `task.spawn` or to
6
+ -- `signal:Connect` runs later, on a new thread, where that `xpcall` is not on
7
+ -- the stack: its errors would name lines of the bundle. `guard` gives such a
8
+ -- callback the same handler — `__FAIL__`, the bundle's own — and raises what
9
+ -- it returns on the callback's thread, where Roblox reports it as before.
10
+ --
11
+ -- The error is raised again, never swallowed: code that relied on it
12
+ -- stopping the callback still sees it stop. Outside a bundle there is nothing
13
+ -- to map, and callbacks are passed through untouched.
14
+
15
+ local __NAME__ = {}
16
+ local fail = __FAIL__
17
+
18
+ local function guard(callback)
19
+ if type(callback) ~= "function" or fail == nil then
20
+ return callback
21
+ end
22
+ return function(...)
23
+ local results = table.pack(xpcall(callback, fail, ...))
24
+ if not results[1] then
25
+ error(results[2], 0)
26
+ end
27
+ return table.unpack(results, 2, results.n)
28
+ end
29
+ end
30
+
31
+ __NAME__.guard = guard
32
+
33
+ -- `signal:Connect(f)` and its siblings.
34
+ function __NAME__.Connect(signal, callback)
35
+ return signal:Connect(guard(callback))
36
+ end
37
+
38
+ function __NAME__.Once(signal, callback)
39
+ return signal:Once(guard(callback))
40
+ end
41
+
42
+ function __NAME__.ConnectParallel(signal, callback)
43
+ return signal:ConnectParallel(guard(callback))
44
+ end
45
+
46
+ -- Services that keep a callback and run it later.
47
+ function __NAME__.BindToRenderStep(service, name, priority, callback)
48
+ return service:BindToRenderStep(name, priority, guard(callback))
49
+ end
50
+
51
+ function __NAME__.BindToClose(game, callback)
52
+ return game:BindToClose(guard(callback))
53
+ end
54
+
55
+ function __NAME__.BindAction(service, name, callback, ...)
56
+ return service:BindAction(name, guard(callback), ...)
57
+ end
58
+
59
+ function __NAME__.BindActionAtPriority(service, name, callback, ...)
60
+ return service:BindActionAtPriority(name, guard(callback), ...)
61
+ end
62
+
63
+ -- `task`, with the functions that start a thread guarding what they start.
64
+ -- A thread passed instead of a function is left as it is. Everything else is
65
+ -- `task`'s own. Standing in for the global, rather than rewriting calls,
66
+ -- covers `local spawn = task.spawn` too.
67
+ __NAME__.task = setmetatable({
68
+ spawn = function(target, ...)
69
+ return task.spawn(guard(target), ...)
70
+ end,
71
+ defer = function(target, ...)
72
+ return task.defer(guard(target), ...)
73
+ end,
74
+ delay = function(duration, target, ...)
75
+ return task.delay(duration, guard(target), ...)
76
+ end,
77
+ }, { __index = task })
78
+
79
+ -- HttpService's JSON, as tilua's values have it: `[]` is an array and `{}`
80
+ -- an object, empty or not — `JSONEncode` alone writes every empty table as
81
+ -- `[]` — and what `JSONDecode` reads back is the same. `__JSON__` is the
82
+ -- language's; the Async ones yield nothing here, the work being the same.
83
+ function __NAME__.JSONEncode(_, value)
84
+ return __JSON__.encode(value)
85
+ end
86
+
87
+ function __NAME__.JSONDecode(_, text)
88
+ return __JSON__.decode(text)
89
+ end
90
+
91
+ __NAME__.JSONEncodeAsync = __NAME__.JSONEncode
92
+ __NAME__.JSONDecodeAsync = __NAME__.JSONDecode
93
+
94
+ -- Where Luau answers several values, tilua has one: an array. A Roblox method
95
+ -- whose type says it returns several — `workspace:FindPartOnRay(ray)`,
96
+ -- `signal:Wait()`, `cf:ToOrientation()` — is called through this, which
97
+ -- hands its values back as that array.
98
+ function __NAME__.values(name, receiver, ...)
99
+ return { receiver[name](receiver, ...) }
100
+ end
101
+
102
+ -- The same for Luau's own globals that answer several values.
103
+ __NAME__.globals = {
104
+ string_unpack = function(...)
105
+ return { string.unpack(...) }
106
+ end,
107
+ coroutine_close = function(co)
108
+ return { coroutine.close(co) }
109
+ end,
110
+ utf8_codepoint = function(...)
111
+ return { utf8.codepoint(...) }
112
+ end,
113
+ -- An iteration — `{ step, state, first }` — whose steps answer one
114
+ -- `{ position, code }` each, as a loop walks them.
115
+ utf8_codes = function(s)
116
+ local step, state, first = utf8.codes(s)
117
+ return {
118
+ function(_, previous)
119
+ local position, code = step(state, previous ~= nil and previous[1] or first)
120
+ if position == nil then
121
+ return nil
122
+ end
123
+ return { position, code }
124
+ end,
125
+ s,
126
+ nil,
127
+ }
128
+ end,
129
+ utf8_graphemes = function(s, i, j)
130
+ local step = utf8.graphemes(s, i, j)
131
+ return function()
132
+ local first, last = step()
133
+ if first == nil then
134
+ return nil
135
+ end
136
+ return { first, last }
137
+ end
138
+ end,
139
+ }