Luvit 2.5.6 Documentation

Table of Contents

About this Documentation#

The goal of this documentation is to comprehensively explain the Luvit API, both from a reference as well as a conceptual point of view. Each section describes a built-in module or high-level concept.

Where appropriate, property types, method arguments, and the arguments provided to event handlers are detailed in a list underneath the topic heading.

Every .html document has a corresponding .json document presenting the same information in a structured manner. This feature is experimental, and added for the benefit of IDEs and other utilities that wish to do programmatic things with the documentation.

Every .html and .json file is generated based on the corresponding .markdown file in the doc/api/ folder in luvit's source tree. The documentation is generated using the tools/doc/generate.js program. The HTML template is located at doc/template.html.

There's also a lot of examples in this repo that may be helpful.


The luvit CLI tool can be used as a scripting platform just like node. This can be used to run lua scripts as standalone servers, clients, or other tools.

This simple web server written in Luvit responds with Hello World for every request.

local http = require('http')

http.createServer(function (req, res)
  local body = "Hello world\n"
  res:setHeader("Content-Type", "text/plain")
  res:setHeader("Content-Length", #body)
end):listen(1337, '')

print('Server running at')

To run the server, put the code into a file called server.lua and execute it with using luvit

> luvit server.lua
Server running at

This script is a standalone HTTP server, there is no need for Apache or Nginx to act as host. All of the examples in the documentation can be run similarly.


A mutable buffer using ffi for luvit.

buffer = require('buffer')

Class: buffer.Buffer#

Main buffer class


Inspect a buffer. Returns a string of hexes like <Buffer Hexes>


Reads unsigned 8 bit int at offset


Read 8 bit int at offset


Read a unsigned 16 bit integer in little endian at offset


Read a unsigned 16 bit integer in big endian at offset


Read a signed 16 bit integer in little endian at offset


Read a signed 16 bit integer in big endian at offset


Read a unsigned 32 bit integer in little endian at offset


Read a signed 32 bit integer in little endian at offset


Read a signed 32 bit integer in big endian at offset

Buffer:toString([i, j])#

Stringify the buffer from the ith to the jth position, or the whole thing if i and j arent specified

Child Process#

It is possible to stream data through a child's stdin, stdout, and stderr in a fully non-blocking way.

childprocess.spawn(command, args, options)#

Spawns a command line process.

Since the data coming in is a stream, you may want to pass it through a filter like the luvit line emitter package to get lines instead.

function example()
  local LineEmitter = require('line-emitter').LineEmitter
  local childProcess = require('childprocess')
  local function run(command, args, options)
    local stdout, stderr = LineEmitter:new(), LineEmitter:new()
    local child = childProcess.spawn(command, args, options)
    return child, stdout, stderr

  local child = run('ls', {'-hal'}, {})
  child:on('data', print)


total 2
drwxr-xr-x   31 root  wheel   1.1K Aug 21 16:39 .
drwxr-xr-x   31 root  wheel   1.1K Aug 21 16:39 ..

Options can have the following k-v pairs:

detached = [Boolean]
stdio = [Array]
cwd = [String]
uid = [Number]
gid = [Number]

childprocess.exec(command[, options], callback)#

Executes the supplied command and returns data returned in the callback.
The callback can be either a function or a thread for coroutine style code.
The command can have arguments e.g. childprocess.exec('ls -a', print).

Options can have the following k-v pairs:

timeout = [Number]  
maxBuffer = [Integer, default: 4 * 1024]
signal = [String, default: 'SIGTERM'] 
shell = [String, default: 'cmd.exe' or '/bin/sh']

Additionally since this function delegates to Spawn, all spawn option k-vs are also valid.

childprocess.execFile(file[, args, options, callback])#

Similiar to exec but the arguments for the command/file must be supplied as a string to the second parameter. Also, callback is optional as well here.


Utilities for working with luvit streams and codecs.

local codec = require('codec')


Wraps an emitter with coroutines. Returns read and write functions.


Given a raw uv_stream_t userdara, return coro-friendly read/write functions.


Allows one to chain coroutines


Core object model for luvit using simple prototypes and inheritance. We support single inheritance for classes.

core.instanceof(obj, class)#

Given an object which inherits from a class, and a class, returns whether the object is an instance of that class.

> em = core.Emitter:new()
> core.instanceof(em, core.Emitter)

Class: core.Object#

The base object class. It provides simple prototypal inheritance and inheritable constructors. All other objects inherit from this.


Creates a new instance of the base object


Creates a new instance and calls obj:initialize(...) if it exists.

local Rectangle = Object:extend()
function Rectangle:initialize(w, h)
  self.w = w
  self.h = h
function Rectangle:getArea()
  return self.w * self.h
local rect = Rectangle:new(3, 4)


Creates a new sub-class.

local Square = Rectangle:extend()
function Square:initialize(w)
  self.w = w
  self.h = h

Class: core.Emitter#

This class can be used directly whenever an event emitter is needed.

local emitter = Emitter:new()
emitter:on('foo', p)
emitter:emit('foo', 1, 2, 3)

Also it can easily be sub-classed.

local Custom = Emitter:extend()
local c = Custom:new()
c:on('bar', onBar)

Unlike EventEmitter in node.js, Emitter class doesn't auto binds self reference. This means, if a callback handler is expecting a self reference, utils.bind() should be used, and the callback handler should have a self at the beginning its parameter list.

function some_func(self, a, b, c) end
emitter:on('end', utils.bind(some_func, emitter))
emitter:emit('end', 'a', 'b', 'c')

Emitter:on(name, callback)#

Adds an event listener (callback) for the named event name.

em = Emitter:new()
em:on('data', function(data) print(data) end)

Emitter:once(name, callback)#

Same as Emitter:on except it de-registers itself after the first event.


Returns the count of the listeners bound to an event with the name name

Emitter:emit(name, ...)#

Emit a named event to all listeners with optional data arguments

> em = Emitter:new()
> em:on('data', function(data) print(data) end)
> em:emit('data', 'foo')

Emitter:removeListener(name, callback)#

Removes a listener so it no longer catches events

> em = Emitter:new()
> em:on('data', function(data) print(data) end)
> em:emit('data', 'foo')
> em:removeListener('data', function() em:emit('data', 'foo') end)
> -- nothing printed


Removes all listeners. Name is optional and if supplied will make it act like removeListener


Returns listeners for the event with name name


Utility that binds the named method self[name] for use as a callback. The first argument (err) is re-routed to the "error" event instead.

local Joystick = Emitter:extend()
function Joystick:initialize(device)
  self:wrap("onOpen"), self.onOpen)
