larvaedocs
GitHub

Rules

Thirty six rules shipped, twenty seven under darklua's names and nine larvae only

updated Aug 16, 20266 min read

Rules are the transforms larvae applies to each output file. They live in the [rules] table of larvae.toml.

There are 36 rules: 9 that only larvae has, and 27 that match darklua name for name, so a .darklua.json rule list ports over unchanged. Every rule is off until the config turns it on. A rule takes true, or a table with the options its row names.

An unknown rule name is an error, never ignored, which is the policy the rest of configuration follows. A rule list that loads is a rule list that ran.

toml
[rules]
remove_types = true
compute_expression = true
const_requires = true

larvae's own rules

Nine rules under larvae's own names. Seven have no darklua equivalent at all; remove_comments and append_text_comment sit here rather than in the parity set because larvae's defaults differ from darklua's.

Rule Value What it does
const_requires bool Turn local X = require(...) into const X = require(...). Skips multi bindings and annotated locals.
remove_comments bool or table Remove comments. true, or a table with except regexes for comments to keep. Defaults to ["^--!"] so Luau directives survive; set [] to match darklua.
append_text_comment table Insert a comment at the start or end of every file. Exactly one of text (the literal comment) or file (read the comment from this path), and location = "start" (default) or "end".
add_luau_directive string Write a Luau directive at the top of every file, ex: "strict" emits --!strict. An existing directive of the same family is left alone.
remove_calls list or table Remove statement position calls to the named functions, ex: print or debug.profilebegin. Names may be dotted paths; method calls and computed callees are never matched, and a call whose value is used is left alone.
use_get_service bool Rewrite game.Players into game:GetService("Players") for the known services, which keeps working when a service is renamed or not created yet. A local named game defeats it.
dedupe_requires bool Top level local X = require(...) statements that resolve to the same module collapse, the later ones become aliases of the first. Skips const, annotated and multi binding locals.
inject_module_path string Name of a constant defined at the top of every file that references it, holding that file's DataModel path, ex: "@game/ReplicatedStorage/shared/util". Warns when no mount covers the file.
freeze_module bool Wrap a module's returned table in table.freeze, only when nothing can write to it, so field writes, rebinds and metatable patterns turn the rule off for that file.

In particular remove_comments keeps --! directives by default, because removing a Luau directive silently changes how the code runs. Set except = [] to match darklua.

toml
[rules]
add_luau_directive = "strict"
remove_calls = ["print", "warn", "debug.profilebegin"]

[rules.append_text_comment]
text = "generated by larvae, do not edit"
location = "start"

The darklua parity set

All 27 run under darklua's own names, so a ported config behaves the way the reader expects.

Rule Value What it does
compute_expression bool Fold constant expressions to their value. Only folds when the result prints back exactly, so fractions, values past exact double range and strings holding escapes are left alone.
convert_function_to_assignment bool Rewrite function foo() into foo = function(), and function o:m() into o.m = function(self). Attributed functions are left alone.
convert_index_to_field bool Rewrite t["field"] into t.field, and the same for table constructor keys, when the literal spells a valid name that is not a reserved word.
convert_local_function_to_assign bool Rewrite local function f() into local f = function(), only when the body never mentions f, since the local form is in scope inside itself.
convert_luau_number bool Rewrite binary literals like 0b1010 as hex and strip digit separators, both being Luau only syntax.
convert_square_root_call bool Rewrite math.sqrt(x) into (x ^ 0.5). The result is always parenthesised so it survives being the base of another power.
filter_after_early_return bool Delete the statements after a do ... return ... end block, which can never run. Stops if a type alias is among them, since an exported one is visible outside the block.
group_local_assignment bool Merge a run of adjacent local declarations into one. Conservative, it stops at a call, a dependency between them, an annotation, a comment or anything but whitespace in between.
make_assignment_local bool Turn a const declaration back into a local one, the inverse of const_requires, for output that has to stay plain Lua.
remove_assertions bool or table Remove assert(...) statements.
remove_attribute bool or table Strip function attributes, ex: @native. true removes every one, or a table with match regexes tested against the attribute name without its @.
remove_compound_assignment bool Expand x += 1 into x = x + 1 for every compound operator. Targets that would have to run code twice, ex: a computed key holding a call, are left alone.
remove_continue bool Rewrite a loop containing continue into the repeat ... until true form with continue spelled break. Loops that also break at the same level, and repeat loops whose condition can read body locals, are left alone.
remove_debug_profiling bool or table Remove debug.profilebegin and debug.profileend statements.
remove_empty_do bool Drop do end blocks that contain nothing. A lone semicolon counts as content. Nested empties shed one layer per run.
remove_floor_division bool Rewrite a // b into math.floor(a / b), and a //= b into a = math.floor(a / b).
remove_function_call_parens bool Rewrite f("x") into f"x" and f({}) into f{} when a call takes exactly one string or table argument.
remove_if_expression bool Rewrite if c then a else b into c and a or b. Only applied when the then value can never be false or nil, otherwise the and/or form would not be equivalent and the expression is left alone.
remove_interpolated_string bool or table Rewrite backtick strings into string.format calls. true, or a table with strategy: "string" wraps each value in tostring and formats with %s, "tostring" uses Luau's %*. Multi line and nested backtick strings are left alone.
remove_method_call bool Rewrite obj:m(x) into obj.m(obj, x). Only for a plain identifier receiver, anything else would be evaluated twice.
remove_method_definition bool Rewrite function C:m() into function C.m(self), making the implicit self parameter explicit.
remove_nil_declaration bool Rewrite local x = nil into local x and drop trailing nil values from multi bindings. Skips const, which must keep a value.
remove_types bool Strip every type annotation: bindings, parameters, return types, generic lists, type aliases and the tail of a :: assertion.
remove_unused_if_branch bool Prune if branches whose condition is a known constant. A branch that always runs is unwrapped, or becomes a do block when it declares locals so their scope is preserved.
remove_unused_variable bool or table Remove unused locals and local functions.
remove_unused_while bool Delete a while loop whose condition is a constant false.
rename_variables bool or table Rename locals and params to short names.

remove_unused_variable and rename_variables also accept apply_to and skip globs in their table form, which limit the rule to files:

toml
[rules]
rename_variables = { apply_to = ["src/**"], skip = ["src/vendor/**"] }

darklua rules that are not rules here

Three darklua names are deliberately not larvae rules, because larvae already does each job elsewhere. Naming one in [rules] is an error, and the error points at the larvae way to do the same thing.

darklua rule where it lives in larvae
convert_require the [requires] table
inject_global_value [defines]
remove_spaces generator = "dense"

When rules run

[process] run_order (default 1) positions larvae's own rules relative to worms, so a worm saying "before" or "after" has something to be relative to. See configuration.

Rules that come from a worm

A worm can ship rules of its own. They are switched on under [worms.<name>].rules, never in [rules]:

toml
[worms.markup]
repo = "someone/markup-worm"
version = "2.1.0"
rules = { tidy = true }

[rules] is larvae's own table and is typed against the names on this page, so a worm's rule cannot shadow a builtin. Namespaced under its worm, a worm rule can share a name with one of larvae's and mean something different. Switching on a rule a worm does not declare is an error naming it. See using worms.