@tilua-types/roblox 2.1.0 → 3.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
@@ -12,9 +12,13 @@
12
12
  * task.spawn(work, 1) -> tilua_roblox.task.spawn(work, 1)
13
13
  *
14
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
- * and `coroutine` is left alone: `coroutine.resume` answering `false, err` is
17
- * part of what it promises.
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`).
18
22
  *
19
23
  * `print`, `error` and the console come from `@tilua-types/lua`, which this
20
24
  * package depends on.
@@ -57,6 +61,23 @@ function isSignal(type) {
57
61
  m.kind === "object" && m.properties.has("Connect") && m.properties.has("Once") && m.properties.has("Wait"))
58
62
  }
59
63
 
64
+ /** Luau globals answering several values, which the runtime gathers. */
65
+ const GATHERED_GLOBALS = new Set(["string.unpack", "coroutine.close", "utf8.codepoint", "utf8.codes", "utf8.graphemes"])
66
+
67
+ /** Does every signature of `receiver`'s `method` return a tuple — several
68
+ * values, as tilua has them in one array?
69
+ * @type {(receiver: Type | undefined, method: string) => boolean} */
70
+ function returnsSeveral(receiver, method) {
71
+ const members = parts(receiver)
72
+ if (!members.length) return false
73
+ return members.every(m => {
74
+ if (m.kind !== "object") return false
75
+ const found = m.properties.get(method)?.type
76
+ const signatures = !found ? [] : found.kind === "intersection" ? found.types : [found]
77
+ return signatures.length > 0 && signatures.every(f => f.kind === "function" && f.returns.kind === "tuple")
78
+ })
79
+ }
80
+
60
81
  /** @type {(type: Type | undefined, className: string) => boolean} */
61
82
  function isInstanceOf(type, className) {
62
83
  const members = parts(type)
@@ -72,11 +93,20 @@ const plugin = {
72
93
  if (SIGNAL_METHODS.has(method) && isSignal(receiver)) return { callee: `${use("roblox")}.${method}` }
73
94
  const service = SERVICE_METHODS.get(method)
74
95
  if (service !== undefined && isInstanceOf(receiver, service)) return { callee: `${use("roblox")}.${method}` }
96
+ if (returnsSeveral(receiver, method)) {
97
+ return { callee: `${use("roblox")}.values`, prepend: [JSON.stringify(method)] }
98
+ }
99
+ return undefined
100
+ },
101
+
102
+ globalCall({ name, use }) {
103
+ if (GATHERED_GLOBALS.has(name)) return { callee: `${use("roblox")}.globals.${name.replace(".", "_")}` }
75
104
  return undefined
76
105
  },
77
106
 
78
107
  globalValue({ name, use }) {
79
108
  if (name === "task") return `${use("roblox")}.task`
109
+ if (GATHERED_GLOBALS.has(name)) return `${use("roblox")}.globals.${name.replace(".", "_")}`
80
110
  return undefined
81
111
  },
82
112
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tilua-types/roblox",
3
- "version": "2.1.0",
3
+ "version": "3.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": [
@@ -15,7 +15,7 @@
15
15
  "lowering": "lowering.mjs"
16
16
  },
17
17
  "dependencies": {
18
- "@tilua-types/lua": "^2.1.0"
18
+ "@tilua-types/lua": "^3.0.0"
19
19
  },
20
20
  "keywords": [
21
21
  "tilua",
@@ -75,3 +75,50 @@ __NAME__.task = setmetatable({
75
75
  return task.delay(duration, guard(target), ...)
76
76
  end,
77
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
+ }