-
Notifications
You must be signed in to change notification settings - Fork 196
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(world): add namespaceLabel to system config #3057
Changes from all commits
11a3d2d
b9415f9
8e319b3
d5d63fc
65ecfb1
543dbb0
6de0cef
1e96f01
209521e
4e6e0f7
9e46c16
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"@latticexyz/config": patch | ||
"@latticexyz/store": patch | ||
--- | ||
|
||
Fixed a few type issues with `namespaceLabel` in tables and added/clarified TSDoc for config input/output objects. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
"@latticexyz/cli": patch | ||
"@latticexyz/world": patch | ||
--- | ||
|
||
Add a strongly typed `namespaceLabel` to the system config output. | ||
It corresponds to the `label` of the namespace the system belongs to and can't be set manually. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,13 +24,39 @@ export type Schema = { | |
}; | ||
|
||
export type Table = { | ||
/** | ||
* Human-readable label for this table. Used as config keys, library names, and filenames. | ||
* Labels are not length constrained like resource names, but special characters should be avoided to be compatible with the filesystem, Solidity compiler, etc. | ||
*/ | ||
readonly label: string; | ||
/** | ||
* Human-readable label for this table's namespace. Used for namespace config keys and directory names. | ||
*/ | ||
readonly namespaceLabel: string; | ||
/** | ||
* Table type used in table's resource ID and determines how storage and events are used by this table. | ||
*/ | ||
readonly type: satisfy<ResourceType, "table" | "offchainTable">; | ||
/** | ||
* Table namespace used in table's resource ID and determines access control. | ||
*/ | ||
readonly namespace: string; | ||
readonly namespaceLabel: string; | ||
/** | ||
* Table name used in table's resource ID. | ||
*/ | ||
readonly name: string; | ||
/** | ||
* Table's resource ID. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like the property descriptions. Just curious is there a reason why it uses single-line comments in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that file is internal, so not as important to have good docs and those are mostly internal notes the tsdoc here will get included as part of your IDE tooltips and maybe eventually generated into documentation |
||
*/ | ||
readonly tableId: Hex; | ||
/** | ||
* Schema definition for this table's records. | ||
*/ | ||
readonly schema: Schema; | ||
/** | ||
* Primary key for records of this table. An array of zero or more schema field names. | ||
* Using an empty array acts like a singleton, where only one record can exist for this table. | ||
*/ | ||
readonly key: readonly string[]; | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,9 +24,9 @@ export const TABLE_DEPLOY_DEFAULTS = { | |
export type TABLE_DEPLOY_DEFAULTS = typeof TABLE_DEPLOY_DEFAULTS; | ||
|
||
export const TABLE_DEFAULTS = { | ||
namespace: "", | ||
namespaceLabel: "", | ||
type: "table", | ||
Comment on lines
+27
to
28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just wonder why only these two properties are used as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see now, |
||
} as const satisfies Pick<TableInput, "namespace" | "type">; | ||
} as const satisfies Pick<TableInput, "namespaceLabel" | "type">; | ||
|
||
export type TABLE_DEFAULTS = typeof TABLE_DEFAULTS; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,11 +18,17 @@ export type TableDeployInput = Partial<TableDeploy>; | |
|
||
export type TableInput = { | ||
/** | ||
* Human-readable table label. Used as config keys, table library names, and filenames. | ||
* Human-readable label for this table. Used as config keys, library names, and filenames. | ||
* Labels are not length constrained like resource names, but special characters should be avoided to be compatible with the filesystem, Solidity compiler, etc. | ||
*/ | ||
readonly label: string; | ||
/** | ||
* Human-readable label for this table's namespace. Used for namespace config keys and directory names. | ||
* Defaults to the nearest namespace in the config or root namespace if not set. | ||
*/ | ||
readonly namespaceLabel?: string; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably too big of a change now and not worth the effort but wonder if defining namespace as its own type would make sense e.g: type NamespaceInput = {
id: string;
label?: string;
}
type Table Input = {
namespace?: NamespaceInput;
// ...
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this would be a breaking change unfortunately
|
||
/** | ||
* Table type used in table's resource ID and determines how storage and events are used by this table. | ||
* Defaults to `table` if not set. | ||
*/ | ||
readonly type?: "table" | "offchainTable"; | ||
|
@@ -31,17 +37,19 @@ export type TableInput = { | |
* Defaults to the nearest namespace in the config or root namespace if not set. | ||
*/ | ||
readonly namespace?: string; | ||
/** | ||
* Human-readable namespace label. | ||
* Defaults to the nearest namespace in the config or root namespace if not set. | ||
*/ | ||
readonly namespaceLabel?: string; | ||
/** | ||
* Table name used in table's resource ID. | ||
* Defaults to the first 16 characters of `label` if not set. | ||
*/ | ||
readonly name?: string; | ||
/** | ||
* Schema definition for this table's records. | ||
*/ | ||
readonly schema: SchemaInput; | ||
/** | ||
* Primary key for records of this table. An array of zero or more schema field names. | ||
* Using an empty array acts like a singleton, where only one record can exist for this table. | ||
*/ | ||
readonly key: readonly string[]; | ||
readonly codegen?: TableCodegenInput; | ||
readonly deploy?: TableDeployInput; | ||
|
@@ -52,7 +60,7 @@ export type TableShorthandInput = SchemaInput | string; | |
export type TablesInput = { | ||
// remove label and namespace as these are set contextually | ||
// and allow defining a table using shorthand | ||
readonly [label: string]: Omit<TableInput, "label" | "namespace" | "namespaceLabel"> | TableShorthandInput; | ||
readonly [label: string]: Omit<TableInput, "label" | "namespaceLabel" | "namespace"> | TableShorthandInput; | ||
}; | ||
|
||
export type CodegenInput = Partial<Codegen>; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -47,7 +47,7 @@ export type ValidateTableOptions = { inStoreContext: boolean }; | |
|
||
export type requiredTableKey<inStoreContext extends boolean> = Exclude< | ||
requiredKeyOf<TableInput>, | ||
inStoreContext extends true ? "label" | "namespace" : "" | ||
inStoreContext extends true ? "label" | "namespaceLabel" | "namespace" : never | ||
>; | ||
|
||
export type validateTable< | ||
|
@@ -59,9 +59,9 @@ export type validateTable< | |
? validateKeys<getStaticAbiTypeKeys<conform<get<input, "schema">, SchemaInput>, scope>, get<input, key>> | ||
: key extends "schema" | ||
? validateSchema<get<input, key>, scope> | ||
: key extends "label" | "namespace" | ||
: key extends "label" | "namespaceLabel" | "namespace" | ||
? options["inStoreContext"] extends true | ||
? ErrorMessage<"Overrides of `label` and `namespace` are not allowed for tables in this context"> | ||
? ErrorMessage<"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context"> | ||
: key extends keyof input | ||
? narrow<input[key]> | ||
: never | ||
|
@@ -115,8 +115,13 @@ export function validateTable<input, scope extends Scope = AbiTypeScope>( | |
throw new Error(`Table \`name\` must fit into a \`bytes16\`, but "${input.name}" is too long.`); | ||
} | ||
|
||
if (options.inStoreContext && (hasOwnKey(input, "label") || hasOwnKey(input, "namespace"))) { | ||
throw new Error("Overrides of `label` and `namespace` are not allowed for tables in this context."); | ||
if ( | ||
options.inStoreContext && | ||
(hasOwnKey(input, "label") || hasOwnKey(input, "namespaceLabel") || hasOwnKey(input, "namespace")) | ||
) { | ||
throw new Error( | ||
"Overrides of `label`, `namespaceLabel`, and `namespace` are not allowed for tables in this context.", | ||
); | ||
} | ||
} | ||
|
||
|
@@ -151,10 +156,10 @@ export function resolveTableCodegen<input extends TableInput>(input: input): res | |
export type resolveTable<input, scope extends Scope = Scope> = input extends TableInput | ||
? { | ||
readonly label: input["label"]; | ||
readonly type: undefined extends input["type"] ? typeof TABLE_DEFAULTS.type : input["type"]; | ||
readonly namespaceLabel: undefined extends input["namespaceLabel"] | ||
? typeof TABLE_DEFAULTS.namespace | ||
? typeof TABLE_DEFAULTS.namespaceLabel | ||
: input["namespaceLabel"]; | ||
readonly type: undefined extends input["type"] ? typeof TABLE_DEFAULTS.type : input["type"]; | ||
readonly namespace: string; | ||
readonly name: string; | ||
readonly tableId: Hex; | ||
|
@@ -171,8 +176,10 @@ export function resolveTable<input extends TableInput, scope extends Scope = Abi | |
input: input, | ||
scope: scope = AbiTypeScope as unknown as scope, | ||
): resolveTable<input, scope> { | ||
const namespaceLabel = input.namespaceLabel ?? TABLE_DEFAULTS.namespace; | ||
const namespaceLabel = input.namespaceLabel ?? TABLE_DEFAULTS.namespaceLabel; | ||
// validate ensures this is length constrained | ||
const namespace = input.namespace ?? namespaceLabel; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find it slightly odd that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
const label = input.label; | ||
const name = input.name ?? label.slice(0, 16); | ||
const type = input.type ?? TABLE_DEFAULTS.type; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
export { setup, cleanup as teardown } from "@ark/attest"; | ||
import { setup } from "@ark/attest"; | ||
|
||
export default () => setup({ updateSnapshots: true }); |
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.
Wonder if these special characters should be specified here? I realize "special character" has a pretty universal meaning but it can still be unclear if "-" is allowed, for example. Having said that, curious if there are any other constraints like can a label start with number, etc?
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 don't know the range of special characters in various OS's so I'll leave it to user discretion
if a label has a non-fs compatible character, they'll know quickly because tablegen/worldgen will fail to write files named with those labels