@latticexyz/cli 1.40.0 → 2.0.0-alpha.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 (81) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-ATAWDHWC.js +67 -0
  3. package/dist/{chunk-6AQ6LFVZ.js → chunk-J4DJQNIC.js} +743 -103
  4. package/dist/chunk-O57QENJ6.js +23039 -0
  5. package/dist/{chunk-S3V3XX7N.js → chunk-SLIMIO4Z.js} +1 -1
  6. package/dist/config/index.d.ts +746 -8
  7. package/dist/config/index.js +63 -17
  8. package/dist/index.d.ts +1 -2
  9. package/dist/index.js +14 -10
  10. package/dist/mud.js +1055 -49
  11. package/dist/utils/deprecated/index.js +2 -2
  12. package/dist/utils/index.d.ts +56 -7
  13. package/dist/utils/index.js +17 -3
  14. package/package.json +16 -11
  15. package/src/commands/deploy-v2.ts +96 -0
  16. package/src/commands/deprecated/call-system.ts +1 -1
  17. package/src/commands/deprecated/deploy-contracts.ts +1 -1
  18. package/src/commands/deprecated/test.ts +9 -6
  19. package/src/commands/deprecated/trace.ts +1 -1
  20. package/src/commands/gas-report.ts +1 -1
  21. package/src/commands/index.ts +4 -0
  22. package/src/commands/tablegen.ts +4 -18
  23. package/src/commands/worldgen.ts +55 -0
  24. package/src/config/commonSchemas.ts +19 -5
  25. package/src/config/dynamicResolution.ts +49 -0
  26. package/src/config/index.ts +20 -0
  27. package/src/config/loadStoreConfig.ts +3 -89
  28. package/src/config/parseStoreConfig.test-d.ts +40 -0
  29. package/src/config/parseStoreConfig.ts +314 -0
  30. package/src/config/validation.ts +71 -0
  31. package/src/config/world/index.ts +4 -0
  32. package/src/config/world/loadWorldConfig.test-d.ts +11 -0
  33. package/src/config/world/loadWorldConfig.ts +26 -0
  34. package/src/config/world/parseWorldConfig.ts +55 -0
  35. package/src/config/world/resolveWorldConfig.ts +80 -0
  36. package/src/config/world/userTypes.ts +72 -0
  37. package/src/index.ts +13 -5
  38. package/src/mud.ts +4 -0
  39. package/src/render-solidity/common.ts +138 -0
  40. package/src/render-solidity/field.ts +137 -0
  41. package/src/render-solidity/index.ts +10 -0
  42. package/src/render-solidity/record.ts +154 -0
  43. package/src/render-solidity/renderSystemInterface.ts +31 -0
  44. package/src/render-solidity/renderTable.ts +164 -0
  45. package/src/render-solidity/renderTypeHelpers.ts +99 -0
  46. package/src/render-solidity/renderTypes.ts +19 -0
  47. package/src/render-solidity/renderTypesFromConfig.ts +13 -0
  48. package/src/render-solidity/renderWorld.ts +24 -0
  49. package/src/{render-table/renderTablesFromConfig.ts → render-solidity/tableOptions.ts} +45 -37
  50. package/src/render-solidity/tablegen.ts +33 -0
  51. package/src/render-solidity/types.ts +110 -0
  52. package/src/render-solidity/userType.ts +132 -0
  53. package/src/render-solidity/worldgen.ts +60 -0
  54. package/src/utils/contractToInterface.ts +130 -0
  55. package/src/utils/deploy-v2.ts +512 -0
  56. package/src/utils/deprecated/build.ts +1 -1
  57. package/src/utils/deprecated/typegen.ts +1 -1
  58. package/src/utils/errors.ts +12 -2
  59. package/src/utils/execLog.ts +22 -0
  60. package/src/utils/formatAndWrite.ts +12 -0
  61. package/src/utils/foundry.ts +94 -0
  62. package/src/utils/getChainId.ts +10 -0
  63. package/src/utils/index.ts +2 -1
  64. package/src/utils/typeUtils.ts +17 -0
  65. package/dist/chunk-B6VWCGHZ.js +0 -199
  66. package/dist/chunk-JKAA3WMC.js +0 -55
  67. package/dist/chunk-JNGSW4AP.js +0 -493
  68. package/dist/chunk-PJ6GS2R4.js +0 -22
  69. package/dist/chunk-UC3QPOON.js +0 -35
  70. package/dist/loadStoreConfig-37f99136.d.ts +0 -164
  71. package/dist/render-table/index.d.ts +0 -29
  72. package/dist/render-table/index.js +0 -24
  73. package/dist/renderTable-9e6410c5.d.ts +0 -72
  74. package/src/config/loadStoreConfig.test-d.ts +0 -11
  75. package/src/render-table/common.ts +0 -67
  76. package/src/render-table/field.ts +0 -132
  77. package/src/render-table/index.ts +0 -6
  78. package/src/render-table/record.ts +0 -176
  79. package/src/render-table/renderTable.ts +0 -109
  80. package/src/render-table/types.ts +0 -51
  81. package/src/utils/forgeConfig.ts +0 -45
