-
Notifications
You must be signed in to change notification settings - Fork 188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(cli): refactor tablegen and add more advanced features #437
Conversation
packages/store/src/tables/Route.sol
Outdated
struct Route { | ||
address addr; | ||
bytes4 selector; | ||
uint8 executionMode; | ||
} | ||
|
||
library Route_ { | ||
library RouteTable { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I missed the naming conversation but did ya'll consider RouteStore
as a name option?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'll be confusing when a table that writes to Store
is also called Store
. We already have World
, which is Store
. Wouldn't want everything to be a Store
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My thought is that users will mostly be interacting with these autogen files, not the underlying ones (i.e. Store). But I understand if this creates confusion on our end.
"Table" just feels like an overloaded term. Folks with SQL experience will have preconceived notions about what it does/should do, and folks without SQL experience may be a little confused by it the term "table". We have a chance to shed this here.
(All that said, I don't feel super strongly, just wanting to stress test our name choices as it'll be hard to change later)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the SQL analogy (I have SQL experience, although I'm obviously not a great example).
We even have hooks/indexers. And a planned postgres integration. In solidity it's just a limited key/value store of course.
But I'm starting to think of how foreign keys would fit in here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to circle back on this: we all chatted in discord and ended up with removing the suffix altogether on libraries, and adding "data" suffix to structs, allowing users to choose their naming scheme
} | ||
export class NotInsideProjectError extends Error { | ||
name = "NotInsideProjectError"; | ||
message = "You are not inside a MUD project"; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
small thing: I would probably add
export class MudCliError extends Error {}
then
export class NotInsideProjectError extends MudCliError {
...
}
just so downstream folks can easily catch all CLI errors in one conditional
(I am thinking we might eventually have a centralized MudError
but a cli-specific one in the meantime is still handy)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, I'm not sure how these interact with Zod error classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just so downstream folks can easily catch all CLI errors in one conditional
There aren't really supposed to be downstream folks rn, the renderer is cli-only currently, and everything is handled by logError
.
When I do make it standalone that sounds like a good thing to add though. Zod errors can probably be wrapped to also be identifiable somehow
console.log(chalk.yellow(`Error during output formatting: ${message}`)); | ||
return content; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not blocking but we can also call out to forge fmt
and use the project's local foundry.toml
(in the same way that we use it for src
etc. dirs) for formatting config
cat File.sol | forge fmt --raw -
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method isn't really file-related, it's used at the render stage, so it's not aware of the filesystem at all, and when renderer is standalone it could even be used without files at all.
Also since it's all js using prettier is just more convenient.
I think if people want custom formatting they can do their own fmt
, this func is just for new mudders who don't have that set up yet, so they don't see super ugly files
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another very impressive PR! Just a couple smaller nits / questions
|
||
const FullTable = z | ||
.object({ | ||
route: OrdinaryRoute.default("/tables"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like this can't be empty correct? I think we should allow registering tables at the root level of a World (eg. /RootTable
), which would require passing the empty root route here, however this wouldn't work as nicely with using the same route as output path for the generated file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, it's the one case that messes up route->folder.
Do we really need root tables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might be useful, if only to allow users to minimize route lengths. Just feels like we shouldn't prevent a setup that uses tables at the root. We could even just put the auto-generated file into the "base directory" (right now foundry's src
config - but we could add a config field to allow overriding the table base directory).
Not blocking for this PR though, let's discuss and change in a follow up if needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just allowing root routes is easy actually - replace validateRoute with validateBaseRoute in zod schema.
Having an extra config option for baseDirectory is also pretty trivial, although baseRoute+baseDirectory feels like a bit much.
Btw I don't bundle systems and tables together here. Systems are writers, and for systems that have access to everything (i.e. use delegatecall) I agree root is the best place.
Problems I have with root tables:
- Encourages flat setup. It's intuitive for small projects, but projects that need MUD aren't really small imo. No root simplifies the switch from "/tables" to "/skills", "/items" etc.
- Tables no longer have access groups. If you want to give access to several at once, you'd give root route. You shouldn't give out root access.
- Unlike systems, root tables don't signify a root permission. They don't have to exist
Rather than root routes I think it'd be more useful to consider shorthands/config reorgs for setting the same route for multiple tables/systems
My current folders (they would more or less become routes in v2, and this sorta setup is what I'm optimizing for):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other hand, if route and folder path are completely separated, it feels like my problems with root tables kinda evaporate. And maybe we should have route: ""
by default, but path: "/tables"
by default, and have no significant relationship between the 2
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Encourages flat setup. It's intuitive for small projects, but projects that need MUD aren't really small imo. No root simplifies the switch from "/tables" to "/skills", "/items" etc.
I think with v2 there are a lot of good reasons for small projects to use MUD too (eg default compatibility with indexers and network stack), so my preference would be to make all project configurations possible, including simple/flat ones.
I still agree with making more complex / nested project structures like your example easy to achieve too. After thinking about it more I think separating on-chan route
and filesystem outputPath
like you proposed makes the most sense, because it allows for any configuration of routes and filesystem structure. This also makes the id computation consistent with systems, where it's always keccak256(baseRoute/route/SystemName)
with route
being ""
by default. (Also for systems route
is independent from the file system path too because they are not auto-generated/)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While working on the system deploy script I am realizing it would be most intuitive if route
allows users to completely override the route, without a default /SystemName
or /TableName
appended at the end. So basically if route
is omitted the default route should be baseRoute/SystemOrTableName
, while if the route key is present it should be baseRoute/route
. Otherwise we might prevent some configurations where the route has to be some explicit value that's not the contract name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While working on the system deploy script I am realizing it would be most intuitive if
route
allows users to completely override the route, without a default/SystemName
or/TableName
appended at the end. So basically ifroute
is omitted the default route should bebaseRoute/SystemOrTableName
, while if the route key is present it should bebaseRoute/route
. Otherwise we might prevent some configurations where the route has to be some explicit value that's not the contract name.
Sounds good! I can change that in store config in one of the upcoming PRs
Co-authored-by: alvarius <[email protected]>
Co-authored-by: alvarius <[email protected]>
Co-authored-by: alvarius <[email protected]>
Pretty much rewrote the whole thing.
StoreUserConfig is a good summary of what's going on.
All tables in
store
are now autogenerated, check them out.I didn't want to mess with
world
too much, so made justRouteAccess
autogenerated (it's interesting because it has 2 keys with different types, and usesstoreArgument
flag)#438 has a summary