function Joystick:onOpen(fd)
  -- and so forth

Emitter:propagate(eventName, target)#

Propagate the event to another emitter.

Class: core.Error#

This is for code that wants structured error messages.


How to handle strings

Datagram | UDP#

Node-style udp module for luvit

local dgram = require('dgram')

dgram.createSocket(type, callback)#

Creates a new datagram socket Callback is triggered every time the 'message' event gets emitted

Class: dgram.Socket#

Socket extends Emitter and inherits all the events thereof. The dgram Socket class encapsulates the datagram functionality. It should be created via dgram.createSocket(...)


Start receiving on socket


Stop listening on socket

Socket:setTimeout(msecs, callback)#

Sets a socket timeout

Socket:send(data, port, host, callback)#

Sends data down the udp socket

Socket:bind(port, host, options)#

Starts listening on the specified port and host.


Closes a socket instance and fires the callback after cleanup


Returns an object containing the address information for a socket. For UDP sockets, this object will contain address , family and port.


  • status - Boolean Sets or clears the SO_BROADCAST socket option. When this option is set, UDP packets may be sent to a local interface's broadcast address.

Socket:setMembership(multicastAddress[, multicastInterface], op)#

Sets membership status for a multicast group. Op can be 'join' or 'leave'.

Socket:addMembership(multicastAddress[, interfaceAddress])#

  • multicastAddress String
  • multicastInterface String, Optional Tells the kernel to join a multicast group with IP_ADD_MEMBERSHIP socket option.

If multicastInterface is not specified, the OS will try to add membership to all valid interfaces.

Socket:dropMembership(multicastAddress[, interfaceAddress])#

  • multicastAddress String
  • multicastInterface String, Optional Opposite of addMembership - tells the kernel to leave a multicast group with IP_DROP_MEMBERSHIP socket option. This is automatically called by the kernel when the socket is closed or process terminates, so most apps will never need to call this.

If multicastInterface is not specified, the OS will try to drop membership to all valid interfaces.


  • ttl Integer Sets the IP_TTL socket option. TTL stands for "Time to Live," but in this context it specifies the number of IP hops that a packet is allowed to go through. Each router or gateway that forwards a packet decrements the TTL. If the TTL is decremented to 0 by a router, it will not be forwarded. Changing TTL values is typically done for network probes or when multicasting.

The argument to setTTL() is a number of hops between 1 and 255. The default on most systems is 64.