@@ -14,8 +14,8 @@ import {
14
14
  hsr,
15
15
  keccak256,
16
16
  resetLibDeploy
17
- } from "../../chunk-S3V3XX7N.js";
18
- import "../../chunk-PJ6GS2R4.js";
17
+ } from "../../chunk-SLIMIO4Z.js";
18
+ import "../../chunk-ATAWDHWC.js";
19
19
  import "../../chunk-O6HOO6WA.js";
20
20
  export {
21
21
  IDregex,
@@ -1,5 +1,7 @@
1
- import { ZodError } from 'zod';
1
+ import { ZodError, z } from 'zod';
2
2
  import { ValidationError } from 'zod-validation-error';
3
+ import { MUDConfig } from '../config/index.js';
4
+ import '@latticexyz/schema-type';
3
5
 
4
6
  declare function fromZodErrorCustom(error: ZodError, prefix: string): ValidationError;
5
7
  declare class NotInsideProjectError extends Error {
@@ -10,35 +12,82 @@ declare class NotESMConfigError extends Error {
10
12
  name: string;
11
13
  message: string;
12
14
  }
13
- declare function logError(error: Error): void;
15
+ declare class MUDError extends Error {
16
+ name: string;
17
+ }
18
+ declare function UnrecognizedSystemErrorFactory(path: string[], systemName: string): z.ZodError<any>;
19
+ declare function logError(error: unknown): void;
14
20
 
15
21
  interface ForgeConfig {
16
22
  src: string;
17
23
  test: string;
24
+ script: string;
18
25
  out: string;
19
26
  libs: string[];
27
+ eth_rpc_url: string | null;
20
28
  [key: string]: unknown;
21
29
  }
22
30
  /**
23
31
  * Get forge config as a parsed json object.
24
32
  */
25
- declare function getForgeConfig(): Promise<ForgeConfig>;
33
+ declare function getForgeConfig(profile?: string): Promise<ForgeConfig>;
26
34
  /**
27
35
  * Get the value of "src" from forge config.
28
36
  * The path to the contract sources relative to the root of the project.
29
37
  */
30
- declare function getSrcDirectory(): Promise<string>;
38
+ declare function getSrcDirectory(profile?: string): Promise<string>;
39
+ /**
40
+ * Get the value of "script" from forge config.
41
+ * The path to the contract sources relative to the root of the project.
42
+ */
43
+ declare function getScriptDirectory(profile?: string): Promise<string>;
31
44
  /**
32
45
  * Get the value of "test" from forge config.
33
46
  * The path to the test contract sources relative to the root of the project.
34
47
  */
35
- declare function getTestDirectory(): Promise<string>;
48
+ declare function getTestDirectory(profile?: string): Promise<string>;
36
49
  /**
37
50
  * Get the value of "out" from forge config.
38
51
  * The path to put contract artifacts in, relative to the root of the project.
39
52
  */
40
- declare function getOutDirectory(): Promise<string>;
53
+ declare function getOutDirectory(profile?: string): Promise<string>;
54
+ /**
55
+ * Get the value of "eth_rpc_url" from forge config, default to "http://127.0.0.1:8545"
56
+ * @param profile The foundry profile to use
57
+ * @returns The rpc url
58
+ */
59
+ declare function getRpcUrl(profile?: string): Promise<string>;
60
+ /**
61
+ * Execute a forge command
62
+ * @param args The arguments to pass to forge
63
+ * @param options { profile?: The foundry profile to use; silent?: If true, nothing will be logged to the console }
64
+ */
65
+ declare function forge(args: string[], options?: {
66
+ profile?: string;
67
+ silent?: boolean;
68
+ }): Promise<void>;
69
+ /**
70
+ * Execute a cast command
71
+ * @param args The arguments to pass to cast
72
+ * @returns Stdout of the command
73
+ */
74
+ declare function cast(args: string[], options?: {
75
+ profile?: string;
76
+ }): Promise<string>;
41
77
 
42
78
  declare function formatSolidity(content: string, prettierConfigPath?: string): Promise<string>;
43
79
 
44
- export { ForgeConfig, NotESMConfigError, NotInsideProjectError, formatSolidity, fromZodErrorCustom, getForgeConfig, getOutDirectory, getSrcDirectory, getTestDirectory, logError };
80
+ interface DeployConfig {
81
+ profile?: string;
82
+ rpc: string;
83
+ privateKey: string;
84
+ priorityFeeMultiplier: number;
85
+ debug?: boolean;
86
+ }
87
+ interface DeploymentInfo {
88
+ blockNumber: number;
89
+ worldAddress: string;
90
+ }
91
+ declare function deploy(mudConfig: MUDConfig, deployConfig: DeployConfig): Promise<DeploymentInfo>;
92
+
93
+ export { DeployConfig, DeploymentInfo, ForgeConfig, MUDError, NotESMConfigError, NotInsideProjectError, UnrecognizedSystemErrorFactory, cast, deploy, forge, formatSolidity, fromZodErrorCustom, getForgeConfig, getOutDirectory, getRpcUrl, getScriptDirectory, getSrcDirectory, getTestDirectory, logError };
@@ -1,26 +1,40 @@
1
1
  import {
2
+ deploy,
2
3
  formatSolidity
3
- } from "../chunk-UC3QPOON.js";
4
+ } from "../chunk-O57QENJ6.js";
4
5
  import {
6
+ MUDError,
5
7
  NotESMConfigError,
6
8
  NotInsideProjectError,
9
+ UnrecognizedSystemErrorFactory,
7
10
  fromZodErrorCustom,
8
11
  logError
9
- } from "../chunk-JKAA3WMC.js";
12
+ } from "../chunk-J4DJQNIC.js";
10
13
  import {
14
+ cast,
15
+ forge,
11
16
  getForgeConfig,
12
17
  getOutDirectory,
18
+ getRpcUrl,
19
+ getScriptDirectory,
13
20
  getSrcDirectory,
14
21
  getTestDirectory
15
- } from "../chunk-PJ6GS2R4.js";
22
+ } from "../chunk-ATAWDHWC.js";
16
23
  import "../chunk-O6HOO6WA.js";
