@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,159 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local getRuntimeConfig = TS.import(script, script.Parent.Parent, "utility", "runtimeConfig").getRuntimeConfig
4
+ --[[
5
+ *
6
+ * When something is registered, in terms of the build's active scopes.
7
+ *
8
+ * A condition holds when `activeIn` is empty or names an active scope, and `inactiveIn` names
9
+ * none. Conditions combine by AND: a class is registered only when the module's condition, its
10
+ * registration's and its own all hold, so a class can narrow the module's condition and never
11
+ * widen it.
12
+
13
+ ]]
14
+ local configured
15
+ local override
16
+ local function getConfiguredScopes()
17
+ if override ~= nil then
18
+ return override
19
+ end
20
+ if configured == nil then
21
+ local _result = getRuntimeConfig().scopes
22
+ if _result ~= nil then
23
+ _result = _result.active
24
+ end
25
+ local _condition = _result
26
+ if _condition == nil then
27
+ _condition = {}
28
+ end
29
+ configured = _condition
30
+ end
31
+ return configured
32
+ end
33
+ --[[
34
+ *
35
+ * The scopes this build is compiled with, as written in `flamework.config.json` (usually from
36
+ * the environment). `"*"` in the list stands for every scope.
37
+
38
+ ]]
39
+ local function getActiveScopes()
40
+ return getConfiguredScopes()
41
+ end
42
+ --* Whether a scope is active in this build.
43
+ local function isScopeActive(scope)
44
+ local active = getConfiguredScopes()
45
+ local _condition = table.find(active, "*") ~= nil
46
+ if not _condition then
47
+ local _scope = scope
48
+ _condition = table.find(active, _scope) ~= nil
49
+ end
50
+ return _condition
51
+ end
52
+ --[[
53
+ *
54
+ * The condition of something that was not given one. Lists of conditions hold this rather than
55
+ * `undefined`: an array with a hole in it is not an array Luau can measure or walk.
56
+
57
+ ]]
58
+ local NO_CONDITION = {}
59
+ --* Whether a condition holds against the active scopes. No condition always holds.
60
+ local function holdsCondition(condition)
61
+ if condition == nil then
62
+ return true
63
+ end
64
+ local _condition = condition.inactiveIn ~= nil
65
+ if _condition then
66
+ local _exp = condition.inactiveIn
67
+ -- ▼ ReadonlyArray.some ▼
68
+ local _result = false
69
+ for _k, _v in _exp do
70
+ if isScopeActive(_v, _k - 1, _exp) then
71
+ _result = true
72
+ break
73
+ end
74
+ end
75
+ -- ▲ ReadonlyArray.some ▲
76
+ _condition = _result
77
+ end
78
+ if _condition then
79
+ return false
80
+ end
81
+ local _condition_1 = condition.activeIn ~= nil and #condition.activeIn > 0
82
+ if _condition_1 then
83
+ local _exp = condition.activeIn
84
+ -- ▼ ReadonlyArray.some ▼
85
+ local _result = false
86
+ for _k, _v in _exp do
87
+ if isScopeActive(_v, _k - 1, _exp) then
88
+ _result = true
89
+ break
90
+ end
91
+ end
92
+ -- ▲ ReadonlyArray.some ▲
93
+ _condition_1 = not _result
94
+ end
95
+ if _condition_1 then
96
+ return false
97
+ end
98
+ return true
99
+ end
100
+ --* Whether every condition holds.
101
+ local function holdsEveryCondition(conditions)
102
+ for _, condition in conditions do
103
+ if not holdsCondition(condition) then
104
+ return false
105
+ end
106
+ end
107
+ return true
108
+ end
109
+ --* Whether a condition asks for anything at all, so that a message can leave the empty ones out.
110
+ local function hasCondition(condition)
111
+ return condition ~= nil and ((condition.activeIn ~= nil and #condition.activeIn > 0) or (condition.inactiveIn ~= nil and #condition.inactiveIn > 0))
112
+ end
113
+ --[[
114
+ *
115
+ * Describes the conditions that applied to something, and the active set they were judged
116
+ * against, for an error message: `activeIn [a, b]; inactiveIn [c]; active scopes [a]`.
117
+
118
+ ]]
119
+ local function describeConditions(conditions)
120
+ local parts = {}
121
+ for _, condition in conditions do
122
+ if not hasCondition(condition) then
123
+ continue
124
+ end
125
+ if condition.activeIn ~= nil and #condition.activeIn > 0 then
126
+ local _arg0 = `activeIn [{table.concat(condition.activeIn, ", ")}]`
127
+ table.insert(parts, _arg0)
128
+ end
129
+ if condition.inactiveIn ~= nil and #condition.inactiveIn > 0 then
130
+ local _arg0 = `inactiveIn [{table.concat(condition.inactiveIn, ", ")}]`
131
+ table.insert(parts, _arg0)
132
+ end
133
+ end
134
+ local _arg0 = `active scopes [{table.concat(getConfiguredScopes(), ", ")}]`
135
+ table.insert(parts, _arg0)
136
+ return table.concat(parts, "; ")
137
+ end
138
+ --[[
139
+ *
140
+ * Replaces the active scopes for the rest of the run, or restores the configured ones with
141
+ * `undefined`. For the test harness, which has no `config.json`; a game's scopes are what it was
142
+ * compiled with.
143
+ *
144
+ * @internal
145
+
146
+ ]]
147
+ local function __setActiveScopes(scopes)
148
+ override = scopes
149
+ end
150
+ return {
151
+ getActiveScopes = getActiveScopes,
152
+ isScopeActive = isScopeActive,
153
+ holdsCondition = holdsCondition,
154
+ holdsEveryCondition = holdsEveryCondition,
155
+ hasCondition = hasCondition,
156
+ describeConditions = describeConditions,
157
+ __setActiveScopes = __setActiveScopes,
158
+ NO_CONDITION = NO_CONDITION,
159
+ }
@@ -0,0 +1,128 @@
1
+ import type { Modding } from "../modding";
2
+ import type { Module } from "../module/module";
3
+ import type { ProviderConfig, ProviderRegistrationOptions } from "../module/moduleDefinition";
4
+ import type { HookOptions } from "../module/moduleHooks";
5
+ import type { ScopeCondition } from "../module/scopes";
6
+ import type { Constructor } from "../utility/constructors";
7
+ export declare class PluginDefinition {
8
+ /** Names the plugin in error messages. */
9
+ readonly name: string;
10
+ constructor(
11
+ /** Names the plugin in error messages. */
12
+ name: string,
13
+ /** @internal */
14
+ setup: (target: PluginTarget) => void,
15
+ /**
16
+ * A slot at most one plugin fills per module. On the builder, including a plugin whose slot
17
+ * is taken replaces the plugin in it; at ignition, a second plugin for a filled slot is
18
+ * refused. Two lifecycle plugins would tick everything twice, which is what this prevents.
19
+ *
20
+ * @internal
21
+ */
22
+ slot?: string | undefined);
23
+ }
24
+ /**
25
+ * What a plugin's setup is handed: the module the plugin is being included in, and the ways a
26
+ * plugin can act on it. Everything here registers into that module.
27
+ *
28
+ * These are function-typed properties rather than methods, as on `Module`: roblox-ts tells the two
29
+ * apart, and the implementation is a table of closures with no `this`.
30
+ */
31
+ export interface PluginTarget {
32
+ /**
33
+ * The module being set up. It has not ignited, so nothing can be resolved from it yet; hold it
34
+ * for the hooks, which run once it can.
35
+ */
36
+ readonly module: Module;
37
+ /**
38
+ * The module's own scope condition, from `ignite`, when it has one. Everything the module
39
+ * registers is subject to it; {@link isActive} folds it in, so this is for messages.
40
+ */
41
+ readonly scope?: ScopeCondition;
42
+ /**
43
+ * Whether something with these conditions is registered in this module: the module's own
44
+ * condition and every one given must hold. A plugin that keeps a registry of its own -- the
45
+ * components plugin, say -- asks this for each class, so that its classes are scoped the way the
46
+ * module's providers are.
47
+ */
48
+ isActive: (...conditions: ScopeCondition[]) => boolean;
49
+ /**
50
+ * Registers a class provider in the module, constructed with dependency injection during
51
+ * ignition like any provider the module registered itself.
52
+ */
53
+ registerClassProvider: (provider: Constructor, options?: ProviderRegistrationOptions) => void;
54
+ /**
55
+ * Registers every exported `@Provider()` class under a source folder, as the module builder's
56
+ * `registerProviders` does. This is how a plugin ships a folder of providers. The options apply
57
+ * to every class found.
58
+ *
59
+ * @metadata macro
60
+ */
61
+ registerProviders: <T extends string>(path: T, options?: ProviderRegistrationOptions, resolved?: Modding.Intrinsic<"path", [T], string[]>) => void;
62
+ /**
63
+ * Registers every exported `@Provider()` class under every folder a compile-time glob matches.
64
+ *
65
+ * @metadata macro
66
+ */
67
+ registerProvidersGlob: <T extends string>(glob: T, options?: ProviderRegistrationOptions, resolved?: Modding.Intrinsic<"pathglob", [T], string>) => void;
68
+ /**
69
+ * Registers a class, function or alias provider in the module.
70
+ *
71
+ * @metadata macro
72
+ */
73
+ registerProvider: <T>(config: ProviderConfig, id?: string | Modding.Target.Id<T>) => void;
74
+ /**
75
+ * Provides a ready-made object under its type's id, so that the module's providers can inject it
76
+ * and `resolveDependency` finds it. This is how a plugin hands the module the thing it built.
77
+ *
78
+ * The object joins the interfaces it implements once every plugin has been set up, and leaves
79
+ * them when the module extinguishes, like a provider the module constructed.
80
+ *
81
+ * @metadata macro
82
+ */
83
+ provideInstance: <T extends object>(instance: T, id?: string | Modding.Target.Id<T>) => void;
84
+ /**
85
+ * Includes another plugin in the module, set up now, before this one continues. A plugin reached
86
+ * more than once in one ignition -- included by the module and by a plugin, or by two plugins --
87
+ * is set up once. With a scope condition that does not hold, the inclusion is skipped.
88
+ */
89
+ includePlugin: (plugin: PluginDefinition, options?: ScopeCondition) => void;
90
+ /**
91
+ * Runs before the module's providers are constructed. Nothing can be resolved yet; this is where
92
+ * a plugin registers state that providers will look at while being constructed.
93
+ */
94
+ onPreIgnite: (callback: (module: Module) => void, options?: HookOptions) => void;
95
+ /** Runs after every provider has been constructed. */
96
+ onPostIgnite: (callback: (module: Module) => void, options?: HookOptions) => void;
97
+ /** Runs when the module extinguishes, before its providers are released. */
98
+ onExtinguished: (callback: (module: Module) => void, options?: HookOptions) => void;
99
+ /**
100
+ * Observes every object in the module that implements `T`: providers as they are constructed,
101
+ * and anything attached through `createClassInstance` or `listen`. Matching is structural, from
102
+ * the `implements` clause the transformer recorded, so the class needs a Flamework decorator.
103
+ *
104
+ * @metadata macro
105
+ */
106
+ observe: <T>(config: InterfaceConfiguration<T>, id?: string | Modding.Target.Id<T>) => void;
107
+ }
108
+ export interface InterfaceConfiguration<T> {
109
+ /** Invoked when an object implementing the interface is constructed or attached. */
110
+ onAdded?: (value: T, context: InterfaceContext) => void;
111
+ /** Invoked when an object implementing the interface is released, or its module extinguishes. */
112
+ onRemoved?: (value: T, context: InterfaceContext) => void;
113
+ }
114
+ /**
115
+ * What kind of object an observer is being told about.
116
+ *
117
+ * - `provider`: a provider the module constructed, during ignition or lazily, or one a plugin
118
+ * provided.
119
+ * - `instance`: an object attached through `createClassInstance` or `listen`, which is owned by
120
+ * whoever created it (for example, a component owned by `Components`).
121
+ */
122
+ export type InterfaceTargetKind = "provider" | "instance";
123
+ export interface InterfaceContext {
124
+ /** The id of the interface being observed. */
125
+ interfaceId: string;
126
+ /** Whether the object is a provider of the module, or an instance attached to it. */
127
+ kind: InterfaceTargetKind;
128
+ }
@@ -0,0 +1,61 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ --[[
3
+ *
4
+ * A plugin: a name, and a setup function run once per ignition of every module that includes it.
5
+ *
6
+ * The setup is handed the module being ignited, before any of its providers exist, and registers
7
+ * whatever the plugin adds to it -- providers, hooks, observers, other plugins. State the setup
8
+ * creates belongs to that one ignition: a plugin included by two modules, or by one definition
9
+ * ignited twice, is set up separately for each and shares nothing between them unless it closes
10
+ * over module-level state on purpose.
11
+
12
+ ]]
13
+ --[[
14
+ *
15
+ * The slot the lifecycle plugin fills: every module starts with one, and a module never runs two.
16
+ *
17
+ * @internal
18
+
19
+ ]]
20
+ local LIFECYCLE_SLOT = "lifecycle"
21
+ local PluginDefinition
22
+ do
23
+ PluginDefinition = setmetatable({}, {
24
+ __tostring = function()
25
+ return "PluginDefinition"
26
+ end,
27
+ })
28
+ PluginDefinition.__index = PluginDefinition
29
+ function PluginDefinition.new(...)
30
+ local self = setmetatable({}, PluginDefinition)
31
+ return self:constructor(...) or self
32
+ end
33
+ function PluginDefinition:constructor(name, setup, slot)
34
+ self.name = name
35
+ self.setup = setup
36
+ self.slot = slot
37
+ end
38
+ end
39
+ --[[
40
+ *
41
+ * What a plugin's setup is handed: the module the plugin is being included in, and the ways a
42
+ * plugin can act on it. Everything here registers into that module.
43
+ *
44
+ * These are function-typed properties rather than methods, as on `Module`: roblox-ts tells the two
45
+ * apart, and the implementation is a table of closures with no `this`.
46
+
47
+ ]]
48
+ --[[
49
+ *
50
+ * What kind of object an observer is being told about.
51
+ *
52
+ * - `provider`: a provider the module constructed, during ignition or lazily, or one a plugin
53
+ * provided.
54
+ * - `instance`: an object attached through `createClassInstance` or `listen`, which is owned by
55
+ * whoever created it (for example, a component owned by `Components`).
56
+
57
+ ]]
58
+ return {
59
+ LIFECYCLE_SLOT = LIFECYCLE_SLOT,
60
+ PluginDefinition = PluginDefinition,
61
+ }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Re-exports `t` so that generated guards can import it through `@flamework-experimental/core/out/prelude`.
3
+ *
4
+ * The transformer does this when the consuming project resolves a different `@rbxts/t` than core
5
+ * does, so that guards always run against the version core was built and tested with.
6
+ */
7
+ import { t } from "@rbxts/t";
8
+ export { t };
@@ -0,0 +1,14 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ --[[
4
+ *
5
+ * Re-exports `t` so that generated guards can import it through `@flamework-experimental/core/out/prelude`.
6
+ *
7
+ * The transformer does this when the consuming project resolves a different `@rbxts/t` than core
8
+ * does, so that guards always run against the version core was built and tested with.
9
+
10
+ ]]
11
+ local t = TS.import(script, TS.getModule(script, "@rbxts", "t").lib.ts).t
12
+ return {
13
+ t = t,
14
+ }
@@ -0,0 +1,27 @@
1
+ import type { ScopeCondition } from "./module/scopes";
2
+ export interface ProviderDecoratorConfig extends ScopeCondition {
3
+ /**
4
+ * A lazy provider is not constructed during ignition. It is constructed the first time something
5
+ * resolves it -- a constructor parameter, `resolveDependency`, or `createClassInstance` -- and is
6
+ * otherwise never created.
7
+ *
8
+ * This is the v2 equivalent of v1's `@Optional()`. A lazy provider first resolved after ignition
9
+ * still receives `onInit` and `onStart` from the lifecycle plugin, at the moment it is constructed.
10
+ *
11
+ * Defaults to `false`.
12
+ */
13
+ lazy?: boolean;
14
+ }
15
+ /**
16
+ * Register a class as a provider.
17
+ *
18
+ * Unlike Flamework v1's `@Service` and `@Controller`, a provider is not bound to a realm. Which
19
+ * providers exist on which realm is decided by the module that registers them, so this metadata
20
+ * must be defined on both the client and the server.
21
+ *
22
+ * `activeIn` and `inactiveIn` scope the class: it is registered only when they hold against the
23
+ * build's active scopes, on top of whatever condition the module and the registration set.
24
+ *
25
+ * @metadata reflect identifier flamework:dependencies flamework:implements flamework:parameters injectable
26
+ */
27
+ export declare function Provider(config?: ProviderDecoratorConfig): (constructor: object) => void;
@@ -0,0 +1,26 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local Reflect = TS.import(script, script.Parent, "reflect").Reflect
4
+ --[[
5
+ *
6
+ * Register a class as a provider.
7
+ *
8
+ * Unlike Flamework v1's `@Service` and `@Controller`, a provider is not bound to a realm. Which
9
+ * providers exist on which realm is decided by the module that registers them, so this metadata
10
+ * must be defined on both the client and the server.
11
+ *
12
+ * `activeIn` and `inactiveIn` scope the class: it is registered only when they hold against the
13
+ * build's active scopes, on top of whatever condition the module and the registration set.
14
+ *
15
+ * @metadata reflect identifier flamework:dependencies flamework:implements flamework:parameters injectable
16
+
17
+ ]]
18
+ local function Provider(config)
19
+ return function(constructor)
20
+ Reflect.defineMetadata(constructor, "flamework:provider", true)
21
+ Reflect.defineMetadata(constructor, "flamework:providerConfig", config or {})
22
+ end
23
+ end
24
+ return {
25
+ Provider = Provider,
26
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Reflection/metadata API
3
+ */
4
+ export declare namespace Reflect {
5
+ /**
6
+ * Apply metadata onto this object.
7
+ */
8
+ function defineMetadata(obj: object, key: string, value: unknown, property?: string): void;
9
+ /**
10
+ * Apply metadata in batch onto this object.
11
+ */
12
+ function defineMetadataBatch(obj: object, list: {
13
+ [key: string]: unknown;
14
+ }, property?: string): void;
15
+ /**
16
+ * Delete metadata from this object.
17
+ */
18
+ function deleteMetadata(obj: object, key: string, property?: string): void;
19
+ /**
20
+ * Get metadata from this object.
21
+ * Type parameter is an assertion.
22
+ */
23
+ function getOwnMetadata<T>(obj: object, key: string, property?: string): T | undefined;
24
+ /**
25
+ * Check if this object has the specified metadata key.
26
+ */
27
+ function hasOwnMetadata(obj: object, key: string, property?: string): boolean;
28
+ /**
29
+ * Retrieve all metadata keys for this object.
30
+ */
31
+ function getOwnMetadataKeys(obj: object, property?: string): string[];
32
+ /**
33
+ * Retrieves all properties (that contain metadata) on this object.
34
+ */
35
+ function getOwnProperties(obj: object): string[];
36
+ /**
37
+ * Retrieve all values for the specified key from the object and its parents.
38
+ * Type parameter is an assertion.
39
+ */
40
+ function getMetadatas<T extends defined>(obj: object, key: string, property?: string): T[];
41
+ /**
42
+ * Get metadata from this object or its parents.
43
+ * Type parameter is an assertion.
44
+ */
45
+ function getMetadata<T>(obj: object, key: string, property?: string): T | undefined;
46
+ /**
47
+ * Check if this object or any of its parents has the specified metadata key.
48
+ */
49
+ function hasMetadata(obj: object, key: string, property?: string): boolean;
50
+ /**
51
+ * Retrieve all metadata keys for this object and its parents.
52
+ */
53
+ function getMetadataKeys(obj: object, property?: string): string[];
54
+ /**
55
+ * Retrieves all properties (that contain metadata) on this object and its parents.
56
+ */
57
+ function getProperties(obj: object): string[];
58
+ /** @hidden Internal use, do not use */
59
+ function resetObject(object: object): void;
60
+ }