@quenty/tie 10.6.0 → 10.7.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/CHANGELOG.md +19 -0
- package/README.md +4 -0
- package/package.json +16 -15
- package/src/Shared/Members/Methods/TieMethodDefinition.lua +44 -0
- package/src/Shared/{Implementation → Members/Methods}/TieMethodImplementation.lua +4 -5
- package/src/Shared/Members/Methods/TieMethodInterfaceUtils.lua +58 -0
- package/src/Shared/{Interface → Members/Properties}/TiePropertyChangedSignalConnection.lua +1 -1
- package/src/Shared/Members/Properties/TiePropertyDefinition.lua +58 -0
- package/src/Shared/{Interface → Members/Properties}/TiePropertyInterface.lua +42 -59
- package/src/Shared/Members/Signals/TieSignalConnection.lua +63 -0
- package/src/Shared/Members/Signals/TieSignalDefinition.lua +38 -0
- package/src/Shared/{Implementation → Members/Signals}/TieSignalImplementation.lua +29 -15
- package/src/Shared/Members/Signals/TieSignalInterface.lua +90 -0
- package/src/Shared/Members/TieMemberDefinition.lua +104 -0
- package/src/Shared/Members/TieMemberInterface.lua +94 -0
- package/src/Shared/Realms/TieRealmUtils.lua +41 -0
- package/src/Shared/{Definition/Types → Realms}/TieRealms.lua +3 -4
- package/src/Shared/Services/TieRealmService.lua +31 -0
- package/src/Shared/TieDefinition.lua +708 -0
- package/src/Shared/TieImplementation.lua +167 -0
- package/src/Shared/TieInterface.lua +129 -0
- package/src/Shared/{Encoding → Utils}/TieUtils.lua +4 -1
- package/test/modules/Server/Action/Action.lua +4 -7
- package/test/modules/Server/Door.lua +5 -10
- package/test/scripts/Server/ServerMain.server.lua +3 -3
- package/src/Shared/Definition/TieDefinition.lua +0 -507
- package/src/Shared/Definition/TieMethodDefinition.lua +0 -61
- package/src/Shared/Definition/TiePropertyDefinition.lua +0 -64
- package/src/Shared/Definition/TieSignalDefinition.lua +0 -59
- package/src/Shared/Definition/Types/TieRealmUtils.lua +0 -60
- package/src/Shared/Implementation/TieImplementation.lua +0 -129
- package/src/Shared/Interface/TieInterface.lua +0 -122
- package/src/Shared/Interface/TieInterfaceUtils.lua +0 -70
- package/src/Shared/Interface/TieMethodInterfaceUtils.lua +0 -43
- package/src/Shared/Interface/TieSignalConnection.lua +0 -89
- package/src/Shared/Interface/TieSignalInterface.lua +0 -61
- /package/src/Shared/{Implementation → Members/Properties}/TiePropertyImplementation.lua +0 -0
- /package/src/Shared/{Implementation → Members/Properties}/TiePropertyImplementationUtils.lua +0 -0
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
This class represents the implementation for a given definition. For the lifetime
|
|
3
|
+
of the class, this implementation will be exposed to consumption by both someone
|
|
4
|
+
using the tie interface, and anyone invoking its methods via the normal Roblox API.
|
|
5
|
+
|
|
6
|
+
@class TieImplementation
|
|
7
|
+
]=]
|
|
8
|
+
|
|
9
|
+
local require = require(script.Parent.loader).load(script)
|
|
10
|
+
|
|
11
|
+
local BaseObject = require("BaseObject")
|
|
12
|
+
local TieRealmUtils = require("TieRealmUtils")
|
|
13
|
+
local TieRealms = require("TieRealms")
|
|
14
|
+
local String = require("String")
|
|
15
|
+
|
|
16
|
+
local TieImplementation = setmetatable({}, BaseObject)
|
|
17
|
+
TieImplementation.ClassName = "TieImplementation"
|
|
18
|
+
TieImplementation.__index = TieImplementation
|
|
19
|
+
|
|
20
|
+
function TieImplementation.new(tieDefinition, adornee, implementer, implementationTieRealm)
|
|
21
|
+
assert(TieRealmUtils.isTieRealm(implementationTieRealm), "Bad implementationTieRealm")
|
|
22
|
+
|
|
23
|
+
local self = setmetatable(BaseObject.new(), TieImplementation)
|
|
24
|
+
|
|
25
|
+
self._tieDefinition = assert(tieDefinition, "No definition")
|
|
26
|
+
self._adornee = assert(adornee, "No adornee")
|
|
27
|
+
self._actualSelf = implementer or {}
|
|
28
|
+
self._implementationTieRealm = assert(implementationTieRealm, "Bad implementationTieRealm")
|
|
29
|
+
|
|
30
|
+
self._implParent = self._maid:Add(Instance.new(tieDefinition:GetImplClass()))
|
|
31
|
+
self._implParent.Archivable = false
|
|
32
|
+
|
|
33
|
+
self._memberImplementations = {}
|
|
34
|
+
self._memberMap = self._tieDefinition:GetMemberMap()
|
|
35
|
+
|
|
36
|
+
self:_buildMemberImplementations(implementer)
|
|
37
|
+
|
|
38
|
+
self._implParent.Parent = self._adornee
|
|
39
|
+
|
|
40
|
+
return self
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
function TieImplementation:GetImplementationTieRealm()
|
|
44
|
+
return self._implementationTieRealm
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
function TieImplementation:GetImplParent()
|
|
48
|
+
return self._implParent
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
function TieImplementation:__index(index)
|
|
52
|
+
if TieImplementation[index] then
|
|
53
|
+
return TieImplementation[index]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
if index == "_implParent"
|
|
57
|
+
or index == "_adornee"
|
|
58
|
+
or index == "_tieDefinition"
|
|
59
|
+
or index == "_memberImplementations"
|
|
60
|
+
or index == "_implementationTieRealm"
|
|
61
|
+
or index == "_memberMap"
|
|
62
|
+
or index == "_actualSelf" then
|
|
63
|
+
|
|
64
|
+
return rawget(self, index)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
local memberMap = rawget(self, "_memberMap")
|
|
68
|
+
local memberDefinition = memberMap[index]
|
|
69
|
+
local implementationTieRealm = rawget(self, "_implementationTieRealm")
|
|
70
|
+
|
|
71
|
+
if memberDefinition then
|
|
72
|
+
if memberDefinition:IsAllowedForImplementation(self._implementationTieRealm) then
|
|
73
|
+
return memberDefinition:GetInterface(self._implParent, self, implementationTieRealm)
|
|
74
|
+
else
|
|
75
|
+
error(string.format("[TieImplementation] - %q is not available on %s", memberDefinition:GetFriendlyName(), self._implementationTieRealm))
|
|
76
|
+
end
|
|
77
|
+
else
|
|
78
|
+
error(string.format("Bad index %q for TieImplementation", tostring(index)))
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
function TieImplementation:__newindex(index, value)
|
|
83
|
+
if index == "_implParent"
|
|
84
|
+
or index == "_adornee"
|
|
85
|
+
or index == "_tieDefinition"
|
|
86
|
+
or index == "_memberImplementations"
|
|
87
|
+
or index == "_implementationTieRealm"
|
|
88
|
+
or index == "_memberMap"
|
|
89
|
+
or index == "_actualSelf" then
|
|
90
|
+
|
|
91
|
+
rawset(self, index, value)
|
|
92
|
+
elseif self._memberImplementations[index] then
|
|
93
|
+
self._memberImplementations[index]:SetImplementation(value, self._actualSelf)
|
|
94
|
+
elseif TieImplementation[index] then
|
|
95
|
+
error(string.format("Cannot set %q in TieImplementation", tostring(index)))
|
|
96
|
+
else
|
|
97
|
+
error(string.format("Bad index %q for TieImplementation", tostring(index)))
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
function TieImplementation:_buildMemberImplementations(implementer)
|
|
102
|
+
for _, memberDefinition in pairs(self._memberMap) do
|
|
103
|
+
local memberName = memberDefinition:GetMemberName()
|
|
104
|
+
local found = nil
|
|
105
|
+
|
|
106
|
+
if implementer then
|
|
107
|
+
found = implementer[memberName]
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if memberDefinition:IsRequiredForImplementation(self._implementationTieRealm) then
|
|
111
|
+
if not found then
|
|
112
|
+
error(self:_getErrorMessageRequiredMember(memberDefinition))
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
if found then
|
|
117
|
+
if not memberDefinition:IsAllowedForImplementation(self._implementationTieRealm) then
|
|
118
|
+
error(self:_getErrorMessageForNotAllowedMember(memberDefinition))
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
local memberImplementation = self._maid:Add(memberDefinition:Implement(self._implParent, found, self._actualSelf, self._implementationTieRealm))
|
|
123
|
+
self._memberImplementations[memberDefinition:GetMemberName()] = memberImplementation
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
self._implParent.Name = self._tieDefinition:GetNewContainerName(self._implementationTieRealm)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
function TieImplementation:_getErrorMessageForNotAllowedMember(memberDefinition)
|
|
130
|
+
local errorMessage = string.format("[TieImplementation] - Member implements %s only member %s (we are a %s implementation)",
|
|
131
|
+
memberDefinition:GetMemberTieRealm(),
|
|
132
|
+
memberDefinition:GetFriendlyName(),
|
|
133
|
+
self._implementationTieRealm)
|
|
134
|
+
|
|
135
|
+
if self._implementationTieRealm == TieRealms.SHARED then
|
|
136
|
+
if memberDefinition:GetMemberTieRealm() ~= TieRealms.SHARED then
|
|
137
|
+
errorMessage = string.format("%s\n\tHINT: This is declared as a %s implementation. %s is only allowed on %s.",
|
|
138
|
+
errorMessage,
|
|
139
|
+
self._implementationTieRealm,
|
|
140
|
+
memberDefinition:GetFriendlyName(),
|
|
141
|
+
memberDefinition:GetMemberTieRealm())
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
return errorMessage
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
function TieImplementation:_getErrorMessageRequiredMember(memberDefinition)
|
|
149
|
+
local errorMessage = string.format("[TieImplementation] - Missing %s member %s (we are a %s implementation)",
|
|
150
|
+
memberDefinition:GetMemberTieRealm(),
|
|
151
|
+
memberDefinition:GetFriendlyName(),
|
|
152
|
+
self._implementationTieRealm)
|
|
153
|
+
|
|
154
|
+
if self._implementationTieRealm == TieRealms.SHARED then
|
|
155
|
+
if memberDefinition:GetMemberTieRealm() ~= TieRealms.SHARED then
|
|
156
|
+
errorMessage = string.format("%s\n\tHINT: This is declared as a %s implementation. Shared implements require both client and server components. You could also specify the implementation realm by writing %sInterface.%s:Implement(...)",
|
|
157
|
+
errorMessage,
|
|
158
|
+
self._implementationTieRealm,
|
|
159
|
+
self._tieDefinition:GetName(),
|
|
160
|
+
String.uppercaseFirstLetter(memberDefinition:GetMemberTieRealm()))
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
return errorMessage
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
return TieImplementation
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
--[=[
|
|
2
|
+
Tie interfaces can be retrieved from an implementation and allow access to a specific call into the interface
|
|
3
|
+
|
|
4
|
+
@class TieInterface
|
|
5
|
+
]=]
|
|
6
|
+
|
|
7
|
+
local require = require(script.Parent.loader).load(script)
|
|
8
|
+
|
|
9
|
+
local TieSignalInterface = require("TieSignalInterface")
|
|
10
|
+
local TiePropertyInterface = require("TiePropertyInterface")
|
|
11
|
+
local TieMethodInterfaceUtils = require("TieMethodInterfaceUtils")
|
|
12
|
+
|
|
13
|
+
local TieInterface = {}
|
|
14
|
+
TieInterface.ClassName = "TieInterface"
|
|
15
|
+
TieInterface.__index = TieInterface
|
|
16
|
+
|
|
17
|
+
function TieInterface.new(definition, implParent, adornee, interfaceTieRealm)
|
|
18
|
+
local self = setmetatable({}, TieInterface)
|
|
19
|
+
|
|
20
|
+
assert(implParent or adornee, "ImplParent or adornee required")
|
|
21
|
+
|
|
22
|
+
self._definition = assert(definition, "No definition")
|
|
23
|
+
self._interfaceTieRealm = assert(interfaceTieRealm, "No interfaceTieRealm")
|
|
24
|
+
self._implParent = implParent -- could be nil
|
|
25
|
+
self._adornee = adornee -- could be nil
|
|
26
|
+
self._memberDefinitionMap = self._definition:GetMemberMap()
|
|
27
|
+
|
|
28
|
+
return self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
--[=[
|
|
32
|
+
Returns whether this version of the definition is implemented to standard or not.
|
|
33
|
+
|
|
34
|
+
@return boolean
|
|
35
|
+
]=]
|
|
36
|
+
function TieInterface:IsImplemented()
|
|
37
|
+
local implParent = rawget(self, "_implParent")
|
|
38
|
+
local adornee = rawget(self, "_adornee")
|
|
39
|
+
local definition = rawget(self, "_definition")
|
|
40
|
+
local interfaceTieRealm = rawget(self, "_interfaceTieRealm")
|
|
41
|
+
|
|
42
|
+
if implParent then
|
|
43
|
+
if adornee then
|
|
44
|
+
if implParent.Parent ~= adornee then
|
|
45
|
+
return false
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
if definition:GetValidContainerNameSet(interfaceTieRealm)[implParent.Name] then
|
|
49
|
+
return false
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
return definition:IsImplementation(implParent, interfaceTieRealm)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
return definition:HasImplementation(adornee, interfaceTieRealm)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
--[=[
|
|
60
|
+
Gets the adornee the tie interface is on if it can be found.
|
|
61
|
+
|
|
62
|
+
@return Instance | nil
|
|
63
|
+
]=]
|
|
64
|
+
function TieInterface:GetTieAdornee()
|
|
65
|
+
local adornee = rawget(self, "_adornee")
|
|
66
|
+
if adornee then
|
|
67
|
+
return adornee
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
local implParent = rawget(self, "_implParent")
|
|
71
|
+
if implParent then
|
|
72
|
+
return implParent.Parent
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
return nil
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
--[=[
|
|
79
|
+
Observes if the interface is implemented
|
|
80
|
+
|
|
81
|
+
@return Observable<boolean>
|
|
82
|
+
]=]
|
|
83
|
+
function TieInterface:ObserveIsImplemented()
|
|
84
|
+
local implParent = rawget(self, "_implParent")
|
|
85
|
+
local adornee = rawget(self, "_adornee")
|
|
86
|
+
local definition = rawget(self, "_definition")
|
|
87
|
+
local interfaceTieRealm = rawget(self, "_interfaceTieRealm")
|
|
88
|
+
|
|
89
|
+
if implParent then
|
|
90
|
+
if adornee then
|
|
91
|
+
return definition:ObserveIsImplementationOn(implParent, adornee, interfaceTieRealm)
|
|
92
|
+
else
|
|
93
|
+
return definition:ObserveIsImplementation(implParent, interfaceTieRealm)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
return definition:ObserveIsImplemented(adornee, interfaceTieRealm)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
function TieInterface:__index(index)
|
|
101
|
+
local interfaceTieRealm = rawget(self, "_interfaceTieRealm")
|
|
102
|
+
|
|
103
|
+
local member = rawget(self, "_memberDefinitionMap")[index]
|
|
104
|
+
local definition = rawget(self, "_definition")
|
|
105
|
+
local adornee = rawget(self, "_adornee")
|
|
106
|
+
local implParent = rawget(self, "_implParent")
|
|
107
|
+
|
|
108
|
+
if member then
|
|
109
|
+
if member:IsAllowedOnInterface(interfaceTieRealm) then
|
|
110
|
+
if member.ClassName == "TieMethodDefinition" then
|
|
111
|
+
return TieMethodInterfaceUtils.get(self, member, implParent, adornee, interfaceTieRealm)
|
|
112
|
+
elseif member.ClassName == "TieSignalDefinition" then
|
|
113
|
+
return TieSignalInterface.new(implParent, adornee, member, interfaceTieRealm)
|
|
114
|
+
elseif member.ClassName == "TiePropertyDefinition" then
|
|
115
|
+
return TiePropertyInterface.new(implParent, adornee, member, interfaceTieRealm)
|
|
116
|
+
else
|
|
117
|
+
error(string.format("Unknown member definition %q", tostring(member.ClassName)))
|
|
118
|
+
end
|
|
119
|
+
else
|
|
120
|
+
error(string.format("[TieInterface] - %s is not allowed in realm '%s'. Specify realm to %s.", member:GetFriendlyName(), interfaceTieRealm, member:GetMemberTieRealm()))
|
|
121
|
+
end
|
|
122
|
+
elseif TieInterface[index] then
|
|
123
|
+
return TieInterface[index]
|
|
124
|
+
else
|
|
125
|
+
error(string.format("[TieInterface] - Bad %q is not a member of %s", tostring(index), definition:GetName()))
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
return TieInterface
|
|
@@ -14,7 +14,10 @@ function TieUtils.encode(...)
|
|
|
14
14
|
local results = table.pack(...)
|
|
15
15
|
|
|
16
16
|
for i=1, results.n do
|
|
17
|
-
if type(results[i]) == "table"
|
|
17
|
+
if type(results[i]) == "table"
|
|
18
|
+
or type(results[i]) == "function"
|
|
19
|
+
or typeof(results[i]) == "userdata" then -- newproxy() symbols
|
|
20
|
+
|
|
18
21
|
local saved = results[i]
|
|
19
22
|
results[i] = function()
|
|
20
23
|
return saved -- Pack into a callback so we can transfer data.
|
|
@@ -15,18 +15,15 @@ Action.__index = Action
|
|
|
15
15
|
function Action.new(obj)
|
|
16
16
|
local self = setmetatable(BaseObject.new(obj), Action)
|
|
17
17
|
|
|
18
|
-
self.Activated = Signal.new()
|
|
19
|
-
self._maid:GiveTask(self.Activated)
|
|
18
|
+
self.Activated = self._maid:Add(Signal.new())
|
|
20
19
|
|
|
21
|
-
self.DisplayName = Instance.new("StringValue")
|
|
20
|
+
self.DisplayName = self._maid:Add(Instance.new("StringValue"))
|
|
22
21
|
self.DisplayName.Value = "Action"
|
|
23
|
-
self._maid:GiveTask(self.DisplayName)
|
|
24
22
|
|
|
25
|
-
self.IsEnabled = Instance.new("BoolValue")
|
|
23
|
+
self.IsEnabled = self._maid:Add(Instance.new("BoolValue"))
|
|
26
24
|
self.IsEnabled.Value = false
|
|
27
|
-
self._maid:GiveTask(self.IsEnabled)
|
|
28
25
|
|
|
29
|
-
self._maid:GiveTask(ActionInterface:Implement(self._obj, self))
|
|
26
|
+
self._maid:GiveTask(ActionInterface.Server:Implement(self._obj, self))
|
|
30
27
|
|
|
31
28
|
return self
|
|
32
29
|
end
|
|
@@ -17,20 +17,15 @@ Door.__index = Door
|
|
|
17
17
|
function Door.new(obj)
|
|
18
18
|
local self = setmetatable(BaseObject.new(obj), Door)
|
|
19
19
|
|
|
20
|
-
self.Opening = Signal.new()
|
|
21
|
-
self._maid:
|
|
20
|
+
self.Opening = self._maid:Add(Signal.new())
|
|
21
|
+
self.Closing = self._maid:Add(Signal.new())
|
|
22
22
|
|
|
23
|
-
self.
|
|
24
|
-
self._maid:GiveTask(self.Closing)
|
|
25
|
-
|
|
26
|
-
self.IsOpen = Instance.new("BoolValue")
|
|
23
|
+
self.IsOpen = self._maid:Add(Instance.new("BoolValue"))
|
|
27
24
|
self.IsOpen.Value = false
|
|
28
|
-
self._maid:GiveTask(self.IsOpen)
|
|
29
25
|
|
|
30
|
-
self.LastPromise = ValueObject.new()
|
|
31
|
-
self._maid:GiveTask(self.LastPromise)
|
|
26
|
+
self.LastPromise = self._maid:Add(ValueObject.new())
|
|
32
27
|
|
|
33
|
-
self._maid:GiveTask(OpenableInterface:Implement(self._obj, self))
|
|
28
|
+
self._maid:GiveTask(OpenableInterface.Server:Implement(self._obj, self))
|
|
34
29
|
|
|
35
30
|
return self
|
|
36
31
|
end
|
|
@@ -25,7 +25,7 @@ if DO_DOOR_WINDOW_TEST then
|
|
|
25
25
|
window.Parent = workspace
|
|
26
26
|
Window.new(window)
|
|
27
27
|
|
|
28
|
-
local doorInterface = OpenableInterface:
|
|
28
|
+
local doorInterface = OpenableInterface:Find(door)
|
|
29
29
|
doorInterface.Opening:Connect(function()
|
|
30
30
|
print("Opening event fired")
|
|
31
31
|
end)
|
|
@@ -47,7 +47,7 @@ if DO_DOOR_WINDOW_TEST then
|
|
|
47
47
|
doorInterface:PromiseClose()
|
|
48
48
|
|
|
49
49
|
print("door:IsImplemented()", doorInterface:IsImplemented())
|
|
50
|
-
print("door:IsImplemented()", OpenableInterface:
|
|
50
|
+
print("door:IsImplemented()", OpenableInterface:Find(workspace) ~= nil)
|
|
51
51
|
|
|
52
52
|
door.Openable.PromiseOpen:Invoke()():Then(function()
|
|
53
53
|
print("Opened promise resolved")
|
|
@@ -73,7 +73,7 @@ do
|
|
|
73
73
|
|
|
74
74
|
-- Implement via interface calls
|
|
75
75
|
do
|
|
76
|
-
local thrust = ActionInterface:Implement(adornee)
|
|
76
|
+
local thrust = ActionInterface.Server:Implement(adornee)
|
|
77
77
|
-- thrust:GetFolder().Name = "Action_Thrust"
|
|
78
78
|
thrust.DisplayName.Value = "Thrust"
|
|
79
79
|
|