17
24
  export {
25
+ MUDError,
18
26
  NotESMConfigError,
19
27
  NotInsideProjectError,
28
+ UnrecognizedSystemErrorFactory,
29
+ cast,
30
+ deploy,
31
+ forge,
20
32
  formatSolidity,
21
33
  fromZodErrorCustom,
22
34
  getForgeConfig,
23
35
  getOutDirectory,
36
+ getRpcUrl,
37
+ getScriptDirectory,
24
38
  getSrcDirectory,
25
39
  getTestDirectory,
26
40
  logError
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@latticexyz/cli",
3
- "version": "1.40.0",
3
+ "version": "2.0.0-alpha.0",
4
4
  "description": "Command line interface for mud",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,15 +16,18 @@
16
16
  },
17
17
  "scripts": {
18
18
  "prepare": "yarn build && chmod u+x git-install.sh",
19
+ "codegen": "ts-node --esm --files ./scripts/codegen.ts",
19
20
  "lint": "eslint . --ext .ts",
20
21
  "dev": "tsup --watch",
21
22
  "build": "tsup",
22
23
  "link": "yarn link",
23
- "test": "vitest typecheck --run && echo 'todo: add tests'",
24
+ "test": "vitest typecheck --run && yarn test:contracts",
25
+ "test:contracts": "yarn codegen && forge test",
24
26
  "git:install": "bash git-install.sh",
25
- "release": "npm publish || echo 'version already published'"
27
+ "release": "npm publish --access=public"
26
28
  },
