@latticexyz/cli 1.41.1-alpha.41 → 1.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/chunk-4STWSICF.js +26139 -0
  2. package/dist/chunk-6V563IAZ.js +283 -0
  3. package/dist/chunk-7KQJTK2K.js +3842 -0
  4. package/dist/{chunk-ATAWDHWC.js → chunk-FPG73MVN.js} +5 -1
  5. package/dist/{chunk-O6HOO6WA.js → chunk-L4YLJHLJ.js} +1 -9
  6. package/dist/{chunk-J4DJQNIC.js → chunk-SKNB74MT.js} +129 -568
  7. package/dist/chunk-VQTZJIFF.js +353 -0
  8. package/dist/chunk-WZFXLDPK.js +761 -0
  9. package/dist/index.d.ts +2 -3
  10. package/dist/index.js +0 -21
  11. package/dist/mud.d.ts +1 -1
  12. package/dist/mud.js +326 -4452
  13. package/dist/mud2.d.ts +1 -0
  14. package/dist/mud2.js +25 -0
  15. package/dist/render-solidity/index.d.ts +171 -0
  16. package/dist/render-solidity/index.js +49 -0
  17. package/dist/render-ts/index.d.ts +26 -0
  18. package/dist/render-ts/index.js +14 -0
  19. package/dist/utils/deprecated/index.js +3 -3
  20. package/dist/utils/index.d.ts +13 -18
  21. package/dist/utils/index.js +14 -16
  22. package/package.json +21 -21
  23. package/src/commands/deploy-v2.ts +80 -64
  24. package/src/commands/deprecated/index.ts +22 -0
  25. package/src/commands/deprecated/test.ts +1 -1
  26. package/src/commands/gas-report.ts +54 -55
  27. package/src/commands/index.ts +6 -17
  28. package/src/commands/set-version.ts +172 -0
  29. package/src/commands/tablegen.ts +5 -5
  30. package/src/commands/test-v2.ts +71 -0
  31. package/src/commands/tsgen.ts +33 -0
  32. package/src/commands/worldgen.ts +5 -4
  33. package/src/contracts/BulkUpload.sol +13 -20
  34. package/src/contracts/Deploy.sol +3 -3
  35. package/src/contracts/LibDeploy.sol +1 -1
  36. package/src/contracts/LibDeployStub.sol +1 -1
  37. package/src/index.ts +1 -15
  38. package/src/mud.ts +4 -3
  39. package/src/mud2.ts +29 -0
  40. package/src/render-solidity/common.ts +4 -4
  41. package/src/render-solidity/field.ts +25 -2
  42. package/src/render-solidity/record.ts +14 -10
  43. package/src/render-solidity/renderSystemInterface.ts +4 -4
  44. package/src/render-solidity/renderTableIndex.ts +15 -0
  45. package/src/render-solidity/renderTypesFromConfig.ts +1 -1
  46. package/src/render-solidity/tableOptions.ts +2 -2
  47. package/src/render-solidity/tablegen.ts +15 -13
  48. package/src/render-solidity/types.ts +2 -1
  49. package/src/render-solidity/userType.ts +1 -2
  50. package/src/render-solidity/worldgen.ts +8 -9
  51. package/src/render-ts/index.ts +5 -0
  52. package/src/render-ts/recsV1TableOptions.ts +39 -0
  53. package/src/render-ts/renderRecsV1Tables.ts +31 -0
  54. package/src/render-ts/schemaTypesToRecsTypeStrings.ts +202 -0
  55. package/src/render-ts/tsgen.ts +12 -0
  56. package/src/render-ts/types.ts +13 -0
  57. package/src/utils/contractToInterface.ts +5 -3
  58. package/src/utils/deploy-v2.ts +90 -84
  59. package/src/utils/errors.ts +3 -34
  60. package/src/utils/format.ts +6 -0
  61. package/src/utils/formatAndWrite.ts +11 -2
  62. package/src/utils/foundry.ts +9 -0
  63. package/src/utils/index.ts +1 -0
  64. package/dist/chunk-O57QENJ6.js +0 -23039
  65. package/dist/chunk-SLIMIO4Z.js +0 -14358
  66. package/dist/config/index.d.ts +0 -763
  67. package/dist/config/index.js +0 -83
  68. package/src/config/commonSchemas.ts +0 -34
  69. package/src/config/dynamicResolution.ts +0 -49
  70. package/src/config/index.ts +0 -24
  71. package/src/config/loadConfig.ts +0 -39
  72. package/src/config/loadStoreConfig.ts +0 -18
  73. package/src/config/parseStoreConfig.test-d.ts +0 -40
  74. package/src/config/parseStoreConfig.ts +0 -314
  75. package/src/config/validation.ts +0 -163
  76. package/src/config/world/index.ts +0 -4
  77. package/src/config/world/loadWorldConfig.test-d.ts +0 -11
  78. package/src/config/world/loadWorldConfig.ts +0 -26
  79. package/src/config/world/parseWorldConfig.ts +0 -55
  80. package/src/config/world/resolveWorldConfig.ts +0 -80
  81. package/src/config/world/userTypes.ts +0 -72
  82. package/src/utils/typeUtils.ts +0 -17