Node-style dns module for luvit

local dns = require('dns')

dns.query(servers, name, dnsclass, qtype, callback)#

dns.resolve4(name, callback)#

dns.resolve6(name, callback)#

dns.resolveSrv(name, callback)#

dns.resolveMx(name, callback)#

dns.resolveNs(name, callback)#

dns.resolveTxt(name, callback)#




Sets the timeout to the default timeout of 2 seconds


Sets the list of servers to the default list

    ['host'] = '',
    ['port'] = 53,
    ['tcp'] = false
    ['host'] = '',
    ['port'] = 53,
    ['tcp'] = false


Options is a table with key file. E,g

{file = '/etc/resolv.conf'}


Node-style filesystem module for luvit

local fs = require('fs')

Uses lib uv under the hood. A lot of these fuctions are very similiar to linux system calls and can be understood by reading the man pages of linux command line commnds with the same names.

The asynchronous form always takes a completion callback as its last argument. The arguments passed to the completion callback depend on the method, but the first argument is always reserved for an exception. If the operation was completed successfully, then the first argument will be null or undefined.

Sync versions of functions usually return true if they succeed or an error if they dont and no data is expected. Otherwise they return the data on success.

fs.close(fileDescriptor, callback)#

Close a file. No arguments other than a possible exception are given to the completion callback.


Synchronous file close[, flags, mode], callback)#

Asynchronous file open. flags can be:

  • 'r' - Open file for reading. An exception occurs if the file does not exist.

  • 'r+' - Open file for reading and writing. An exception occurs if the file does not exist.

  • 'rs' - Open file for reading in synchronous mode. Instructs the operating system to bypass the local file system cache.

    This is primarily useful for opening files on NFS mounts as it allows you to skip the potentially stale local cache. It has a very real impact on I/O performance so don't use this flag unless you need it.

    Note that this doesn't turn into a synchronous blocking call. If that's what you want then you should be using fs.openSync()

  • 'rs+' - Open file for reading and writing, telling the OS to open it synchronously. See notes for 'rs' about using this with caution.

  • 'w' - Open file for writing. The file is created (if it does not exist) or truncated (if it exists).

  • 'wx' - Like 'w' but fails if path exists.

  • 'w+' - Open file for reading and writing. The file is created (if it does not exist) or truncated (if it exists).

  • 'wx+' - Like 'w+' but fails if path exists.

  • 'a' - Open file for appending. The file is created if it does not exist.

  • 'ax' - Like 'a' but fails if path exists.

  • 'a+' - Open file for reading and appending. The file is created if it does not exist.

  • 'ax+' - Like 'a+' but fails if path exists.

mode sets the file mode (permission and sticky bits), but only if the file was created. It defaults to 0666, readable and writeable.

The callback gets two arguments (err, fd).

The exclusive flag 'x' (O_EXCL flag in open(2)) ensures that path is newly created. On POSIX systems, path is considered to exist even if it is a symlink to a non-existent file. The exclusive flag may or may not work with network file systems.

On Linux, positional writes don't work when the file is opened in append mode. The kernel ignores the position argument and always appends the data to the end of the file.

fs.openSync(path, flags[, mode])#

Synchronous version of Returns an integer representing the file descriptor., [, size, offset], callback)#

Read data from the file specified by fd.

offset is the offset in the buffer to start reading at.

size is an integer specifying the number of bytes to read. Defaults to 4096.

The callback is given the three arguments, (err, bytesRead, buffer).

fs.readSync(fd[, size, offset])#

Synchronous file read

fs.unlink(path, callback)#

Asynchronous delete file. No arguments other than a possible exception are given to the completion callback.


Synchronous unlink. Returns undefined.

fs.write(fd[, offset], data, callback)#

Writes a data in string data to a file fd calling a function callback with err or nil when done. offset is the offset in the buffer to start writing at.

fs.writeSync(fs[, offset,] data)#

Synchronous version of the above write function

fs.mkdir(path[, mode], callback)#

Creates a directory with name path and returns a callback with err or nil. Mode is the permissions set on the directory, defaults to octal 0777

fs.mkdirSync(path, mode)#

Sync version of mkdir.

fs.mkdtemp(template, callback)#

Makes a directory from a template object


Sync version of mkdtemp

fs.rmdir(path, callback)#

Removes a directory


Sync version of rmdir

fs.readdir(path, callback)#

Reads a directory, returning files and folders in it in the callback. First arg of cb is nil or err This function is not recursive. Use the luvit-walk package for a recursive variant