27
29
  "devDependencies": {
30
+ "@latticexyz/store": "^2.0.0-alpha.0",
28
31
  "@types/ejs": "^3.1.1",
29
32
  "@types/glob": "^7.2.0",
30
33
  "@types/node": "^17.0.34",
@@ -37,17 +40,19 @@
37
40
  "dependencies": {
38
41
  "@improbable-eng/grpc-web": "^0.15.0",
39
42
  "@improbable-eng/grpc-web-node-http-transport": "^0.15.0",
40
- "@latticexyz/schema-type": "^1.40.0",
41
- "@latticexyz/services": "^1.40.0",
42
- "@latticexyz/solecs": "^1.40.0",
43
- "@latticexyz/std-contracts": "^1.40.0",
43
+ "@latticexyz/schema-type": "^2.0.0-alpha.0",
44
+ "@latticexyz/services": "^2.0.0-alpha.0",
45
+ "@latticexyz/solecs": "^2.0.0-alpha.0",
46
+ "@latticexyz/std-contracts": "^2.0.0-alpha.0",
47
+ "@solidity-parser/parser": "^0.16.0",
44
48
  "@typechain/ethers-v5": "^10.1.1",
45
49
  "chalk": "^5.0.1",
46
50
  "chokidar": "^3.5.3",
51
+ "dotenv": "^16.0.3",
47
52
  "ds-test": "https://github.com/dapphub/ds-test.git#c9ce3f25bde29fc5eb9901842bf02850dfd2d084",
48
53
  "ejs": "^3.1.8",
49
54
  "ethers": "^5.7.2",
50
- "execa": "^6.1.0",
55
+ "execa": "^7.0.0",
51
56
  "find-up": "^6.3.0",
52
57
  "forge-std": "https://github.com/foundry-rs/forge-std.git#b4f121555729b3afb3c5ffccb62ff4b6e2818fd3",
53
58
  "glob": "^8.0.3",
@@ -62,8 +67,8 @@
62
67
  "typechain": "^8.1.1",
63
68
  "typescript": "^4.9.5",
64
69
  "yargs": "^17.7.1",
65
- "zod": "^3.20.6",
66
- "zod-validation-error": "^0.3.2"
70
+ "zod": "^3.21.4",
71
+ "zod-validation-error": "^1.0.1"
67
72
  },
68
- "gitHead": "914a1e0ae4a573d685841ca2ea921435057deb8f"
73
+ "gitHead": "fcb2166c25edd27ead54f0afa1b71d2583939603"
69
74
  }
