Notes for editing .wurst code in the Wurst Standard Library repo. This is
a library, not a map project: most packages here are the wrappers and
abstractions that consuming map projects build on, so API shape, naming, and
backwards compatibility matter more than in app code.
- Prefer simple, maintainable code. Fix root causes; avoid brittle workarounds, duplicated branches, and special-case patches.
- Keep packages focused and below ~500 lines; split by feature, responsibility, or data type.
- Treat the public API as a contract. Avoid breaking signatures, names, or behavior of exported members without good reason.
- When unsure about Wurst syntax or local APIs, inspect nearby working code before guessing.
- Keep tests narrow. Add/update tests for behavior, parsing, compiletime generation, or shared utilities.
- Avoid broad refactors unless they directly reduce risk or complexity for the requested change.
- Fix compiler warnings unless they are intentionally suppressed.
Install dependencies:
grill installAfter Wurst changes, run quiet checks first:
grill typecheck --quiet
grill test --quietIf quiet output reports a failure, rerun narrowly using the failed file, line, package, or test name:
grill typecheck
grill test PackageOrTestNameAvoid full noisy reruns unless there is no target. Done means relevant errors/warnings are fixed or explicitly explained.
Every .wurst file starts with a package; blocks are indentation-based (tabs or 4 spaces, never mixed):
package MyPackage
import Wurstunit
init
print("loaded")
- Use
letunless mutation is needed; prefer obvious type inference. Do not write Jass-styletakes/returns nothing. - Package members are private by default (
publicto export); class members are public by default (private/protectedto restrict). - Every package implicitly imports
WurstunlessNoWurstis imported.import publicre-exports; plainimportdoes not. - Package init is top-to-bottom; imports initialize before importers. Avoid
initlaterunless breaking an unavoidable init cycle. continueskips an iteration;skipis a no-op. Statements end at newline; continue after(,[, operators, or before.,..,),].
Naming: packages/classes UpperCamelCase; tuples/functions/members/locals lowerCamelCase; top-level constants UPPER_SNAKE_CASE.
- Prefer extension functions for readable APIs and the
..cascade operator for setup chains. - Prefer
vec2tuples overlocationhandles unless required. - Prefer polymorphism/data modeling over large
instanceof/typeIdchains. Avoid uncheckedcastTounless proven safe. - Use the highest practical abstraction (e.g. hashmap-style over raw hashtables); drop to lower-level only in critical hot paths.
- Use asset constants from asset packages instead of raw asset path strings.
CreateTrigger()
..registerAnyUnitEvent(EVENT_PLAYER_UNIT_ISSUED_ORDER)
..addCondition(Condition(function cond))
..addAction(function action)
public function unit.getX2() returns real
return GetUnitX(this)
Lambdas need a target type (no standalone inference). Closures capture locals by value; stored/object-backed closures often need cleanup. Lambdas used as code cannot take parameters or capture locals.
new objects generally need destroy. Tuples are value types and must not be destroyed. super(...) must be the first constructor statement; overridden methods require override. Interfaces declare required methods; modules (use) inject reusable members.
Prefer T: generics for performance-sensitive or instance-heavy containers; old T generics erase through integer casts and can share storage.
class Box<T:>
T value
Use compiletime generation for object-editor data. Prefer wrappers and ID generators so IDs stay stable and collision-free; avoid hardcoded new object IDs unless existing code intentionally does so.
let value = compiletime(fac(5))
@compiletime function createSpell()
new AbilityDefinitionMountainKingThunderBolt(SPELL_ID)
..setName("Wurst Bolt")
package MyTests
import Wurstunit
@Test public function multiplicationWorks()
12.assertEquals(3 * 4)
Tests should be small, deterministic, self-contained, and assertion-driven. If quiet output lists a failed package/test, rerun that target before expanding scope.
- spaces around binary operators (
a + b); no space before call parentheses (foo(1)); no spaces around./..; no spaces inside()/[]. - comments use
// Comment; doc comments/** ... */appear in autocomplete. - avoid manual horizontal alignment; prefix intentionally unused variables with
_.
- Wurst code must be inside
package; indentation defines blocks. array.lengthis only the initial length.newobjects and stored closure objects often needdestroy.- Lambdas need a known target type; lambdas used as
codecannot capture locals. - Varargs are limited by Jass's 31-argument limit.
When rules conflict:
- Correctness
- Performance requirements of the code path
- Readability and abstraction level