@latticexyz/cli 2.0.0-alpha.49 → 2.0.0-alpha.5

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-6V563IAZ.js +283 -0
  2. package/dist/{chunk-ATAWDHWC.js → chunk-FPG73MVN.js} +5 -1
  3. package/dist/chunk-KJTPZOUH.js +3864 -0
  4. package/dist/{chunk-O6HOO6WA.js → chunk-L4YLJHLJ.js} +1 -9
  5. package/dist/{chunk-KPBNUPK6.js → chunk-SKNB74MT.js} +155 -159
  6. package/dist/chunk-VQTZJIFF.js +353 -0
  7. package/dist/{chunk-MXDV47JM.js → chunk-WZFXLDPK.js} +75 -24
  8. package/dist/chunk-YL4GJLLL.js +26139 -0
  9. package/dist/index.d.ts +2 -4
  10. package/dist/index.js +0 -22
  11. package/dist/mud.d.ts +1 -1
  12. package/dist/mud.js +319 -3971
  13. package/dist/mud2.d.ts +1 -0
  14. package/dist/mud2.js +25 -0
  15. package/dist/render-solidity/index.d.ts +3 -3
  16. package/dist/render-solidity/index.js +3 -4
  17. package/dist/render-ts/index.d.ts +2 -3
  18. package/dist/render-ts/index.js +3 -4
  19. package/dist/utils/deprecated/index.js +3 -3
  20. package/dist/utils/index.d.ts +9 -19
  21. package/dist/utils/index.js +7 -18
  22. package/package.json +19 -20
  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 +2 -17
  28. package/src/commands/set-version.ts +39 -10
  29. package/src/commands/tablegen.ts +5 -5
  30. package/src/commands/test-v2.ts +71 -0
  31. package/src/commands/tsgen.ts +1 -1
  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 +13 -1
  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 +3 -3
  51. package/src/render-ts/recsV1TableOptions.ts +2 -2
  52. package/src/render-ts/renderRecsV1Tables.ts +2 -2
  53. package/src/render-ts/schemaTypesToRecsTypeStrings.ts +136 -136
  54. package/src/render-ts/tsgen.ts +1 -1
  55. package/src/render-ts/types.ts +1 -1
  56. package/src/utils/contractToInterface.ts +5 -3
  57. package/src/utils/deploy-v2.ts +85 -78
  58. package/src/utils/errors.ts +3 -34
  59. package/src/utils/foundry.ts +9 -0
  60. package/dist/chunk-5NC2OON2.js +0 -164
  61. package/dist/chunk-7GA2K5A6.js +0 -283
  62. package/dist/chunk-LPWKZQUI.js +0 -454
  63. package/dist/chunk-Q7D3SKYJ.js +0 -22908
  64. package/dist/chunk-SLIMIO4Z.js +0 -14358
  65. package/dist/config/index.d.ts +0 -408
  66. package/dist/config/index.js +0 -85
  67. package/dist/parseStoreConfig-899f574e.d.ts +0 -369
  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 -56
  80. package/src/config/world/resolveWorldConfig.ts +0 -80
  81. package/src/config/world/userTypes.ts +0 -74
  82. package/src/utils/typeUtils.ts +0 -17
@@ -39,6 +39,8 @@ type GasReportEntry = {
39
39
 
40
40
  type GasReport = GasReportEntry[];
41
41
 
42
+ const tempFileSuffix = "MudGasReport";
43
+
42
44
  const commandModule: CommandModule<Options, Options> = {
43
45
  command: "gas-report",
44
46
 
@@ -52,43 +54,43 @@ const commandModule: CommandModule<Options, Options> = {
52
54
  });
53
55
  },
54
56
 