@@ -0,0 +1,96 @@
1
+ import chalk from "chalk";
2
+ import glob from "glob";
3
+ import path, { basename } from "path";
4
+ import type { CommandModule } from "yargs";
5
+ import { loadWorldConfig } from "../config/world/index.js";
6
+ import { deploy } from "../utils/deploy-v2.js";
7
+ import { logError, MUDError } from "../utils/errors.js";
8
+ import { forge, getRpcUrl, getSrcDirectory } from "../utils/foundry.js";
9
+ import { mkdirSync, writeFileSync } from "fs";
10
+ import { loadStoreConfig } from "../config/loadStoreConfig.js";
11
+ import { getChainId } from "../utils/getChainId.js";
12
+
13
+ type Options = {
14
+ configPath?: string;
15
+ printConfig?: boolean;
16
+ profile?: string;
17
+ privateKey: string;
18
+ priorityFeeMultiplier: number;
19
+ clean?: boolean;
20
+ debug?: boolean;
21
+ };
22
+
23
+ const commandModule: CommandModule<Options, Options> = {
24
+ command: "deploy-v2",
25
+
26
+ describe: "Deploy MUD v2 contracts",
27
+
28
+ builder(yargs) {
29
+ return yargs.options({
30
+ configPath: { type: "string", desc: "Path to the config file" },
31
+ clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
32
+ printConfig: { type: "boolean", desc: "Print the resolved config" },
33
+ profile: { type: "string", desc: "The foundry profile to use" },
34
+ debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
35
+ priorityFeeMultiplier: {
36
+ type: "number",
37
+ desc: "Multiply the estimated priority fee by the provided factor",
38
+ default: 1,
39
+ },
40
+ });
41
+ },
42
+
43
+ async handler(args) {
44
+ args.profile = args.profile ?? process.env.FOUNDRY_PROFILE;
45
+ const { configPath, printConfig, profile, clean } = args;
46
+
47
+ const rpc = await getRpcUrl(profile);
48
+ console.log(
49
+ chalk.bgBlue(
50
+ chalk.whiteBright(`\n Deploying MUD v2 contracts${profile ? " with profile " + profile : ""} to RPC ${rpc} \n`)
51
+ )
52
+ );
53
+
54
+ if (clean) await forge(["clean"], { profile });
55
+
56
+ // Run forge build
57
+ await forge(["build"], { profile });
58
+
59
+ // Get a list of all contract names
60
+ const srcDir = await getSrcDirectory();
61
+ const existingContracts = glob
62
+ .sync(`${srcDir}/**/*.sol`)
63
+ // Get the basename of the file
64
+ .map((path) => basename(path, ".sol"));
65
+
66
+ // Load and resolve the config
67
+ const worldConfig = await loadWorldConfig(configPath, existingContracts);
68
+ const storeConfig = await loadStoreConfig(configPath);
69
+ const mudConfig = { ...worldConfig, ...storeConfig };
70
+
71
+ if (printConfig) console.log(chalk.green("\nResolved config:\n"), JSON.stringify(mudConfig, null, 2));
72
+
73
+ try {
74
+ const privateKey = process.env.PRIVATE_KEY;
75
+ if (!privateKey) throw new MUDError("Missing PRIVATE_KEY environment variable");
76
+ const deploymentInfo = await deploy(mudConfig, { ...args, rpc, privateKey });
77
+
78
+ // Write deployment result to file (latest and timestamp)
79
+ const chainId = await getChainId(rpc);
80
+ const outputDir = path.join(mudConfig.deploysDirectory, chainId.toString());
81
+ mkdirSync(outputDir, { recursive: true });
82
+ writeFileSync(path.join(outputDir, "latest.json"), JSON.stringify(deploymentInfo, null, 2));
83
+ writeFileSync(path.join(outputDir, Date.now() + ".json"), JSON.stringify(deploymentInfo, null, 2));
84
+
85
+ console.log(chalk.bgGreen(chalk.whiteBright(`\n Deployment result (written to ${outputDir}): \n`)));
86
+ console.log(deploymentInfo);
87
+ } catch (error: any) {
88
+ logError(error);
89
+ process.exit(1);
90
+ }
91
+
92
+ process.exit(0);
93
+ },
94
+ };
95
+
96
+ export default commandModule;
@@ -2,7 +2,7 @@ import { defaultAbiCoder as abi } from "ethers/lib/utils.js";
2
2
  import path from "path";
3
3
  import type { CommandModule } from "yargs";
4
4
  import { execLog } from "../../utils/deprecated/index.js";
5
- import { getTestDirectory } from "../../utils/forgeConfig.js";
5
+ import { getTestDirectory } from "../../utils/foundry.js";
6
6
 
