@eryx/luau/analysis Module

Luau type checker, type inference, autocomplete, and config resolution.

Wraps the native Luau analysis engine to provide full type checking, per-position type inference, module-level type-pack queries, autocompletion, .luaurc config discovery, and require() path resolution.

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

-- Type-check a source string
local result = analysis.check(source, { mode = "strict", annotate = true })
for _, err in result.errors do
    print(err.message, err.location.beginline)
end

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

-- Autocomplete after "t."
local completions = analysis.autocomplete('local t = {x=1}\nt.', 2, 3)
for name, entry in completions.entries do
    print(name, entry.type)
end

Summary

Functions

analysis.typeAt(source: string, line: number, column: number, options: TypeAtOptions?)(string | TypeAtResult)?
analysis.resolve(pathLike: PathLike, requirePath: string?)(string?, string?)
analysis.parseLuaurc(source: string, path: string, overwriteAliases: boolean?, compat: boolean?)LuauConfig

API Reference

Functions

analysis.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 = analysis.check(source, { mode = "strict", annotate = true })
for _, err in result.errors do
    print(err.message, err.location.beginline)
end
if result.annotated then
    print(result.annotated)
end
analysis.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.

analysis.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 = analysis.typeAt(source, 1, 7)  -- position of 'x'
print(ty)  -- "number"
analysis.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

The inferred type as a string, or nil.

analysis.typeofModule

Returns the inferred return type pack for a Luau module.

This runs the type checker for the provided source and then returns the module's exported return pack, i.e. the type-level shape produced by the module's top-level return statement(s).

By default this returns a human-readable string. Pass { detailed = true } to receive a structured type-pack payload.

local source = "return { answer = 42 }"
local moduleType = analysis.typeofModule(source)
print(moduleType) -- "({ answer: number })"
analysis.typeofModule(source: string, options: ModuleTypeOptions?)(string | ModuleTypeResult)?

Parameters

source: string

The Luau module source code.

Module type inference options.

Returns

The inferred module return pack as a string, or nil.

analysis.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 = analysis.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
analysis.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.

analysis.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 = analysis.resolve("C:/project/src/main.luau", "./utils")
print(target)  -- "C:\\project\\src\\utils.luau"
analysis.resolve(pathLike: PathLike, requirePath: string?)(string?, string?)

Parameters

pathLike: PathLike

Absolute path of the source file containing the require.

requirePath: string?

The require string to resolve.

Returns

Absolute path to the resolved file, or nil if not found.

Error message string if resolution failed, otherwise nil.

analysis.getconfig

Returns the active merged Luau config for the current require context.

Lookup follows the same caller-sensitive rules used by require, luau.resolve, and type-checker file resolution, including VFS/module context handling and parent-directory config merging.

When folderPath is provided, lookup starts from that folder path instead of the current caller context.

The returned table includes language mode, lint/type flags, globals, and resolved alias metadata.

local cfg = analysis.getconfig()
if cfg.found then
	print(cfg.languageMode, cfg.configDir)
end
for alias, info in cfg.aliases do
	print(alias, info.qualified)
end
analysis.getconfig(folderPath: PathLike?)LuauConfig

Parameters

folderPath: PathLike?

Optional folder path to start config discovery from.

Returns

Current merged config state.

analysis.parseLuaurc

analysis.parseLuaurc(source: string, path: string, overwriteAliases: boolean?, compat: boolean?)LuauConfig

Types

Location

type Location = ast.Location
Implements: ast.Location

DefinitionSource

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

CheckOptions

type CheckOptions = { mode: ("strict" | "nonstrict" | "nocheck")?, annotate: boolean?, definitions: { DefinitionSource }?, filePath: string? }
mode: ("strict" | "nonstrict" | "nocheck")?

Type-checking strictness. "strict" enables full checking, "nonstrict" (default) is lenient, "nocheck" disables checking.

annotate: boolean?

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

definitions: { DefinitionSource }?

Additional .d.luau-style definition sources to load before type checking.

filePath: string?

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

TypeErrorInfo

type TypeErrorInfo = { message: string, location: Location, category: "TypeError" | "SyntaxError", moduleName: string? }
message: string

Human-readable error message.

location: Location

Source location of the error.

category: "TypeError" | "SyntaxError"

Error category: "TypeError" for type errors, "SyntaxError" for parse errors.

moduleName: string?

Human-readable module path that produced the error, when available.

LintInfo

type LintInfo = { severity: "error" | "warning", code: number, name: string, message: string, location: Location }
severity: "error" | "warning"

Lint severity level.

code: number

Numeric lint code.

name: string

Stable lint code name (e.g. "LocalUnused").

message: string

Human-readable lint message.

location: Location

Source location for the diagnostic.

LintResult

type LintResult = { errors: { LintInfo }, warnings: { LintInfo }, all: { LintInfo } }
errors: { LintInfo }

Lint diagnostics with "error" severity.

warnings: { LintInfo }

Lint diagnostics with "warning" severity.

all: { LintInfo }

All lint diagnostics in source order, regardless of severity.

CheckResult

