@rbxts/prototype 0.0.1
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/out/index.d.ts +3 -0
- package/out/init.lua +13 -0
- package/out/prototype-ref.d.ts +4 -0
- package/out/prototype-ref.lua +25 -0
- package/out/prototype.d.ts +65 -0
- package/out/prototype.lua +438 -0
- package/out/types.d.ts +23 -0
- package/package.json +43 -0
package/out/index.d.ts
ADDED
package/out/init.lua
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v2.3.0-dev-d7847ea
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local exports = {}
|
|
4
|
+
for _k, _v in TS.import(script, script, "prototype-ref") or {} do
|
|
5
|
+
exports[_k] = _v
|
|
6
|
+
end
|
|
7
|
+
for _k, _v in TS.import(script, script, "prototype") or {} do
|
|
8
|
+
exports[_k] = _v
|
|
9
|
+
end
|
|
10
|
+
for _k, _v in TS.import(script, script, "types") or {} do
|
|
11
|
+
exports[_k] = _v
|
|
12
|
+
end
|
|
13
|
+
return exports
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { PrototypeHandler } from "./prototype";
|
|
2
|
+
export declare const PROTOTYPE_REF_SYMBOL = "$PrototypeRef";
|
|
3
|
+
export declare function IsPrototypeRef(value: unknown): value is string;
|
|
4
|
+
export declare function GetPrototypeFromRef(value: string, prototypeManager: PrototypeHandler): import("./types").IPrototype | undefined;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v2.3.0-dev-d7847ea
|
|
2
|
+
local PROTOTYPE_REF_SYMBOL = "$PrototypeRef"
|
|
3
|
+
local function IsPrototypeRef(value)
|
|
4
|
+
local _value = value
|
|
5
|
+
local _condition = type(_value) == "string"
|
|
6
|
+
if _condition then
|
|
7
|
+
_condition = string.split(value, ":")[1] == PROTOTYPE_REF_SYMBOL
|
|
8
|
+
end
|
|
9
|
+
return _condition
|
|
10
|
+
end
|
|
11
|
+
local function GetPrototypeFromRef(value, prototypeManager)
|
|
12
|
+
local id = string.split(value, ":")[2]
|
|
13
|
+
local _binding = prototypeManager:TryIndexWithoutKind(id)
|
|
14
|
+
local success = _binding[1]
|
|
15
|
+
local prototype = _binding[2]
|
|
16
|
+
if not success then
|
|
17
|
+
return nil
|
|
18
|
+
end
|
|
19
|
+
return prototype
|
|
20
|
+
end
|
|
21
|
+
return {
|
|
22
|
+
IsPrototypeRef = IsPrototypeRef,
|
|
23
|
+
GetPrototypeFromRef = GetPrototypeFromRef,
|
|
24
|
+
PROTOTYPE_REF_SYMBOL = PROTOTYPE_REF_SYMBOL,
|
|
25
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/// <reference types="@rbxts/compiler-types" />
|
|
2
|
+
/// <reference types="@rbxts/compiler-types" />
|
|
3
|
+
/// <reference types="@rbxts/compiler-types" />
|
|
4
|
+
/// <reference types="@rbxts/compiler-types" />
|
|
5
|
+
/// <reference types="@rbxts/types" />
|
|
6
|
+
/// <reference types="@rbxts/types" />
|
|
7
|
+
import { Modding } from "@flamework/core";
|
|
8
|
+
import { Constructor } from "@flamework/core/out/utility";
|
|
9
|
+
import { DataFieldOptions, InheritanceBehaviorCallback, IPrototype, PrototypeOptions } from "./types";
|
|
10
|
+
type GetFieldMetadata<T> = {
|
|
11
|
+
Name: Modding.Generic<T, "text">;
|
|
12
|
+
Guard: T extends IPrototype ? Modding.Generic<IPrototype, "guard"> : Modding.Generic<ConvertClassToObject<T>, "guard">;
|
|
13
|
+
};
|
|
14
|
+
type GetFieldsMetadata<T> = ExcludeMembers<Required<{
|
|
15
|
+
[K in keyof T]: GetFieldMetadata<ConvertClassToObject<T[K]>>;
|
|
16
|
+
}>, never>;
|
|
17
|
+
type ConvertClassToObject<T> = T extends IPrototype ? IPrototype : T extends Map<any, any> | Set<any> | any[] | Promise<any> | Instance | Omit<CheckableTypes, keyof CheckablePrimitives> ? T : T extends object ? {
|
|
18
|
+
[K in keyof T]: ConvertClassToObject<T[K]>;
|
|
19
|
+
} : T;
|
|
20
|
+
interface PrototypeMetadata<T extends IPrototype = IPrototype> {
|
|
21
|
+
Properties: GetFieldsMetadata<T>;
|
|
22
|
+
}
|
|
23
|
+
/** @metadata macro reflect identifier flamework:implements */
|
|
24
|
+
export declare function Prototype<T extends IPrototype>(options?: PrototypeOptions, metadata?: Modding.Many<PrototypeMetadata<T>>): (target: Constructor<T>) => void;
|
|
25
|
+
/** @metadata reflect identifier */
|
|
26
|
+
export declare function DataField<T extends IPrototype, P extends keyof T>(options?: DataFieldOptions<T[P]>): (target: T, propertyName: P) => void;
|
|
27
|
+
export declare function InheritanceBehavior<T extends IPrototype, P extends keyof T>(callback: InheritanceBehaviorCallback<T[P]>): (target: T, propertyName: P) => void;
|
|
28
|
+
export declare class PrototypeKindData {
|
|
29
|
+
private ctor;
|
|
30
|
+
private kindName;
|
|
31
|
+
private handler;
|
|
32
|
+
readonly Instances: Map<string, {
|
|
33
|
+
Instance?: IPrototype | undefined;
|
|
34
|
+
IsCompiled: boolean;
|
|
35
|
+
IsResolvedInheritance: boolean;
|
|
36
|
+
SourceInstance: IPrototype;
|
|
37
|
+
}>;
|
|
38
|
+
private fields;
|
|
39
|
+
constructor(ctor: Constructor<IPrototype>, kindName: string, handler: PrototypeHandler);
|
|
40
|
+
ResolveProperty(fieldMetadata: GetFieldMetadata<unknown>, fieldName: string, value: unknown, instance: IPrototype): unknown;
|
|
41
|
+
ResolveInheritance(id: string): void;
|
|
42
|
+
private resolveAllPrototypeRefs;
|
|
43
|
+
private getSourceProperty;
|
|
44
|
+
Compile(id: string): void;
|
|
45
|
+
GetSource(id: string): IPrototype;
|
|
46
|
+
Get(id: string): IPrototype | undefined;
|
|
47
|
+
Register(instance: object): void;
|
|
48
|
+
}
|
|
49
|
+
/** @metadata reflect identifier */
|
|
50
|
+
export declare class PrototypeHandler {
|
|
51
|
+
private prototypes;
|
|
52
|
+
private allRegisteredPrototypes;
|
|
53
|
+
constructor();
|
|
54
|
+
private collectDescendants;
|
|
55
|
+
private registerKing;
|
|
56
|
+
GetSourcePrototype(id: string): IPrototype | undefined;
|
|
57
|
+
GetKind(id: string): PrototypeKindData | undefined;
|
|
58
|
+
TryIndexWithoutKind(prototypeId: string): [success: false] | [success: true, prototype: IPrototype];
|
|
59
|
+
/** @metadata macro */
|
|
60
|
+
TryIndex<T extends IPrototype>(prototypeId: string, kindName?: Modding.Generic<T, "text"> | string): [success: false] | [success: true, prototype: T];
|
|
61
|
+
TryIndex(prototypeId: string, kindName: string): [success: false] | [success: true, prototype: IPrototype];
|
|
62
|
+
Compile(): void;
|
|
63
|
+
RegisterPrototype(prototype: IPrototype, kindName: string): void;
|
|
64
|
+
}
|
|
65
|
+
export {};
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v2.3.0-dev-d7847ea
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
-- eslint-disable @typescript-eslint/no-explicit-any
|
|
4
|
+
local t = TS.import(script, TS.getModule(script, "@rbxts", "t").lib.ts).t
|
|
5
|
+
local _core = TS.import(script, TS.getModule(script, "@flamework", "core").out)
|
|
6
|
+
local Flamework = _core.Flamework
|
|
7
|
+
local Reflect = _core.Reflect
|
|
8
|
+
local _prototype_ref = TS.import(script, script.Parent, "prototype-ref")
|
|
9
|
+
local GetPrototypeFromRef = _prototype_ref.GetPrototypeFromRef
|
|
10
|
+
local IsPrototypeRef = _prototype_ref.IsPrototypeRef
|
|
11
|
+
local InheritingPrototypeValidator = Flamework.createGuard(t.interface({
|
|
12
|
+
Parents = t.array(t.string),
|
|
13
|
+
}))
|
|
14
|
+
--* @metadata macro reflect identifier flamework:implements
|
|
15
|
+
local PrototypeHandler
|
|
16
|
+
local function Prototype(options, metadata)
|
|
17
|
+
if options == nil then
|
|
18
|
+
options = {}
|
|
19
|
+
end
|
|
20
|
+
return function(target)
|
|
21
|
+
if not metadata then
|
|
22
|
+
error("No metadata provided")
|
|
23
|
+
end
|
|
24
|
+
local kinds = Reflect.getMetadata(PrototypeHandler, "Prototype:Kinds") or {}
|
|
25
|
+
local _target = target
|
|
26
|
+
table.insert(kinds, _target)
|
|
27
|
+
Reflect.defineMetadata(PrototypeHandler, "Prototype:Kinds", kinds)
|
|
28
|
+
Reflect.defineMetadata(target, "Prototype:Options", options)
|
|
29
|
+
Reflect.defineMetadata(target, "Prototype:Metadata", metadata)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
--* @metadata reflect identifier
|
|
33
|
+
local function DataField(options)
|
|
34
|
+
if options == nil then
|
|
35
|
+
options = {}
|
|
36
|
+
end
|
|
37
|
+
return function(target, propertyName)
|
|
38
|
+
local dataFields = Reflect.getMetadata(target, "Prototype:DataFields") or {}
|
|
39
|
+
local _propertyName = propertyName
|
|
40
|
+
table.insert(dataFields, _propertyName)
|
|
41
|
+
Reflect.defineMetadata(target, "Prototype:DataFields", dataFields)
|
|
42
|
+
local propertyTags = Reflect.getMetadata(target, "Prototype:PropertyTags") or {}
|
|
43
|
+
local usedTags = Reflect.getMetadata(target, "Prototype:UsedPropertyTags") or {}
|
|
44
|
+
Reflect.defineMetadata(target, "Prototype:PropertyTags", propertyTags)
|
|
45
|
+
Reflect.defineMetadata(target, "Prototype:UsedPropertyTags", usedTags)
|
|
46
|
+
Reflect.defineMetadata(target, "Prototype:DataFieldBehavior", options.Behavior, propertyName)
|
|
47
|
+
local _condition = options.Tag ~= nil
|
|
48
|
+
if _condition then
|
|
49
|
+
local _tag = options.Tag
|
|
50
|
+
_condition = usedTags[_tag] ~= nil
|
|
51
|
+
end
|
|
52
|
+
if _condition then
|
|
53
|
+
error(`Duplicate field detected: {options.Tag}, for class: {target}`)
|
|
54
|
+
end
|
|
55
|
+
local _exp = propertyName
|
|
56
|
+
local _condition_1 = options.Tag
|
|
57
|
+
if _condition_1 == nil then
|
|
58
|
+
_condition_1 = propertyName
|
|
59
|
+
end
|
|
60
|
+
propertyTags[_exp] = _condition_1
|
|
61
|
+
if options.Tag ~= nil then
|
|
62
|
+
local _tag = options.Tag
|
|
63
|
+
usedTags[_tag] = true
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
local function InheritanceBehavior(callback)
|
|
68
|
+
return function(target, propertyName)
|
|
69
|
+
Reflect.defineMetadata(target, "Prototype:InheritanceBehavior", callback, propertyName)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
local prototypeValidator = Flamework.createGuard(t.interface({
|
|
73
|
+
Id = t.string,
|
|
74
|
+
}))
|
|
75
|
+
local PrototypeKindData
|
|
76
|
+
do
|
|
77
|
+
PrototypeKindData = setmetatable({}, {
|
|
78
|
+
__tostring = function()
|
|
79
|
+
return "PrototypeKindData"
|
|
80
|
+
end,
|
|
81
|
+
})
|
|
82
|
+
PrototypeKindData.__index = PrototypeKindData
|
|
83
|
+
function PrototypeKindData.new(...)
|
|
84
|
+
local self = setmetatable({}, PrototypeKindData)
|
|
85
|
+
return self:constructor(...) or self
|
|
86
|
+
end
|
|
87
|
+
function PrototypeKindData:constructor(ctor, kindName, handler)
|
|
88
|
+
self.ctor = ctor
|
|
89
|
+
self.kindName = kindName
|
|
90
|
+
self.handler = handler
|
|
91
|
+
self.Instances = {}
|
|
92
|
+
self.fields = {}
|
|
93
|
+
local metadata = Reflect.getMetadata(ctor, "Prototype:Metadata")
|
|
94
|
+
local dataFields = Reflect.getMetadata(ctor, "Prototype:DataFields") or {}
|
|
95
|
+
if not (table.find(dataFields, "Id") ~= nil) then
|
|
96
|
+
table.insert(dataFields, "Id")
|
|
97
|
+
end
|
|
98
|
+
for _, fieldNameOriginal in dataFields do
|
|
99
|
+
local fieldMetadata = metadata.Properties[fieldNameOriginal]
|
|
100
|
+
self.fields[fieldNameOriginal] = fieldMetadata
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
function PrototypeKindData:ResolveProperty(fieldMetadata, fieldName, value, instance)
|
|
104
|
+
if fieldMetadata.Guard == nil then
|
|
105
|
+
error(`No guard found for field: {fieldName}, prototypeKing: {self.kindName}, prototype: {instance.Id}`)
|
|
106
|
+
end
|
|
107
|
+
if not fieldMetadata.Guard(value) then
|
|
108
|
+
error(`Invalid value for field: {fieldName}, prototypeKing: {self.kindName}, prototype: {instance.Id}. Expected: {fieldMetadata.Name}, got: {value}`)
|
|
109
|
+
end
|
|
110
|
+
return value
|
|
111
|
+
end
|
|
112
|
+
function PrototypeKindData:ResolveInheritance(id)
|
|
113
|
+
if not Flamework._implements(self.ctor, "@rbxts/prototype:types@IInheritingPrototype") then
|
|
114
|
+
return nil
|
|
115
|
+
end
|
|
116
|
+
local _instances = self.Instances
|
|
117
|
+
local _id = id
|
|
118
|
+
local instanceData = _instances[_id]
|
|
119
|
+
if not instanceData then
|
|
120
|
+
error(`Prototype with id: {id} does not exist`)
|
|
121
|
+
end
|
|
122
|
+
if instanceData.IsResolvedInheritance then
|
|
123
|
+
return nil
|
|
124
|
+
end
|
|
125
|
+
if not InheritingPrototypeValidator(instanceData.SourceInstance) or #instanceData.SourceInstance.Parents == 0 then
|
|
126
|
+
instanceData.IsResolvedInheritance = true
|
|
127
|
+
return nil
|
|
128
|
+
end
|
|
129
|
+
local clonedInstance = table.clone(instanceData.SourceInstance)
|
|
130
|
+
for _, parentId in instanceData.SourceInstance.Parents do
|
|
131
|
+
local parentInstance = self.handler:GetSourcePrototype(parentId)
|
|
132
|
+
if parentInstance == nil then
|
|
133
|
+
error(`Parent prototype with id: {parentId} does not exist. PrototypeKing: {self.kindName}, prototypeId: {id}`)
|
|
134
|
+
end
|
|
135
|
+
for field, metadata in self.fields do
|
|
136
|
+
local parentFieldName = self:getSourceProperty(self.handler:GetKind(parentId).ctor, field)
|
|
137
|
+
local parentKind = self.handler:GetKind(parentId)
|
|
138
|
+
local fieldName = self:getSourceProperty(self.ctor, field)
|
|
139
|
+
local parentValue = parentInstance[parentFieldName]
|
|
140
|
+
local _parentValueType = parentKind
|
|
141
|
+
if _parentValueType ~= nil then
|
|
142
|
+
_parentValueType = _parentValueType.fields[parentFieldName]
|
|
143
|
+
end
|
|
144
|
+
local parentValueType = _parentValueType
|
|
145
|
+
if parentValueType == nil then
|
|
146
|
+
continue
|
|
147
|
+
end
|
|
148
|
+
if parentValueType.Name ~= metadata.Name then
|
|
149
|
+
error(`Parent prototype with id: {parentId} types do not match. PrototypeKing: {self.kindName}, prototypeId: {id}`)
|
|
150
|
+
end
|
|
151
|
+
if clonedInstance[fieldName] == nil then
|
|
152
|
+
clonedInstance[fieldName] = parentValue
|
|
153
|
+
continue
|
|
154
|
+
end
|
|
155
|
+
local inheritanceBehavior = Reflect.getOwnMetadata(self.ctor, "Prototype:InheritanceBehavior", field)
|
|
156
|
+
if inheritanceBehavior == nil then
|
|
157
|
+
continue
|
|
158
|
+
end
|
|
159
|
+
clonedInstance[fieldName] = inheritanceBehavior(clonedInstance[fieldName], parentValue)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
instanceData.IsResolvedInheritance = true
|
|
163
|
+
instanceData.SourceInstance = clonedInstance
|
|
164
|
+
end
|
|
165
|
+
function PrototypeKindData:resolveAllPrototypeRefs(id)
|
|
166
|
+
local _instances = self.Instances
|
|
167
|
+
local _id = id
|
|
168
|
+
local instanceData = _instances[_id]
|
|
169
|
+
if not instanceData then
|
|
170
|
+
return nil
|
|
171
|
+
end
|
|
172
|
+
local recursiveResolve
|
|
173
|
+
recursiveResolve = function(value)
|
|
174
|
+
local _value = value
|
|
175
|
+
if type(_value) == "table" then
|
|
176
|
+
for key, val in pairs(value) do
|
|
177
|
+
local resolved = recursiveResolve(val)
|
|
178
|
+
if resolved then
|
|
179
|
+
value[key] = resolved
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
return nil
|
|
183
|
+
end
|
|
184
|
+
if IsPrototypeRef(value) then
|
|
185
|
+
return GetPrototypeFromRef(value, self.handler)
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
for fieldName, fieldMetadata in self.fields do
|
|
189
|
+
local fieldNameOriginal = self:getSourceProperty(self.ctor, fieldName)
|
|
190
|
+
local value = instanceData.SourceInstance[fieldNameOriginal]
|
|
191
|
+
local resolved = recursiveResolve(value)
|
|
192
|
+
if resolved then
|
|
193
|
+
instanceData.SourceInstance[fieldNameOriginal] = resolved
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
function PrototypeKindData:getSourceProperty(kindCtor, fieldName)
|
|
198
|
+
local propertyTags = Reflect.getMetadata(kindCtor, "Prototype:PropertyTags") or {}
|
|
199
|
+
local _fieldName = fieldName
|
|
200
|
+
local _condition = propertyTags[_fieldName]
|
|
201
|
+
if _condition == nil then
|
|
202
|
+
_condition = fieldName
|
|
203
|
+
end
|
|
204
|
+
return _condition
|
|
205
|
+
end
|
|
206
|
+
function PrototypeKindData:Compile(id)
|
|
207
|
+
local _instances = self.Instances
|
|
208
|
+
local _id = id
|
|
209
|
+
local instanceData = _instances[_id]
|
|
210
|
+
if not instanceData then
|
|
211
|
+
error(`Prototype with id: {id} does not exist`)
|
|
212
|
+
end
|
|
213
|
+
if instanceData.IsCompiled then
|
|
214
|
+
return nil
|
|
215
|
+
end
|
|
216
|
+
if instanceData.Instance == nil then
|
|
217
|
+
error(`Prototype with id: {id} is not pre-compiled`)
|
|
218
|
+
end
|
|
219
|
+
self:resolveAllPrototypeRefs(id)
|
|
220
|
+
self:ResolveInheritance(id)
|
|
221
|
+
for field, fieldMetadata in self.fields do
|
|
222
|
+
local fieldName = self:getSourceProperty(self.ctor, field)
|
|
223
|
+
local value = instanceData.SourceInstance[fieldName]
|
|
224
|
+
instanceData.SourceInstance[fieldName] = self:ResolveProperty(fieldMetadata, field, value, instanceData.SourceInstance)
|
|
225
|
+
local behavior = Reflect.getOwnMetadata(self.ctor, "Prototype:DataFieldBehavior", field)
|
|
226
|
+
if behavior then
|
|
227
|
+
instanceData.SourceInstance[fieldName] = behavior(instanceData.SourceInstance[fieldName], self, self.handler)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
local _instances_1 = self.Instances
|
|
231
|
+
local _id_1 = id
|
|
232
|
+
local sourceInstance = _instances_1[_id_1].SourceInstance
|
|
233
|
+
for fieldName in self.fields do
|
|
234
|
+
local sourceInstancePropertyName = self:getSourceProperty(self.ctor, fieldName)
|
|
235
|
+
instanceData.Instance[fieldName] = sourceInstance[sourceInstancePropertyName]
|
|
236
|
+
end
|
|
237
|
+
instanceData.IsCompiled = true
|
|
238
|
+
end
|
|
239
|
+
function PrototypeKindData:GetSource(id)
|
|
240
|
+
local _instances = self.Instances
|
|
241
|
+
local _id = id
|
|
242
|
+
local instanceData = _instances[_id]
|
|
243
|
+
if not instanceData then
|
|
244
|
+
error(`Prototype with id: {id} does not exist`)
|
|
245
|
+
end
|
|
246
|
+
return instanceData.SourceInstance
|
|
247
|
+
end
|
|
248
|
+
function PrototypeKindData:Get(id)
|
|
249
|
+
local _instances = self.Instances
|
|
250
|
+
local _id = id
|
|
251
|
+
local instanceData = _instances[_id]
|
|
252
|
+
if not instanceData then
|
|
253
|
+
error(`Prototype with id: {id} does not exist`)
|
|
254
|
+
end
|
|
255
|
+
return instanceData.Instance
|
|
256
|
+
end
|
|
257
|
+
function PrototypeKindData:Register(instance)
|
|
258
|
+
if not prototypeValidator(instance) then
|
|
259
|
+
error(`Invalid prototype`)
|
|
260
|
+
end
|
|
261
|
+
local _instances = self.Instances
|
|
262
|
+
local _id = instance.Id
|
|
263
|
+
if _instances[_id] ~= nil then
|
|
264
|
+
error(`Prototype with id: {instance.Id} already exists`)
|
|
265
|
+
end
|
|
266
|
+
local newInstance = self.ctor.new()
|
|
267
|
+
newInstance.Id = instance.Id
|
|
268
|
+
local _instances_1 = self.Instances
|
|
269
|
+
local _id_1 = instance.Id
|
|
270
|
+
local _arg1 = {
|
|
271
|
+
SourceInstance = instance,
|
|
272
|
+
Instance = newInstance,
|
|
273
|
+
IsCompiled = false,
|
|
274
|
+
IsResolvedInheritance = false,
|
|
275
|
+
}
|
|
276
|
+
_instances_1[_id_1] = _arg1
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
--* @metadata reflect identifier
|
|
280
|
+
do
|
|
281
|
+
PrototypeHandler = setmetatable({}, {
|
|
282
|
+
__tostring = function()
|
|
283
|
+
return "PrototypeHandler"
|
|
284
|
+
end,
|
|
285
|
+
})
|
|
286
|
+
PrototypeHandler.__index = PrototypeHandler
|
|
287
|
+
function PrototypeHandler.new(...)
|
|
288
|
+
local self = setmetatable({}, PrototypeHandler)
|
|
289
|
+
return self:constructor(...) or self
|
|
290
|
+
end
|
|
291
|
+
function PrototypeHandler:constructor()
|
|
292
|
+
self.prototypes = {}
|
|
293
|
+
self.allRegisteredPrototypes = {}
|
|
294
|
+
local kinds = Reflect.getOwnMetadata(PrototypeHandler, "Prototype:Kinds") or {}
|
|
295
|
+
for _, kind in kinds do
|
|
296
|
+
self:registerKing(kind)
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
function PrototypeHandler:collectDescendants(id, ids)
|
|
300
|
+
if ids == nil then
|
|
301
|
+
ids = {}
|
|
302
|
+
end
|
|
303
|
+
local _allRegisteredPrototypes = self.allRegisteredPrototypes
|
|
304
|
+
local _id = id
|
|
305
|
+
local protoData = _allRegisteredPrototypes[_id]
|
|
306
|
+
if not protoData then
|
|
307
|
+
return nil
|
|
308
|
+
end
|
|
309
|
+
local _instances = protoData.Instances
|
|
310
|
+
local _id_1 = id
|
|
311
|
+
local data = _instances[_id_1]
|
|
312
|
+
local instance = data.SourceInstance
|
|
313
|
+
local _condition = not InheritingPrototypeValidator(instance)
|
|
314
|
+
if not _condition then
|
|
315
|
+
local _ids = ids
|
|
316
|
+
local _id_2 = instance.Id
|
|
317
|
+
_condition = table.find(_ids, _id_2) ~= nil
|
|
318
|
+
if not _condition then
|
|
319
|
+
_condition = data.IsCompiled
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
if _condition then
|
|
323
|
+
return nil
|
|
324
|
+
end
|
|
325
|
+
for _, parent in instance.Parents do
|
|
326
|
+
self:collectDescendants(parent, ids)
|
|
327
|
+
end
|
|
328
|
+
local _ids = ids
|
|
329
|
+
local _id_2 = instance.Id
|
|
330
|
+
table.insert(_ids, _id_2)
|
|
331
|
+
return ids
|
|
332
|
+
end
|
|
333
|
+
function PrototypeHandler:registerKing(kind)
|
|
334
|
+
local kindName = `{kind}`
|
|
335
|
+
if self.prototypes[kindName] ~= nil then
|
|
336
|
+
error(`Prototype with id: {kindName} already exists`)
|
|
337
|
+
end
|
|
338
|
+
local kindData = PrototypeKindData.new(kind, kindName, self)
|
|
339
|
+
self.prototypes[kindName] = kindData
|
|
340
|
+
end
|
|
341
|
+
function PrototypeHandler:GetSourcePrototype(id)
|
|
342
|
+
local _allRegisteredPrototypes = self.allRegisteredPrototypes
|
|
343
|
+
local _id = id
|
|
344
|
+
local kind = _allRegisteredPrototypes[_id]
|
|
345
|
+
local _result = kind
|
|
346
|
+
if _result ~= nil then
|
|
347
|
+
_result = _result:GetSource(id)
|
|
348
|
+
end
|
|
349
|
+
return _result
|
|
350
|
+
end
|
|
351
|
+
function PrototypeHandler:GetKind(id)
|
|
352
|
+
local _allRegisteredPrototypes = self.allRegisteredPrototypes
|
|
353
|
+
local _id = id
|
|
354
|
+
local kind = _allRegisteredPrototypes[_id]
|
|
355
|
+
return kind
|
|
356
|
+
end
|
|
357
|
+
function PrototypeHandler:TryIndexWithoutKind(prototypeId)
|
|
358
|
+
local _allRegisteredPrototypes = self.allRegisteredPrototypes
|
|
359
|
+
local _prototypeId = prototypeId
|
|
360
|
+
if not (_allRegisteredPrototypes[_prototypeId] ~= nil) then
|
|
361
|
+
return { false }
|
|
362
|
+
end
|
|
363
|
+
local _allRegisteredPrototypes_1 = self.allRegisteredPrototypes
|
|
364
|
+
local _prototypeId_1 = prototypeId
|
|
365
|
+
local instance = _allRegisteredPrototypes_1[_prototypeId_1]:Get(prototypeId)
|
|
366
|
+
if not instance then
|
|
367
|
+
return { false }
|
|
368
|
+
end
|
|
369
|
+
return { true, instance }
|
|
370
|
+
end
|
|
371
|
+
function PrototypeHandler:TryIndex(prototypeId, kindName)
|
|
372
|
+
local _prototypes = self.prototypes
|
|
373
|
+
local _kindName = kindName
|
|
374
|
+
local kind = _prototypes[_kindName]
|
|
375
|
+
if not kind then
|
|
376
|
+
return { false }
|
|
377
|
+
end
|
|
378
|
+
local _instances = kind.Instances
|
|
379
|
+
local _prototypeId = prototypeId
|
|
380
|
+
local _condition = not (_instances[_prototypeId] ~= nil)
|
|
381
|
+
if not _condition then
|
|
382
|
+
local _instances_1 = kind.Instances
|
|
383
|
+
local _prototypeId_1 = prototypeId
|
|
384
|
+
_condition = not _instances_1[_prototypeId_1].Instance
|
|
385
|
+
end
|
|
386
|
+
if _condition then
|
|
387
|
+
return { false }
|
|
388
|
+
end
|
|
389
|
+
local _instances_1 = kind.Instances
|
|
390
|
+
local _prototypeId_1 = prototypeId
|
|
391
|
+
return { true, _instances_1[_prototypeId_1].Instance }
|
|
392
|
+
end
|
|
393
|
+
function PrototypeHandler:Compile()
|
|
394
|
+
local ids = {}
|
|
395
|
+
for id, Kind in self.allRegisteredPrototypes do
|
|
396
|
+
if Kind.Instances[id].IsCompiled then
|
|
397
|
+
continue
|
|
398
|
+
end
|
|
399
|
+
local source = Kind.Instances[id].SourceInstance
|
|
400
|
+
if not InheritingPrototypeValidator(source) or #source.Parents == 0 then
|
|
401
|
+
table.insert(ids, id)
|
|
402
|
+
continue
|
|
403
|
+
end
|
|
404
|
+
self:collectDescendants(id, ids)
|
|
405
|
+
end
|
|
406
|
+
for _, id in ids do
|
|
407
|
+
self.allRegisteredPrototypes[id]:Compile(id)
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
function PrototypeHandler:RegisterPrototype(prototype, kindName)
|
|
411
|
+
local _prototypes = self.prototypes
|
|
412
|
+
local _kindName = kindName
|
|
413
|
+
local kind = _prototypes[_kindName]
|
|
414
|
+
if not kind then
|
|
415
|
+
error(`Prototype with kind key: {kindName} does not exist`)
|
|
416
|
+
end
|
|
417
|
+
local _allRegisteredPrototypes = self.allRegisteredPrototypes
|
|
418
|
+
local _id = prototype.Id
|
|
419
|
+
if _allRegisteredPrototypes[_id] ~= nil then
|
|
420
|
+
error(`Prototype with id: {prototype.Id} already exists`)
|
|
421
|
+
end
|
|
422
|
+
kind:Register(prototype)
|
|
423
|
+
local _allRegisteredPrototypes_1 = self.allRegisteredPrototypes
|
|
424
|
+
local _id_1 = prototype.Id
|
|
425
|
+
_allRegisteredPrototypes_1[_id_1] = kind
|
|
426
|
+
end
|
|
427
|
+
do
|
|
428
|
+
-- (Flamework) PrototypeHandler metadata
|
|
429
|
+
Reflect.defineMetadata(PrototypeHandler, "identifier", "@rbxts/prototype:prototype@PrototypeHandler")
|
|
430
|
+
end
|
|
431
|
+
end
|
|
432
|
+
return {
|
|
433
|
+
Prototype = Prototype,
|
|
434
|
+
DataField = DataField,
|
|
435
|
+
InheritanceBehavior = InheritanceBehavior,
|
|
436
|
+
PrototypeKindData = PrototypeKindData,
|
|
437
|
+
PrototypeHandler = PrototypeHandler,
|
|
438
|
+
}
|
package/out/types.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { PrototypeKindData, PrototypeHandler } from "./prototype";
|
|
2
|
+
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
+
export interface IPrototype {
|
|
5
|
+
Id: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface IInheritingPrototype {
|
|
9
|
+
Parents?: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PrototypeOptions {
|
|
13
|
+
Name?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export type InheritanceBehaviorCallback<T> = (current: T, parent: T) => T;
|
|
17
|
+
|
|
18
|
+
export type DataFieldBehavior<T> = (data: T, kindData: PrototypeKindData, handler: PrototypeHandler) => T;
|
|
19
|
+
|
|
20
|
+
export interface DataFieldOptions<T> {
|
|
21
|
+
Tag?: string;
|
|
22
|
+
Behavior?: DataFieldBehavior<T>;
|
|
23
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rbxts/prototype",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "out/init.lua",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "rbxtsc",
|
|
8
|
+
"watch": "rbxtsc -w",
|
|
9
|
+
"test:watch": "rbxtsc -w --type=game -p test -i test/include",
|
|
10
|
+
"serve": "rojo serve test/default.project.json",
|
|
11
|
+
"prepublishOnly": "npm run build"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [],
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"types": "out/index.d.ts",
|
|
17
|
+
"files": [
|
|
18
|
+
"out",
|
|
19
|
+
"!**/*.tsbuildinfo",
|
|
20
|
+
"!**/*.spec.lua"
|
|
21
|
+
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@rbxts/compiler-types": "^2.3.0-types.1",
|
|
27
|
+
"@rbxts/types": "^1.0.780",
|
|
28
|
+
"@typescript-eslint/eslint-plugin": "^6.19.0",
|
|
29
|
+
"@typescript-eslint/parser": "^6.19.0",
|
|
30
|
+
"eslint": "^8.56.0",
|
|
31
|
+
"eslint-config-prettier": "^9.1.0",
|
|
32
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
33
|
+
"eslint-plugin-roblox-ts": "^0.0.36",
|
|
34
|
+
"prettier": "^3.2.4",
|
|
35
|
+
"rbxts-transformer-flamework": "^1.3.1",
|
|
36
|
+
"roblox-ts": "^2.3.0-dev-d7847ea",
|
|
37
|
+
"typescript": "^5.4.5"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@flamework/core": "^1.3.1",
|
|
41
|
+
"@rbxts/testez": "^0.4.2-ts.0"
|
|
42
|
+
}
|
|
43
|
+
}
|