Sync version of readdir

fs.scandir(path, callback)#

Similiar to readdir but the callback here gets a function instead of a table containing the list of files. Every time this function is invoked it returns the name of the file/dir and the type of the file/dir (either file or directory).


Simply returns the iterator function retrieved in the async scandirs callback

fs.exists(path, callback)#

Checks if a file exists. Callback is called with true or false and an error or nil in the first and second args respectively.


Sync version of exists. Returns the args the callback gets in the async version

fs.stat(path, callback)#

> fs.stat('/', function(err, stat) print(err) statData = stat end)
uv_fs_t: 0x00ada5c0
> nil
{ mtime = { nsec = 0, sec = 1440200375 },
  atime = { nsec = 0, sec = 1444233226 }, ino = 2, nlink = 31, uid = 0,
  blksize = 4096, ctime = { nsec = 0, sec = 1440200375 }, rdev = 0,
  size = 1122, mode = 16877, type = 'directory',
  birthtime = { nsec = 0, sec = 1428616447 }, flags = 0, gid = 0, gen = 0,
  dev = 16777220, blocks = 0 }


Sync version of fs.stat. Returns either an error or the stat object

fs.fstat(fd, callback)#

Similiar to stat but expects a file descriptor as retrieved from open or read instead of a path


Sync fstat

fs.lstat(path, callback)#

lstat() is identical to stat(), except that if path is a symbolic link, then the link itself is stat-ed, not the file that it refers to.


Sync lstat

fs.rename(path, newPath, callback)#

Renames a file or directory located at the given path to the new path. The callback is called with either the error or true

fs.renameSync(path, newPath)#

Sync version of rename

fs.fsync(fd, callback)#

Async fsync. No arguments other than a possible exception are given to the completion callback.

fsync() transfers ("flushes") all modified in-core data of (i.e., modified buffer cache pages for) the file referred to by the file descriptor fd to the disk device (or other permanent storage device) so that all changed information can be retrieved even after the system crashed or was rebooted. This includes writing through or flushing a disk cache if present. The call blocks until the device reports that the transfer has completed. It also flushes metadata information associated with the file (see stat(2)).

Calling fsync() does not necessarily ensure that the entry in the directory containing the file has also reached disk. For that an explicit fsync() on a file descriptor for the directory is also needed.


Sync version of fsync

fs.fdatasync(fd, callback)#

fdatasync() is similar to fsync(), but does not flush modified metadata unless that metadata is needed in order to allow a subsequent data retrieval to be correctly handled. For example, changes to st_atime or st_mtime (respectively, time of last access and time of last modification; see stat(2)) do not require flushing because they are not necessary for a subsequent data read to be handled correctly. On the other hand, a change to the file size (st_size, as made by say ftruncate(2)), would require a metadata flush.

The aim of fdatasync() is to reduce disk activity for applications that do not require all metadata to be synchronized with the disk.


Sync fdatasync

fs.ftruncate(fname[, offset], callback)#

Shrink or extend the size of each FILE to the specified size

A FILE argument that does not exist is created.

If a FILE is larger than the specified size, the extra data is lost. If a FILE is shorter, it is extended and the extended part (hole) reads as zero bytes.

fs.ftruncateSync(fname[, offset])#

Sync truncate

fs.sendFile(outFd, inFd, offset, length, callback)#

sendfile() copies data between one file descriptor and another. Because this copying is done within the kernel, sendfile() is more efficient than the combination of read(2) and write(2), which would require transferring data to and from user space.

fs.sendfileSync(outFd, inFd, offset, length)#

Sync sendfile

fs.access(path[, flags], callback)#

Tests a user's permissions for the file specified by path. mode is an optional integer that specifies the accessibility checks to be performed. The following constants define the possible values of mode. It is possible to create a mask consisting of the bitwise OR of two or more values.

  • fs.F_OK - File is visible to the calling process. This is useful for determining if a file exists, but says nothing about rwx permissions. Default if no mode is specified.
  • fs.R_OK - File can be read by the calling process.
  • fs.W_OK - File can be written by the calling process.
  • fs.X_OK - File can be executed by the calling process. This has no effect on Windows (will behave like fs.F_OK).
  • The final argument, callback, is a callback function that is invoked with a possible error argument. If any of the accessibility checks fail, the error argument will be populated. The following example checks if the file /etc/passwd can be read and written by the current process.

fs.chmod(path, mode, callback)#

Asynchronous fchmod(2). No arguments other than a possible exception are given to the completion callback.