55
- async handler({ path, save, compare }) {
56
- let gasReport: GasReport = [];
57
+ async handler({ path: files, save, compare }) {
58
+ const validFiles = files.filter((file) => file.endsWith(".t.sol"));
59
+ const tempFiles = await Promise.all(validFiles.map((file) => createGasReport(file)));
60
+
61
+ process.once("SIGINT", () => {
62
+ console.log("caught sigint, deleting temp files");
63
+ tempFiles.forEach((file) => rmSync(file));
64
+ });
57
65
 
58
- // Iterate through all files provided in the path
59
- for (const file of path) {
60
- gasReport = gasReport.concat(await runGasReport(file));
66
+ let gasReport: GasReport;
67
+ try {
68
+ gasReport = await runGasReport();
69
+ } catch {
70
+ setTimeout(() => process.exit());
71
+ return;
72
+ } finally {
73
+ // Delete the temporary files
74
+ tempFiles.forEach((file) => rmSync(file));
61
75
  }
62
76
 
63
77
  // If this gas report should be compared to an existing one, load the existing one
64
- const compareGasReport: GasReport = [];
65
78
  if (compare) {
66
79
  try {
67
- const compareFileContents = readFileSync(compare, "utf8");
68
- // Create a regex to extract the name, function call and gas used
69
- const compareGasReportRegex = new RegExp(/\((.*)\) \| (.*) \[(.*)\]: (.*)/g);
70
- // Loop through the matches and add the resuls to the compareGasReport
71
- let compareGasReportMatch;
72
- while ((compareGasReportMatch = compareGasReportRegex.exec(compareFileContents)) !== null) {
73
- const source = compareGasReportMatch[1];
74
- const name = compareGasReportMatch[2];
75
- const functionCall = compareGasReportMatch[3];
76
- const gasUsed = compareGasReportMatch[4];
77
-
78
- compareGasReport.push({ source, name, functionCall, gasUsed: parseInt(gasUsed) });
79
- }
80
+ const compareGasReport: GasReport = JSON.parse(readFileSync(compare, "utf8"));
81
+ // Merge the previous gas report with the new one
82
+ gasReport = gasReport.map((entry) => {
83
+ const prevEntry = compareGasReport.find(
84
+ (e) => e.name === entry.name && e.functionCall === entry.functionCall
85
+ );
86
+ return { ...entry, prevGasUsed: prevEntry?.gasUsed };
87
+ });
80
88
  } catch {
81
89
  console.log(chalk.red(`Gas report to compare not found: ${compare}`));
82
90
  compare = undefined;
83
91
  }
84
92
  }
85
93
 
86
- // Merge the previous gas report with the new one
87
- gasReport = gasReport.map((entry) => {
88
- const prevEntry = compareGasReport.find((e) => e.name === entry.name && e.functionCall === entry.functionCall);
89
- return { ...entry, prevGasUsed: prevEntry?.gasUsed };
90
- });
91
-
92
94
  // Print gas report
93
95
  printGasReport(gasReport, compare);
94
96
 
@@ -101,16 +103,11 @@ const commandModule: CommandModule<Options, Options> = {
101
103
 
102
104
  export default commandModule;
103
105
 
104
- async function runGasReport(path: string): Promise<GasReport> {
105
- if (!path.endsWith(".t.sol")) {
106
- console.log("Skipping gas report for", chalk.bold(path), "(not a test file)");
107
- return [];
108
- }
109
- console.log("Running gas report for", chalk.bold(path));
110
- const gasReport: GasReport = [];
106
+ async function createGasReport(filename: string): Promise<string> {
107
+ console.log("Creating gas report for", chalk.bold(filename));
111
108
 
112
109
  // Parse the given test file, and add gas reporting wherever requested by a `// !gasreport` comment
113
- const fileContents = readFileSync(path, "utf8");
110
+ const fileContents = readFileSync(filename, "utf8");
114
111
  let newFile = fileContents;
115
112
 
116
113
  // Use a regex to find first line of each function
@@ -139,7 +136,7 @@ async function runGasReport(path: string): Promise<GasReport> {
139
136
  _gasreport = gasleft();
140
137
  ${functionCall}
141
138
  _gasreport = _gasreport - gasleft();
142
- console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _gasreport);`
139
+ console.log("GAS REPORT(${filename}): ${name} [${functionCall.replaceAll('"', '\\"')}]:", _gasreport);`
143
140
  );
144
141
  }
145
142
 
@@ -148,41 +145,47 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
148
145
 
149
146
  // Write the new file to disk (temporarily)
150
147
  // Create the temp file by replacing the previous file name with MudGasReport
151
- const tempFileName = path.replace(/\.t\.sol$/, "MudGasReport.t.sol");
148
+ const tempFileName = filename.replace(/\.t\.sol$/, `${tempFileSuffix}.t.sol`);
152
149
  writeFileSync(tempFileName, newFile);
153
150
 
154
- // Run the generated file using forge
155
- const child = execa("forge", ["test", "--match-path", tempFileName, "-vvv"], {
156
- stdio: ["inherit", "pipe", "inherit"],
157
- });
151
+ return tempFileName;
152
+ }
153
+
154
+ async function runGasReport(): Promise<GasReport> {
155
+ console.log("Running gas report");
156
+ const gasReport: GasReport = [];
158
157
 
159
158
  // Extract the logs from the child process
160
159
  let logs = "";
161
160
  try {
161
+ // Run the generated file using forge
162
+ const child = execa("forge", ["test", "--match-path", `*${tempFileSuffix}*`, "-vvv"], {
163
+ stdio: ["inherit", "pipe", "inherit"],
164
+ });
162
165
  logs = (await child).stdout;
163
- rmSync(tempFileName);
164
- } catch (e: any) {
165
- console.log(e.stdout ?? e);
166
+ } catch (error: any) {
167
+ console.log(error.stdout ?? error);
166
168
  console.log(chalk.red("\n-----------\nError while running the gas report (see above)"));
167
- rmSync(tempFileName);
168
- process.exit();
169
+ throw error;
169
170
  }
170
171
 
171
172
  // Extract the gas reports from the logs
172
173
 
173
174
  // Create a regex to find all lines starting with `GAS REPORT:` and extract the name, function call and gas used
174
- const gasReportRegex = new RegExp(/GAS REPORT: (.*) \[(.*)\]: (.*)/g);
175
+ const gasReportRegex = new RegExp(/GAS REPORT\((.*)\): (.*) \[(.*)\]: (.*)/g);
175
176
 
176
177
  // Loop through the matches and print the gas report
177
178
  let gasReportMatch;
178
179
  while ((gasReportMatch = gasReportRegex.exec(logs)) !== null) {
179
- const name = gasReportMatch[1];
180
- const functionCall = gasReportMatch[2].replace(";", "");
181
- const gasUsed = gasReportMatch[3];
182
-
183
- gasReport.push({ source: path, name, functionCall, gasUsed: parseInt(gasUsed) });
180
+ const source = gasReportMatch[1];
181
+ const name = gasReportMatch[2];
182
+ const functionCall = gasReportMatch[3].replace(";", "");
183
+ const gasUsed = parseInt(gasReportMatch[4]);
184
+ gasReport.push({ source, name, functionCall, gasUsed });
184
185
  }
185
186
 
187
+ gasReport.sort((a, b) => a.source.localeCompare(b.source));
188
+
186
189
  return gasReport;
187
190
  }
188
191
 
@@ -212,9 +215,5 @@ function printGasReport(gasReport: GasReport, compare?: string) {
212
215
 
213
216
  function saveGasReport(gasReport: GasReport, path: string) {
214
217
  console.log(chalk.bold(`Saving gas report to ${path}`));
215
- const serializedGasReport = gasReport
216
- .map((entry) => `(${entry.source}) | ${entry.name} [${entry.functionCall}]: ${entry.gasUsed}`)
217
- .join("\n");
218
-
219
- writeFileSync(path, serializedGasReport);
218
+ writeFileSync(path, `${JSON.stringify(gasReport, null, 2)}\n`);
220
219
  }
@@ -1,14 +1,5 @@
1
1
  import { CommandModule } from "yargs";
2
2
 
3
- import bulkupload from "./deprecated/bulkupload.js";
4
- import callSystem from "./deprecated/call-system.js";
5
- import codegenLibdeploy from "./deprecated/codegen-libdeploy.js";
6
- import deployContracts from "./deprecated/deploy-contracts.js";
7
- import systemTypes from "./deprecated/system-types.js";
8
- import test from "./deprecated/test.js";
9
- import trace from "./deprecated/trace.js";
10
- import types from "./deprecated/types.js";
11
-
12
3
  import devnode from "./devnode.js";
13
4
  import faucet from "./faucet.js";
14
5
  import gasReport from "./gas-report.js";
@@ -18,24 +9,18 @@ import tsgen from "./tsgen.js";
18
9
  import deployV2 from "./deploy-v2.js";
19
10
  import worldgen from "./worldgen.js";
20
11
  import setVersion from "./set-version.js";
12
+ import testV2 from "./test-v2.js";
21
13
 
22
14
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Each command has different options
23
15
  export const commands: CommandModule<any, any>[] = [
24
- bulkupload,
25
- callSystem,
26
- codegenLibdeploy,
27
- deployContracts,
28
16
  deployV2,
29
17
  devnode,
30
18
  faucet,
31
19
  gasReport,
32
20
  hello,
33
- systemTypes,
34
21
  tablegen,
35
22
  tsgen,
36
- test,
37
- trace,
38
- types,
39
23
  worldgen,
40
24
  setVersion,
25
+ testV2,
41
26
  ];
@@ -2,14 +2,16 @@ import chalk from "chalk";
2
2
  import { existsSync, readFileSync, rmSync, writeFileSync } from "fs";
3
3
  import path from "path";
4
4
  import type { CommandModule } from "yargs";
5
- import { logError, MUDError } from "../utils/errors.js";
6
- import localPackageJson from "../../package.json";
5
+ import { MUDError } from "@latticexyz/config";
6
+ import { logError } from "../utils/errors.js";
7
+ import localPackageJson from "../../package.json" assert { type: "json" };
7
8
 
8
9
  type Options = {
9
10
  backup?: boolean;
10
11
  force?: boolean;
11
12
  restore?: boolean;
12
13
  mudVersion?: string;
14
+ link?: string;
13
15
  };
14
16
 
15
17
  const BACKUP_FILE = ".mudbackup";
@@ -29,13 +31,19 @@ const commandModule: CommandModule<Options, Options> = {
29
31
  },
30
32
  restore: { type: "boolean", description: `Restore the previous MUD versions from "${BACKUP_FILE}"` },
31
33
  mudVersion: { alias: "v", type: "string", description: "The MUD version to install" },
34
+ link: { alias: "l", type: "string", description: "Relative path to the local MUD root directory to link" },
32
35
  });
33
36
  },
34
37
 
35
38
  async handler(options) {
36
39
  try {
37
- if (!options.mudVersion && !options.restore) {
38
- throw new MUDError(`Version parameter is required unless --restore is provided.`);
40
+ if (!options.mudVersion && !options.link && !options.restore) {
41
+ throw new MUDError("`--mudVersion` or `--link` is required unless --restore is provided.");
42
+ }
43
+
44
+ // `link` and `mudVersion` are mutually exclusive
45
+ if (options.link && options.mudVersion) {
46
+ throw new MUDError("Options `--link` and `--mudVersion` are mutually exclusive");
39
47
  }
40
48
 
41
49
  // Resolve the `canary` version number if needed
@@ -62,11 +70,17 @@ const commandModule: CommandModule<Options, Options> = {
62
70
  };
63
71
 
64
72
  function updatePackageJson(filePath: string, options: Options): { workspaces?: string[] } {
65
- const { backup, restore, force, mudVersion } = options;
73
+ const { restore, force, link } = options;
74
+ let { backup, mudVersion } = options;
75
+
66
76
  const backupFilePath = path.join(path.dirname(filePath), BACKUP_FILE);
77
+ const backupFileExists = existsSync(backupFilePath);
78
+
79
+ // Create a backup file for previous MUD versions by default if linking to local MUD
80
+ if (link && !backupFileExists) backup = true;
67
81
 
68
82
  // If `backup` is true and force not set, check if a backup file already exists and throw an error if it does
69
- if (backup && !force && existsSync(backupFilePath)) {
83
+ if (backup && !force && backupFileExists) {
70
84
  throw new MUDError(
71
85
  `A backup file already exists at ${backupFilePath}.\nUse --force to overwrite it or --restore to restore it.`
72
86
  );
@@ -105,16 +119,14 @@ function updatePackageJson(filePath: string, options: Options): { workspaces?: s
105
119
  // Update the dependencies
106
120
  for (const key in packageJson.dependencies) {
107
121
  if (key.startsWith(MUD_PREFIX)) {
108
- packageJson.dependencies[key] =
109
- restore && backupJson ? backupJson.dependencies[key] : mudVersion || packageJson.dependencies[key];
122
+ packageJson.dependencies[key] = resolveMudVersion(key, "dependencies");
110
123
  }
111
124
  }
112
125
 
113
126
  // Update the devDependencies
114
127
  for (const key in packageJson.devDependencies) {
115
128
  if (key.startsWith(MUD_PREFIX)) {
116
- packageJson.devDependencies[key] =
117
- restore && backupJson ? backupJson.devDependencies[key] : mudVersion || packageJson.devDependencies[key];
129
+ packageJson.devDependencies[key] = resolveMudVersion(key, "devDependencies");
118
130
  }
119
131
  }
120
132
 
@@ -133,6 +145,13 @@ function updatePackageJson(filePath: string, options: Options): { workspaces?: s
133
145
  }
134
146
 
135
147
  return packageJson;
148
+
149
+ function resolveMudVersion(key: string, type: "dependencies" | "devDependencies") {
150
+ if (restore && backupJson) return backupJson[type][key];
151
+ if (link) mudVersion = resolveLinkPath(filePath, link, key);
152
+ if (!mudVersion) return packageJson[type][key];
153
+ return mudVersion;
154
+ }
136
155
  }
137
156
 
138
157
  function readPackageJson(path: string): {
@@ -168,4 +187,14 @@ function logComparison(prev: Record<string, string>, curr: Record<string, string
168
187
  }
169
188
  }
170
189
 
190
+ /**
191
+ * Returns path of the package to link, given a path to a local MUD clone and a package
192
+ */
193
+ function resolveLinkPath(packageJsonPath: string, mudLinkPath: string, pkg: string) {
194
+ const pkgName = pkg.replace(MUD_PREFIX, "");
195
+ const packageJsonToRootPath = path.relative(path.dirname(packageJsonPath), process.cwd());
196
+ const linkPath = path.join(packageJsonToRootPath, mudLinkPath, "packages", pkgName);
197
+ return "link:" + linkPath;
198
+ }
199
+
171
200
  export default commandModule;
@@ -1,7 +1,8 @@
1
+ import path from "path";
1
2
  import type { CommandModule } from "yargs";
2
- import { loadStoreConfig } from "../config/loadStoreConfig.js";
3
- import { getSrcDirectory } from "../utils/foundry.js";
3
+ import { loadStoreConfig } from "@latticexyz/config";
4
4
  import { tablegen } from "../render-solidity/tablegen.js";
5
+ import { getSrcDirectory } from "../utils/index.js";
5
6
 
6
7
  type Options = {
7
8
  configPath?: string;
@@ -19,11 +20,10 @@ const commandModule: CommandModule<Options, Options> = {
19
20
  },
20
21
 
21
22
  async handler({ configPath }) {
22
- const srcDirectory = await getSrcDirectory();
23
-
24
23
  const config = await loadStoreConfig(configPath);
24
+ const srcDir = await getSrcDirectory();
25
25
 
26
- await tablegen(config, srcDirectory);
26
+ await tablegen(config, path.join(srcDir, config.codegenDirectory));
27
27
 
28
28
  process.exit(0);
29
29
  },
@@ -0,0 +1,71 @@
1
+ import type { CommandModule } from "yargs";
2
+ import { deployHandler, DeployOptions } from "./deploy-v2.js";
3
+ import { yDeployOptions } from "./deploy-v2.js";
4
+ import { anvil, forge, getRpcUrl, getTestDirectory } from "../utils/foundry.js";
5
+ import chalk from "chalk";
6
+ import { rmSync, writeFileSync } from "fs";
7
+ import path from "path";
8
+
9
+ type Options = DeployOptions & { port?: number; worldAddress?: string; forgeOptions?: string };
10
+
11
+ const WORLD_ADDRESS_FILE = ".mudtest";
12
+
13
+ const commandModule: CommandModule<Options, Options> = {
14
+ command: "test-v2",
15
+
16
+ describe: "Run tests in MUD v2 contracts",
17
+
18
+ builder(yargs) {
19
+ return yargs.options({
20
+ ...yDeployOptions,
21
+ port: { type: "number", description: "Port to run internal node for fork testing on", default: 4242 },
22
+ worldAddress: {
23
+ type: "string",
24
+ description:
25
+ "Address of an existing world contract. If provided, deployment is skipped and the RPC provided in the foundry.toml is used for fork testing.",
26
+ },
27
+ forgeOptions: { type: "string", description: "Options to pass to forge test" },
28
+ });
29
+ },
30
+
31
+ async handler(args) {
32
+ // Start an internal anvil process if no world address is provided
33
+ if (!args.worldAddress) {
34
+ const anvilArgs = ["--block-base-fee-per-gas", "0", "--port", String(args.port)];
35
+ anvil(anvilArgs);
36
+ }
37
+
38
+ const forkRpc = args.worldAddress ? await getRpcUrl(args.profile) : `http://127.0.0.1:${args.port}`;
39
+
40
+ const worldAddress =
41
+ args.worldAddress ??
42
+ (
43
+ await deployHandler({
44
+ ...args,
45
+ saveDeployment: false,
46
+ rpc: forkRpc,
47
+ })
48
+ ).worldAddress;
49
+
50
+ console.log(chalk.blue("World address", worldAddress));
51
+
52
+ // Create a temporary file to pass the world address to the tests
53
+ writeFileSync(WORLD_ADDRESS_FILE, worldAddress);
54
+
55
+ const userOptions = args.forgeOptions?.replaceAll("\\", "").split(" ") ?? [];
56
+ try {
57
+ const testResult = await forge(["test", "--fork-url", forkRpc, ...userOptions], {
58
+ profile: args.profile,
59
+ });
60
+ console.log(testResult);
61
+ } catch (e) {
62
+ console.error(e);
63
+ }
64
+
65
+ rmSync(WORLD_ADDRESS_FILE);
66
+
67
+ process.exit(0);
68
+ },
69
+ };
70
+
71
+ export default commandModule;
@@ -1,5 +1,5 @@
1
1
  import type { CommandModule } from "yargs";
2
- import { loadStoreConfig } from "../config/loadStoreConfig.js";
2
+ import { loadStoreConfig } from "@latticexyz/config";
3
3
  import { tsgen } from "../render-ts/tsgen.js";
4
4
 
5
5
  type Options = {
@@ -1,6 +1,5 @@
1
1
  import type { CommandModule } from "yargs";
2
- import { loadStoreConfig } from "../config/loadStoreConfig.js";
3
- import { loadWorldConfig } from "../config/index.js";
2
+ import { loadStoreConfig, loadWorldConfig } from "@latticexyz/config";
4
3
  import { getSrcDirectory } from "../utils/foundry.js";
5
4
  import glob from "glob";
6
5
  import path, { basename } from "path";
@@ -42,11 +41,13 @@ const commandModule: CommandModule<Options, Options> = {
42
41
  const storeConfig = await loadStoreConfig(configPath);
43
42
  const mudConfig = { ...worldConfig, ...storeConfig };
44
43
 
44
+ const outputBaseDirectory = path.join(srcDir, mudConfig.codegenDirectory);
45
+
45
46
  // clear the worldgen directory
46
- if (clean) rmSync(path.join(srcDir, worldConfig.worldgenDirectory), { recursive: true, force: true });
47
+ if (clean) rmSync(path.join(outputBaseDirectory, mudConfig.worldgenDirectory), { recursive: true, force: true });
47
48
 
48
49
  // generate new interfaces
49
- await worldgen(mudConfig, existingContracts, srcDir);
50
+ await worldgen(mudConfig, existingContracts, outputBaseDirectory);
50
51
 
51
52
  process.exit(0);
52
53
  },
@@ -1,14 +1,14 @@
1
1
  // SPDX-License-Identifier: MIT
2
2
  pragma solidity >=0.8.0;
3
3
 
4
- import {Script} from "forge-std/Script.sol";
5
- import {console} from "forge-std/console.sol";
4
+ import { Script } from "forge-std/Script.sol";
5
+ import { console } from "forge-std/console.sol";
6
6
 
7
- import {BulkSetStateSystem, ID as BulkSetStateSystemID, ECSEvent} from "std-contracts/systems/BulkSetStateSystem.sol";
8
- import {World} from "solecs/World.sol";
9
- import {System} from "solecs/System.sol";
10
- import {getAddressById} from "solecs/utils.sol";
11
- import {Set} from "solecs/Set.sol";
7
+ import { BulkSetStateSystem, ID as BulkSetStateSystemID, ECSEvent } from "std-contracts/systems/BulkSetStateSystem.sol";
8
+ import { World } from "solecs/World.sol";
9
+ import { System } from "solecs/System.sol";
10
+ import { getAddressById } from "solecs/utils.sol";
11
+ import { Set } from "solecs/Set.sol";
12
12
 
13
13
  struct ParsedState {
14
14
  string[] componentIds;
@@ -33,11 +33,7 @@ struct State {
33
33
  * forge script --sig "run(string, address)" --rpc-url http://localhost:8545 src/contracts/BulkUpload.sol:BulkUpload path/to/ecs-map-test.json <WORLD_ADDRESS>
34
34
  */
35
35
  contract BulkUpload is Script {
36
- function run(
37
- string memory path,
38
- address worldAddress,
39
- uint256 eventsPerTx
40
- ) public {
36
+ function run(string memory path, address worldAddress, uint256 eventsPerTx) public {
41
37
  vmSafe.startBroadcast();
42
38
 
43
39
  // Read JSON
@@ -108,9 +104,10 @@ contract BulkUpload is Script {
108
104
  }
109
105
  }
110
106
 
111
- function transformEventsToOnlyUseNeededEntities(uint256[] memory entities, ECSEvent[] memory events)
112
- returns (uint256[] memory, ECSEvent[] memory)
113
- {
107
+ function transformEventsToOnlyUseNeededEntities(
108
+ uint256[] memory entities,
109
+ ECSEvent[] memory events
110
+ ) returns (uint256[] memory, ECSEvent[] memory) {
114
111
  Set uniqueEntityIndices = new Set();
115
112
 
116
113
  // Find unique entity indices
@@ -167,11 +164,7 @@ function hexToBytes(string memory s) pure returns (bytes memory) {
167
164
  return r;
168
165
  }
169
166
 
170
- function substring(
171
- string memory str,
172
- uint256 start,
173
- uint256 end
174
- ) pure returns (string memory) {
167
+ function substring(string memory str, uint256 start, uint256 end) pure returns (string memory) {
175
168
  bytes memory strBytes = bytes(str);
176
169
  bytes memory result = new bytes(end - start);
177
170
  for (uint256 i = start; i < end; i++) {
@@ -2,11 +2,11 @@
2
2
  pragma solidity >=0.8.0;
3
3
 
4
4
  // Foundry
5
- import {Script} from "forge-std/Script.sol";
6
- import {console} from "forge-std/console.sol";
5
+ import { Script } from "forge-std/Script.sol";
6
+ import { console } from "forge-std/console.sol";
7
7
 
8
8
  // Libraries
9
- import {LibDeploy, DeployResult} from "./LibDeploy.sol";
9
+ import { LibDeploy, DeployResult } from "./LibDeploy.sol";
10
10
 
11
11
  contract Deploy is Script {
12
12
  function broadcastDeploy(
@@ -7,7 +7,7 @@ pragma solidity >=0.8.0;
7
7
  // To manually generate the real LibDeploy.sol use
8
8
  // `mud codegen-libdeploy`.
9
9
 
10
- import {IWorld} from "solecs/interfaces/IWorld.sol";
10
+ import { IWorld } from "solecs/interfaces/IWorld.sol";
11
11
 
12
12
  struct DeployResult {
13
13
  IWorld world;
@@ -7,7 +7,7 @@ pragma solidity >=0.8.0;
7
7
  // To manually generate the real LibDeploy.sol use
8
8
  // `mud codegen-libdeploy`.
9
9
 
10
- import {IWorld} from "solecs/interfaces/IWorld.sol";
10
+ import { IWorld } from "solecs/interfaces/IWorld.sol";
11
11
 
12
12
  struct DeployResult {
13
13
  IWorld world;
package/src/index.ts CHANGED
@@ -1,15 +1 @@
1
- export { loadStoreConfig } from "./config/loadStoreConfig.js";
2
- export { parseStoreConfig } from "./config/parseStoreConfig.js";
3
- export { loadWorldConfig, resolveWorldConfig, parseWorldConfig } from "./config/world/index.js";
4
- export { resolveTableId } from "./config/dynamicResolution.js";
5
-
6
- export type {
7
- StoreUserConfig,
8
- StoreConfig,
9
- WorldUserConfig,
10
- ResolvedWorldConfig,
11
- MUDUserConfig,
12
- MUDConfig,
13
- } from "./config/index.js";
14
-
15
- export { storeConfig, mudConfig } from "./config/index.js";
1
+ export {};
package/src/mud.ts CHANGED
@@ -1,8 +1,9 @@
1
- #!/usr/bin/env -S TS_NODE_COMPILER_OPTIONS={\"module\":\"esnext\"} node --loader=ts-node/esm --no-warnings
1
+ #!/usr/bin/env node
2
2
 
3
3
  import yargs from "yargs";
4
4
  import { hideBin } from "yargs/helpers";
5
- import { commands } from "./commands/index.js";
5
+ import { commands as v2 } from "./commands/index.js";
6
+ import { commands as v1 } from "./commands/deprecated/index.js";
6
7
  import { logError } from "./utils/errors.js";
7
8
 
8
9
  // Load .env file into process.env
@@ -14,7 +15,7 @@ yargs(hideBin(process.argv))
14
15
  .scriptName("mud")
15
16
  // Use the commands directory to scaffold
16
17
  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- command array overload isn't typed, see https://github.com/yargs/yargs/blob/main/docs/advanced.md#esm-hierarchy
17
- .command(commands as any)
18
+ .command([...v1, ...v2] as any)
18
19
  // Enable strict mode.
19
20
  .strict()
20
21
  // Custom error handler
package/src/mud2.ts ADDED
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+
3
+ import yargs from "yargs";
4
+ import { hideBin } from "yargs/helpers";
5
+ import { commands } from "./commands/index.js";
6
+ import { logError } from "./utils/errors.js";
7
+
8
+ // Load .env file into process.env
9
+ import * as dotenv from "dotenv";
10
+ dotenv.config();
11
+
12
+ yargs(hideBin(process.argv))
13
+ // Explicit name to display in help (by default it's the entry file, which may not be "mud" for e.g. ts-node)
14
+ .scriptName("mud")
15
+ // Use the commands directory to scaffold
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- command array overload isn't typed, see https://github.com/yargs/yargs/blob/main/docs/advanced.md#esm-hierarchy
17
+ .command(commands as any)
18
+ // Enable strict mode.
19
+ .strict()
20
+ // Custom error handler
21
+ .fail((msg, err) => {
22
+ console.log("");
23
+ logError(err);
24
+ console.log("");
25
+
26
+ process.exit(1);
27
+ })
28
+ // Useful aliases.
29
+ .alias({ h: "help" }).argv;
@@ -27,7 +27,7 @@ export function renderCommonData({
27
27
  }: Pick<RenderTableOptions, "staticResourceData" | "primaryKeys">) {
28
28
  // static resource means static tableId as well, and no tableId arguments
29
29
  const _tableId = staticResourceData ? "" : "_tableId";
30
- const _typedTableId = staticResourceData ? "" : "uint256 _tableId";
30
+ const _typedTableId = staticResourceData ? "" : "bytes32 _tableId";
31
31
 
32
32
  const _keyArgs = renderArguments(primaryKeys.map(({ name }) => name));
33
33
  const _typedKeyArgs = renderArguments(primaryKeys.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
@@ -100,11 +100,11 @@ export function renderWithStore(
100
100
  }
101
101
 
102
102
  export function renderTableId(staticResourceData: StaticResourceData) {
103
- const hardcodedTableId = `uint256(bytes32(abi.encodePacked(bytes16("${staticResourceData.namespace}"), bytes16("${staticResourceData.fileSelector}"))))`;
103
+ const hardcodedTableId = `bytes32(abi.encodePacked(bytes16("${staticResourceData.namespace}"), bytes16("${staticResourceData.name}")))`;
104
104
 
105
105
  const tableIdDefinition = `
106
- uint256 constant _tableId = ${hardcodedTableId};
107
- uint256 constant ${staticResourceData.tableIdName} = _tableId;
106
+ bytes32 constant _tableId = ${hardcodedTableId};
107
+ bytes32 constant ${staticResourceData.tableIdName} = _tableId;
108
108
  `;
109
109
  return {
110
110
  hardcodedTableId,