@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
@@ -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;
@@ -0,0 +1,33 @@
1
+ import type { CommandModule } from "yargs";
2
+ import { loadStoreConfig } from "@latticexyz/config";
3
+ import { tsgen } from "../render-ts/tsgen.js";
4
+
5
+ type Options = {
6
+ configPath: string;
7
+ out: string;
8
+ };
9
+
10
+ const commandModule: CommandModule<Options, Options> = {
11
+ command: "tsgen",
12
+
13
+ describe: "Autogenerate MUD typescript definitions based on the config file",
14
+
15
+ builder(yargs) {
16
+ return yargs.options({
17
+ configPath: { type: "string", demandOption: true, desc: "Path to the config file" },
18
+ out: { type: "string", demandOption: true, desc: "Directory to output MUD typescript definition files" },
19
+ });
20
+ },
21
+
22
+ async handler(args) {
23
+ const { configPath, out } = args;
24
+
25
+ const config = await loadStoreConfig(configPath);
26
+
27
+ await tsgen(config, out);
28
+
29
+ process.exit(0);
30
+ },
31
+ };
32
+
33
+ export default commandModule;
@@ -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,
@@ -41,8 +41,6 @@ export function renderFieldMethods(options: RenderTableOptions) {
41
41
  `
42
42
  );
43
43
 
44
- // TODO: this is super inefficient right now, need to add support for pushing to arrays to the store core library to avoid reading/writing the entire array
45
- // (see https://github.com/latticexyz/mud/issues/438)
46
44
  if (field.isDynamic) {
47
45
  const portionData = fieldPortionData(field);
48
46
 
@@ -61,6 +59,29 @@ export function renderFieldMethods(options: RenderTableOptions) {
61
59
  }
62
60
  `
63
61
  );
62
+
63
+ result += renderWithStore(
64
+ storeArgument,
65
+ (_typedStore, _store, _commentSuffix) => `
66
+ /** Update ${portionData.title} of ${field.name}${_commentSuffix} at \`_index\` */
67
+ function update${field.methodNameSuffix}(${renderArguments([
68
+ _typedStore,
69
+ _typedTableId,
70
+ _typedKeyArgs,
71
+ "uint256 _index",
72
+ `${portionData.typeWithLocation} ${portionData.name}`,
73
+ ])}) internal {
74
+ ${_primaryKeysDefinition}
75
+ ${_store}.updateInField(
76
+ _tableId,
77
+ _primaryKeys,
78
+ ${index},
79
+ _index * ${portionData.elementLength},
80
+ ${portionData.encoded}
81
+ );
82
+ }
83
+ `
84
+ );
64
85
  }
65
86
  }
66
87
  return result;
@@ -109,6 +130,7 @@ function fieldPortionData(field: RenderTableField) {
109
130
  name: "_element",
110
131
  encoded: renderEncodeField({ ...field.arrayElement, arrayElement: undefined, name, methodNameSuffix }),
111
132
  title: "an element",
133
+ elementLength: field.arrayElement.staticByteLength,
112
134
  };
113
135
  } else {
114
136
  const name = "_slice";
@@ -117,6 +139,7 @@ function fieldPortionData(field: RenderTableField) {
117
139
  name,
118
140
  encoded: renderEncodeField({ ...field, name, methodNameSuffix }),
119
141
  title: "a slice",
142
+ elementLength: 1,
120
143
  };
121
144
  }
122
145
  }
