@eryx/luau Module

JSON

Luau source code parser, compiler, and type checker.

Parses Luau source into a structured AST (Abstract Syntax Tree) with full type-safety. Also provides bytecode compilation, loading, native JIT compilation, bytecode disassembly, full type checking, type inference at positions, and autocompletion.

Every node carries a type discriminator string and a location with 1-based line/column positions.

local luau = require("@eryx/luau")

local result = luau.parse(source, { captureComments = true })
for _, stat in result.root.body do
    print(stat.type, stat.location.start.line)
end

-- Type check a file
local checked = luau.check(source, { mode = "strict", annotate = true })
print(checked.annotated) -- source with type annotations

-- Query a type at a position
local ty = luau.typeAt(source, 1, 7)
print(ty) -- e.g. "number"

Summary

Functions

luau.parse(source: string, options: ParseOptions?)ParseResult
luau.prettyPrint(source: string)string
luau.compile(source: string, options: CompileOptions?)string
luau.load(sourceOrBytecode: string, chunkname: string?)((...any) → ...any)
luau.disassemble(source: string, options: DisassembleOptions?)string
luau.check(source: string, options: CheckOptions?)CheckResult
luau.typeAt(source: string, line: number, column: number, options: TypeAtOptions?)(string | TypeAtResult)?
luau.autocomplete(source: string, line: number, column: number, options: AutocompleteOptions?)AutocompleteResult
luau.resolve(filePath: string, requirePath: string)string?

API Reference

Functions

luau.parse

Parses Luau source code and returns a structured AST.

The returned root is a Block node whose body contains an array of statement nodes. Every node carries a type string discriminator and a location with 1-based line/column positions.

Pass { captureComments = true } to include a comments array in the result.

