Linting
A lint rule that stops one feature from requiring another
Updated
Rogen doesn't check your requires. Because every path names its side and its feature, a linter can catch a require that crosses a boundary before the game runs.
Luau
Lute's linter runs rules written in Luau. The rule require_boundaries.luau reads the sourcemap to learn where each file lands, follows each require to the instance it names, and reports shared code that requires a side, a feature that requires another feature not listed in sharedFeatures, and a require of an instance that no file provides.
-
Install Lute with
rokit add luau-lang/lute, and save the rule:curl -o lints/require_boundaries.luau --create-dirs https://rogen-roblox.vercel.app/lint/require_boundaries.luau -
Add a
.config.luau.featureRootsare the targets of your routes:.config.luau return { lute = { lint = { rulepaths = { "lints" }, ruleconfigs = { require_boundaries = { options = { sourcemap = "sourcemap.json", featureRoots = { "ServerScriptService", "StarterPlayer.StarterPlayerScripts", "ReplicatedStorage.Shared", }, sharedFeatures = { "Util" }, }, }, }, }, }, } -
Write the sourcemap, then lint:
rogen sourcemap -o sourcemap.json lute lint --no-default-lints src
Each crossed boundary is an error, such as feature Inventory requires feature Shop: ServerScriptService.Shop.ShopService, and lute lint exits 1, so a CI job that runs it fails.
roblox-ts
An import names a file, so ESLint's import/no-restricted-paths does the same job: give each feature a zone, and each side a zone that keeps out the other side's folders.