Leap
(Lua extension accessibility pre-processor) is a fast pre-processor of a "modernized" and extended version of lua that pre-processes in pure executable lua.
Think of it as an effective "modernity" leap into the future to make lua a feature-rich language.
Leap is inspired by the functionality and syntax found in JS and is primarily intended for FiveM, this however does not deny the possibility of extension to wider horizons.
To use leap you can simply download it and use its functions within the resource at your choice (you will need to add leap between the resource's dependencies), when the resource will start leap will take the job of preprocessing the necessary files.
Example:
your_resource_that_use_leap > fxmanifest.lua
:
fx_version "cerulean"
game "gta5"
server_script "server.lua"
dependency "leap" -- This is necessary to have the resource automatically preprocessed
You can also directly use the leap restart your_resource_that_use_leap
command to preprocess the file directly with shadow writing.
To use leap on the escrow or outside the leap ecosystem you can make leap build the files into a standalone version with the command leap build your_resource_that_use_leap
Leap uses a shadow writing system (we called it that) that works in the following way: After preprocessing the files, FiveM will read the files, cache them and start the resource with those cached files as soon as we start the resource, we instantly rewrite the old files so that it looks like nothing happened. This will be done in very few ms (5/10), so from VSC or any other IDE that has the auto refresh feature when updating a file it will look like it was never overwritten
leap restart <resource>
restarts the resource by preprocessing it before restarting it using shadow writing, this command is quite useful when creating a resource, since you don't have to rebuild it every time and restart the resource but it's like everything in one command.
TIP: these commands can also be used in the cfg after the leap startup.
leap build <resource>
pre-processes the resource by creating a subfolder named build
that contains the pre-processed version of the resource
resource structure tree after build:
│ fxmanifest.lua
│
├───build
│ └───server
│ main.lua
│
└───server
main.lua
Warning Command designed only for development, you need to enable the development status
leap rebuild
rebuild with esbuild directly from fxserver instead of having to open a separate process (simply run npm run build
)
An arrow function expression is a compact alternative to a traditional function expression. Is simply an alternative to writing anonymous functions
Syntaxes:
(param1, paramN) => {
-- code
}
param => {
-- code
}
Example:
Citizen.CreateThread(() => {
print("test")
})
AddEventHandler("eventName", (text) => {
print(('I just received %s'):format(text))
})
Classes are a model for creating objects (a particular data structure), providing initial values for state (member variables or attributes), and implementing behavior (member functions or methods).
It is possible as well to extend already existing classes, each method of the class that extends the other class will have as a base a variable named super
which is an instantiated object of the original class, calling this variable as a function will call the constructor of the original class, otherwise the data of the original class can be accessed.
Constructor parameters are those passed when a new object is instantiated. Read more here
Note Classes have their own type, so calling
type(obj)
with an instantiated class will return the class name
Syntax:
Note Methods automatically hold the
self
variable referring to the instantiated objectclass className { var1 = 1, constructor = function() print(self.var1) end }
Example:
class BaseClass {
someVariable = 100,
constructor = function()
print("instantiated base class")
end
}
class AdvancedClass extends BaseClass {
constructor = function()
print("instantiated advanced class")
self.super()
-- right now they should printout the same value, since they have not been touched
print(self.super.someVariable)
print(self.someVariable)
end
}
AdvancedClass()
-- output:
--[[
instantiated advanced class
instantiated base class
100
100
]]
By definition, a decorator is a function that takes another function and extends the behavior of the latter function without explicitly modifying it. Its like wrappers You can also pass parameters to the decorators.
Syntax:
function decoratorName(func, a, b)
return function(c, d)
func(c,d)
end
end
@decoratorName(a, b)
function fnName(c, d)
-- code
end
Example:
function stopwatch(func)
return function(...)
local time = GetGameTimer()
local data = func(...)
print(func.name.." taken "..(GetGameTimer() - time).."ms to execute")
return data
end
end
@stopwatch
function someMathIntensiveFunction(a, b, pow)
for i=1, 500000 do
math.pow(a*b, pow)
end
return math.pow(a*b, pow)
end
someMathIntensiveFunction(10, 50, 100)
-- output:
--[[
someMathIntensiveFunction taken 2ms to execute
]]
Default function parameters allow named parameters to be initialized with default values if no value or nil is passed.
Syntax:
function fnName(param1 = defaultValue1, ..., paramN = defaultValueN) {
-- code
}
Example:
function multiply(a, b = 1)
return a * b
end
print(multiply(5, 2))
-- Expected output: 10
print(multiply(5))
-- Expected output: 5
The new operator lets create an instance of an object. Is actually converted during the preprocessing process with empty,so it is simply eliminated. Its use is simply to make it clear in the code when you are instantiating an object or calling a function
Syntax:
new Class()
Example:
class BaseClass {
someVariable = 100,
constructor = function()
print("instantiated base class")
end
}
local base = new BaseClass()
Another method of writing the not equal operator (~=)
Syntax:
if true != false then
-- code
end
Example:
local a = 10
local b = 20
if a != b then
print("not equal")
end
Warning for now this operator only works with variables, so writing
...{100, 200, 300}
will not work
This operator allows you to unpack arrays (not hashmaps) into multiple variables.
The preprocessor converts this operator into the table.unpack
function.
Syntax:
a,b,c = ...array
Example:
local numbers = {100, 200, 300}
local number1, number2, number3 = ...numbers
console.log(number1, number2, number3)
-- output
--[[
100 200 300
]]
We have added the ability to add types in function parameters, this will give you the ability to specify the required types and prevent bugs.
Note Classes can also be used as types
Syntax:
function funcName(<type> param1)
-- code
end
Example:
function DebugText(<string> text)
print("debug: "..text)
end
DebugText("test") -- debug: test
DebugText(100) -- Error loading script *.lua in resource ****: @****/*.lua:7: text: string expected, got number
class Example {
myVar = true
}
class Another {
myVar = false
}
local exampleObj = new Example()
local anotherObj = new Another()
function FunctionThatAcceptOnlyExampleClass(<Example> example)
print("You passed the right variable!")
end
FunctionThatAcceptOnlyExampleClass(exampleObj) -- You passed the right variable!
FunctionThatAcceptOnlyExampleClass(exampleObj) -- Error loading script *.lua in resource ****: @****/*.lua:16: example: Example expected, got Another
First of all, thank you for your dedication and willingness to contribute to the development of Leap! :heart:
Important Note: Before executing the
npm run build
command or theleap rebuild
command, make sure to install the necessary npm modules by using the commandnpm i
.
To begin developing with Leap, simply download or clone the repository and make edits to the files located within the src
folder. The files are organized by feature and supporting modules. The resulting output file is out.js
, which can be generated using the npm run build
command or on the cfx server using the leap rebuild
command.
We utilize esbuild since, based on our testing and understanding, FiveM does not support ES (ECMAScript) or the import declaration.
Once everything is built and Leap has been restarted, you only need to build or restart the specific resource of interest with Leap.
Enables some additional features like resource startup times (preprocessing time and writing time) logging and the leap rebuild
command
To enable the development status you need to set the convar leap:dev
to 1
, Read more about convars here: Convars - Cfx.re Docs.
Convar | Default | Parameter |
---|---|---|
leap:dev | 0 | int |
server.cfg:
set leap:dev 1