fs.chmodSync(fd, mode)#

Sync chmod.

fs.fchmod(fd, mode, callback)#

Asynchronous fchmod(2). No arguments other than a possible exception are given to the completion callback.

fs.fchmodSync(fd, mode0#

Sync fchmod

fs.utime(path, atime, mtime, callback)#

Async utime. Chages file last access and modification times

fs.utimeSync(path, atime, mtime)#

Sync utime

fs.futime(fd, atime, mtime, callback)#

Changes file timestamps

fs.futimeSync(fd, atime, mtime, callback)#

Sync futime, newPath, callback)#

link() creates a new link (also known as a hard link) to an existing file. If newpath exists it will not be overwritten.

This new name may be used exactly as the old one for any operation; both names refer to the same file (and so have the same permissions and ownership) and it is impossible to tell which name was the "original".

fs.linkSync(path, newPath)#

Sync link

fs.symlink(path, newPath[, option], callback)#

Creates soft link instead of a hard link as in link

fs.symlinkSync(path, newPath[, options])#

Sync symlink

fs.readlink(path, callback)#

Asynchronous readlink(2). The callback gets two arguments (err, linkString). Prints value of a symbolic link or canonical file name


Sync readlink

fs.chown(path, uid, gid, callback)#

Async chown. Changes ownership of a file

fs.chownSync(path, uid, gid)#

Sync chown

fs.fchown(fd, uid, gid, callback)#

Like chown but works with file descriptors

fs.fchownSync(fd, uid, gid)#

Sync fchown

fs.readFile(path, callback)#

Reads a file to a string buffer which is returned as the second argument in the callback. Works with virtual filesystems as well


Sync readFile

fs.writeFile(path, data, callback)#

Writes a file.

fs.writeFileSync(path, data)#

Sync writeFile

fs.appendFile(filename, data[, callback])#

Appends data to a file

fs.appendFileSync(path, data)#

Sync version of append file.

Class: fs.WriteStream#

Creates a writeable stream You can extend the following class methods in your extended instance.


