@flamework-experimental/core 2.0.0-alpha.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.
Files changed (65) hide show
  1. package/README.md +66 -0
  2. package/flamework.build +17 -0
  3. package/out/dependency.d.ts +18 -0
  4. package/out/dependency.luau +32 -0
  5. package/out/flamework.d.ts +78 -0
  6. package/out/flamework.luau +138 -0
  7. package/out/index.d.ts +28 -0
  8. package/out/init.luau +40 -0
  9. package/out/injectable.d.ts +13 -0
  10. package/out/injectable.luau +23 -0
  11. package/out/lifecycle/lifecycleInterfaces.d.ts +94 -0
  12. package/out/lifecycle/lifecycleInterfaces.luau +55 -0
  13. package/out/lifecycle/lifecyclePlugin.d.ts +85 -0
  14. package/out/lifecycle/lifecyclePlugin.luau +424 -0
  15. package/out/modding.d.ts +171 -0
  16. package/out/modding.luau +66 -0
  17. package/out/module/defaultModule.d.ts +5 -0
  18. package/out/module/defaultModule.luau +28 -0
  19. package/out/module/module.d.ts +78 -0
  20. package/out/module/module.luau +811 -0
  21. package/out/module/moduleBuilder.d.ts +88 -0
  22. package/out/module/moduleBuilder.luau +169 -0
  23. package/out/module/moduleDefinition.d.ts +105 -0
  24. package/out/module/moduleDefinition.luau +79 -0
  25. package/out/module/moduleHooks.d.ts +23 -0
  26. package/out/module/moduleHooks.luau +19 -0
  27. package/out/module/providerRegistration.d.ts +22 -0
  28. package/out/module/providerRegistration.luau +80 -0
  29. package/out/module/scopes.d.ts +40 -0
  30. package/out/module/scopes.luau +159 -0
  31. package/out/plugin/pluginDefinition.d.ts +128 -0
  32. package/out/plugin/pluginDefinition.luau +61 -0
  33. package/out/prelude.d.ts +8 -0
  34. package/out/prelude.luau +14 -0
  35. package/out/provider.d.ts +27 -0
  36. package/out/provider.luau +26 -0
  37. package/out/reflect.d.ts +60 -0
  38. package/out/reflect.luau +310 -0
  39. package/out/serialization/types.d.ts +86 -0
  40. package/out/serialization/types.luau +9 -0
  41. package/out/utility/constructors.d.ts +4 -0
  42. package/out/utility/constructors.luau +12 -0
  43. package/out/utility/convertConciseDependencyInfo.d.ts +5 -0
  44. package/out/utility/convertConciseDependencyInfo.luau +29 -0
  45. package/out/utility/getClassImplements.d.ts +7 -0
  46. package/out/utility/getClassImplements.luau +27 -0
  47. package/out/utility/getClassesInPath.d.ts +23 -0
  48. package/out/utility/getClassesInPath.luau +91 -0
  49. package/out/utility/globs.d.ts +9 -0
  50. package/out/utility/globs.luau +64 -0
  51. package/out/utility/metadata.d.ts +12 -0
  52. package/out/utility/metadata.luau +43 -0
  53. package/out/utility/pathRoot.d.ts +17 -0
  54. package/out/utility/pathRoot.luau +105 -0
  55. package/out/utility/recycleThread.d.ts +1 -0
  56. package/out/utility/recycleThread.luau +31 -0
  57. package/out/utility/runtimeConfig.d.ts +59 -0
  58. package/out/utility/runtimeConfig.luau +25 -0
  59. package/out/utility/tsImport.d.ts +6 -0
  60. package/out/utility/tsImport.luau +15 -0
  61. package/out/utility/types.d.ts +16 -0
  62. package/out/utility/types.luau +22 -0
  63. package/out/utility/writable.d.ts +4 -0
  64. package/out/utility/writable.luau +2 -0
  65. package/package.json +33 -0