7
7
  type Options = {
8
8
  rpc?: string;
@@ -2,7 +2,7 @@ import type { CommandModule } from "yargs";
2
2
  import { DeployOptions, generateAndDeploy, hsr } from "../../utils/deprecated/index.js";
3
3
  import openurl from "openurl";
4
4
  import chalk from "chalk";
5
- import { getSrcDirectory } from "../../utils/forgeConfig.js";
5
+ import { getSrcDirectory } from "../../utils/foundry.js";
6
6
 
7
7
  type Options = DeployOptions & {
8
8
  watch?: boolean;
@@ -1,6 +1,6 @@
1
1
  import type { CommandModule } from "yargs";
2
2
  import { execLog, generateLibDeploy, resetLibDeploy } from "../../utils/deprecated/index.js";
3
- import { getTestDirectory } from "../../utils/forgeConfig.js";
3
+ import { getTestDirectory } from "../../utils/foundry.js";
4
4
 
5
5
  type Options = {
6
6
  forgeOpts?: string;
@@ -35,15 +35,18 @@ const commandModule: CommandModule<Options, Options> = {
35
35
  ...(forgeOpts?.split(" ") || []),
36
36
  ]);
37
37
 
38
- // Reset LibDeploy.sol
39
- console.log("Reset LibDeploy.sol");
40
- await resetLibDeploy(testDir);
41
-
42
- process.on("SIGINT", () => {
38
+ process.on("SIGINT", async () => {
43
39
  console.log("\ngracefully shutting down from SIGINT (Crtl-C)");
44
40
  child.kill();
41
+ await resetLibDeploy(testDir);
45
42
  process.exit();
46
43
  });
44
+
45
+ await child;
46
+
47
+ // Reset LibDeploy.sol
48
+ console.log("Reset LibDeploy.sol");
49
+ await resetLibDeploy(testDir);
47
50
  },
48
51
  };
49
52
 
@@ -4,7 +4,7 @@ import { readFileSync } from "fs";
4
4
  import { Contract } from "ethers";
5
5
  import { JsonRpcProvider } from "@ethersproject/providers";
6
6
  import WorldAbi from "@latticexyz/solecs/abi/World.json" assert { type: "json" };
7
- import { getSrcDirectory } from "../../utils/forgeConfig.js";
7
+ import { getSrcDirectory } from "../../utils/foundry.js";
8
8
  import path from "path";
9
9
  import { componentsDir, systemsDir } from "../../utils/deprecated/constants.js";
10
10
 
@@ -156,7 +156,7 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
156
156
  stdio: ["inherit", "pipe", "inherit"],
157
157
  });
158
158
 
159
- // Extrect the logs from the child process
159
+ // Extract the logs from the child process
160
160
  let logs = "";
