@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.
Files changed (38) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +4 -0
  3. package/package.json +16 -15
  4. package/src/Shared/Members/Methods/TieMethodDefinition.lua +44 -0
  5. package/src/Shared/{Implementation → Members/Methods}/TieMethodImplementation.lua +4 -5
  6. package/src/Shared/Members/Methods/TieMethodInterfaceUtils.lua +58 -0
  7. package/src/Shared/{Interface → Members/Properties}/TiePropertyChangedSignalConnection.lua +1 -1
  8. package/src/Shared/Members/Properties/TiePropertyDefinition.lua +58 -0
  9. package/src/Shared/{Interface → Members/Properties}/TiePropertyInterface.lua +42 -59
  10. package/src/Shared/Members/Signals/TieSignalConnection.lua +63 -0
  11. package/src/Shared/Members/Signals/TieSignalDefinition.lua +38 -0
  12. package/src/Shared/{Implementation → Members/Signals}/TieSignalImplementation.lua +29 -15
  13. package/src/Shared/Members/Signals/TieSignalInterface.lua +90 -0
  14. package/src/Shared/Members/TieMemberDefinition.lua +104 -0
  15. package/src/Shared/Members/TieMemberInterface.lua +94 -0
  16. package/src/Shared/Realms/TieRealmUtils.lua +41 -0
  17. package/src/Shared/{Definition/Types → Realms}/TieRealms.lua +3 -4
  18. package/src/Shared/Services/TieRealmService.lua +31 -0
  19. package/src/Shared/TieDefinition.lua +708 -0
  20. package/src/Shared/TieImplementation.lua +167 -0
  21. package/src/Shared/TieInterface.lua +129 -0
  22. package/src/Shared/{Encoding → Utils}/TieUtils.lua +4 -1
  23. package/test/modules/Server/Action/Action.lua +4 -7
  24. package/test/modules/Server/Door.lua +5 -10
  25. package/test/scripts/Server/ServerMain.server.lua +3 -3
  26. package/src/Shared/Definition/TieDefinition.lua +0 -507
  27. package/src/Shared/Definition/TieMethodDefinition.lua +0 -61
  28. package/src/Shared/Definition/TiePropertyDefinition.lua +0 -64
  29. package/src/Shared/Definition/TieSignalDefinition.lua +0 -59
  30. package/src/Shared/Definition/Types/TieRealmUtils.lua +0 -60
  31. package/src/Shared/Implementation/TieImplementation.lua +0 -129
  32. package/src/Shared/Interface/TieInterface.lua +0 -122
  33. package/src/Shared/Interface/TieInterfaceUtils.lua +0 -70
  34. package/src/Shared/Interface/TieMethodInterfaceUtils.lua +0 -43
  35. package/src/Shared/Interface/TieSignalConnection.lua +0 -89
  36. package/src/Shared/Interface/TieSignalInterface.lua +0 -61
  37. /package/src/Shared/{Implementation → Members/Properties}/TiePropertyImplementation.lua +0 -0
  38. /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" or type(results[i]) == "function" then
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:GiveTask(self.Opening)
20
+ self.Opening = self._maid:Add(Signal.new())
21
+ self.Closing = self._maid:Add(Signal.new())
22
22
 
23
- self.Closing = Signal.new()
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:Get(door)
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:Get(workspace):IsImplemented())
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