This repository was archived by the owner on Dec 27, 2025. It is now read-only.
sync#2
Open
cheesycod wants to merge 642 commits into
Open
Conversation
…or exactly 1 instance (#864) Previous behavior was to check for at least one instance of the specified substring, which was a bit misleading.
journey to shipping Lute V1: resolves [CLI-192826 ](https://roblox.atlassian.net/browse/CLI-192826)
Updates all existing uses of `0 / 0` in our codebase to `math.nan`, updates the suggested fix during linting, and adds a new lint warning for new uses of `0 / 0`.
I also added `Token` to the union which defines `AstNode`, and changed its `istoken` field to `kind = "token"`, as this plays nicer with how the type system interacts with tagged unions. Overall, I feel that this aligns our AST types to play nicer with the type system.
This is an introductory bit on how to write a simple hello world program in Lute. It also walks through the directory structure required to setup a project, which is useful in subsequent chapters.
A lot of these were code too complex errors (most likely in Normalization based on a previous example I minimized) that I had to silence with any casts.
This tutorial walks a user through some basics of writing programs with Luau: 1. How do you require standard library functionality 2. The difference between luau provided functions and lute provided functions 3. Writing a program that talks to the outside world 4. Input validation 5. Command line arguments in Luau
Normalizing all paths in `tools/check.luau`, fixing issues on Windows Fixes #881 Please add the `infra` tag as I am unable to
Resolves #522 This PR refactors `task.spawn, defer, resume` to share most of their logic for creating the stack and handing control off to newly created threads. The cause of the bug in #522 was that the stack didn't get set up correctly in the parent stack due to `lua_xmove` popping from the top, so the value that got returned was not callable with `coroutine.status` (because it wasn't a thread). The code I've added documents the invariant that I wanted to maintain along with helpers for correctly setting up the stack. I've added tests for the following cases: {task.defer, task.spawn, task.resume } called with { thread | function (except for task.resume, which only takes a thread passed { 0 arguments to resume with, > 0 arguments to resume with }. I also introduced 'deferSelf' for the argumentless version of task.defer that says to immediately yield the current thread.
Consulted with @wmccrthy and existing ones already only use strings. Now that AST nodes are frozen, constructing them is a bit more of a pain, and this simplifies the codemod story.
I've added a subcommand to `lute` to make it easier to start new
projects, similar to `zig init` or `cargo new`. This command is invoked
with:
```
lute new <project-name>
```
and sets up a project with the following structure:
```
project-name/
main.luau
main.test.luau
.config.luau
```
This command sets up the following default project configuration using
the `.config.luau` format, with comments included for convenience.
```luau
return {
lute = {
lint = {
-- Array of globbed strings, representing paths to exempt from linting,
ignores = {},
-- Global values passed to each linting rule,
globals = {},
-- Array of strings from which to load local lint rules,
rulepaths = {},
-- Per rule overrides,
ruleconfigs = {
-- Array of globbed strings, representing paths exempt from this rule,
-- ignores: {string}?,
-- Override a rule's default severity,
-- severity: ("warn" | "error" | "info" | "hint")?,
-- Pass custom options through to a rule,
-- options: { [string]: unknown }?,
-- Disable this rule,
-- off: boolean?,
},
},
},
luau = {
-- Default language mode to use for typechecking,
languagemode = "strict",
-- Aliases for builtin libraries and lint rules
aliases = {
lute = "~/.lute/typedefs/0.1.0/lute",
std = "~/.lute/typedefs/0.1.0/std",
lint = "~/.lute/typedefs/0.1.0/lint",
},
},
}
```
I think this is a good starting point, but I'm happy to take any
suggestions for improvements to this command. I think this is a pretty
sane set of defaults. I'd love to hear if folks have opinions on file
names - `main.luau` isn't a common entry point, so we could do something
like `projectName.luau` and `projectName.test.luau` instead of
`main.luau` and `main.test.luau`.
Changes I've made:
1. Extract some of the common logic between `lute setup` and `lute new`
into a common file.
2. Update `lute test` to search for tests from the current directory,
instead of a dedicated tests/ directory, This is informed by a
discussion I had with @Nicell about Luau engineers colocating tests with
source files.
in the journey to shipping a stable version of Lute, we've decided to rename all types in lute APIs to be `PascalCase` from now on. This PR updates all the usages and type definitions, so will probably be a breaking change for users when merged
**Luau**: Updated from `0.712` to `0.713` **Release Notes:** https://github.com/luau-lang/luau/releases/tag/0.713 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com> Co-authored-by: ariel <arielweiss@roblox.com>
The arrays generated by `luthier.luau`([line](https://github.com/luau-lang/lute/blob/93a18677dca27a989a786d88ef6b631400ff058c/tools/luthier.luau#L298)) are lookup tables for embedded source files. If I understand correctly, they are not used at compile time, so `constexpr` gives no practical benefit over `const`. Using `constexpr` forces the compiler to evaluate `strlen` at compile time for every string literal when constructing `std::string_view`. With many or large embedded files, this can exceed the compiler's limits. This has already happened in PR #863. Switching these arrays to `const` should resolve the issue.
**Lute**: Updated from `0.1.0-nightly.20260306` to `0.1.0-nightly.20260320` **Release Notes:** https://github.com/luau-lang/lute/releases/tag/0.1.0-nightly.20260320 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com> Co-authored-by: ariel <arielweiss@roblox.com>
Adds and uses `assert.that(value: unknown, msg: string?): Failure?` in lieu of places we have `assert.eq(_, true)` We considered naming this `assert.true` and `assert.truthy`, but agreed on `assert.that` since it's the [new (suggested) API for NUnit](https://docs.nunit.org/articles/nunit/writing-tests/assertions/assertion-models/constraint.html)
) We've defined a version string in CMake, which gets turned into a header that C++ commands can consume. However, the code in lute uses a hardcoded version of this string. We need to expose this information to the cli commands so that they can use the correct version when setting up new projects or generating type definition files. This PR sets up a global table called `version` with shape: `{version: string, versionFull : string, versionSuffix : string}` for consumption _exclusively_ by the CLI commands. User code and code loaded by various lute apis in the tests cannot use this global (as those are sandboxed environments).
Fix #643 `TOML` `deserialization` of quoted keys containing dots, which were incorrectly split into separate keys. Adds quote-aware path splitting for `deserialization` and key quoting for `serialization` so round-trips preserve structure. Now we can run this code: ```luau local pp = require("@batteries/pp") local toml = require("@batteries/toml") local content = [=[ [assets.package] assetId = "120786139379662" [images."icon.png"] assetId = "95124518202499" hash = "fac185770cf5e824d4c0a9b59e547df42dc10011c5ad139bfc2c7e1507eef631" ]=] local deserialized = toml.deserialize(content) local serialized = toml.serialize(deserialized) print("\nDeserialized:") print(pp(deserialized)) print("\nSerialized:") print(serialized) ``` and get: ```console Deserialized: { assets = { package = { assetId = "120786139379662", }, }, images = { ["icon.png"] = { assetId = "95124518202499", hash = "fac185770cf5e824d4c0a9b59e547df42dc10011c5ad139bfc2c7e1507eef631", }, }, } Serialized: [assets.package] assetId = "120786139379662" [images."icon.png"] hash = "fac185770cf5e824d4c0a9b59e547df42dc10011c5ad139bfc2c7e1507eef631" assetId = "95124518202499" ```
updating path types and query to PascalCase
Right now, users have to write something like this to get `require` calls([example](https://github.com/luau-lang/lute/blob/e0faf05ee8d274be25c9e686e95c88af42d9589c/examples/query.luau#L7)): ```luau local requireCalls = query .findallfromroot(ast, utils.isExprCall) :filter(function(call) local calledFunc = call.func return calledFunc.tag == "global" and calledFunc.name.text == "require" end) ``` writing their own `helpers`([example](https://github.com/luau-lang/lute/blob/e0faf05ee8d274be25c9e686e95c88af42d9589c/lute/cli/commands/lint/rules/unused_variable.luau#L19)): ```luau local function isRequireCall(expr: syntax.AstExpr) return expr.tag == "call" and expr.func.tag == "global" and expr.func.name.text == "require" end ``` It would be nice if `utils` had `utils.isRequireCall`. Then it would be simplified to: ```luau local requireCalls = query.findallfromroot(ast, utils.isRequireCall) ``` Thanks to @Vighnesh-V for [highlighting](https://github.com/luau-lang/lute/pull/878/changes#r2934146238) the issue and @skberkeley for the `API` [suggestion](https://github.com/luau-lang/lute/pull/878/changes#r2934155678). --------- Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
If you try to run the `process` example, an error throws: ``` 0 Hello, lute! @std/task.luau:60: attempt to index number with 'success' stacktrace: @std/task.luau:60 function awaitall ./examples/process.luau:15 ``` This occurs as we iterate over `tasks`, which is equal to a `table.pack` return value. This means `tasks` has an `n` property and is not entirely array-like. We can use `ipairs` when iterating over `tasks` to avoid the bug
…ed by `@lute/time` (#900) We've had a long-standing split between `@std/time` and `@lute/time` where the former provided an entirely userland implementation of duration, but the latter provided both durations and instants from C++. In the interest of getting the standard library generally into shape and avoiding these confusing duplications (with differences!) between the runtime and the standard library, this PR eliminates the `@std/time` that already exists, and replaces it with one that re-exports the runtime functionality. Making this a proper replacement required both implementing `__mul` and `__div`, as well as fixing a number of smaller bugs that were scattered throughout the runtime implementation of duration.
Adds explicit `jumpToAlias` implementations to support FileVfs handling unprefixed relative paths in configuration files. Earlier, we were able to get away with reusing the same `resetToPath` function for both resetting to a path (such as when initializing FileVfs to point to the project entry point script) and for jumping to aliases. We now need to split these back into two different implementations (although, there is a good amount of logic reused) because the "reset" path requires us to resolve relative paths from the current working directory, but the "jumpToAlias" path requires us to resolve them relative to the .luaurc/.config.luau in which they were defined. This must be done here and not in Luau.Require, as Luau.Require relies on prefixes to determine path type. The absence of a prefix in this case means that the embedder (Lute) must be responsible for path resolution.
…heck` (#862) This PR ensures that `lute check` correctly resolves and uses embedded source code for the `@std`, `@lute`, and `@batteries` namespaces during static analysis. Previously, `lute check` used a basic file resolver that only searched the physical disk. Since Lute's standard library and runtime definitions are embedded directly into the executable, `require` calls to these namespaces would fail to resolve. This caused Luau to treat standard modules as `any`, effectively disabling typechecking for code that relied on Lute's built-in APIs. - **Refactored `resolveRequire`**: Updated the core resolution logic in `lute/luau/src/resolverequire.cpp` to support both physical disk and virtual embedded paths. - **Implemented `readSourceFromVfs`**: Added a utility to retrieve source code directly from Lute's internal memory buffers when an `@` alias is used. - **Updated Resolvers**: Integrated the new resolution and reading logic into `LuteModuleResolver` and `LuteFileResolver`. - **Build System Integration**: Updated `lute/luau/CMakeLists.txt` to link the analysis library against `Lute.Std`, `Lute.Lute`, and `Lute.Batteries`, ensuring the embedded sources are available at compile time. - **Improved Global Registry**: Ensured the `require` function is correctly recognized as a built-in global during the analysis phase. Fixes #773 --------- Co-authored-by: Master Oogway <ActualMasterOogway@users.noreply.github.com> Co-authored-by: Vighnesh Vijay <vvijay@roblox.com>
This PR adds documentation that summarizes a) how to write tests, b) how to run tests, c) how to organize your tests using suites. I've also explicitly called out testing as part of the cool developer tooling we've built, and linked it in the CLI reference. The plan for the Developer Tooling section is to extend it with blurbs about `lute lint`, `lute check`, and `lute compile` (and any others that we add).
) The github web archive url redirects across hosts before serving the download. The http clients drops the Authorization header on cross-host redirects, so the download lands unauthenticated and 404s on private repos. The zipball api endpoint redirects to a short-lived, pre-authorized download URL that doesn't depend on the header surviving the redirect.
Removing the "Watch iterator time taken" debug print in `fs.test.luau` since we're no longer running into hangs or longer timeouts Restoring the previous version of the test with the timeout
Small fixups to the CST: - Renames `CstStatCompoundAssign.operand` to be operator. This was a misnomer before. - Makes `CstExprFunction`'s `generics` and `genericPacks` nonoptional and just empty tables if a function doesn't have generics. - Adds `hasVararg` to `CstExprFunction` in preparation for adding `AstExprFunction`. Currently, vararg presence is indicated by a nilable `...` token, but this field won't be present in `AstExprFunction`. - Adds `isExported` to `CstStatTypeAlias` and `CstStatTypeFunction`. Like `CstExprFunction`, exported-ness is indicated by nilable `export` token which will be absent from their AST counterparts. - Use `Luau::CstTypeGroup` and `Luau::CstExprGroup` which were recently added to correctly encode the position of closing parentheses.
Config type structure incorrectly included `warn` instead of `warning`
…to them (#954) Makes `@lint` and `@transform` generally available to consumers of lute by moving the types they refer to into `std` and modifying `lute setup` to generate chained aliases pointing to them. Also: - Restricts how much of the lute codebase within which they're available by modifying .luaurc files - Updates relevant requires to use `@lint` and `@transform` - Makes the needed change in `clifvs` to support this --------- Co-authored-by: ariel <arielweiss@roblox.com>
Our update luau/lute job started failing with ``` remote: Duplicate header: "Authorization" fatal: unable to access 'https://github.com/luau-lang/lute/': The requested URL returned error: 400 ``` After some Googling, it turns out that `create-pull-request@v7` is incompatible with `actions/checkout@v6`, and that we should use at least [v7.0.9](https://github.com/peter-evans/create-pull-request/releases/tag/v7.0.9) instead. I synced our fork of `create-pull-request` to the upstream, including tags, and bumped the version we use in the create Luau/Lute job. While testing I had to add a base branch argument which I kept since it doesn't hurt.
**Luau**: Updated from `0.725` to `0.726` **Release Notes:** https://github.com/luau-lang/luau/releases/tag/0.726 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: skberkeley <66887530+skberkeley@users.noreply.github.com>
This PR replaces the greedy BFS resolver with backtracking solver supporting multi-major versions # Core loop The solver repeatedly picks the next unresolved slot, selects the highest satisfying candidate, propagates its dependencies as new constraints, and advances. When a slot has zero satisfying candidates, it backtracks up the decision stack trying alternative versions at earlier decision points until it finds a viable path or exhausts all options. ## Behaviors - Backtracking. When no candidate satisfies accumulated constraints, the solver unwinds the decision stack and tries alternatives at earlier decision levels. - Multi-major coexistence. Versions are grouped into compatibility slots (pkg@1, pkg@2, pkg@0.1). Only one version per slot; different slots resolve independently. ^1.0.0 and ^2.0.0 of the same package no longer conflict. - Allow circular dependencies. Resolver successfully resolves circular dependencies and does not report an error - Conflict reporting. Names the conflicting package and lists all unsatisfiable constraints with their sources. ## Optimizations - MRV heuristic. The slot with the fewest viable candidates is resolved first to fail fast and reduce backtracking. --------- Co-authored-by: ariel <arielweiss@roblox.com>
tested in a private channel --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
**Lute**: Updated from `1.0.1-nightly.20260612` to `1.0.1-nightly.20260624` **Release Notes:** https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260624 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: skberkeley <66887530+skberkeley@users.noreply.github.com>
## Summary - Adds dev_dependencies section to loom.config.luau manifest format - Dev dependencies are resolved for the root project only — transitive packages' dev dependencies are ignored (i.e. not included in index information on publish) - Supports --exclude-dev flag on lute pkg install to exclude dev dependencies - No lockfile distinction: Dev and prod deps share the same dependencies map in the lockfile. At install/link time, the manifest - Single solver pass: Dev and prod deps are resolved together so shared transitive deps unify to one version. - Duplicate alias validation: An alias appearing in both dependencies and dev_dependencies is an error at parse time.
@jkelaty-rbx's investigations into networking hangs on Windows (#1178) seem to be pointing to something going wrong with the DNS resolver in curl. I see that v8.20.0 had some changes to the DNS resolver, and v8.21.0 has further ones. It's possible that we're hitting some bugs there, so I'd like to see if we can keep the DNS resolution asynchronous by just upgrading to the latest curl release.
**Lute**: Updated from `1.0.1-nightly.20260624` to `1.0.1-nightly.20260625` **Release Notes:** https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260625 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
**Luau**: Updated from `0.726` to `0.727` **Release Notes:** https://github.com/luau-lang/luau/releases/tag/0.727 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
I've often found myself trying to manually extract the JSON from `lute lint`'s output, which is complicated by the fact that `lute lint` prints errors thrown during parsing and rule execution to stdout. With this, we're forced to manually find the opening JSON brace in order to properly extract diagnostics, which is brittle. This problem is solved with an `output` flag, that writes diagnostics to a provided file path, separating them cleanly from other stdout output.
…1202) Adds the basic ability to set breakpoint to a target file. Introduces a `lute/debug` library that will be contributed to for future debugging features. Notes * hit breakpoints don't actually stop execution currently * debugging files that are loaded from `require` is not yet supported * while the library will eventually be exposed to Luau scripts, right now it is C++ only
**Lute**: Updated from `1.0.1-nightly.20260625` to `1.0.1-nightly.20260701` **Release Notes:** https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260701 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
**Luau**: Updated from `0.727` to `0.728` **Release Notes:** https://github.com/luau-lang/luau/releases/tag/0.728 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
Summary - Make lute pkg install read the existing loom.lock.luau before resolving. If the lockfile satisfies the current manifest and path dependencies haven't changed, skip resolution entirely. - When re-resolution is needed, the solver prefers previously-locked registry versions to minimize version churn - Add --locked flag that errors if the lockfile is missing or doesn't match the manifest
The CLI battery's `help` method was showing empty parens if an option didn't have any aliases. I added a check not to emit it if there is no alias, and snapshot tests documenting it.
Title is self-explanatory. I feel like I've ended up implementing bespoke versions of these quite often in side projects, so I think they'd be useful to have. Open to name-change ideas --------- Co-authored-by: ariel <aweiss@hey.com> Co-authored-by: ariel <arielweiss@roblox.com>
Updates all the lint messages that begin with "XYZ detected". Slightly changes some wording to read better. --------- Co-authored-by: Sora Kanosue <kanosuesora@gmail.com> Co-authored-by: ariel <aweiss@hey.com>
Adds a non-default lint to flag on reassignment of parameters in functions.
…1181) As part of introducing AST types to Lute, we would like AST types to subtype structurally against CST types. However, the AST returned by the Luau parser provides no way to distinguish between table type properties that are bracketed and those that aren't. This means that the eventual Lute AST will have a single type for bracketed and non-bracketed table type properties, so the Lute CST should too.
Fixes #1172. On Windows, `io.input()` returned the line with its trailing terminator still attached. That meant a path read from input would fail in `fs.open()` with "no such file or directory" even when the file was right there. The cause is that `io.input()` just returned `io.read()` directly. `io.read()` is the raw read primitive, so it returns the bytes from stdin as-is, including the line terminator (`\r\n` on Windows, `\n` on Unix). I fixed it in `io.input()` instead of `io.read()` so the raw read keeps returning exactly what it read, while the line-oriented helper hands back a clean string you can pass straight to filesystem APIs. It strips a single trailing terminator and leaves interior and leading whitespace alone. I added `IoInputSuite` to `tests/std/io.test.luau`. Each case pipes a value into a small script so the platform's own terminator gets appended (`\r\n` on Windows, which is the case in #1172, and `\n` on Unix), then checks that `io.input()` returns the clean string. The cases cover a basic value, a path with separators, and preserving interior whitespace. I verified this locally on Windows with the MSVC (VS 2022) build. The new suite passes and the rest of the test suite is unaffected.
**Lute**: Updated from `1.0.1-nightly.20260701` to `1.0.1-nightly.20260710` **Release Notes:** https://github.com/luau-lang/lute/releases/tag/v1.0.1-nightly.20260710 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
**Luau**: Updated from `0.728` to `0.729` **Release Notes:** https://github.com/luau-lang/luau/releases/tag/0.729 --- *This PR was automatically created by the [Update Luau workflow](https://github.com/luau-lang/lute/actions/workflows/update-prs.yml)* Co-authored-by: aatxe <744293+aatxe@users.noreply.github.com>
- Add overrides support to loom, allowing projects to force specific
versions or sources for any transitive dependency (similar to npm/pnpm
overrides)
- Two override modes: version pin (force an exact registry version) and
source redirect (replace a registry package with a local path or github
source)
- Lockfile version bumps to 4 only when overrides are present; projects
without overrides stay on version 3
Overrides are declared at the project root in loom.config.luau:
```
return {
package = { ... },
overrides = {
-- Pin a transitive dependency to an exact version
citrus = { sourceKind = "registry", source = "citrus", version = "3.0.0" },
-- Or redirect to a local fork
citrus = { sourceKind = "path", source = "./citrus-fork" },
},
}
```
The resolver removes conflicting constraints for overridden packages,
builds a modified universe respecting the pins, and stitches
source-redirected packages back into the dependency graph after solving.
The lockfile records a fingerprint of
active overrides so changes trigger re-resolution.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.