I would greatly appreciate any contributions and feedback, including issues, PRs, or even messages on Discord saying "hey can you add this to seal"!
A library is a good candidate for @extra if:
- It's mostly implemented or implementable in Luau with or without seal.
- Users may want to customize it (@std libs can't be customized at runtime but @extra can)
- Users may want to run it directly as a CLI program.
To add a library to @extra, just add it, make sure it works, and open a pull request.
A library is a good candidate for @std if:
- There's a good chance everyone would want/need it
- It's mostly implemented in Rust, and would be difficult or impossible to translate to other Luau runtimes
- It'd be impossible to implement in user code.
- There's a Rust crate for it that we could add easily and isn't async and won't massively increase seal's executable binary size.
- We'll need to rely on it internally in seal (this is why
@std/semveris in the standard library and@extra/ttisn't)
I recommend installing the seal precommit hook by running seal ./src/scripts/precommit.luau. This will automatically regen the reference docs and update the README.md every time you make a commit.
- Write API and documentation in typedefs, according to the existing format. We start with typedefs so we can generate signature constants and run the reference script. After you finish writing inline documentation, regenerate markdown documentation by running
seal ./docs/docscripts/reference.luau. Generated docs aren't going to be perfect, we'll fix them later. - Run
./src/scripts/signature_generation/generate.luauto create new signature constants from your typedefs. - Implement the code in Rust or Luau in
./src/std_*libname*. We usestd_*prefixes to avoid name clashes with the Rust standard library. - Use the newest/most recently refactored existing libraries (especially
@std/process,@std/fs, and@std/thread) as templates for your Rust code structure. - Rust error handling:
- Don't use
.unwrapor.expectin Rust code unless you're 99-100% sure it won't panic. - Every error case reachable by user code should be covered by a
wrap_err!, with an ideally handcrafted error message and the luau-side function_name in front. - If there's an invariant that if reached means there's actually a bug, use an explicit
panic!orunreachable!. - Users should not see the word "Lua" in an error message (this comes from directly bubbling up
mluauerrors).
- Don't use
- Casing conventions bikeshedding
- Top level library functions should be luaucase and short. If they end up ugly/unreadable then either rename them, put them in a sublib, or make them snake_case. New APIs should match the existing APIs, for example functions that purposely try not to wrap_err! should be named
libname.try_*in snake_case. - Try to keep the names short and sweet so we don't have to combine words in luaucase: like
json.rawinstead ofjson.encoderaw. - Library properties should be snake_case unless you can keep them to one word.
- Object-like method names should be snake_case unless they match or partially match a luaucase api.
- Top level library functions should be luaucase and short. If they end up ugly/unreadable then either rename them, put them in a sublib, or make them snake_case. New APIs should match the existing APIs, for example functions that purposely try not to wrap_err! should be named
- please don't run a formatter over the whole codebase.
- I don't mind if
wrap_err!s go off the RHS of the page if that means vertical space is better used for code. - On the other hand, let's try to keep non-wrap_err! code and comments to 85-110 colwidth?
- I don't mind if
- Inline documentation goes in
./.seal/typedefs/std/*.- For documentation, try to stick with the newer docs headers like seen in the
@std/processAPI docs. - No Moonwave
@attributes, they make code less readable and we don't use Moonwave.
- For documentation, try to stick with the newer docs headers like seen in the
- Register the library in
./src/require/mod.rsand./.seal/typedefs/std/init.luauin 3 places:- The Big Beautiful Table (BBT) in
./src/require/mod.rs, which handles when the library is required directly (@std/mylib) - the Small Beautiful Table in
./src/require/mod.rs, which handles when the entire@stdis required at once. - in
./.seal/typedefs/std/init.luauto providerequiresupport when the entire@stdis required at once.
- The Big Beautiful Table (BBT) in
- Add tests in
./tests/luau/std/libname/*or./tests/luau/std/libname.luau.