@@ -0,0 +1,310 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ --[[
3
+ *
4
+ * Reflection/metadata API
5
+
6
+ ]]
7
+ local Reflect = {}
8
+ do
9
+ local _container = Reflect
10
+ --* object -> property -> key -> value
11
+ local metadata = setmetatable({}, {
12
+ __mode = "k",
13
+ })
14
+ local NO_PROP_MARKER = {}
15
+ local function getObjMetadata(obj, prop, create)
16
+ local _condition = prop
17
+ if _condition == nil then
18
+ _condition = NO_PROP_MARKER
19
+ end
20
+ local realProp = _condition
21
+ if create then
22
+ local _obj = obj
23
+ local objMetadata = metadata[_obj]
24
+ if not objMetadata then
25
+ local _exp = obj
26
+ objMetadata = {}
27
+ local _objMetadata = objMetadata
28
+ metadata[_exp] = _objMetadata
29
+ end
30
+ local propMetadata = objMetadata[realProp]
31
+ if not propMetadata then
32
+ local _objMetadata = objMetadata
33
+ propMetadata = {}
34
+ local _propMetadata = propMetadata
35
+ _objMetadata[realProp] = _propMetadata
36
+ end
37
+ return propMetadata
38
+ else
39
+ local _obj = obj
40
+ local _result = metadata[_obj]
41
+ if _result ~= nil then
42
+ _result = _result[realProp]
43
+ end
44
+ return _result
45
+ end
46
+ end
47
+ local function getParentConstructor(obj)
48
+ local metatable = getmetatable(obj)
49
+ if metatable and type(metatable) == "table" then
50
+ return rawget(metatable, "__index")
51
+ end
52
+ end
53
+ --[[
54
+ *
55
+ * Apply metadata onto this object.
56
+
57
+ ]]
58
+ local function defineMetadata(obj, key, value, property)
59
+ local metadata = getObjMetadata(obj, property, true)
60
+ local _key = key
61
+ local _value = value
62
+ metadata[_key] = _value
63
+ end
64
+ _container.defineMetadata = defineMetadata
65
+ --[[
66
+ *
67
+ * Apply metadata in batch onto this object.
68
+
69
+ ]]
70
+ local function defineMetadataBatch(obj, list, property)
71
+ local metadata = getObjMetadata(obj, property, true)
72
+ for key, value in pairs(list) do
73
+ metadata[key] = value
74
+ end
75
+ end
76
+ _container.defineMetadataBatch = defineMetadataBatch
77
+ --[[
78
+ *
79
+ * Delete metadata from this object.
80
+
81
+ ]]
82
+ local function deleteMetadata(obj, key, property)
83
+ local metadata = getObjMetadata(obj, property)
84
+ local _result = metadata
85
+ if _result ~= nil then
86
+ local _key = key
87
+ _result[_key] = nil
88
+ end
89
+ end
90
+ _container.deleteMetadata = deleteMetadata
91
+ --[[
92
+ *
93
+ * Get metadata from this object.
94
+ * Type parameter is an assertion.
95
+
96
+ ]]
97
+ local function getOwnMetadata(obj, key, property)
98
+ local metadata = getObjMetadata(obj, property)
99
+ local _result = metadata
100
+ if _result ~= nil then
101
+ local _key = key
102
+ _result = _result[_key]
103
+ end
104
+ return _result
105
+ end
106
+ _container.getOwnMetadata = getOwnMetadata
107
+ --[[
108
+ *
109
+ * Check if this object has the specified metadata key.
110
+
111
+ ]]
112
+ local function hasOwnMetadata(obj, key, property)
113
+ local metadata = getObjMetadata(obj, property)
114
+ local _result = metadata
115
+ if _result ~= nil then
116
+ local _key = key
117
+ _result = _result[_key] ~= nil
118
+ end
119
+ local _condition = _result
120
+ if _condition == nil then
121
+ _condition = false
122
+ end
123
+ return _condition
124
+ end
125
+ _container.hasOwnMetadata = hasOwnMetadata
126
+ --[[
127
+ *
128
+ * Retrieve all metadata keys for this object.
129
+
130
+ ]]
131
+ local function getOwnMetadataKeys(obj, property)
132
+ local metadata = getObjMetadata(obj, property)
133
+ local keys = {}
134
+ local _result = metadata
135
+ if _result ~= nil then
136
+ -- ▼ ReadonlyMap.forEach ▼
137
+ local _callback = function(_, key)
138
+ local _key = key
139
+ table.insert(keys, _key)
140
+ return #keys
141
+ end
142
+ for _k, _v in _result do
143
+ _callback(_v, _k, _result)
144
+ end
145
+ -- ▲ ReadonlyMap.forEach ▲
146
+ end
147
+ return keys
148
+ end
149
+ _container.getOwnMetadataKeys = getOwnMetadataKeys
150
+ --[[
151
+ *
152
+ * Retrieves all properties (that contain metadata) on this object.
153
+
154
+ ]]
155
+ local function getOwnProperties(obj)
156
+ local _obj = obj
157
+ local properties = metadata[_obj]
158
+ if not properties then
159
+ return {}
160
+ end
161
+ local keys = {}
162
+ for key in properties do
163
+ if key ~= NO_PROP_MARKER then
164
+ table.insert(keys, key)
165
+ end
166
+ end
167
+ return keys
168
+ end
169
+ _container.getOwnProperties = getOwnProperties
170
+ --[[
171
+ *
172
+ * Retrieve all values for the specified key from the object and its parents.
173
+ * Type parameter is an assertion.
174
+
175
+ ]]
176
+ local function getMetadatas(obj, key, property)
177
+ local values = {}
178
+ local value = getOwnMetadata(obj, key, property)
179
+ if value ~= nil then
180
+ table.insert(values, value)
181
+ end
182
+ local parent = getParentConstructor(obj)
183
+ if parent then
184
+ local _exp = getMetadatas(parent, key, property)
185
+ -- ▼ ReadonlyArray.forEach ▼
186
+ local _callback = function(value)
187
+ local _value = value
188
+ table.insert(values, _value)
189
+ return #values
190
+ end
191
+ for _k, _v in _exp do
192
+ _callback(_v, _k - 1, _exp)
193
+ end
194
+ -- ▲ ReadonlyArray.forEach ▲
195
+ end
196
+ return values
197
+ end
198
+ _container.getMetadatas = getMetadatas
199
+ --[[
200
+ *
201
+ * Get metadata from this object or its parents.
202
+ * Type parameter is an assertion.
203
+
204
+ ]]
205
+ local function getMetadata(obj, key, property)
206
+ local value = getOwnMetadata(obj, key, property)
207
+ if value ~= nil then
208
+ return value
209
+ end
210
+ local parent = getParentConstructor(obj)
211
+ if parent then
212
+ return getMetadata(parent, key, property)
213
+ end
214
+ end
215
+ _container.getMetadata = getMetadata
216
+ --[[
217
+ *
218
+ * Check if this object or any of its parents has the specified metadata key.
219
+
220
+ ]]
221
+ local function hasMetadata(obj, key, property)
222
+ local value = hasOwnMetadata(obj, key, property)
223
+ if value then
224
+ return value
225
+ end
226
+ local parent = getParentConstructor(obj)
227
+ if parent then
228
+ return hasMetadata(parent, key, property)
229
+ end
230
+ return false
231
+ end
232
+ _container.hasMetadata = hasMetadata
233
+ --[[
234
+ *
235
+ * Retrieve all metadata keys for this object and its parents.
236
+
237
+ ]]
238
+ local function getMetadataKeys(obj, property)
239
+ local _set = {}
240
+ for _, _v in getOwnMetadataKeys(obj, property) do
241
+ _set[_v] = true
242
+ end
243
+ local keys = _set
244
+ local parent = getParentConstructor(obj)
245
+ if parent then
246
+ local _exp = getMetadataKeys(parent, property)
247
+ -- ▼ ReadonlyArray.forEach ▼
248
+ local _callback = function(key)
249
+ local _key = key
250
+ keys[_key] = true
251
+ return keys
252
+ end
253
+ for _k, _v in _exp do
254
+ _callback(_v, _k - 1, _exp)
255
+ end
256
+ -- ▲ ReadonlyArray.forEach ▲
257
+ end
258
+ local _array = {}
259
+ local _length = #_array
260
+ for _v in keys do
261
+ _length += 1
262
+ _array[_length] = _v
263
+ end
264
+ return _array
265
+ end
266
+ _container.getMetadataKeys = getMetadataKeys
267
+ --[[
268
+ *
269
+ * Retrieves all properties (that contain metadata) on this object and its parents.
270
+
271
+ ]]
272
+ local function getProperties(obj)
273
+ local _set = {}
274
+ for _, _v in getOwnProperties(obj) do
275
+ _set[_v] = true
276
+ end
277
+ local keys = _set
278
+ local parent = getParentConstructor(obj)
279
+ if parent then
280
+ local _exp = getProperties(parent)
281
+ -- ▼ ReadonlyArray.forEach ▼
282
+ local _callback = function(key)
283
+ local _key = key
284
+ keys[_key] = true
285
+ return keys
286
+ end
287
+ for _k, _v in _exp do
288
+ _callback(_v, _k - 1, _exp)
289
+ end
290
+ -- ▲ ReadonlyArray.forEach ▲
291
+ end
292
+ local _array = {}
293
+ local _length = #_array
294
+ for _v in keys do
295
+ _length += 1
296
+ _array[_length] = _v
297
+ end
298
+ return _array
299
+ end
300
+ _container.getProperties = getProperties
301
+ --* @hidden Internal use, do not use
302
+ local function resetObject(object)
303
+ local _object = object
304
+ metadata[_object] = nil
305
+ end
306
+ _container.resetObject = resetObject
307
+ end
308
+ return {
309
+ Reflect = Reflect,
310
+ }
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Types for Flamework's static serialization. There is no runtime here: the transformer generates
3
+ * the encode and decode code for each type at the call site, straight `buffer` reads and writes with
4
+ * nothing describing the type left in the output.
5
+ */
6
+ export declare namespace Serialization {
7
+ /** What `Flamework.createSerializer<T>()` returns. */
8
+ interface Serializer<T> {
9
+ /**
10
+ * Encodes `value`. The second result is the blob list: values with no buffer representation
11
+ * (Instances, `unknown`, most Roblox datatypes), referenced from the buffer by index. It is
12
+ * `undefined` when the type has no such values, and a table (possibly empty) when it has.
13
+ */
14
+ serialize: (value: T) => LuaTuple<[buffer, Array<defined> | undefined]>;
15
+ /**
16
+ * Decodes a payload produced by {@link serialize}. Raises on malformed input, so wrap it in
17
+ * `pcall` for data from an untrusted peer; the networking package does.
18
+ */
19
+ deserialize: (payload: buffer, blobs?: Array<defined>) => T;
20
+ }
21
+ /**
22
+ * Decodes a packed argument list, which is how networking unpacks what a remote delivered. One is
23
+ * generated per event and function; the matching encoding is generated inline at every call
24
+ * site, so no encoder exists as a value at runtime.
25
+ */
26
+ type Decoder<T extends Array<unknown> = Array<unknown>> = (payload: buffer, blobs: Array<defined>) => T;
27
+ /** An unsigned byte, 0 to 255. */
28
+ type u8 = number & {
29
+ readonly __brand: "u8";
30
+ };
31
+ /** A signed byte, -128 to 127. */
32
+ type i8 = number & {
33
+ readonly __brand: "i8";
34
+ };
35
+ /** An unsigned 16-bit integer, 0 to 65535. */
36
+ type u16 = number & {
37
+ readonly __brand: "u16";
38
+ };
39
+ /** A signed 16-bit integer, -32768 to 32767. */
40
+ type i16 = number & {
41
+ readonly __brand: "i16";
42
+ };
43
+ /** An unsigned 32-bit integer. */
44
+ type u32 = number & {
45
+ readonly __brand: "u32";
46
+ };
47
+ /** A signed 32-bit integer. */
48
+ type i32 = number & {
49
+ readonly __brand: "i32";
50
+ };
51
+ /** A single-precision float: four bytes, about seven significant digits. */
52
+ type f32 = number & {
53
+ readonly __brand: "f32";
54
+ };
55
+ /** A double-precision float, which is what a plain `number` is written as. */
56
+ type f64 = number & {
57
+ readonly __brand: "f64";
58
+ };
59
+ /**
60
+ * A non-negative integer written as a LEB128 varint: one byte below 128, two below 16384, up to
61
+ * five bytes. The right choice for counts, ids and other small-most-of-the-time integers.
62
+ */
63
+ type varint = number & {
64
+ readonly __brand: "varint";
65
+ };
66
+ /** A string of at most 255 bytes: a fixed one-byte length. */
67
+ type string8 = string & {
68
+ readonly __brand: "u8_string";
69
+ };
70
+ /** A string of at most 65535 bytes: a fixed two-byte length. */
71
+ type string16 = string & {
72
+ readonly __brand: "u16_string";
73
+ };
74
+ /** A string with a fixed four-byte length. */
75
+ type string32 = string & {
76
+ readonly __brand: "u32_string";
77
+ };
78
+ /** A buffer of at most 65535 bytes: a fixed two-byte length. */
79
+ type buffer16 = buffer & {
80
+ readonly __brand: "u16_buffer";
81
+ };
82
+ /** A buffer with a fixed four-byte length. */
83
+ type buffer32 = buffer & {
84
+ readonly __brand: "u32_buffer";
85
+ };
86
+ }
@@ -0,0 +1,9 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ --[[
3
+ *
4
+ * Types for Flamework's static serialization. There is no runtime here: the transformer generates
5
+ * the encode and decode code for each type at the call site, straight `buffer` reads and writes with
6
+ * nothing describing the type left in the output.
7
+
8
+ ]]
9
+ return nil
@@ -0,0 +1,4 @@
1
+ export type Constructor<T = object> = new (...args: never[]) => T;
2
+ export type AbstractConstructor<T = object> = abstract new (...args: never[]) => T;
3
+ export declare function isConstructor(obj: object): obj is Constructor;
4
+ export declare function isAbstractConstructor(obj: object): obj is AbstractConstructor;
@@ -0,0 +1,12 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local isAbstractConstructor
3
+ local function isConstructor(obj)
4
+ return isAbstractConstructor(obj) and obj.new ~= nil
5
+ end
6
+ function isAbstractConstructor(obj)
7
+ return obj.constructor ~= nil
8
+ end
9
+ return {
10
+ isConstructor = isConstructor,
11
+ isAbstractConstructor = isAbstractConstructor,
12
+ }
@@ -0,0 +1,5 @@
1
+ import type { Modding } from "../modding";
2
+ /**
3
+ * Converts concise dependency info into `Modding.DependencyInfo`
4
+ */
5
+ export declare function convertConciseDependencyInfo(dependency?: string | Modding.DependencyInfo): Modding.DependencyInfo;
@@ -0,0 +1,29 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local cachedDependencyInfo = {}
3
+ --[[
4
+ *
5
+ * Converts concise dependency info into `Modding.DependencyInfo`
6
+
7
+ ]]
8
+ local function convertConciseDependencyInfo(dependency)
9
+ local _arg0 = dependency ~= nil
10
+ assert(_arg0)
11
+ local _dependency = dependency
12
+ if type(_dependency) == "string" then
13
+ local _dependency_1 = dependency
14
+ local metadata = cachedDependencyInfo[_dependency_1]
15
+ if not metadata then
16
+ local _exp = dependency
17
+ metadata = {
18
+ id = dependency,
19
+ }
20
+ local _metadata = metadata
21
+ cachedDependencyInfo[_exp] = _metadata
22
+ end
23
+ return metadata
24
+ end
25
+ return dependency
26
+ end
27
+ return {
28
+ convertConciseDependencyInfo = convertConciseDependencyInfo,
29
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The interfaces a class implements, own and inherited, each once: the transformer writes every
3
+ * class's own heritage clause, so a subclass that re-declares an interface its parent implements
4
+ * carries the id twice up the chain, and attached to it twice -- the lifecycle's ordered lists ran
5
+ * `onInit` and `onStart` twice for it.
6
+ */
7
+ export declare function getClassImplements(constructor: object): string[];
@@ -0,0 +1,27 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local Reflect = TS.import(script, script.Parent.Parent, "reflect").Reflect
4
+ --[[
5
+ *
6
+ * The interfaces a class implements, own and inherited, each once: the transformer writes every
7
+ * class's own heritage clause, so a subclass that re-declares an interface its parent implements
8
+ * carries the id twice up the chain, and attached to it twice -- the lifecycle's ordered lists ran
9
+ * `onInit` and `onStart` twice for it.
10
+
11
+ ]]
12
+ local function getClassImplements(constructor)
13
+ local classImplements = {}
14
+ local seen = {}
15
+ for _, implementList in Reflect.getMetadatas(constructor, "flamework:implements") do
16
+ for _1, implementId in implementList do
17
+ if not (seen[implementId] ~= nil) then
18
+ seen[implementId] = true
19
+ table.insert(classImplements, implementId)
20
+ end
21
+ end
22
+ end
23
+ return classImplements
24
+ end
25
+ return {
26
+ getClassImplements = getClassImplements,
27
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Requires one ModuleScript through the roblox-ts runtime, as an `import` would, and returns what
3
+ * it exported. A module that fails to load raises with its full name and how long it took.
4
+ */
5
+ export declare function importModule(moduleScript: ModuleScript): defined | undefined;
6
+ /**
7
+ * Requires every ModuleScript at and under the specified Rojo path, in tree order, and returns
8
+ * what each exported, leaving out the ones that exported nothing. This is the loading half of
9
+ * {@link getClassesInPath}; a plugin whose modules register themselves as a side effect of loading
10
+ * -- test files, say -- only needs this half.
11
+ *
12
+ * The path is relative to the tree's root (`game` in a place, the model's root in a plugin), which
13
+ * `resolveRbxPath` finds.
14
+ */
15
+ export declare function requireModulesInPath(rbxPath: readonly string[]): Array<defined>;
16
+ /**
17
+ * Requires every ModuleScript at and under the specified Rojo path and returns every exported value
18
+ * that carries its own Flamework identifier.
19
+ *
20
+ * A module that fails to load raises, as it did in v1: a class that silently fails to register
21
+ * would otherwise only show up later as an unresolvable dependency, far from the cause.
22
+ */
23
+ export declare function getClassesInPath(rbxPath: readonly string[]): Array<object>;
@@ -0,0 +1,91 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local tsImport = TS.import(script, script.Parent, "tsImport").tsImport
4
+ local Reflect = TS.import(script, script.Parent.Parent, "reflect").Reflect
5
+ local resolveRbxPath = TS.import(script, script.Parent, "pathRoot").resolveRbxPath
6
+ --[[
7
+ *
8
+ * Requires one ModuleScript through the roblox-ts runtime, as an `import` would, and returns what
9
+ * it exported. A module that fails to load raises with its full name and how long it took.
10
+
11
+ ]]
12
+ local function importModule(moduleScript)
13
+ local start = os.clock()
14
+ local success, value = pcall(function()
15
+ return tsImport(moduleScript)
16
+ end)
17
+ local endTime = math.floor((os.clock() - start) * 1000)
18
+ if not success then
19
+ error(`{moduleScript:GetFullName()} failed to load ({endTime}ms): {value}`, 0)
20
+ end
21
+ return value
22
+ end
23
+ --[[
24
+ *
25
+ * Requires every ModuleScript at and under the specified Rojo path, in tree order, and returns
26
+ * what each exported, leaving out the ones that exported nothing. This is the loading half of
27
+ * {@link getClassesInPath}; a plugin whose modules register themselves as a side effect of loading
28
+ * -- test files, say -- only needs this half.
29
+ *
30
+ * The path is relative to the tree's root (`game` in a place, the model's root in a plugin), which
31
+ * `resolveRbxPath` finds.
32
+
33
+ ]]
34
+ local function requireModulesInPath(rbxPath)
35
+ local _rbxPath = rbxPath
36
+ assert(_rbxPath)
37
+ local preloadPath = resolveRbxPath(rbxPath)
38
+ local loaded = {}
39
+ if preloadPath:IsA("ModuleScript") then
40
+ local value = importModule(preloadPath)
41
+ if value ~= nil then
42
+ table.insert(loaded, value)
43
+ end
44
+ end
45
+ for _, instance in preloadPath:GetDescendants() do
46
+ if instance:IsA("ModuleScript") then
47
+ local value = importModule(instance)
48
+ if value ~= nil then
49
+ table.insert(loaded, value)
50
+ end
51
+ end
52
+ end
53
+ return loaded
54
+ end
55
+ --[[
56
+ *
57
+ * Requires every ModuleScript at and under the specified Rojo path and returns every exported value
58
+ * that carries its own Flamework identifier.
59
+ *
60
+ * A module that fails to load raises, as it did in v1: a class that silently fails to register
61
+ * would otherwise only show up later as an unresolvable dependency, far from the cause.
62
+
63
+ ]]
64
+ local function getClassesInPath(rbxPath)
65
+ local foundClasses = {}
66
+ for _, value in requireModulesInPath(rbxPath) do
67
+ if not (type(value) == "table") then
68
+ continue
69
+ end
70
+ -- This is an `export =` on a Flamework class.
71
+ if Reflect.hasOwnMetadata(value, "identifier") then
72
+ table.insert(foundClasses, value)
73
+ continue
74
+ end
75
+ for _1, member in pairs(value) do
76
+ -- This is an `export` on a Flamework class.
77
+ --
78
+ -- Own metadata only: an undecorated subclass inherits its parent's identifier, and
79
+ -- must not be mistaken for a registered class of its own.
80
+ if type(member) == "table" and Reflect.hasOwnMetadata(member, "identifier") then
81
+ table.insert(foundClasses, member)
82
+ end
83
+ end
84
+ end
85
+ return foundClasses
86
+ end
87
+ return {
88
+ importModule = importModule,
89
+ requireModulesInPath = requireModulesInPath,
90
+ getClassesInPath = getClassesInPath,
91
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Returns the Rojo paths a compile-time glob resolved to.
3
+ */
4
+ export declare function getGlobPaths(glob: string): string[][];
5
+ /**
6
+ * Requires every ModuleScript under every path the glob matched and returns the exported classes,
7
+ * each at most once.
8
+ */
9
+ export declare function getClassesInGlob(glob: string): Array<object>;
@@ -0,0 +1,64 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local getClassesInPath = TS.import(script, script.Parent, "getClassesInPath").getClassesInPath
4
+ local findMetadataContainer = TS.import(script, script.Parent, "metadata").findMetadataContainer
5
+ --[[
6
+ *
7
+ * The shape of `include/flamework/globs.json`, which the transformer writes for game projects.
8
+ *
9
+ * Keys are the glob strings exactly as they appear in the emitted code (obfuscated when obfuscation
10
+ * is on); values are the Rojo paths that matched them at compile time.
11
+
12
+ ]]
13
+ local globContainer
14
+ --[[
15
+ *
16
+ * Returns the Rojo paths a compile-time glob resolved to.
17
+
18
+ ]]
19
+ local function getGlobPaths(glob)
20
+ if globContainer == nil then
21
+ local _condition = findMetadataContainer("globs")
22
+ if _condition == nil then
23
+ _condition = false
24
+ end
25
+ globContainer = _condition
26
+ end
27
+ local _result
28
+ if globContainer == false then
29
+ _result = nil
30
+ else
31
+ local _result_1 = globContainer.game
32
+ if _result_1 ~= nil then
33
+ local _glob = glob
34
+ _result_1 = _result_1[_glob]
35
+ end
36
+ _result = _result_1
37
+ end
38
+ local paths = _result
39
+ if paths == nil then
40
+ error(`Flamework has no paths for the glob '{glob}'. ` .. "Globs are resolved at compile time into include/flamework/globs.json, which only game projects emit; " .. "make sure the include directory is part of your Rojo project and that the glob matched at least one file.", 0)
41
+ end
42
+ return paths
43
+ end
44
+ --[[
45
+ *
46
+ * Requires every ModuleScript under every path the glob matched and returns the exported classes,
47
+ * each at most once.
48
+
49
+ ]]
50
+ local function getClassesInGlob(glob)
51
+ local classes = {}
52
+ for _, path in getGlobPaths(glob) do
53
+ for _1, found in getClassesInPath(path) do
54
+ if not (table.find(classes, found) ~= nil) then
55
+ table.insert(classes, found)
56
+ end
57
+ end
58
+ end
59
+ return classes
60
+ end
61
+ return {
62
+ getGlobPaths = getGlobPaths,
63
+ getClassesInGlob = getClassesInGlob,
64
+ }