161
161
  try {
162
162
  logs = (await child).stdout;
@@ -14,6 +14,8 @@ import faucet from "./faucet.js";
14
14
  import gasReport from "./gas-report.js";
15
15
  import hello from "./hello.js";
16
16
  import tablegen from "./tablegen.js";
17
+ import deployV2 from "./deploy-v2.js";
18
+ import worldgen from "./worldgen.js";
17
19
 
18
20
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
19
21
  export const commands: CommandModule<any, any>[] = [
@@ -21,6 +23,7 @@ export const commands: CommandModule<any, any>[] = [
21
23
  callSystem,
22
24
  codegenLibdeploy,
23
25
  deployContracts,
26
+ deployV2,
24
27
  devnode,
25
28
  faucet,
26
29
  gasReport,
@@ -30,4 +33,5 @@ export const commands: CommandModule<any, any>[] = [
30
33
  test,
31
34
  trace,
32
35
  types,
36
+ worldgen,
33
37
  ];
@@ -1,10 +1,7 @@
1
1
  import type { CommandModule } from "yargs";
2
- import { mkdirSync, writeFileSync } from "fs";
3
- import path from "path";
4
2
  import { loadStoreConfig } from "../config/loadStoreConfig.js";
5
- import { renderTablesFromConfig } from "../render-table/renderTablesFromConfig.js";
6
- import { getSrcDirectory } from "../utils/forgeConfig.js";
7
- import { formatSolidity } from "../utils/format.js";
3
+ import { getSrcDirectory } from "../utils/foundry.js";
4
+ import { tablegen } from "../render-solidity/tablegen.js";
8
5
 
9
6
  type Options = {
10
7
  configPath?: string;
@@ -22,22 +19,11 @@ const commandModule: CommandModule<Options, Options> = {
22
19
  },
23
20
 
24
21
  async handler({ configPath }) {
25
- const srcDir = await getSrcDirectory();
22
+ const srcDirectory = await getSrcDirectory();
26
23
 
27
24
  const config = await loadStoreConfig(configPath);
28
- const renderedTables = renderTablesFromConfig(config);
29
25
 
30
- for (const { output, tableName } of renderedTables) {
31
- const formattedOutput = await formatSolidity(output);
32
-
33
- const tablePath = config.tables[tableName].route;
34
- const outputDirectory = path.join(srcDir, tablePath);
35
- mkdirSync(outputDirectory, { recursive: true });
36
-
37
- const outputPath = path.join(outputDirectory, `${tableName}.sol`);
38
- writeFileSync(outputPath, formattedOutput);
39
- console.log(`Generated schema: ${outputPath}`);
40
- }
26
+ await tablegen(config, srcDirectory);
41
27
 
42
28
  process.exit(0);
43
29
  },
@@ -0,0 +1,55 @@
1
+ import type { CommandModule } from "yargs";
2
+ import { loadStoreConfig } from "../config/loadStoreConfig.js";
3
+ import { loadWorldConfig } from "../config/index.js";
4
+ import { getSrcDirectory } from "../utils/foundry.js";
5
+ import glob from "glob";
6
+ import path, { basename } from "path";
7
+ import { worldgen } from "../render-solidity/worldgen.js";
8
+ import { rmSync } from "fs";
9
+
10
+ type Options = {
11
+ configPath?: string;
12
+ clean?: boolean;
13
+ };
14
+
15
+ const commandModule: CommandModule<Options, Options> = {
16
+ command: "worldgen",
17
+
18
+ describe: "Autogenerate interfaces for Systems and World based on existing contracts and the config file",
19
+
20
+ builder(yargs) {
21
+ return yargs.options({
22
+ configPath: { type: "string", desc: "Path to the config file" },
23
+ clean: { type: "boolean", desc: "Clear the worldgen directory before generating new interfaces" },
24
+ });
25
+ },
26
+
27
+ async handler(args) {
28
+ const { configPath, clean } = args;
29
+ const srcDir = await getSrcDirectory();
30
+
31
+ // Get a list of all contract names
32
+ const existingContracts = glob.sync(`${srcDir}/**/*.sol`).map((path) => ({
33
+ path,
34
+ basename: basename(path, ".sol"),
35
+ }));
36
+
37
+ // Load and resolve the config
38
+ const worldConfig = await loadWorldConfig(
39
+ configPath,
40
+ existingContracts.map(({ basename }) => basename)
41
+ );
42
+ const storeConfig = await loadStoreConfig(configPath);
43
+ const mudConfig = { ...worldConfig, ...storeConfig };
44
+
45
+ // clear the worldgen directory
46
+ if (clean) rmSync(path.join(srcDir, worldConfig.worldgenDirectory), { recursive: true, force: true });
47
+
48
+ // generate new interfaces
49
+ await worldgen(mudConfig, existingContracts, srcDir);
50
+
51
+ process.exit(0);
52
+ },
53
+ };
54
+
55
+ export default commandModule;
@@ -2,19 +2,33 @@ import { z } from "zod";
2
2
  import {
3
3
  validateBaseRoute,
4
4
  validateCapitalizedName,
5
+ validateEthereumAddress,
6
+ validateEnum,
7
+ validateName,
5
8
  validateRoute,
6
9
  validateSingleLevelRoute,
7
10
  validateUncapitalizedName,
11
+ validateSelector,
8
12
  } from "./validation.js";
9
13
 
10
14
  /** Capitalized names of objects, like tables and systems */
11
- export const ObjectName = z.string().superRefine(validateCapitalizedName);
15
+ export const zObjectName = z.string().superRefine(validateCapitalizedName);
12
16
  /** Uncapitalized names of values, like keys and columns */
13
- export const ValueName = z.string().superRefine(validateUncapitalizedName);
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);
14
22
 
15
23
  /** Ordinary routes */
16
- export const OrdinaryRoute = z.string().superRefine(validateRoute);
24
+ export const zOrdinaryRoute = z.string().superRefine(validateRoute);
17
25
  /** Routes with exactly 1 non-empty level */
18
- export const SingleLevelRoute = z.string().superRefine(validateSingleLevelRoute);
26
+ export const zSingleLevelRoute = z.string().superRefine(validateSingleLevelRoute);
19
27
  /** Base routes (can be an empty string) */
20
- export const BaseRoute = z.string().superRefine(validateBaseRoute);
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);
@@ -0,0 +1,49 @@
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,4 +1,24 @@
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
+
1
18
  export * from "./commonSchemas.js";
2
19
  export * from "./loadConfig.js";
3
20
  export * from "./loadStoreConfig.js";
21
+ export * from "./parseStoreConfig.js";
22
+ export * from "./world/index.js";
4
23
  export * from "./validation.js";
24
+ export * from "./dynamicResolution.js";