local path, cb, chunk = 'valid/path', validFunc, 'validString'
local WritableChild = fs.WriteStream:extend()
function WritableChild:_write(data, callback)
  print('Wrote: '
local writable = WritableChild:new(path, cb)
writable:on('open', function() print('file opened')
writable:write(chunk) -- optional callback

WriteStream:initialize(path, options)#

You can set the path to the file and options here. Options is a table with the following key-value pairs

  • fd - File descriptor

  • flags - 'w' for write. See for other possible flags

  • mode - file mode to write to. Defaults to 438 which is equivalent to octal 0666

  • start - Start position


Callback to fire when the write stream is opened. This callback gets no arguments. An open event is also emitted with the file descriptor when the file is opened

WriteStream:_write(data, callback)#

Internal write utility. Bind the declared _write in your inherited class to be called when the file is opened


Closes or destroys the write stream. Calls self:destroy()


Closes the write stream

fs.createWriteStream(path, options)#

Creates and returns a new write stream, that is an instance of the aforementioned WriteStream class with the given path and options

Class: fs.WriteStreamSync#

A synchronous version of the WriteStream class. Extends WriteStream

Class: fs.ReadStream#

A parent class for creating readable streams from files. You should extend the following class methods in your extended instance

ReadStream:initialize(path, options)#

Initializer for the ReadStream class. Options table key values: fd - file descriptor mode path offset chunkSize length


Callback to fire when the read stream is opened. This callback gets no arguments. An open event is also emitted with the file descriptor when the file is opened


Reads a file, n chunk bytes at a time. You can set the n in the init options


Closes the readstream.


Destroys the readstream. Gets called by close. Emits 'error' with err if theres an error.

fs.createReadStream(path, options)#

Function which creates and returns a new read stream instance with the set options and path


Levenshtein distance for property-not-found hints in modules.

string.levenshtein(str1, str2)#

Adds a levenshtein distance function to luas native string library. The string library in luvit gets auto populated with luas string library and inbuilt methods. You can use it by simply going string.levenshtein(str1, str2). No require statements needed.

HTTP Codec#

A simple pair of functions for converting between hex and raw strings.
local httpCodec = require('http-codec')


Returns a function. See the source at http.lua:ServerResponse for an example.


Returns a function which takes one argument. See the source at http.lua for an example.


Node-style http client and server module for luvit

local http = require('http')

Value: http.headerMeta#

Provide a nice case insensitive interface to headers. Pulled from

Class: http.IncomingMessage#

Incoming message class, extends net.Socket.

IncomingMessage:initialize(head, socket)#

Head is headers. Headers declared in this child class, i.e. options expected in the head table:

- version - httpVersion
// Server specific
- method
- path - url
// Client specific
- code - statusCode
- reason - statusMessage


Resumes self.socket

Class: http.ServerResponse#

ServerResponse:setHeader(name, value)#




ServerResponse:write(chunk, callback)#


ServerResponse:writeHead(newStatusCode, newHeaders)#

http.handleConnections(socket, onRequest)#


Class: http.ClientRequest#



ClientRequest:write(data, cb)#

ClientRequest:done(data, cb)#

ClientRequest:setTimeout(msecs, callback)#


http.request(options, onResponse)#

http.get(options, onResponse)#


Node-style https client and server module for luvit. HTTPS is the HTTP protocol over TLS/SSL.

local https = require('https')

https.createServer(options, onRequest)#

https.request(options, callback)#

https.get(options, onResponse)#


local json = require('json')

Alternatively you can use lpeg like so:

local json = require('json').use_lpeg()

json.stringify(value [, state])#

Serialize a Lua table into a JSON string.

local tbl = { username = "Groucho" }
local json_str = json.stringify( tbl )

json.encode(value[, state])#

Alias for json.stringify

json.parse(str [, pos][, nullval][, ...])#

Deserialize a JSON string into a Lua table.

local json_str = '{ "username": "Groucho" }'
local tbl = json.parse( json_str )

json.decode(str[, pos, nullval, ...])#

Alias for json.parse

Value: json.null#

A null property type for JSON encoding.

local tbl = { user = "Jane", is_working = json.null }
local json_str = json.stringify( tbl )


Quotes a string. Based on the regexp "escapable" in

Light operating system helper#

Also known as los. Its' a tiny helper to get os name in luvit.

local los = require('los')


Returns either Windows, Linux, OSX, BSD, POSIX or Other depending on the host operating system.


Node-style net client and server module for luvit

local net = require('net')

Class: Socket#


The Socket initializer called when an instance is generated with Socket:new(). You can pass in a number to options and the module will try to guess if a handler of type TCP or PIPE is required, or specify a handler like so: Socket:new({handle = 'Valid handle type'})

Socket:bind(ip, port)#




Socket:keepalive(enable, delay)#




Works as either

local options = {
  host = ...,
  port = ...
connect(options, [cb])


connect(port, [host, cb])

Socket:destroy(exception[, callback])#


Default queueSize is 128


Class: Server#

Server:initialize([options,] connectionListener)#

Server:destroy(err, callback)#

Server:listen(port[, ip], callback)#



createConnection(port, host, callback)
or createConnection({port = ..., host = ..., callback = ...})

Creates, configures, connects and returns a new Socket instance.


Alias for net.createConnection(...)

net.createServer(options, connectionListener)#

Creates, configures, initializes and returns a new Server instance.


This module contains utilities for handling and transforming file paths. Almost all these methods perform only string transformations. The file system is not consulted to check whether paths are valid. Supports both windows and posix.

Use require('path') to use this module. The following methods are provided:


Gets the filesystems root path.


Gets the filesystems default path seperator

path.pathEquals(a, b)#

Checks if path a is equal to b


Normalize a string path, taking care of '..' and '.' parts.

When multiple slashes are found, they're replaced by a single one; when the path contains a trailing slash, it is preserved. On Windows backslashes are used.


Joins a splat of different strings together with the default seperator to form a valid path

path.resolve([from ...], to)#

Works backwards, joining the arguments until it resolves to an absolute path. If an absolute path is not resolved, then the current working directory is prepended


> path.resolve('/foo/bar', '/tmp/file/')

path.relative(from, to)#

Returns the relative path from 'from' to 'to' If no relative path can be solved, then 'to' is returned


Return the directory name of a path. Similar to the Unix dirname command.

path.basename(filepath, expected_ext)#

Return the last portion of a path. Similar to the Unix basename command.


Return the extension of the path, from the last '.' to end of string in the last portion of the path. If there is no '.' in the last portion of the path or the first character of it is '.', then it returns an empty string. Examples:


Checks if filepath is absolute


Checks if the path follows Microsofts universal naming convention


Drive-relative paths are unique to Windows and use the format <letter>:filepath


Returns file path with posix seperators

Pretty print#

A lua value pretty printer and colorizer for terminals.

local prettyPrint = require('pretty-print')


Index lets you optionally pick a theme, 16 or 256.

Value: prettyPrint.theme#

Table of keys and values of the available themes


Works like the default lua print function. We also override the default lua print function


prettyPrint.dump(value, recurse, nocolor)#


prettyPrint.colorize(colorName, string, resetName)#


Userdata Value: prettyPrint.stdin#

Userdata Value: prettyPrint.stdout#

Userdata Value: prettyPrint.stderr#


Node-style global process table for luvit

local process = require('process')


Query String#

This module provides utilities for dealing with query strings. It provides the following methods:

querystring.stringify(obj[, sep][, eq][, options])#

Serialize an object to a query string. Optionally override the default separator ('&') and assignment ('=') characters.

Options object may contain encodeURIComponent property (querystring.escape by default), it can be used to encode string with non-utf8 encoding if necessary.


querystring.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' })
// returns

querystring.stringify({foo: 'bar', baz: 'qux'}, ';', ':')
// returns

// Suppose gbkEncodeURIComponent function already exists,
// it can encode string with `gbk` encoding
querystring.stringify({ w: '中文', foo: 'bar' }, null, null,
  { encodeURIComponent: gbkEncodeURIComponent })
// returns

querystring.parse(str[, sep][, eq][, options])#

Deserialize a query string to an object. Optionally override the default separator ('&') and assignment ('=') characters.

Options object may contain maxKeys property (equal to 1000 by default), it'll be used to limit processed keys. Set it to 0 to remove key count limitation.

Options object may contain decodeURIComponent property (querystring.unescape by default), it can be used to decode a non-utf8 encoding string if necessary.


// returns
{ foo: 'bar', baz: ['qux', 'quux'], corge: '' }

// Suppose gbkDecodeURIComponent function already exists,
// it can decode `gbk` encoding string
querystring.parse('w=%D6%D0%CE%C4&foo=bar', null, null,
  { decodeURIComponent: gbkDecodeURIComponent })
// returns
{ w: '中文', foo: 'bar' }


Escapes special characters in a url





Un-escapes special characters in a url





A readline interface for terminals in pure lua.

local readline = require('readline')

Class: readline.History#








Class readline.Editor#




















Editor:readLine(prompt, callback)#

readline.readLine(prompt[, options], callback)#


Implementation of a read-execute-print-loop in Luvit. Used by the Luvit repl which is returned when the Luvit binary is executed without args.
Some of the examples/samples in these docs are generated by running luvit code in this repl.
Additionally require names in the docs follow the ones automatically added into the repl during bootup (e.g. pretty-print is name-spaced as prettyPrint in the repl).
All the luvit deps are injected into the repl at runtime to make it easier to try and experiment with the luvit ecosystem.


Luvit's custom require system with relative requires and sane search paths.
This allows us to have the convenience of having node style require statements to include libraries.


A port of node.js's stream module for luvit.

local Stream = require('Stream')

Class: Stream.Stream#

This is the stream core or base. Extends the emitter class described in Core.

You will most likely not use this class. The only relevant part of this class, the pipe method, is overriden in Readable.

Class: Stream.ReadableState#

Used to hold state by the Readable class

ReadableState:initialize(options, stream)#

Options table:

  • HighWaterMark - Defaults to 16, maxes out at 128MB. 128MB limit cannot be overwritten without modifying luvit/deps/stream/stream_readable
  • objectMode - If false/nil then the highWaterMark is set to 16 * 1024

Class: Stream.Readable#

Extends Stream.Stream, implements a readable stream interface. Uses ReadableState to keep track of self._readableState


Manually shove something into the read buffer. This returns true if the highWaterMark has not been hit yet, similar to how Writable.write() returns true if you should write() some more.


Unshift should always be something directly out of read()


Reads and returns n chunk bytes


Internal method executed by Readable:read. Can be overwritten in child classes.


Removes pipes to dest

Readable:on(ev, fn)#

Triggers a callback fn when an event ev is triggered. E.g.

> local child = require('stream').Readable
> child:on('foo', function() print('bar') end)
> child:emit('foo')
> child:on('bar', function(data) print(data) end)
> child:emit('bar', 'foo')


Alias for Readable:on
You can use Readable:addListener for an implicit self or use Readable.addListener(self, ...)


Resumes a stream


Pauses a stream

Class: Stream.WriteReq#

Used internally within the Writable class.

Class: Stream.WritableState#

Used internally within the Writable class to hold state.

WritableState:initialize(options, stream)#

Options table:

  • HighWaterMark - Defaults to 16, maxes out at 128MB. 128MB limit cannot be overwritten without modifying luvit/deps/stream/stream_readable
  • objectMode - If false/nil then the highWaterMark is set to 16 * 1024

Class: Stream.Writable#

The writable stream class
Emits end when done


You can modify the writable state options here, or set them.

Writable:write(chunk, cb)#

Manually write a chunk


Kind of like pause


Kind of like resume

Class: Stream.Duplex#

A Duplex stream is both readable and writable and inherits the functionality and methods of the aforementioned readable and writable classes.


These options are passed along to the initializers of the readable and writable streams this class uses.
Furthermore, we can have the following key values in the options table.

  • readable - false/true
  • writable - false/true
  • allowHalfOpen - false/true

Class: Stream.Transform#

a transform stream is a readable/writable stream where you do something with the data. Sometimes it's called a "filter", but that's not a great name for it, since that implies a thing where some bits pass through, and others are simply ignored. (That would be a valid example of a transform, of course.)

While the output is causally related to the input, it's not a necessarily symmetric or synchronous transformation. For example, a zlib stream might take multiple plain-text writes(), and then emit a single compressed chunk some time in the future.

Here's how this works:

The Transform stream has all the aspects of the readable and writable stream classes. When you write(chunk), that calls _write(chunk,cb) internally, and returns false if there's a lot of pending writes buffered up. When you call read(), that calls _read(n) until there's enough pending readable data buffered up.

In a transform stream, the written data is placed in a buffer. When _read(n) is called, it transforms the queued up data, calling the buffered _write cb's as it consumes chunks. If consuming a single written chunk would result in multiple output chunks, then the first outputted bit calls the readcb, and subsequent chunks just go into the read buffer, and will cause it to emit 'readable' if necessary.

This way, back-pressure is actually determined by the reading side, since _read has to be called to start processing a new chunk. However, a pathological inflate type of transform can cause excessive buffering here. For example, imagine a stream where every byte of input is interpreted as an integer from 0-255, and then results in that many bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in 1kb of data being output. In this case, you could write a very small amount of input, and end up with a very large amount of output. In such a pathological inflating mechanism, there'd be no way to tell the system to stop doing the transform. A single 4MB write could cause the system to run out of memory.

However, even in such a pathological case, only a single written chunk would be consumed, and then the rest would wait (un-transformed) until the results of the previous transformed chunk were consumed.


Extendable initializer for the Transform class.

Transform:_transform(chunk, cb)#

The internal transform method. You must define this in your child class. E.g. implement a passthrough filter aka a very fancy way to print hello world

local Transform = require('stream').Transform
local Transformer = Transform:extend()
function Transformer:initialize()
  Transform.initialize(self, {objectMode = true})

function Transformer:_transform(line, cb)
  return cb()

local transformer = Transformer:new()
transformer:on('data', print)
transformer:write('hello world')

Class: Stream.PassThrough#

An extension of the transform stream class with the transform method declared.
Basically just the most minimal sort of Transform stream. Every written chunk gets output as-is.

Class: Stream.Observable#

Observable is a stream that can be observed outside the pipeline. observe() returns a new Readable stream that emits all data that passes through this stream. Streams created by observe() do not affect back-pressure.


Thread module for luvit

local thread = require('thread')

thread.start(threadFunc, ...)#


thread.equals(thread1, thread2)#

thread.self()#, notifyEntry)#

thread.queue(worker, ...)#

Class: thread.Worker#

Luvit threadpool



Javascript style setTimeout and setInterval for luvit

local timer = require('timer')

timer.sleep(delay, thread)#

timer.setTimeout(delay, callback, ...)#

timer.setInterval(interval, callback, ...)#



Alias for clearInterval


Alias for clearTimeout

timer.setImmediate(callback, ...)#


timer.enroll(time, msecs)#


Node-style url codec for luvit

url.parse(url[, parseQueryString])#

Takes a url string, returns an object. Optional second argument of type bool. Pass in true if you'd like to pass the query part of the url through the querystring modules parse function.

url = require('url')


{ host = '', hostname = '', href = '', protocol = 'https',
  pathname = '/luvit/luvit/blob/master/deps/url.lua', path = '/luvit/luvit/blob/master/deps/url.lua' }


Wrapper around pretty-print with extra tools for luvit

local utils = require('utils')

Everything in pretty-print is available under the utils namespace as well. Additionally utils has the following available functions

utils.bind(fn, self, ...)#


utils.adapt(c, fn, ...)#

Used heavily within luvit to wrap luv methods and expose them.