@@ -1,83 +0,0 @@
1
- import {
2
- DynamicResolutionType,
3
- getDuplicates,
4
- isDynamicResolution,
5
- loadConfig,
6
- loadStoreConfig,
7
- loadWorldConfig,
8
- mudConfig,
9
- parseStaticArray,
10
- parseStoreConfig,
11
- parseWorldConfig,
12
- resolveSystemConfig,
13
- resolveTableId,
14
- resolveWithContext,
15
- resolveWorldConfig,
16
- storeConfig,
17
- validateBaseRoute,
18
- validateCapitalizedName,
19
- validateEnum,
20
- validateEthereumAddress,
21
- validateName,
22
- validateRoute,
23
- validateSelector,
24
- validateSingleLevelRoute,
25
- validateUncapitalizedName,
26
- zAnyCaseName,
27
- zBaseRoute,
28
- zEnumsConfig,
29
- zEthereumAddress,
30
- zObjectName,
31
- zOrdinaryRoute,
32
- zSchemaConfig,
33
- zSelector,
34
- zSingleLevelRoute,
35
- zStoreConfig,
36
- zTableConfig,
37
- zTablesConfig,
38
- zUserEnum,
39
- zValueName,
40
- zWorldConfig
41
- } from "../chunk-J4DJQNIC.js";
42
- import "../chunk-O6HOO6WA.js";
43
- export {
44
- DynamicResolutionType,
45
- getDuplicates,
46
- isDynamicResolution,
47
- loadConfig,
48
- loadStoreConfig,
49
- loadWorldConfig,
50
- mudConfig,
51
- parseStaticArray,
52
- parseStoreConfig,
53
- parseWorldConfig,
54
- resolveSystemConfig,
55
- resolveTableId,
56
- resolveWithContext,
57
- resolveWorldConfig,
58
- storeConfig,
59
- validateBaseRoute,
60
- validateCapitalizedName,
61
- validateEnum,
62
- validateEthereumAddress,
63
- validateName,
64
- validateRoute,
65
- validateSelector,
66
- validateSingleLevelRoute,
67
- validateUncapitalizedName,
68
- zAnyCaseName,
69
- zBaseRoute,
70
- zEnumsConfig,
71
- zEthereumAddress,
72
- zObjectName,
73
- zOrdinaryRoute,
74
- zSchemaConfig,
75
- zSelector,
76
- zSingleLevelRoute,
77
- zStoreConfig,
78
- zTableConfig,
79
- zTablesConfig,
80
- zUserEnum,
81
- zValueName,
82
- zWorldConfig
83
- };
@@ -1,34 +0,0 @@
1
- import { z } from "zod";
2
- import {
3
- validateBaseRoute,
4
- validateCapitalizedName,
5
- validateEthereumAddress,
6
- validateEnum,
7
- validateName,
8
- validateRoute,
9
- validateSingleLevelRoute,
10
- validateUncapitalizedName,
11
- validateSelector,
12
- } from "./validation.js";
13
-
14
- /** Capitalized names of objects, like tables and systems */
15
- export const zObjectName = z.string().superRefine(validateCapitalizedName);
16
- /** Uncapitalized names of values, like keys and columns */
17
- export const zValueName = z.string().superRefine(validateUncapitalizedName);
18
- /** Name that can start with any case */
19
- export const zAnyCaseName = z.string().superRefine(validateName);
20
- /** List of unique enum member names and 0 < length < 256 */
21
- export const zUserEnum = z.array(zObjectName).superRefine(validateEnum);
22
-
23
- /** Ordinary routes */
24
- export const zOrdinaryRoute = z.string().superRefine(validateRoute);
25
- /** Routes with exactly 1 non-empty level */
26
- export const zSingleLevelRoute = z.string().superRefine(validateSingleLevelRoute);
27
- /** Base routes (can be an empty string) */
28
- export const zBaseRoute = z.string().superRefine(validateBaseRoute);
29
-
30
- /** A valid Ethereum address */
31
- export const zEthereumAddress = z.string().superRefine(validateEthereumAddress);
32
-
33
- /** A selector for namespace/file/resource */
34
- export const zSelector = z.string().superRefine(validateSelector);
@@ -1,49 +0,0 @@
1
- import { MUDError } from "../utils/errors.js";
2
- import { ValueWithType } from "./world/userTypes.js";
3
-
4
- export enum DynamicResolutionType {
5
- TABLE_ID,
6
- SYSTEM_ADDRESS,
7
- }
8
-
9
- export type DynamicResolution = {
10
- type: DynamicResolutionType;
11
- input: string;
12
- };
13
-
14
- /**
15
- * Dynamically resolve a table name to a table id at deploy time
16
- */
17
- export function resolveTableId(tableName: string) {
18
- return {
19
- type: DynamicResolutionType.TABLE_ID,
20
- input: tableName,
21
- };
22
- }
23
-
24
- /** Type guard for DynamicResolution */
25
- export function isDynamicResolution(value: unknown): value is DynamicResolution {
26
- return typeof value === "object" && value !== null && "type" in value && "input" in value;
27
- }
28
-
29
- /**
30
- * Turn a DynamicResolution object into a ValueWithType based on the provided context
31
- */
32
- export async function resolveWithContext(
33
- unresolved: any,
34
- context: { systemAddresses?: Record<string, Promise<string>>; tableIds?: Record<string, Uint8Array> }
35
- ): Promise<ValueWithType> {
36
- if (!isDynamicResolution(unresolved)) return unresolved;
37
- let resolved: ValueWithType | undefined = undefined;
38
-
39
- if (unresolved.type === DynamicResolutionType.TABLE_ID) {
40
- const tableId = context.tableIds?.[unresolved.input];
41
- resolved = tableId && { value: tableId, type: "bytes32" };
42
- }
43
-
44
- if (resolved === undefined) {
45
- throw new MUDError(`Could not resolve dynamic resolution: \n${JSON.stringify(unresolved, null, 2)}`);
46
- }
47
-
48
- return resolved;
49
- }
@@ -1,24 +0,0 @@
1
- import { ExtractUserTypes, StringForUnion } from "../utils/typeUtils.js";
2
- import { StoreUserConfig, StoreConfig } from "./parseStoreConfig.js";
3
- import { WorldUserConfig, ResolvedWorldConfig } from "./world/index.js";
4
-
5
- export type MUDUserConfig<
6
- EnumNames extends StringForUnion = StringForUnion,
7
- StaticUserTypes extends ExtractUserTypes<EnumNames> = ExtractUserTypes<EnumNames>
8
- > = StoreUserConfig<EnumNames, StaticUserTypes> & WorldUserConfig;
9
- export type MUDConfig = StoreConfig & ResolvedWorldConfig;
10
-
11
- export function mudConfig<
12
- EnumNames extends StringForUnion = never,
13
- StaticUserTypes extends ExtractUserTypes<EnumNames> = ExtractUserTypes<EnumNames>
14
- >(config: MUDUserConfig<EnumNames, StaticUserTypes>) {
15
- return config;
16
- }
17
-
18
- export * from "./commonSchemas.js";
19
- export * from "./loadConfig.js";
20
- export * from "./loadStoreConfig.js";
21
- export * from "./parseStoreConfig.js";
22
- export * from "./world/index.js";
23
- export * from "./validation.js";
24
- export * from "./dynamicResolution.js";
@@ -1,39 +0,0 @@
1
- import { findUp } from "find-up";
2
- import path from "path";
3
- import { NotESMConfigError, NotInsideProjectError } from "../utils/errors.js";
4
-
5
- // In order of preference files are checked
6
- const configFiles = ["mud.config.ts", "mud.config.mts"];
7
-
8
- export async function loadConfig(configPath?: string): Promise<unknown> {
9
- configPath = await resolveConfigPath(configPath);
10
- try {
11
- return (await import(configPath)).default;
12
- } catch (error) {
13
- if (error instanceof SyntaxError && error.message === "Cannot use import statement outside a module") {
14
- throw new NotESMConfigError();
15
- } else {
16
- throw error;
17
- }
18
- }
19
- }
20
-
21
- async function resolveConfigPath(configPath: string | undefined) {
22
- if (configPath === undefined) {
23
- configPath = await getUserConfigPath();
24
- } else {
25
- if (!path.isAbsolute(configPath)) {
26
- configPath = path.join(process.cwd(), configPath);
27
- configPath = path.normalize(configPath);
28
- }
29
- }
30
- return configPath;
31
- }
32
-
33
- async function getUserConfigPath() {
34
- const tsConfigPath = await findUp(configFiles);
35
- if (tsConfigPath === undefined) {
36
- throw new NotInsideProjectError();
37
- }
38
- return tsConfigPath;
39
- }
@@ -1,18 +0,0 @@
1
- import { ZodError } from "zod";
2
- import { fromZodErrorCustom } from "../utils/errors.js";
3
- import { loadConfig } from "./loadConfig.js";
4
- import { parseStoreConfig } from "./parseStoreConfig.js";
5
-
6
- export async function loadStoreConfig(configPath?: string) {
7
- const config = await loadConfig(configPath);
8
-
9
- try {
10
- return parseStoreConfig(config as any);
11
- } catch (error) {
12
- if (error instanceof ZodError) {
13
- throw fromZodErrorCustom(error, "StoreConfig Validation Error");
14
- } else {
15
- throw error;
16
- }
17
- }
18
- }
@@ -1,40 +0,0 @@
1
- import { describe, expectTypeOf } from "vitest";
2
- import { z } from "zod";
3
- import { storeConfig, zStoreConfig, StoreUserConfig } from "./parseStoreConfig.js";
4
-
5
- describe("StoreUserConfig", () => {
6
- // Typecheck manual interfaces against zod
7
- expectTypeOf<StoreUserConfig>().toEqualTypeOf<z.input<typeof zStoreConfig>>();
8
- // type equality isn't deep for optionals
9
- expectTypeOf<StoreUserConfig["tables"][string]>().toEqualTypeOf<z.input<typeof zStoreConfig>["tables"][string]>();
10
- expectTypeOf<NonNullable<StoreUserConfig["enums"]>[string]>().toEqualTypeOf<
11
- NonNullable<NonNullable<z.input<typeof zStoreConfig>>["enums"]>[string]
12
- >();
13
- // TODO If more nested schemas are added, provide separate tests for them
14
-
15
- // Test possible inference confusion.
16
- // This would fail if you remove `AsDependent` from `StoreUserConfig`
17
- expectTypeOf(
18
- storeConfig({
19
- tables: {
20
- Table1: {
21
- primaryKeys: {
22
- a: "Enum1",
23
- },
24
- schema: {
25
- b: "Enum2",
26
- },
27
- },
28
- Table2: {
29
- schema: {
30
- a: "uint32",
31
- },
32
- },
33
- },
34
- enums: {
35
- Enum1: ["E1"],
36
- Enum2: ["E1"],
37
- },
38
- })
39
- ).toEqualTypeOf<StoreUserConfig<"Enum1" | "Enum2", "Enum1" | "Enum2">>();
40
- });
@@ -1,314 +0,0 @@
1
- import { AbiType, AbiTypes, StaticAbiType, StaticAbiTypes } from "@latticexyz/schema-type";
2
- import { RefinementCtx, z, ZodIssueCode } from "zod";
3
- import { AsDependent, ExtractUserTypes, RequireKeys, StaticArray, StringForUnion } from "../utils/typeUtils.js";
4
- import { zObjectName, zSelector, zUserEnum, zValueName } from "./commonSchemas.js";
5
- import { getDuplicates, parseStaticArray } from "./validation.js";
6
-
7
- const zTableName = zObjectName;
8
- const zKeyName = zValueName;
9
- const zColumnName = zValueName;
10
- const zUserEnumName = zObjectName;
11
-
12
- // Fields can use AbiType or one of user-defined wrapper types
13
- // (user types are refined later, based on the appropriate config options)
14
- const zFieldData = z.string();
15
-
16
- type FieldData<UserTypes extends StringForUnion> = AbiType | StaticArray | UserTypes;
17
-
18
- // Primary keys allow only static types
19
- // (user types are refined later, based on the appropriate config options)
20
- const zPrimaryKey = z.string();
21
- const zPrimaryKeys = z.record(zKeyName, zPrimaryKey).default({ key: "bytes32" });
22
-
23
- type PrimaryKey<StaticUserTypes extends StringForUnion> = StaticAbiType | StaticUserTypes;
24
-
25
- /************************************************************************
26
- *
27
- * TABLE SCHEMA
28
- *
29
- ************************************************************************/
30
-
31
- export type FullSchemaConfig<UserTypes extends StringForUnion = StringForUnion> = Record<string, FieldData<UserTypes>>;
32
- export type ShorthandSchemaConfig<UserTypes extends StringForUnion = StringForUnion> = FieldData<UserTypes>;
33
- export type SchemaConfig<UserTypes extends StringForUnion = StringForUnion> =
34
- | FullSchemaConfig<UserTypes>
35
- | ShorthandSchemaConfig<UserTypes>;
36
-
37
- const zFullSchemaConfig = z
38
- .record(zColumnName, zFieldData)
39
- .refine((arg) => Object.keys(arg).length > 0, "Table schema may not be empty");
40
-
41
- const zShorthandSchemaConfig = zFieldData.transform((fieldData) => {
42
- return zFullSchemaConfig.parse({
43
- value: fieldData,
44
- });
45
- });
46
-
47
- export const zSchemaConfig = zFullSchemaConfig.or(zShorthandSchemaConfig);
48
-
49
- /************************************************************************
50
- *
51
- * TABLE
52
- *
53
- ************************************************************************/
54
-
55
- export interface TableConfig<
56
- UserTypes extends StringForUnion = StringForUnion,
57
- StaticUserTypes extends StringForUnion = StringForUnion
58
- > {
59
- /** Output directory path for the file. Default is "tables" */
60
- directory?: string;
61
- /**
62
- * The fileSelector is used with the namespace to register the table and construct its id.
63
- * The table id will be uint256(bytes32(abi.encodePacked(bytes16(namespace), bytes16(fileSelector)))).
64
- * Default is "<tableName>"
65
- * */
66
- fileSelector?: string;
67
- /** Make methods accept `tableId` argument instead of it being a hardcoded constant. Default is false */
68
- tableIdArgument?: boolean;
69
- /** Include methods that accept a manual `IStore` argument. Default is false. */
70
- storeArgument?: boolean;
71
- /** Include a data struct and methods for it. Default is false for 1-column tables; true for multi-column tables. */
72
- dataStruct?: boolean;
73
- /** Table's primary key names mapped to their types. Default is `{ key: "bytes32" }` */
74
- primaryKeys?: Record<string, PrimaryKey<StaticUserTypes>>;
75
- /** Table's column names mapped to their types. Table name's 1st letter should be lowercase. */
76
- schema: SchemaConfig<UserTypes>;
77
- }
78
-
79
- const zFullTableConfig = z
80
- .object({
81
- directory: z.string().default("tables"),
82
- fileSelector: zSelector.optional(),
83
- tableIdArgument: z.boolean().default(false),
84
- storeArgument: z.boolean().default(false),
85
- primaryKeys: zPrimaryKeys,
86
- schema: zSchemaConfig,
87
- dataStruct: z.boolean().optional(),
88
- })
89
- .transform((arg) => {
90
- // default dataStruct value depends on schema's length
91
- if (Object.keys(arg.schema).length === 1) {
92
- arg.dataStruct ??= false;
93
- } else {
94
- arg.dataStruct ??= true;
95
- }
96
- return arg as RequireKeys<typeof arg, "dataStruct">;
97
- });
98
-
99
- const zShorthandTableConfig = zFieldData.transform((fieldData) => {
100
- return zFullTableConfig.parse({
101
- schema: {
102
- value: fieldData,
103
- },
104
- });
105
- });
106
-
107
- export const zTableConfig = zFullTableConfig.or(zShorthandTableConfig);
108
-
109
- /************************************************************************
110
- *
111
- * TABLES
112
- *
113
- ************************************************************************/
114
-
115
- export type TablesConfig<
116
- UserTypes extends StringForUnion = StringForUnion,
117
- StaticUserTypes extends StringForUnion = StringForUnion
118
- > = Record<string, TableConfig<UserTypes, StaticUserTypes> | FieldData<UserTypes>>;
119
-
120
- export const zTablesConfig = z.record(zTableName, zTableConfig).transform((tables) => {
121
- // default fileSelector depends on tableName
122
- for (const tableName of Object.keys(tables)) {
123
- const table = tables[tableName];
124
- table.fileSelector ??= tableName;
125
-
126
- tables[tableName] = table;
127
- }
128
- return tables as Record<string, RequireKeys<(typeof tables)[string], "fileSelector">>;
129
- });
130
-
131
- /************************************************************************
132
- *
133
- * USER TYPES
134
- *
135
- ************************************************************************/
136
-
137
- export type EnumsConfig<EnumNames extends StringForUnion> = never extends EnumNames
138
- ? {
139
- /**
140
- * Enum names mapped to lists of their member names
141
- *
142
- * (enums are inferred to be absent)
143
- */
144
- enums?: Record<EnumNames, string[]>;
145
- }
146
- : StringForUnion extends EnumNames
147
- ? {
148
- /**
149
- * Enum names mapped to lists of their member names
150
- *
151
- * (enums aren't inferred - use `mudConfig` or `storeConfig` helper, and `as const` for variables)
152
- */
153
- enums?: Record<EnumNames, string[]>;
154
- }
155
- : {
156
- /**
157
- * Enum names mapped to lists of their member names
158
- *
159
- * Enums defined here can be used as types in table schemas/keys
160
- */
161
- enums: Record<EnumNames, string[]>;
162
- };
163
-
164
- export const zEnumsConfig = z.object({
165
- enums: z.record(zUserEnumName, zUserEnum).default({}),
166
- });
167
-
168
- /************************************************************************
169
- *
170
- * FINAL
171
- *
172
- ************************************************************************/
173
-
174
- // zod doesn't preserve doc comments
175
- export type StoreUserConfig<
176
- EnumNames extends StringForUnion = StringForUnion,
177
- StaticUserTypes extends ExtractUserTypes<EnumNames> = ExtractUserTypes<EnumNames>
178
- > = EnumsConfig<EnumNames> & {
179
- /** The namespace for table ids. Default is "" (empty string) */
180
- namespace?: string;
181
- /** Path for store package imports. Default is "@latticexyz/store/src/" */
182
- storeImportPath?: string;
183
- /**
184
- * Configuration for each table.
185
- *
186
- * The key is the table name (capitalized).
187
- *
188
- * The value:
189
- * - abi or user type for a single-value table.
190
- * - FullTableConfig object for multi-value tables (or for customizable options).
191
- */
192
- tables: TablesConfig<AsDependent<StaticUserTypes>, AsDependent<StaticUserTypes>>;
193
- /** Path to the file where common user types will be generated and imported from. Default is "Types" */
194
- userTypesPath?: string;
195
- };
196
-
197
- /** Type helper for defining StoreUserConfig */
198
- export function storeConfig<
199
- // (`never` is overridden by inference, so only the defined enums can be used by default)
200
- EnumNames extends StringForUnion = never,
201
- StaticUserTypes extends ExtractUserTypes<EnumNames> = ExtractUserTypes<EnumNames>
202
- >(config: StoreUserConfig<EnumNames, StaticUserTypes>) {
203
- return config;
204
- }
205
-
206
- export type StoreConfig = z.output<typeof zStoreConfig>;
207
-
208
- const StoreConfigUnrefined = z
209
- .object({
210
- namespace: zSelector.default(""),
211
- storeImportPath: z.string().default("@latticexyz/store/src/"),
212
- tables: zTablesConfig,
213
- userTypesPath: z.string().default("Types"),
214
- })
215
- .merge(zEnumsConfig);
216
-
217
- // finally validate global conditions
218
- export const zStoreConfig = StoreConfigUnrefined.superRefine(validateStoreConfig);
219
-
220
- export function parseStoreConfig(config: unknown) {
221
- return zStoreConfig.parse(config);
222
- }
223
-
224
- /************************************************************************
225
- *
226
- * HELPERS
227
- *
228
- ************************************************************************/
229
-
230
- // Validate conditions that check multiple different config options simultaneously
231
- function validateStoreConfig(config: z.output<typeof StoreConfigUnrefined>, ctx: RefinementCtx) {
232
- // Local table variables must be unique within the table
233
- for (const table of Object.values(config.tables)) {
234
- const primaryKeyNames = Object.keys(table.primaryKeys);
235
- const fieldNames = Object.keys(table.schema);
236
- const duplicateVariableNames = getDuplicates([...primaryKeyNames, ...fieldNames]);
237
- if (duplicateVariableNames.length > 0) {
238
- ctx.addIssue({
239
- code: ZodIssueCode.custom,
240
- message: `Field and primary key names within one table must be unique: ${duplicateVariableNames.join(", ")}`,
241
- });
242
- }
243
- }
244
- // Global names must be unique
245
- const tableNames = Object.keys(config.tables);
246
- const staticUserTypeNames = Object.keys(config.enums);
247
- const userTypeNames = staticUserTypeNames;
248
- const globalNames = [...tableNames, ...userTypeNames];
249
- const duplicateGlobalNames = getDuplicates(globalNames);
250
- if (duplicateGlobalNames.length > 0) {
251
- ctx.addIssue({
252
- code: ZodIssueCode.custom,
253
- message: `Table, enum names must be globally unique: ${duplicateGlobalNames.join(", ")}`,
254
- });
255
- }
256
- // User types must exist
257
- for (const table of Object.values(config.tables)) {
258
- for (const primaryKeyType of Object.values(table.primaryKeys)) {
259
- validateStaticAbiOrUserType(staticUserTypeNames, primaryKeyType, ctx);
260
- }
261
- for (const fieldType of Object.values(table.schema)) {
262
- validateAbiOrUserType(userTypeNames, staticUserTypeNames, fieldType, ctx);
263
- }
264
- }
265
- }
266
-
267
- function validateAbiOrUserType(
268
- userTypeNames: string[],
269
- staticUserTypeNames: string[],
270
- type: string,
271
- ctx: RefinementCtx
272
- ) {
273
- if (!(AbiTypes as string[]).includes(type) && !userTypeNames.includes(type)) {
274
- const staticArray = parseStaticArray(type);
275
- if (staticArray) {
276
- validateStaticArray(staticUserTypeNames, staticArray.elementType, staticArray.staticLength, ctx);
277
- } else {
278
- ctx.addIssue({
279
- code: ZodIssueCode.custom,
280
- message: `${type} is not a valid abi type, and is not defined in userTypes`,
281
- });
282
- }
283
- }
284
- }
285
-
286
- function validateStaticAbiOrUserType(staticUserTypeNames: string[], type: string, ctx: RefinementCtx) {
287
- if (!(StaticAbiTypes as string[]).includes(type) && !staticUserTypeNames.includes(type)) {
288
- ctx.addIssue({
289
- code: ZodIssueCode.custom,
290
- message: `${type} is not a static type`,
291
- });
292
- }
293
- }
294
-
295
- function validateStaticArray(
296
- staticUserTypeNames: string[],
297
- elementType: string,
298
- staticLength: number,
299
- ctx: RefinementCtx
300
- ) {
301
- validateStaticAbiOrUserType(staticUserTypeNames, elementType, ctx);
302
-
303
- if (staticLength === 0) {
304
- ctx.addIssue({
305
- code: ZodIssueCode.custom,
306
- message: `Static array length must not be 0`,
307
- });
308
- } else if (staticLength >= 2 ** 16) {
309
- ctx.addIssue({
310
- code: ZodIssueCode.custom,
311
- message: `Static array length must be less than 2**16`,
312
- });
313
- }
314
- }