type CheckResult = { errors: { TypeErrorInfo }, lints: LintResult, annotated: string? }
errors: { TypeErrorInfo }

Type errors found during checking. Empty when there are none.

lints: LintResult

Luau lint diagnostics grouped by severity.

annotated: string?

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

AnalysisTypeDetail

display: string

Human-readable display string for the type.

kind: string

Internal kind tag (e.g. "primitive", "table", "function").

AnalysisTypePackDetail

kind: string

Internal kind tag for the type pack.

TypeAtResult

type TypeAtResult = { display: string, source: "Expression" | "Binding" | "ScopeBinding", type: AnalysisTypeDetail }
display: string

Human-readable type string.

source: "Expression" | "Binding" | "ScopeBinding"

Where the type was found: an expression, a local binding, or a scope binding.

Structured type detail object.

ModuleTypeResult

type ModuleTypeResult = { display: string, source: "Module", typePack: AnalysisTypePackDetail, moduleName: string? }
display: string

Human-readable type pack string.

source: "Module"

Always "Module" for module type results.

Structured type pack detail object.

moduleName: string?

Human-readable module path, when available.

TypeAtOptions

type TypeAtOptions = { mode: ("strict" | "nonstrict" | "nocheck")?, definitions: { DefinitionSource }?, filePath: string?, detailed: boolean? }
mode: ("strict" | "nonstrict" | "nocheck")?

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

definitions: { DefinitionSource }?

Additional type definition sources to load before inference.

filePath: string?

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

detailed: boolean?

If true, return a structured TypeAtResult instead of just a string.

ModuleTypeOptions

type ModuleTypeOptions = { mode: ("strict" | "nonstrict" | "nocheck")?, definitions: { DefinitionSource }?, filePath: string?, detailed: boolean? }
mode: ("strict" | "nonstrict" | "nocheck")?

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

definitions: { DefinitionSource }?

Additional type definition sources to load before inference.

filePath: string?

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

detailed: boolean?

If true, return a structured ModuleTypeResult instead of just a string.

AutocompleteOptions

type AutocompleteOptions = { mode: ("strict" | "nonstrict")?, definitions: { DefinitionSource }?, filePath: string?, detailed: boolean? }
mode: ("strict" | "nonstrict")?

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

definitions: { DefinitionSource }?

Additional type definition sources to load before completion.

filePath: string?

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

detailed: boolean?

If true, include a typeDetail field for each typed completion entry.

AutocompleteEntry

type AutocompleteEntry = { kind: "Property" | "Binding" | "Keyword" | "String" | "Type" | "Module" | "GeneratedFunction" | "RequirePath" | "Unknown", type: string?, typeDetail: AnalysisTypeDetail?, deprecated: boolean?, typeCorrect: ("Correct" | "CorrectFunctionResult")?, insertText: string?, parens: ("CursorAfter" | "CursorInside")? }
kind: "Property" | "Binding" | "Keyword" | "String" | "Type" | "Module" | "GeneratedFunction" | "RequirePath" | "Unknown"

What kind of completion this is.

type: string?

Inferred type of this entry. Absent for keywords and untyped entries.

typeDetail: AnalysisTypeDetail?

Structured type metadata. Only present when options.detailed is true.

deprecated: boolean?

Whether this entry is marked deprecated.

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

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

insertText: string?

Suggested text to insert. Falls back to the completion name when absent.

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

Parentheses hint: "CursorAfter" adds () with cursor after, "CursorInside" adds () with cursor between.

AutocompleteResult

type AutocompleteResult = { context: "Expression" | "Statement" | "Property" | "Type" | "Keyword" | "String" | "Unknown", entries: { [string]: AutocompleteEntry } }
context: "Expression" | "Statement" | "Property" | "Type" | "Keyword" | "String" | "Unknown"

The completion context at the cursor position.

entries: { [string]: AutocompleteEntry }

Map of completion name to its entry details.

LuauConfigAlias

type LuauConfigAlias = { qualified: string, configPath: string, path: string }
qualified: string

Absolute filesystem path resolved from the alias target.

configPath: string

Directory of the config file that defined this alias.

path: string

Raw alias target string as written in the config file.

LuauConfig

type LuauConfig = { found: boolean, configDir: string, languageMode: "strict" | "nonstrict" | "nocheck", enabledLints: number, fatalLints: number, lintErrors: boolean, typeErrors: boolean, globals: { string }, aliases: { [string]: LuauConfigAlias } }
found: boolean

Whether any config file was discovered during lookup.

configDir: string

Directory of the innermost config file that applies to the caller.

languageMode: "strict" | "nonstrict" | "nocheck"

Active language mode from the merged config chain.

enabledLints: number

Bitmask of enabled lint rule codes.

fatalLints: number

Bitmask of lint rule codes treated as fatal.

lintErrors: boolean

Whether lint diagnostics are promoted to errors.

typeErrors: boolean

Whether type diagnostics are promoted to errors.

globals: { string }

Additional global names declared in the config.

aliases: { [string]: LuauConfigAlias }

Resolved alias map from alias key to alias metadata.