mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 05:51:39 +00:00
Add live syncback functionality and optimize service encoding
- Introduced a new endpoint `/api/syncback` for one-click full sync from Roblox Studio to the filesystem, eliminating the need for an active WebSocket connection. - Implemented `SyncbackRequest` and `ServiceChunk` structures to handle service-level properties and child instances during syncback. - Enhanced `encodeService` to include ObjectValue carriers for accurate reference handling and prevent data loss. - Updated the syncback process to utilize Luau-style relative paths for reference attributes, improving path management and consistency. - Integrated session caching in the matching algorithm to optimize performance during syncback operations. These changes significantly improve the live syncback experience, ensuring reliable data synchronization and enhanced performance during development.
This commit is contained in:
parent
7f4b5c4941
commit
b47eef1173
165 changed files with 5205 additions and 206 deletions
148
.cursor/rules/luau-rfcs/property-readonly.md
Normal file
148
.cursor/rules/luau-rfcs/property-readonly.md
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
# Read-only properties
|
||||
|
||||
## Summary
|
||||
|
||||
Allow properties of classes and tables to be inferred as read-only.
|
||||
|
||||
## Motivation
|
||||
|
||||
Currently, Roblox APIs have read-only properties of classes, but our
|
||||
type system does not track this. As a result, users can write (and
|
||||
indeed due to autocomplete, an encouraged to write) programs with
|
||||
run-time errors.
|
||||
|
||||
In addition, user code may have properties (such as methods)
|
||||
that are expected to be used without modification. Currently there is
|
||||
no way for user code to indicate this, even if it has explicit type
|
||||
annotations.
|
||||
|
||||
It is very common for functions to only require read access to a parameter,
|
||||
and this can be inferred during type inference.
|
||||
|
||||
## Design
|
||||
|
||||
### Properties
|
||||
|
||||
Add a modifier to table properties indicating that they are read-only.
|
||||
|
||||
This proposal is not about syntax, but it will be useful for examples to have some. Write:
|
||||
|
||||
* `read p: T` for a read-only property of type `T`.
|
||||
|
||||
For example:
|
||||
```luau
|
||||
function f(t)
|
||||
t.p = 1 + t.p + t.q
|
||||
end
|
||||
```
|
||||
has inferred type:
|
||||
```
|
||||
f: (t: { p: number, read q: number }) -> ()
|
||||
```
|
||||
indicating that `p` is used read-write but `q` is used read-only.
|
||||
|
||||
### Subtyping
|
||||
|
||||
Read-only properties are covariant:
|
||||
|
||||
* If `T` is a subtype of `U` then `{ read p: T }` is a subtype of `{ read p: U }`.
|
||||
|
||||
Read-write properties are a subtype of read-only properties:
|
||||
|
||||
* If `T` is a subtype of `U` then `{ p: T }` is a subtype of `{ read p: U }`.
|
||||
|
||||
### Indexers
|
||||
|
||||
Indexers can be marked read-only just like properties. In
|
||||
particular, this means there are read-only arrays `{read T}`, that are
|
||||
covariant, so we have a solution to the "covariant array problem":
|
||||
|
||||
```luau
|
||||
local dogs: {Dog}
|
||||
function f(a: {read Animal}) ... end
|
||||
f(dogs)
|
||||
```
|
||||
|
||||
It is sound to allow this program, since `f` only needs read access to
|
||||
the array, and `{Dog}` is a subtype of `{read Dog}`, which is a subtype
|
||||
of `{read Animal}`. This would not be sound if `f` had write access,
|
||||
for example `function f(a: {Animal}) a[1] = Cat.new() end`.
|
||||
|
||||
### Functions
|
||||
|
||||
Functions are not normally mutated after they are initialized, so
|
||||
```luau
|
||||
local t = {}
|
||||
function t.f() ... end
|
||||
function t:m() ... end
|
||||
```
|
||||
|
||||
should have type
|
||||
```
|
||||
t : {
|
||||
read f : () -> (),
|
||||
read m : (self) -> ()
|
||||
}
|
||||
```
|
||||
|
||||
If developers want a mutable function,
|
||||
they can use the anonymous function version
|
||||
```luau
|
||||
t.g = function() ... end
|
||||
```
|
||||
|
||||
For example, if we define:
|
||||
```luau
|
||||
type RWFactory<A> = { build : () -> A }
|
||||
```
|
||||
|
||||
then we do *not* have that `RWFactory<Dog>` is a subtype of `RWFactory<Animal>`
|
||||
since the build method is read-write, so users can update it:
|
||||
```luau
|
||||
local mkdog : RWFactory<Dog> = { build = Dog.new }
|
||||
local mkanimal : RWFactory<Animal> = mkdog -- Does not typecheck
|
||||
mkanimal.build = Cat.new -- Assigning to methods is OK for RWFactory
|
||||
local fido : Dog = mkdog.build() -- Oh dear, fido is a Cat at runtime
|
||||
```
|
||||
|
||||
but if we define:
|
||||
```luau
|
||||
type ROFactory<A> = { read build : () -> A }
|
||||
```
|
||||
|
||||
then we do have that `ROFactory<Dog>` is a subtype of `ROFactory<Animal>`
|
||||
since the build method is read-write, so users can update it:
|
||||
```luau
|
||||
local mkdog : ROFactory<Dog> = { build = Dog.new }
|
||||
local mkanimal : ROFactory<Animal> = mkdog -- Typechecks now!
|
||||
mkanimal.build = Cat.new -- Fails to typecheck, since build is read-only
|
||||
```
|
||||
|
||||
Since most idiomatic Lua does not update methods after they are
|
||||
initialized, it seems sensible for the default access for methods should
|
||||
be read-only.
|
||||
|
||||
*This is a possibly breaking change.*
|
||||
|
||||
### Classes
|
||||
|
||||
Classes can also have read-only properties and accessors.
|
||||
|
||||
Methods in classes should be read-only by default.
|
||||
|
||||
Many of the Roblox APIs an be marked as having getters but not
|
||||
setters, which will improve accuracy of type checking for Roblox APIs.
|
||||
|
||||
## Drawbacks
|
||||
|
||||
This is adding to the complexity budget for users,
|
||||
who will be faced with inferred get modifiers on many properties.
|
||||
|
||||
## Alternatives
|
||||
|
||||
Rather than making read-write access the default, we could make read-only the
|
||||
default and add a new modifier for read-write. This is not backwards compatible.
|
||||
|
||||
We could continue with read-write access to methods,
|
||||
which means no breaking changes, but means that users may be faced with type
|
||||
errors such as "`Factory<Dog>` is not a subtype of `Factory<Animal>`".
|
||||
Loading…
Add table
Add a link
Reference in a new issue