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:
Joe 2026-02-18 22:34:52 -06:00
parent 7f4b5c4941
commit b47eef1173
165 changed files with 5205 additions and 206 deletions

View file

@ -0,0 +1,109 @@
---
slug: grammar
title: Syntax Grammar
sidebar:
order: 3
---
This is the complete syntax grammar for Luau in EBNF. More information about the terminal nodes STRING and NUMBER
is available in the [syntax section](../syntax).
```ebnf
chunk ::= block
block ::= {stat [';']} [laststat [';']]
stat ::= varlist '=' explist |
var compoundop exp |
functioncall |
'do' block 'end' |
'while' exp 'do' block 'end' |
'repeat' block 'until' exp |
'if' exp 'then' block {'elseif' exp 'then' block} ['else' block] 'end' |
'for' binding '=' exp ',' exp [',' exp] 'do' block 'end' |
'for' bindinglist 'in' explist 'do' block 'end' |
attributes 'function' funcname funcbody |
attributes 'local' 'function' NAME funcbody |
'local' bindinglist ['=' explist] |
['export'] 'type' NAME ['<' GenericTypeListWithDefaults '>'] '=' Type |
['export'] 'type' 'function' NAME funcbody
laststat ::= 'return' [explist] | 'break' | 'continue'
funcname ::= NAME {'.' NAME} [':' NAME]
funcbody ::= ['<' GenericTypeList '>'] '(' [parlist] ')' [':' ReturnType] block 'end'
parlist ::= bindinglist [',' '...' [':' (GenericTypePack | Type)]] | '...' [':' (GenericTypePack | Type)]
explist ::= {exp ','} exp
binding ::= NAME [':' Type]
bindinglist ::= binding [',' bindinglist] (* equivalent of Lua 5.1 'namelist', except with optional type annotations *)
var ::= NAME | prefixexp '[' exp ']' | prefixexp '.' NAME
varlist ::= var {',' var}
prefixexp ::= var | functioncall | '(' exp ')'
functioncall ::= prefixexp funcargs | prefixexp ':' NAME funcargs
exp ::= asexp { binop exp } | unop exp { binop exp }
ifelseexp ::= 'if' exp 'then' exp {'elseif' exp 'then' exp} 'else' exp
asexp ::= simpleexp ['::' Type]
stringinterp ::= INTERP_BEGIN exp { INTERP_MID exp } INTERP_END
simpleexp ::= NUMBER | STRING | 'nil' | 'true' | 'false' | '...' | tableconstructor | attributes 'function' funcbody | prefixexp | ifelseexp | stringinterp
funcargs ::= '(' [explist] ')' | tableconstructor | STRING
tableconstructor ::= '{' [fieldlist] '}'
fieldlist ::= field {fieldsep field} [fieldsep]
field ::= '[' exp ']' '=' exp | NAME '=' exp | exp
fieldsep ::= ',' | ';'
compoundop ::= '+=' | '-=' | '*=' | '/=' | '//=' | '%=' | '^=' | '..='
binop ::= '+' | '-' | '*' | '/' | '//' | '^' | '%' | '..' | '<' | '<=' | '>' | '>=' | '==' | '~=' | 'and' | 'or'
unop ::= '-' | 'not' | '#'
littable ::= '{' [litfieldlist] '}'
litfieldlist ::= litfield {fieldsep litfield} [fieldsep]
litfield ::= [NAME '='] literal
literal ::= 'nil' | 'false' | 'true' | NUMBER | STRING | littable
litlist ::= literal {',' literal}
pars ::= '(' [litlist] ')' | littable | STRING
parattr ::= NAME [pars]
attribute ::= '@' NAME | '@[' parattr {',' parattr} ']'
attributes ::= {attribute}
SimpleType ::=
'nil' |
SingletonType |
NAME ['.' NAME] [ '<' [TypeParams] '>' ] |
'typeof' '(' exp ')' |
TableType |
FunctionType |
'(' Type ')'
SingletonType ::= STRING | 'true' | 'false'
Union ::= [SimpleType {'?'}] {'|' SimpleType {'?'}}
Intersection ::= [SimpleType] {'&' SimpleType}
Type ::= Union | Intersection
GenericTypePackParameter ::= NAME '...'
GenericTypeList ::= NAME [',' GenericTypeList] | GenericTypePackParameter {',' GenericTypePackParameter}
GenericTypePackParameterWithDefault ::= NAME '...' '=' (TypePack | VariadicTypePack | GenericTypePack)
GenericTypeListWithDefaults ::=
NAME ['=' Type] [',' GenericTypeListWithDefaults] |
GenericTypePackParameterWithDefault {',' GenericTypePackParameterWithDefault}
TypeList ::= Type [',' TypeList] | '...' Type
BoundTypeList ::= [NAME ':'] Type [',' BoundTypeList] | GenericTypePack | VariadicTypePack
TypeParams ::= (Type | TypePack | VariadicTypePack | GenericTypePack) [',' TypeParams]
TypePack ::= '(' [TypeList] ')'
GenericTypePack ::= NAME '...'
VariadicTypePack ::= '...' Type
ReturnType ::= Type | TypePack | GenericTypePack | VariadicTypePack
TableIndexer ::= ['read' | 'write'] '[' Type ']' ':' Type
TableProp ::= ['read' | 'write'] NAME ':' Type
PropList ::= TableProp [fieldsep PropList] | TableIndexer {fieldsep TableProp}
TableType ::= '{' Type '}' | '{' [PropList] '}'
FunctionType ::= ['<' GenericTypeList '>'] '(' [BoundTypeList] ')' '->' ReturnType
```

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,368 @@
---
slug: types-library
title: Type Function Library
sidebar:
order: 2
---
The `types` library is used to create and transform types, and can only be used within [type functions](../types/type-functions).
### `types` library properties
```
types.any
```
The [any](../types/basic-types#any-type) `type`.
```
types.unknown
```
The [unknown](../types/basic-types#unknown-type) `type`.
```
types.never
```
The [never](../types/basic-types#never-type) `type`.
```
types.boolean
```
The boolean `type`.
```
types.buffer
```
The [buffer](../library#buffer-library) `type`.
```
types.number
```
The number `type`.
```
types.string
```
The string `type`.
```
types.thread
```
The thread `type`.
## `types` library functions
```
types.singleton(arg: string | boolean | nil): type
```
Returns the [singleton](../types/basic-types#singleton-types-aka-literal-types) type of the argument.
```
types.negationof(arg: type): type
```
Returns an immutable negation of the argument type.
```
types.optional(arg: type): type
```
Returns a version of the given type that is now optional.
- If the given type is a [union type](../types/unions-and-intersections#union-types), `nil` will be added unconditionally as a component.
- Otherwise, the result will be a union of the given type and the `nil` type.
```
types.unionof(first: type, second: type, ...: type): type
```
Returns an immutable [union](../types/unions-and-intersections#union-types) of two or more arguments.
```
types.intersectionof(first: type, second: type, ...: type): type
```
Returns an immutable [intersection](../types/unions-and-intersections#intersection-types) of two or more arguments.
```
types.newtable(props: { [type]: type | { read: type?, write: type? } }?, indexer: { index: type, readresult: type, writeresult: type? }?, metatable: type?): type
```
Returns a fresh, mutable table `type`. Property keys must be string singleton `type`s. The table's metatable is set if one is provided.
```
types.newfunction(parameters: { head: {type}?, tail: type? }, returns: { head: {type}?, tail: type? }?, generics: {type}?): type
```
Returns a fresh, mutable function `type`, using the ordered parameters of `head` and the variadic tail of `tail`.
```
types.copy(arg: type): type
```
Returns a deep copy of the argument type.
```
types.generic(name: string?, ispack: boolean?): type
```
Creates a [generic](../types/generics#generic-functions) named `name`. If `ispack` is `true`, the result is a [generic pack](../types/basic-types#type-packs).
### `type` instance
`type` instances can have extra properties and methods described in subsections depending on its tag.
```
type.tag: "nil" | "unknown" | "never" | "any" | "boolean" | "number" | "string" | "singleton" | "negation" | "union" | "intersection" | "table" | "function" | "class" | "thread" | "buffer"
```
An immutable property holding the type's tag.
```
__eq(arg: type): boolean
```
Overrides the `==` operator to return `true` if `self` is syntactically equal to `arg`. This excludes semantically equivalent types, `true | false` is unequal to `boolean`.
```
type:is(arg: "nil" | "unknown" | "never" | "any" | "boolean" | "number" | "string" | "singleton" | "negation" | "union" | "intersection" | "table" | "function" | "class" | "thread" | "buffer")
```
Returns `true` if `self` has the argument as its tag.
### Singleton `type` instance
```
singletontype:value(): boolean | nil | "string"
```
Returns the singleton's actual value, like `true` for `types.singleton(true)`.
### Generic `type` instance
```
generictype:name(): string?
```
Returns the name of the [generic](../types/generics#generic-functions) or `nil` if it has no name.
```
generictype:ispack(): boolean
```
Returns `true` if the [generic](../types/generics#generic-functions) is a [pack](../types/basic-types#type-packs), or `false` otherwise.
### Table `type` instance
```
tabletype:setproperty(key: type, value: type?)
```
Sets the type of the property for the given `key`, using the same type for both reading from and writing to the table.
- `key` is expected to be a string singleton type, naming the property.
- `value` will be set as both the `read type` and `write type` of the property.
- If `value` is `nil`, the property is removed.
```
tabletype:setreadproperty(key: type, value: type?)
```
Sets the type for reading from the property named by `key`, leaving the type for writing this property as-is.
- `key` is expected to be a string singleton type, naming the property.
- `value` will be set as the `read type`, the `write type` will be unchanged.
- If `key` is not already present, only a `read type` will be set, making the property read-only.
- If `value` is `nil`, the property is removed.
```
tabletype:setwriteproperty(key: type, value: type?)
```
Sets the type for writing to the property named by `key`, leaving the type for reading this property as-is.
- `key` is expected to be a string singleton type, naming the property.
- `value` will be set as the `write type`, the `read type` will be unchanged.
- If `key` is not already present, only a `write type` will be set, making the property write-only.
- If `value` is `nil`, the property is removed.
```
tabletype:readproperty(key: type): type?
```
Returns the type used for reading values from this property, or `nil` if the property doesn't exist.
```
tabletype:writeproperty(key: type): type?
```
Returns the type used for writing values to this property, or `nil` if the property doesn't exist.
```
tabletype:properties(): { [type]: { read: type?, write: type? } }
```
Returns a table mapping property keys to their read and write types.
```
tabletype:setindexer(index: type, result: type)
```
Sets the table's indexer, using the same type for reads and writes.
```
tabletype:setreadindexer(index: type, result: type)
```
Sets the type resulting from reading from this table via indexing.
```
tabletype:setwriteindexer(index: type, result: type)
```
Sets the type for writing to this table via indexing.
```
tabletype:indexer(): { index: type, readresult: type, writeresult: type }
```
Returns the table's indexer as a table, or `nil` if it doesn't exist.
```
tabletype:readindexer(): { index: type, result: type }?
```
Returns the table's indexer using the result's read type, or `nil` if it doesn't exist.
```
tabletype:writeindexer()
```
Returns the table's indexer using the result's write type, or `nil` if it doesn't exist.
```
tabletype:setmetatable(arg: type)
```
Sets the table's metatable.
```
tabletype:metatable(): type?
```
Gets the table's metatable, or `nil` if it doesn't exist.
### Function `type` instance
```
functiontype:setparameters(head: {type}?, tail: type?)
```
Sets the function's parameters, with the ordered parameters in `head` and the variadic tail in `tail`.
```
functiontype:parameters(): { head: {type}?, tail: type? }
```
Returns the function's parameters, with the ordered parameters in `head` and the variadic tail in `tail`.
```
functiontype:setreturns(head: {type}?, tail: type?)
```
Sets the function's return types, with the ordered parameters in `head` and the variadic tail in `tail`.
```
functiontype:returns(): { head: {type}?, tail: type? }
```
Returns the function's return types, with the ordered parameters in `head` and the variadic tail in `tail`.
```
functiontype:generics(): {type}
```
Returns an array of the function's [generic](../types/generics#generic-functions) `type`s.
```
functiontype:setgenerics(generics: {type}?)
```
Sets the function's [generic](../types/generics#generic-functions) `type`s.
### Negation `type` instance
```
type:inner(): type
```
Returns the `type` being negated.
### Union `type` instance
```
uniontype:components(): {type}
```
Returns an array of the [unioned](../types/unions-and-intersections#union-types) types.
### Intersection `type` instance
```
intersectiontype:components()
```
Returns an array of the [intersected](../types/unions-and-intersections#intersection-types) types.
### Class `type` instance
```
classtype:properties(): { [type]: { read: type?, write: type? } }
```
Returns the properties of the class with their respective `read` and `write` types.
```
classtype:readparent(): type?
```
Returns the type of reading this class' parent, or returns `nil` if the parent class doesn't exist.
```
classtype:writeparent(): type?
```
Returns the type for writing to this class' parent, or returns `nil` if the parent class doesn't exist.
```
classtype:metatable(): type?
```
Returns the class' metatable, or `nil` if it doesn't exist.
```
classtype:indexer(): { index: type, readresult: type, writeresult: type }?
```
Returns the class' indexer, or `nil` if it doesn't exist.
```
classtype:readindexer(): { index: type, result: type }?
```
Returns result type of reading from the class via indexing, or `nil` if it doesn't exist.
```
classtype:writeindexer(): { index: type, result: type }?
```
Returns the type for writing to the class via indexing, or `nil` if it doesn't exist.