@@ -99,16 +99,20 @@ function renderDecodeFunction({ structName, fields, staticFields, dynamicFields
99
99
  ${fieldNamePrefix}${field.name} = ${renderDecodeValueType(field, staticOffsets[index])};
100
100
  `
101
101
  )}
102
- uint256 _start;
103
- uint256 _end = ${totalStaticLength + 32};
104
- ${renderList(
105
- dynamicFields,
106
- (field, index) => `
107
- _start = _end;
108
- _end += _encodedLengths.atIndex(${index});
109
- ${fieldNamePrefix}${field.name} = ${renderDecodeDynamicFieldPartial(field)};
110
- `
111
- )}
102
+ // Store trims the blob if dynamic fields are all empty
103
+ if (_blob.length > ${totalStaticLength}) {
104
+ uint256 _start;
105
+ // skip static data length + dynamic lengths word
106
+ uint256 _end = ${totalStaticLength + 32};
107
+ ${renderList(
108
+ dynamicFields,
109
+ (field, index) => `
110
+ _start = _end;
111
+ _end += _encodedLengths.atIndex(${index});
112
+ ${fieldNamePrefix}${field.name} = ${renderDecodeDynamicFieldPartial(field)};
113
+ `
114
+ )}
115
+ }
112
116
  }
113
117
  `;
114
118
  } else {
@@ -11,10 +11,10 @@ ${renderImports(imports)}
11
11
  interface ${name} {
12
12
  ${renderList(
13
13
  functions,
14
- ({ name, parameters, returnParameters }) => `
15
- function ${functionPrefix}${name}(${renderArguments(parameters)}) external ${renderReturnParameters(
16
- returnParameters
17
- )};
14
+ ({ name, parameters, stateMutability, returnParameters }) => `
15
+ function ${functionPrefix}${name}(
16
+ ${renderArguments(parameters)}
17
+ ) external ${stateMutability} ${renderReturnParameters(returnParameters)};
18
18
  `
19
19
  )}
20
20
  }
@@ -0,0 +1,15 @@
1
+ import { renderList, renderedSolidityHeader } from "./common.js";
2
+ import { TableOptions } from "./tableOptions.js";
3
+
4
+ export function renderTableIndex(options: TableOptions[]) {
5
+ return `${renderedSolidityHeader}
6
+
7
+ ${renderList(options, ({ outputPath, tableName, renderOptions: { structName, staticResourceData } }) => {
8
+ const imports = [tableName];
9
+ if (structName) imports.push(structName);
10
+ if (staticResourceData) imports.push(`${tableName}TableId`);
11
+
12
+ return `import { ${imports.join(", ")} } from "./${outputPath}";`;
13
+ })}
14
+ `;
15
+ }
@@ -1,4 +1,4 @@
1
- import { StoreConfig } from "../config/parseStoreConfig.js";
1
+ import { StoreConfig } from "@latticexyz/config";
2
2
  import { renderTypes } from "./renderTypes.js";
3
3
 
4
4
  export function renderTypesFromConfig(config: StoreConfig) {
@@ -1,6 +1,6 @@
1
1
  import path from "path";
2
2
  import { SchemaTypeArrayToElement } from "@latticexyz/schema-type";
3
- import { StoreConfig } from "../config/parseStoreConfig.js";
3
+ import { StoreConfig } from "@latticexyz/config";
4
4
  import {
5
5
  ImportDatum,
6
6
  RenderTableDynamicField,
@@ -80,7 +80,7 @@ export function getTableOptions(config: StoreConfig): TableOptions[] {
80
80
  return {
81
81
  tableIdName: tableName + "TableId",
82
82
  namespace: config.namespace,
83
- fileSelector: tableData.fileSelector,
83
+ name: tableData.name,
84
84
  };
85
85
  }
86
86
  })();
@@ -1,33 +1,35 @@
1
- import { mkdirSync, writeFileSync } from "fs";
2
1
  import path from "path";
3
- import { StoreConfig } from "../config/index.js";
4
- import { formatSolidity } from "../utils/format.js";
2
+ import { StoreConfig } from "@latticexyz/config";
5
3
  import { getTableOptions } from "./tableOptions.js";
6
4
  import { renderTable } from "./renderTable.js";
7
5
  import { renderTypesFromConfig } from "./renderTypesFromConfig.js";
6
+ import { formatAndWriteSolidity } from "../utils/formatAndWrite.js";
7
+ import { renderTableIndex } from "./renderTableIndex.js";
8
+ import { rmSync } from "fs";
8
9
 
9
10
  export async function tablegen(config: StoreConfig, outputBaseDirectory: string) {
10
11
  const allTableOptions = getTableOptions(config);
12
+
13
+ const uniqueTableDirectories = new Set(allTableOptions.map(({ outputPath }) => path.dirname(outputPath)));
14
+ for (const tableDir of uniqueTableDirectories) {
15
+ rmSync(path.join(outputBaseDirectory, tableDir), { recursive: true, force: true });
16
+ }
17
+
11
18
  // write tables to files
12
19
  for (const { outputPath, renderOptions } of allTableOptions) {
13
20
  const fullOutputPath = path.join(outputBaseDirectory, outputPath);
14
21
  const output = renderTable(renderOptions);
15
- formatAndWrite(output, fullOutputPath, "Generated table");
22
+ formatAndWriteSolidity(output, fullOutputPath, "Generated table");
16
23
  }
17
24
 
18
25
  // write types to file
19
26
  if (Object.keys(config.enums).length > 0) {
20
27
  const fullOutputPath = path.join(outputBaseDirectory, `${config.userTypesPath}.sol`);
21
28
  const output = renderTypesFromConfig(config);
22
- formatAndWrite(output, fullOutputPath, "Generated types file");
29
+ formatAndWriteSolidity(output, fullOutputPath, "Generated types file");
23
30
  }
24
- }
25
-
26
- async function formatAndWrite(output: string, fullOutputPath: string, logPrefix: string) {
27
- const formattedOutput = await formatSolidity(output);
28
-
29
- mkdirSync(path.dirname(fullOutputPath), { recursive: true });
30
31
 
31
- writeFileSync(fullOutputPath, formattedOutput);
32
- console.log(`${logPrefix}: ${fullOutputPath}`);
32
+ const fullOutputPath = path.join(outputBaseDirectory, `Tables.sol`);
33
+ const output = renderTableIndex(allTableOptions);
34
+ formatAndWriteSolidity(output, fullOutputPath, "Generated table index");
33
35
  }
@@ -29,7 +29,7 @@ export interface StaticResourceData {
29
29
  /** Name of the table id constant to render. */
30
30
  tableIdName: string;
31
31
  namespace: string;
32
- fileSelector: string;
32
+ name: string;
33
33
  }
34
34
 
35
35
  export interface RenderTableType {
@@ -95,6 +95,7 @@ export interface RenderSystemInterfaceOptions {
95
95
  export interface RenderSystemInterfaceFunction {
96
96
  name: string;
97
97
  parameters: string[];
98
+ stateMutability: string;
98
99
  returnParameters: string[];
99
100
  }
100
101
 
@@ -1,7 +1,6 @@
1
1
  import { AbiTypeToSchemaType, getStaticByteLength, SchemaType, SchemaTypeToAbiType } from "@latticexyz/schema-type";
2
- import { StoreConfig } from "../config/index.js";
2
+ import { StoreConfig, parseStaticArray } from "@latticexyz/config";
3
3
  import { ImportDatum, RenderTableType } from "./types.js";
4
- import { parseStaticArray } from "../config/validation.js";
5
4
 
6
5
  export type UserTypeInfo = ReturnType<typeof getUserTypeInfo>;
7
6
 
@@ -1,8 +1,8 @@
1
1
  import { readFileSync } from "fs";
2
2
  import path from "path";
3
- import { MUDConfig } from "../config/index.js";
3
+ import { MUDConfig } from "@latticexyz/config";
4
4
  import { contractToInterface } from "../utils/contractToInterface.js";
5
- import { formatAndWrite } from "../utils/formatAndWrite.js";
5
+ import { formatAndWriteSolidity } from "../utils/formatAndWrite.js";
6
6
  import { renderSystemInterface } from "./renderSystemInterface.js";
7
7
  import { renderWorld } from "./renderWorld.js";
8
8
  import { ImportDatum } from "./types.js";
@@ -27,16 +27,16 @@ export async function worldgen(
27
27
  }));
28
28
  const systemInterfaceName = `I${system.basename}`;
29
29
  // create an interface using the external functions and imports
30
- const { fileSelector } = config.systems[system.basename];
30
+ const { name } = config.systems[system.basename];
31
31
  const output = renderSystemInterface({
32
32
  name: systemInterfaceName,
33
- functionPrefix: config.namespace === "" ? "" : `${config.namespace}_${fileSelector}_`,
33
+ functionPrefix: config.namespace === "" ? "" : `${config.namespace}_${name}_`,
34
34
  functions,
35
35
  imports,
36
36
  });
37
37
  // write to file
38
38
  const fullOutputPath = path.join(worldgenBaseDirectory, systemInterfaceName + ".sol");
39
- await formatAndWrite(output, fullOutputPath, "Generated system interface");
39
+ await formatAndWriteSolidity(output, fullOutputPath, "Generated system interface");
40
40
 
41
41
  // prepare imports for IWorld
42
42
  systemInterfaceImports.push({
@@ -47,14 +47,13 @@ export async function worldgen(
47
47
  }
48
48
 
49
49
  // render IWorld
50
- const worldInterfaceName = "IWorld";
51
50
  const output = renderWorld({
52
- interfaceName: worldInterfaceName,
51
+ interfaceName: config.worldInterfaceName,
53
52
  imports: systemInterfaceImports,
54
53
  storeImportPath: config.storeImportPath,
55
54
  worldImportPath: config.worldImportPath,
56
55
  });
57
56
  // write to file
58
- const fullOutputPath = path.join(worldgenBaseDirectory, worldInterfaceName + ".sol");
59
- await formatAndWrite(output, fullOutputPath, "Generated system interface");
57
+ const fullOutputPath = path.join(worldgenBaseDirectory, config.worldInterfaceName + ".sol");
58
+ await formatAndWriteSolidity(output, fullOutputPath, "Generated system interface");
60
59
  }
@@ -0,0 +1,5 @@
1
+ export * from "./recsV1TableOptions.js";
2
+ export * from "./renderRecsV1Tables.js";
3
+ export * from "./schemaTypesToRecsTypeStrings.js";
4
+ export * from "./tsgen.js";
5
+ export * from "./types.js";
@@ -0,0 +1,39 @@
1
+ import { StoreConfig } from "@latticexyz/config";
2
+ import { resolveAbiOrUserType } from "../render-solidity/userType.js";
3
+ import { schemaTypesToRecsTypeStrings } from "./schemaTypesToRecsTypeStrings.js";
4
+ import { RecsV1TableOptions } from "./types.js";
5
+
6
+ export function getRecsV1TableOptions(config: StoreConfig): RecsV1TableOptions {
7
+ const tableOptions = [];
8
+ for (const tableName of Object.keys(config.tables)) {
9
+ const tableData = config.tables[tableName];
10
+
11
+ const fields = Object.keys(tableData.schema).map((name) => {
12
+ const abiOrUserType = tableData.schema[name];
13
+ const { schemaType } = resolveAbiOrUserType(abiOrUserType, config);
14
+
15
+ const recsTypeString = schemaTypesToRecsTypeStrings[schemaType];
16
+
17
+ return {
18
+ recsTypeString,
19
+ name,
20
+ };
21
+ });
22
+
23
+ // WARNING: skip tables without a static tableId
24
+ if (tableData.tableIdArgument) continue;
25
+ const staticResourceData = {
26
+ namespace: config.namespace,
27
+ name: tableData.name,
28
+ };
29
+
30
+ tableOptions.push({
31
+ tableName,
32
+ fields,
33
+ staticResourceData,
34
+ });
35
+ }
36
+ return {
37
+ tables: tableOptions,
38
+ };
39
+ }