local result = luau.parse(source, { captureComments = true })
print("Lines:", result.lines)
print("Errors:", #result.errors)
print("Top-level statements:", #result.root.body)
luau.parse(source: string, options: ParseOptions?)ParseResult

Parameters

source: string

The Luau source code string to parse.

options: ParseOptions?

Parse options (e.g. comment capture).

Returns

The parse result containing the AST root, errors, and optional comments.

luau.prettyPrint

Pretty-prints Luau source code by round-tripping through the parser.

luau.prettyPrint(source: string)string

Parameters

source: string

The Luau source code to format.

Returns

string

The reformatted source code.

luau.compile

Compiles Luau source code to bytecode.

The returned bytecode blob can be passed to load or cached for later use. If the source has syntax errors the bytecode will contain an encoded error that load will surface.

local bytecode = luau.compile(source, { optimizationLevel = 2 })
local fn = luau.load(bytecode, "=cached")
fn()
luau.compile(source: string, options: CompileOptions?)string

Parameters

source: string

The Luau source code to compile.

options: CompileOptions?

Compiler options (optimization, debug, coverage levels).

Returns

string

The compiled bytecode blob.

luau.load

Loads Luau source code or pre-compiled bytecode as a callable function.

Accepts either a source string (which will be compiled automatically) or a bytecode blob previously returned by compile. This is the equivalent of loadstring in standard Lua.

local fn = luau.load("return 1 + 2", "=example")
print(fn()) -- 3
luau.load(sourceOrBytecode: string, chunkname: string?)((...any) → ...any)

Parameters

sourceOrBytecode: string

Luau source code or compiled bytecode.

chunkname: string?

Optional name for the chunk (shown in errors/stack traces, defaults to "=load").

Returns

((...any) → ...any)

The loaded function.

luau.disassemble

Returns a human-readable bytecode listing for the given source.

Compiles the source and returns a formatted disassembly string showing every function's bytecode instructions, optionally with source lines, local variable info, compiler remarks, and type annotations.

local listing = luau.disassemble(source, {
    showLocals  = true,
    showRemarks = true,
})
print(listing)
luau.disassemble(source: string, options: DisassembleOptions?)string

Parameters

source: string

The Luau source code to disassemble.

Disassembly options controlling output detail.

Returns

string

The formatted bytecode listing.

luau.check

Runs the Luau type checker on a source string.

Returns a CheckResult containing any type errors found. When options.annotate is true, also returns the source code rewritten with inferred type annotations attached to every binding and expression. The result also includes built-in Luau lints under result.lints.

local result = luau.check(source, { mode = "strict", annotate = true })
for _, err in result.errors do
    print(err.message, err.location.start.line)
end
if result.annotated then
    print(result.annotated)
end
luau.check(source: string, options: CheckOptions?)CheckResult

Parameters

source: string

The Luau source code to type-check.

options: CheckOptions?

Type-checking options.

Returns

The type-check result.

luau.typeAt

Infers the type at a specific position in Luau source code.

Runs the type checker in strict mode (by default) and queries the inferred type at the given 1-based line and column. Useful for building LSP hover information or type inspection tools.

Returns nil if no type can be determined at that position (e.g. whitespace, comments, or if the position is out of range).

local source = "local x = 42\nprint(x)"
local ty = luau.typeAt(source, 1, 7)  -- position of 'x'
print(ty)  -- "number"
luau.typeAt(source: string, line: number, column: number, options: TypeAtOptions?)(string | TypeAtResult)?

Parameters

source: string

The Luau source code.

line: number

1-based line number.

column: number

1-based column number.

options: TypeAtOptions?

Type inference options.

Returns

(string | TypeAtResult)?

The inferred type as a string, or nil.

luau.autocomplete

Computes autocompletion entries at a cursor position.

Runs type checking and returns contextual completions, including property names, local bindings, keywords, and types - along with their inferred types where available. This is the same engine used by Luau language servers.

local source = 'local t = {foo = 1, bar = "hi"}\nt.'
local result = luau.autocomplete(source, 2, 3)  -- after "t."
for name, entry in result.entries do
    print(name, entry.kind, entry.type)
end
-- foo  Property  number
-- bar  Property  string
luau.autocomplete(source: string, line: number, column: number, options: AutocompleteOptions?)AutocompleteResult

Parameters

source: string

The Luau source code.

line: number

1-based line number of the cursor.

column: number

1-based column number of the cursor.

Autocomplete options.

Returns

The autocomplete result.

luau.resolve

Resolve a require() path relative to a source file.

Given the absolute path of a Luau source file and a require string (relative path like "./foo", "../bar", or alias path like "@alias/mod"), returns the absolute path to the resolved module file, or nil if no matching file was found.

Uses the same resolution rules as the type checker:

  • Extension search order: .luau -> .lua -> dir/init.luau -> dir/init.lua
  • Alias resolution via .luaurc files walking up the directory tree.
  • init.luau files resolve relative requires from the parent directory.
local target = luau.resolve("C:/project/src/main.luau", "./utils")
print(target)  -- "C:\\project\\src\\utils.luau"
luau.resolve(filePath: string, requirePath: string)string?

Parameters

filePath: string

Absolute path of the source file containing the require.

requirePath: string

The require string to resolve.

Returns

string?

Absolute path to the resolved file, or nil.

Types

Position

A position in source code (1-based line and column).

line: number
column: number

Location

A span in source code, from a start Position to an end Position.

start: Position

ParseErrorInfo

A parse error with its location in the source.

message: string
location: Location

CommentInfo

A comment descriptor. Only present when captureComments is enabled in the ParseOptions.

type: "Comment" | "BlockComment" | "BrokenComment"
location: Location

ParseOptions

Options for parse.

captureComments: boolean?

TableAccess

type TableAccess = "Read" | "Write" | "ReadWrite"

AttrType

type AttrType = "Checked" | "Native" | "Deprecated" | "Unknown"

AstAttr

type: AttrType
location: Location
name: string?
args: { AstExpr }
deprecatedInfo: { deprecated: boolean, use: string?, reason: string? }?

AstGenericType

name: string
location: Location
default: AstType?

AstGenericTypePack

name: string
location: Location
default: AstTypePack?

AstTypeOrPack

kind: "Type" | "TypePack" | "Unknown"

AstTypeName

name: string
location: Location

AstTypeList

types: { AstType }

TypeReference

type: "TypeReference"
location: Location
hasParameterList: boolean
name: string
nameLocation: Location
prefix: string?
prefixLocation: Location?
parameters: { AstTypeOrPack }?

TypeTableProp

name: string
type: AstType
location: Location
access: TableAccess
accessLocation: Location?

TypeTableIndexer

indexType: AstType
resultType: AstType
location: Location
access: TableAccess
accessLocation: Location?

TypeTable

type: "TypeTable"
location: Location
props: { TypeTableProp }

TypeFunction

type: "TypeFunction"
location: Location
attributes: { AstAttr }?
generics: { AstGenericType }?
genericPacks: { AstGenericTypePack }?
argTypes: AstTypeList
argNames: { AstTypeName? }
returnTypes: AstTypePack?

TypeTypeof

type: "TypeTypeof"
location: Location
expr: AstExpr

TypeOptional

type: "TypeOptional"
location: Location

TypeUnion

type: "TypeUnion"
location: Location
types: { AstType }

TypeIntersection

type: "TypeIntersection"
location: Location
types: { AstType }

TypeSingletonBool

type: "TypeSingletonBool"
location: Location
value: boolean

TypeSingletonString

type: "TypeSingletonString"
location: Location
value: string

TypeGroup

type: "TypeGroup"
location: Location
inner: AstType

TypeError

type: "TypeError"
location: Location
types: { AstType }
isMissing: boolean
messageIndex: number

TypeUnknown

type: "TypeUnknown"
location: Location

AstType

Union of all type annotation nodes.

TypePackExplicit

type: "TypePackExplicit"
location: Location
types: { AstType }

TypePackVariadic

type: "TypePackVariadic"
location: Location
variadicType: AstType

TypePackGeneric

type: "TypePackGeneric"
location: Location
name: string

TypePackUnknown

type: "TypePackUnknown"
location: Location

AstTypePack

Union of all type-pack nodes (used for return types and variadic packs).

AstLocal

name: string
location: Location
annotation: AstType?
functionDepth: number
loopDepth: number
isConst: boolean
shadow: { name: string, location: Location }?

ExprGroup

type: "ExprGroup"
location: Location
expr: AstExpr

ExprConstantNil

type: "ExprConstantNil"
location: Location

ExprConstantBool

type: "ExprConstantBool"
location: Location
value: boolean

ExprConstantNumber

type: "ExprConstantNumber"
location: Location
value: number
parseResult: "Ok" | "Imprecise" | "Malformed" | "BinOverflow" | "HexOverflow" | "Unknown"

ExprConstantString

type: "ExprConstantString"
location: Location
value: string
quoteStyle: "QuotedSimple" | "QuotedSingle" | "QuotedRaw" | "Unquoted" | "Unknown"
isQuoted: boolean

ExprLocal

type: "ExprLocal"
location: Location
local: AstLocal
upvalue: boolean

ExprGlobal

type: "ExprGlobal"
location: Location
name: string

ExprVarargs

type: "ExprVarargs"
location: Location

ExprCall

type: "ExprCall"
location: Location
func: AstExpr
typeArguments: { AstTypeOrPack }?
args: { AstExpr }
self: boolean
argLocation: Location

ExprIndexName

type: "ExprIndexName"
location: Location
expr: AstExpr
index: string
indexLocation: Location
opPosition: Position
op: string

ExprIndexExpr

type: "ExprIndexExpr"
location: Location
expr: AstExpr
index: AstExpr

ExprFunction

type: "ExprFunction"
location: Location
attributes: { AstAttr }?
debugname: string?
generics: { AstGenericType }?
genericPacks: { AstGenericTypePack }?
args: { AstLocal }
vararg: boolean
varargLocation: Location
varargAnnotation: AstTypePack?
returnAnnotation: AstTypePack?
self: AstLocal?
argLocation: Location?
functionDepth: number
body: Block

ExprTableItem

kind: "List" | "Record" | "General"
key: AstExpr?
value: AstExpr

ExprTable

type: "ExprTable"
location: Location
items: { ExprTableItem }

ExprUnary

type: "ExprUnary"
location: Location
op: string
expr: AstExpr

ExprBinary

type: "ExprBinary"
location: Location
op: string
left: AstExpr
right: AstExpr

ExprTypeAssertion

type: "ExprTypeAssertion"
location: Location
expr: AstExpr
annotation: AstType

ExprIfElse

type: "ExprIfElse"
location: Location
condition: AstExpr
hasThen: boolean
trueExpr: AstExpr
hasElse: boolean
falseExpr: AstExpr

ExprInterpString

type: "ExprInterpString"
location: Location
strings: { string }
expressions: { AstExpr }

ExprInstantiate

type: "ExprInstantiate"
location: Location
expr: AstExpr
typeArguments: { AstTypeOrPack }

ExprError

type: "ExprError"
location: Location
expressions: { AstExpr }
messageIndex: number

ExprUnknown

type: "ExprUnknown"
location: Location

AstExpr

Union of all expression nodes.

Block

type: "Block"
location: Location
hasSemicolon: boolean
body: { AstStat }
hasEnd: boolean

StatIf

type: "StatIf"
location: Location
hasSemicolon: boolean
condition: AstExpr
thenBody: Block
elseBody: (Block | StatIf)?
thenLocation: Location?
elseLocation: Location?

StatWhile

type: "StatWhile"
location: Location
hasSemicolon: boolean
condition: AstExpr
body: Block
hasDo: boolean
doLocation: Location

StatRepeat

type: "StatRepeat"
location: Location
hasSemicolon: boolean
condition: AstExpr
body: Block
hasUntil: boolean

StatBreak

type: "StatBreak"
location: Location
hasSemicolon: boolean

StatContinue

type: "StatContinue"
location: Location
hasSemicolon: boolean

StatReturn

type: "StatReturn"
location: Location
hasSemicolon: boolean
list: { AstExpr }

StatExpr

type: "StatExpr"
location: Location
hasSemicolon: boolean
expr: AstExpr

StatLocal

type: "StatLocal"
location: Location
hasSemicolon: boolean
vars: { AstLocal }
values: { AstExpr }
equalsSignLocation: Location?

StatFor

type: "StatFor"
location: Location
hasSemicolon: boolean
from: AstExpr
step: AstExpr?
body: Block
hasDo: boolean
doLocation: Location

StatForIn

type: "StatForIn"
location: Location
hasSemicolon: boolean
vars: { AstLocal }
values: { AstExpr }
body: Block
hasIn: boolean
inLocation: Location
hasDo: boolean
doLocation: Location

StatAssign

type: "StatAssign"
location: Location
hasSemicolon: boolean
vars: { AstExpr }
values: { AstExpr }

StatCompoundAssign

type: "StatCompoundAssign"
location: Location
hasSemicolon: boolean
op: string
var: AstExpr
value: AstExpr

StatFunction

type: "StatFunction"
location: Location
hasSemicolon: boolean
name: AstExpr

StatLocalFunction

type: "StatLocalFunction"
location: Location
hasSemicolon: boolean
name: AstLocal

StatTypeAlias

type: "StatTypeAlias"
location: Location
hasSemicolon: boolean
name: string
nameLocation: Location
exported: boolean
aliasedType: AstType
generics: { AstGenericType }?
genericPacks: { AstGenericTypePack }?

StatTypeFunction

type: "StatTypeFunction"
location: Location
hasSemicolon: boolean
name: string
nameLocation: Location
exported: boolean
hasErrors: boolean

StatDeclareGlobal

type: "StatDeclareGlobal"
location: Location
hasSemicolon: boolean
name: string
nameLocation: Location
declaredType: AstType

AstParamName

name: string
location: Location

StatDeclareFunction

type: "StatDeclareFunction"
location: Location
hasSemicolon: boolean
attributes: { AstAttr }?
name: string
nameLocation: Location
generics: { AstGenericType }?
genericPacks: { AstGenericTypePack }?
params: AstTypeList
paramNames: { AstParamName }
vararg: boolean
varargLocation: Location
returnTypes: AstTypePack

AstDeclaredExternTypeProperty

name: string
nameLocation: Location
type: AstType
isMethod: boolean
location: Location

StatDeclareExternType

type: "StatDeclareExternType"
location: Location
hasSemicolon: boolean
name: string
superName: string?

StatError

type: "StatError"
location: Location
hasSemicolon: boolean
expressions: { AstExpr }
statements: { AstStat }
messageIndex: number

StatUnknown

type: "StatUnknown"
location: Location

AstStat

Union of all statement nodes.

AstNode

Any AST node (statement, expression, or type annotation).

ParseResult

The result returned by parse.

root: Block
errors: { ParseErrorInfo }
comments: { CommentInfo }?
lines: number

CompileOptions

Options for compile.

optimizationLevel: number?
debugLevel: number?
coverageLevel: number?
typeInfoLevel: number?

DisassembleOptions

Options for disassemble.

optimizationLevel: number?
debugLevel: number?
showLocals: boolean?
showRemarks: boolean?
showTypes: boolean?

DefinitionSource

A definition source for loading type definitions. Can be a plain string (the definition source text) or a table with a source field and optional name (package name, e.g. "@mygame").

type DefinitionSource = string | { source: string, name: string? }

CheckOptions

Options for check

mode: ("strict" | "nonstrict" | "nocheck")?

Type-checking mode: "strict" for full checking, "nonstrict" (default) for lenient checking, "nocheck" for no type checking.

annotate: boolean?

If true, the result includes an annotated field with the source rewritten to include inferred type annotations.

definitions: { DefinitionSource }?

Additional type definition sources to load before type checking. These are .d.luau-style definition strings that declare global types and functions available in the checked source.

filePath: string?

Absolute file path of the source being checked. When provided, require() calls in the source are resolved relative to this path, and .luaurc alias configs are discovered by walking up from it.

TypeErrorInfo

A type error from the type checker.

message: string

Human-readable error message.

location: Location

Source location of the error.

category: "TypeError" | "SyntaxError"

Error category: "TypeError" or "SyntaxError".

LintInfo

A lint diagnostic produced by Luau's built-in linter.

severity: "error" | "warning"

Lint severity category.

code: number

Numeric lint code.

name: string

Stable lint code name (for example "LocalUnused").

message: string

Human-readable lint message.

location: Location

Source location for the lint.

LintResult

Lint diagnostics grouped by severity plus flattened ordering.

errors: { LintInfo }
warnings: { LintInfo }
all: { LintInfo }

CheckResult

The result returned by check.

errors: { TypeErrorInfo }

Type errors found during checking (empty array if none).

lints: LintResult

Built-in Luau lint diagnostics for this source.

annotated: string?

The source code with inferred type annotations attached. Only present when options.annotate is true.

AnalysisTypeDetail

display: string
kind: string

TypeAtResult

display: string
source: "Expression" | "Binding" | "ScopeBinding"

TypeAtOptions

Options for typeAt.

mode: ("strict" | "nonstrict" | "nocheck")?

Type-checking mode. Defaults to "strict" for best inference.

definitions: { DefinitionSource }?

Additional type definition sources to load before inference.

filePath: string?

Absolute file path of the source. Enables require() resolution.

detailed: boolean?

If true, return a structured type object instead of just a string.

AutocompleteOptions

Options for autocomplete.

mode: ("strict" | "nonstrict")?

Type-checking mode. Defaults to "strict" for best results.

definitions: { DefinitionSource }?

Additional type definition sources to load before completion.

filePath: string?

Absolute file path of the source. Enables require() resolution.

detailed: boolean?

If true, include typeDetail for each typed autocomplete entry.

AutocompleteEntry

An autocompletion entry.

kind: "Property" | "Binding" | "Keyword" | "String" | "Type" | "Module" | "GeneratedFunction" | "RequirePath" | "Unknown"

What kind of completion this is.

type: string?

The inferred type of this entry (absent for keywords).

typeDetail: AnalysisTypeDetail?

Structured type metadata (when options.detailed is true).

deprecated: boolean?

Whether this entry is deprecated.

typeCorrect: ("Correct" | "CorrectFunctionResult")?

Whether this entry's type matches what's expected at the cursor.

insertText: string?

Suggested text to insert.

parens: ("CursorAfter" | "CursorInside")?

Parentheses recommendation: "CursorAfter" means add () with cursor after, "CursorInside" means add () with cursor between.

AutocompleteResult

The result returned by autocomplete.

context: "Expression" | "Statement" | "Property" | "Type" | "Keyword" | "String" | "Unknown"

The autocomplete context at the cursor position.

entries: { [string]: AutocompleteEntry }

Map of completion name to entry details.