@latticexyz/cli 1.41.0 → 1.41.1-alpha.41

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 (53) hide show
  1. package/dist/{chunk-GR245KYP.js → chunk-J4DJQNIC.js} +679 -133
  2. package/dist/chunk-O57QENJ6.js +23039 -0
  3. package/dist/config/index.d.ts +610 -296
  4. package/dist/config/index.js +49 -26
  5. package/dist/index.d.ts +2 -110
  6. package/dist/index.js +9 -50
  7. package/dist/mud.js +937 -57
  8. package/dist/utils/index.d.ts +92 -4
  9. package/dist/utils/index.js +2 -3
  10. package/package.json +10 -9
  11. package/src/commands/deploy-v2.ts +11 -15
  12. package/src/commands/index.ts +2 -0
  13. package/src/commands/worldgen.ts +55 -0
  14. package/src/config/commonSchemas.ts +11 -13
  15. package/src/config/dynamicResolution.ts +49 -0
  16. package/src/config/index.ts +15 -3
  17. package/src/config/loadStoreConfig.ts +1 -1
  18. package/src/config/parseStoreConfig.test-d.ts +31 -5
  19. package/src/config/parseStoreConfig.ts +218 -78
  20. package/src/config/validation.ts +25 -0
  21. package/src/config/world/index.ts +4 -0
  22. package/src/config/{loadWorldConfig.test-d.ts → world/loadWorldConfig.test-d.ts} +3 -3
  23. package/src/config/world/loadWorldConfig.ts +26 -0
  24. package/src/config/world/parseWorldConfig.ts +55 -0
  25. package/src/config/world/resolveWorldConfig.ts +80 -0
  26. package/src/config/world/userTypes.ts +72 -0
  27. package/src/index.ts +4 -6
  28. package/src/render-solidity/common.ts +51 -6
  29. package/src/render-solidity/field.ts +40 -44
  30. package/src/render-solidity/index.ts +5 -1
  31. package/src/render-solidity/record.ts +56 -73
  32. package/src/render-solidity/renderSystemInterface.ts +31 -0
  33. package/src/render-solidity/renderTable.ts +98 -70
  34. package/src/render-solidity/renderTypeHelpers.ts +99 -0
  35. package/src/render-solidity/renderTypesFromConfig.ts +2 -2
  36. package/src/render-solidity/renderWorld.ts +24 -0
  37. package/src/render-solidity/{renderTablesFromConfig.ts → tableOptions.ts} +28 -30
  38. package/src/render-solidity/tablegen.ts +20 -22
  39. package/src/render-solidity/types.ts +39 -5
  40. package/src/render-solidity/userType.ts +80 -48
  41. package/src/render-solidity/worldgen.ts +60 -0
  42. package/src/utils/contractToInterface.ts +130 -0
  43. package/src/utils/deploy-v2.ts +268 -101
  44. package/src/utils/formatAndWrite.ts +12 -0
  45. package/src/utils/getChainId.ts +10 -0
  46. package/src/utils/typeUtils.ts +17 -0
  47. package/dist/chunk-AER7UDD4.js +0 -0
  48. package/dist/chunk-XRS7KWBZ.js +0 -547
  49. package/dist/chunk-YZATC2M3.js +0 -397
  50. package/dist/chunk-ZYDMYSTH.js +0 -1178
  51. package/dist/deploy-v2-b7b3207d.d.ts +0 -92
  52. package/src/config/loadWorldConfig.ts +0 -178
  53. package/src/constants.ts +0 -1
package/dist/mud.js CHANGED
@@ -1,23 +1,18 @@
1
1
  #!/usr/bin/env -S TS_NODE_COMPILER_OPTIONS={\"module\":\"esnext\"} node --loader=ts-node/esm --no-warnings
2
- import {
3
- deploymentInfoFilenamePrefix,
4
- renderArguments,
5
- renderList,
6
- renderTablesFromConfig,
7
- renderedSolidityHeader
8
- } from "./chunk-XRS7KWBZ.js";
9
- import {
10
- loadStoreConfig,
11
- loadWorldConfig
12
- } from "./chunk-YZATC2M3.js";
13
2
  import {
14
3
  deploy,
15
- formatSolidity
16
- } from "./chunk-ZYDMYSTH.js";
4
+ formatSolidity,
5
+ getSchemaTypeInfo,
6
+ importForAbiOrUserType,
7
+ resolveAbiOrUserType
8
+ } from "./chunk-O57QENJ6.js";
17
9
  import {
18
10
  MUDError,
11
+ SchemaTypeArrayToElement,
12
+ loadStoreConfig,
13
+ loadWorldConfig,
19
14
  logError
20
- } from "./chunk-GR245KYP.js";
15
+ } from "./chunk-J4DJQNIC.js";
21
16
  import {
22
17
  JsonRpcProvider,
23
18
  componentsDir,
@@ -34,7 +29,6 @@ import {
34
29
  } from "./chunk-SLIMIO4Z.js";
35
30
  import {
36
31
  forge,
37
- getOutDirectory,
38
32
  getRpcUrl,
39
33
  getSrcDirectory,
40
34
  getTestDirectory
@@ -11261,9 +11255,9 @@ var commandModule11 = {
11261
11255
  compare: { type: "string", desc: "Compare to an existing gas report" }
11262
11256
  });
11263
11257
  },
11264
- async handler({ path: path7, save, compare: compare2 }) {
11258
+ async handler({ path: path11, save, compare: compare2 }) {
11265
11259
  let gasReport = [];
11266
- for (const file of path7) {
11260
+ for (const file of path11) {
11267
11261
  gasReport = gasReport.concat(await runGasReport(file));
11268
11262
  }
11269
11263
  const compareGasReport = [];
@@ -11295,14 +11289,14 @@ var commandModule11 = {
11295
11289
  }
11296
11290
  };
11297
11291
  var gas_report_default = commandModule11;
11298
- async function runGasReport(path7) {
11299
- if (!path7.endsWith(".t.sol")) {
11300
- console.log("Skipping gas report for", chalk3.bold(path7), "(not a test file)");
11292
+ async function runGasReport(path11) {
11293
+ if (!path11.endsWith(".t.sol")) {
11294
+ console.log("Skipping gas report for", chalk3.bold(path11), "(not a test file)");
11301
11295
  return [];
11302
11296
  }
11303
- console.log("Running gas report for", chalk3.bold(path7));
11297
+ console.log("Running gas report for", chalk3.bold(path11));
11304
11298
  const gasReport = [];
11305
- const fileContents = readFileSync2(path7, "utf8");
11299
+ const fileContents = readFileSync2(path11, "utf8");
11306
11300
  let newFile = fileContents;
11307
11301
  const functionRegex = new RegExp(/function (.*){/g);
11308
11302
  let functionMatch;
@@ -11326,7 +11320,7 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
11326
11320
  );
11327
11321
  }
11328
11322
  newFile = newFile.replace(/pure/g, "view");
11329
- const tempFileName = path7.replace(/\.t\.sol$/, "MudGasReport.t.sol");
11323
+ const tempFileName = path11.replace(/\.t\.sol$/, "MudGasReport.t.sol");
11330
11324
  writeFileSync(tempFileName, newFile);
11331
11325
  const child = execa2("forge", ["test", "--match-path", tempFileName, "-vvv"], {
11332
11326
  stdio: ["inherit", "pipe", "inherit"]
@@ -11347,7 +11341,7 @@ console.log("GAS REPORT: ${name} [${functionCall.replaceAll('"', '\\"')}]:", _ga
11347
11341
  const name = gasReportMatch[1];
11348
11342
  const functionCall = gasReportMatch[2].replace(";", "");
11349
11343
  const gasUsed = gasReportMatch[3];
11350
- gasReport.push({ source: path7, name, functionCall, gasUsed: parseInt(gasUsed) });
11344
+ gasReport.push({ source: path11, name, functionCall, gasUsed: parseInt(gasUsed) });
11351
11345
  }
11352
11346
  return gasReport;
11353
11347
  }
@@ -11371,10 +11365,10 @@ function printGasReport(gasReport, compare2) {
11371
11365
  const rows = [headers, ...values];
11372
11366
  console.log(table(rows, { border: getBorderCharacters("norc") }));
11373
11367
  }
11374
- function saveGasReport(gasReport, path7) {
11375
- console.log(chalk3.bold(`Saving gas report to ${path7}`));
11368
+ function saveGasReport(gasReport, path11) {
11369
+ console.log(chalk3.bold(`Saving gas report to ${path11}`));
11376
11370
  const serializedGasReport = gasReport.map((entry) => `(${entry.source}) | ${entry.name} [${entry.functionCall}]: ${entry.gasUsed}`).join("\n");
11377
- writeFileSync(path7, serializedGasReport);
11371
+ writeFileSync(path11, serializedGasReport);
11378
11372
  }
11379
11373
 
11380
11374
  // src/commands/hello.ts
@@ -11396,7 +11390,644 @@ var hello_default = commandModule12;
11396
11390
 
11397
11391
  // src/render-solidity/tablegen.ts
11398
11392
  import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
11393
+ import path7 from "path";
11394
+
11395
+ // src/render-solidity/tableOptions.ts
11399
11396
  import path5 from "path";
11397
+ function getTableOptions(config2) {
11398
+ const storeImportPath = config2.storeImportPath;
11399
+ const options = [];
11400
+ for (const tableName of Object.keys(config2.tables)) {
11401
+ const tableData = config2.tables[tableName];
11402
+ const withStruct = tableData.dataStruct;
11403
+ const withRecordMethods = withStruct || Object.keys(tableData.schema).length > 1;
11404
+ const noFieldMethodSuffix = !withRecordMethods && Object.keys(tableData.schema).length === 1;
11405
+ const imports = [];
11406
+ const primaryKeys = Object.keys(tableData.primaryKeys).map((name) => {
11407
+ const abiOrUserType = tableData.primaryKeys[name];
11408
+ const { renderTableType } = resolveAbiOrUserType(abiOrUserType, config2);
11409
+ const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config2);
11410
+ if (importDatum)
11411
+ imports.push(importDatum);
11412
+ if (renderTableType.isDynamic)
11413
+ throw new Error(`Parsing error: found dynamic primary key ${name} in table ${tableName}`);
11414
+ const primaryKey = {
11415
+ ...renderTableType,
11416
+ name,
11417
+ isDynamic: false
11418
+ };
11419
+ return primaryKey;
11420
+ });
11421
+ const fields = Object.keys(tableData.schema).map((name) => {
11422
+ const abiOrUserType = tableData.schema[name];
11423
+ const { renderTableType, schemaType } = resolveAbiOrUserType(abiOrUserType, config2);
11424
+ const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config2);
11425
+ if (importDatum)
11426
+ imports.push(importDatum);
11427
+ const elementType = SchemaTypeArrayToElement[schemaType];
11428
+ const field = {
11429
+ ...renderTableType,
11430
+ arrayElement: elementType !== void 0 ? getSchemaTypeInfo(elementType) : void 0,
11431
+ name,
11432
+ methodNameSuffix: noFieldMethodSuffix ? "" : `${name[0].toUpperCase()}${name.slice(1)}`
11433
+ };
11434
+ return field;
11435
+ });
11436
+ const staticFields = fields.filter(({ isDynamic }) => !isDynamic);
11437
+ const dynamicFields = fields.filter(({ isDynamic }) => isDynamic);
11438
+ const staticResourceData = (() => {
11439
+ if (tableData.tableIdArgument) {
11440
+ return;
11441
+ } else {
11442
+ return {
11443
+ tableIdName: tableName + "TableId",
11444
+ namespace: config2.namespace,
11445
+ fileSelector: tableData.fileSelector
11446
+ };
11447
+ }
11448
+ })();
11449
+ options.push({
11450
+ outputPath: path5.join(tableData.directory, `${tableName}.sol`),
11451
+ tableName,
11452
+ renderOptions: {
11453
+ imports,
11454
+ libraryName: tableName,
11455
+ structName: withStruct ? tableName + "Data" : void 0,
11456
+ staticResourceData,
11457
+ storeImportPath,
11458
+ primaryKeys,
11459
+ fields,
11460
+ staticFields,
11461
+ dynamicFields,
11462
+ withRecordMethods,
11463
+ storeArgument: tableData.storeArgument
11464
+ }
11465
+ });
11466
+ }
11467
+ return options;
11468
+ }
11469
+
11470
+ // src/render-solidity/common.ts
11471
+ import path6 from "path";
11472
+ var renderedSolidityHeader = `// SPDX-License-Identifier: MIT
11473
+ pragma solidity >=0.8.0;
11474
+
11475
+ /* Autogenerated file. Do not edit manually. */`;
11476
+ function renderList(list, renderItem) {
11477
+ return internalRenderList("", list, renderItem);
11478
+ }
11479
+ function renderArguments(args) {
11480
+ const filteredArgs = args.filter((arg) => arg !== void 0 && arg !== "");
11481
+ return internalRenderList(",", filteredArgs, (arg) => arg);
11482
+ }
11483
+ function renderCommonData({
11484
+ staticResourceData,
11485
+ primaryKeys
11486
+ }) {
11487
+ const _tableId = staticResourceData ? "" : "_tableId";
11488
+ const _typedTableId = staticResourceData ? "" : "uint256 _tableId";
11489
+ const _keyArgs = renderArguments(primaryKeys.map(({ name }) => name));
11490
+ const _typedKeyArgs = renderArguments(primaryKeys.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
11491
+ const _primaryKeysDefinition = `
11492
+ bytes32[] memory _primaryKeys = new bytes32[](${primaryKeys.length});
11493
+ ${renderList(
11494
+ primaryKeys,
11495
+ (primaryKey, index) => `_primaryKeys[${index}] = ${renderValueTypeToBytes32(primaryKey.name, primaryKey)};`
11496
+ )}
11497
+ `;
11498
+ return {
11499
+ _tableId,
11500
+ _typedTableId,
11501
+ _keyArgs,
11502
+ _typedKeyArgs,
11503
+ _primaryKeysDefinition
11504
+ };
11505
+ }
11506
+ function solidityRelativeImportPath(fromPath, usedInPath) {
11507
+ return "./" + path6.relative("./" + usedInPath, "./" + fromPath);
11508
+ }
11509
+ function renderImports(imports) {
11510
+ const aggregatedImports = /* @__PURE__ */ new Map();
11511
+ for (const { symbol, fromPath, usedInPath } of imports) {
11512
+ const path11 = solidityRelativeImportPath(fromPath, usedInPath);
11513
+ if (!aggregatedImports.has(path11)) {
11514
+ aggregatedImports.set(path11, /* @__PURE__ */ new Set());
11515
+ }
11516
+ aggregatedImports.get(path11)?.add(symbol);
11517
+ }
11518
+ const renderedImports = [];
11519
+ for (const [path11, symbols] of aggregatedImports) {
11520
+ const renderedSymbols = [...symbols].join(", ");
11521
+ renderedImports.push(`import { ${renderedSymbols} } from "${path11}";`);
11522
+ }
11523
+ return renderedImports.join("\n");
11524
+ }
11525
+ function renderWithStore(storeArgument, callback) {
11526
+ let result = "";
11527
+ result += callback(void 0, "StoreSwitch", "", void 0);
11528
+ if (storeArgument) {
11529
+ result += "\n" + callback("IStore _store", "_store", " (using the specified store)", "_store");
11530
+ }
11531
+ return result;
11532
+ }
11533
+ function renderTableId(staticResourceData) {
11534
+ const hardcodedTableId = `uint256(bytes32(abi.encodePacked(bytes16("${staticResourceData.namespace}"), bytes16("${staticResourceData.fileSelector}"))))`;
11535
+ const tableIdDefinition = `
11536
+ uint256 constant _tableId = ${hardcodedTableId};
11537
+ uint256 constant ${staticResourceData.tableIdName} = _tableId;
11538
+ `;
11539
+ return {
11540
+ hardcodedTableId,
11541
+ tableIdDefinition
11542
+ };
11543
+ }
11544
+ function renderValueTypeToBytes32(name, { staticByteLength, typeUnwrap, internalTypeId }) {
11545
+ const bits = staticByteLength * 8;
11546
+ const innerText = `${typeUnwrap}(${name})`;
11547
+ if (internalTypeId.match(/^uint\d{1,3}$/)) {
11548
+ return `bytes32(uint256(${innerText}))`;
11549
+ } else if (internalTypeId.match(/^int\d{1,3}$/)) {
11550
+ return `bytes32(uint256(uint${bits}(${innerText})))`;
11551
+ } else if (internalTypeId.match(/^bytes\d{1,2}$/)) {
11552
+ return `bytes32(${innerText})`;
11553
+ } else if (internalTypeId === "address") {
11554
+ return `bytes32(bytes20(${innerText}))`;
11555
+ } else if (internalTypeId === "bool") {
11556
+ return `_boolToBytes32(${innerText})`;
11557
+ } else {
11558
+ throw new Error(`Unknown value type id ${internalTypeId}`);
11559
+ }
11560
+ }
11561
+ function internalRenderList(lineTerminator, list, renderItem) {
11562
+ return list.map((item, index) => renderItem(item, index) + (index === list.length - 1 ? "" : lineTerminator)).join("\n");
11563
+ }
11564
+
11565
+ // src/render-solidity/field.ts
11566
+ function renderFieldMethods(options) {
11567
+ const storeArgument = options.storeArgument;
11568
+ const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
11569
+ let result = "";
11570
+ for (const [index, field] of options.fields.entries()) {
11571
+ const _typedFieldName = `${field.typeWithLocation} ${field.name}`;
11572
+ result += renderWithStore(
11573
+ storeArgument,
11574
+ (_typedStore, _store, _commentSuffix) => `
11575
+ /** Get ${field.name}${_commentSuffix} */
11576
+ function get${field.methodNameSuffix}(${renderArguments([
11577
+ _typedStore,
11578
+ _typedTableId,
11579
+ _typedKeyArgs
11580
+ ])}) internal view returns (${_typedFieldName}) {
11581
+ ${_primaryKeysDefinition}
11582
+ bytes memory _blob = ${_store}.getField(_tableId, _primaryKeys, ${index});
11583
+ return ${renderDecodeFieldSingle(field)};
11584
+ }
11585
+ `
11586
+ );
11587
+ result += renderWithStore(
11588
+ storeArgument,
11589
+ (_typedStore, _store, _commentSuffix) => `
11590
+ /** Set ${field.name}${_commentSuffix} */
11591
+ function set${field.methodNameSuffix}(${renderArguments([
11592
+ _typedStore,
11593
+ _typedTableId,
11594
+ _typedKeyArgs,
11595
+ _typedFieldName
11596
+ ])}) internal {
11597
+ ${_primaryKeysDefinition}
11598
+ ${_store}.setField(_tableId, _primaryKeys, ${index}, ${renderEncodeField(field)});
11599
+ }
11600
+ `
11601
+ );
11602
+ if (field.isDynamic) {
11603
+ const portionData = fieldPortionData(field);
11604
+ result += renderWithStore(
11605
+ storeArgument,
11606
+ (_typedStore, _store, _commentSuffix) => `
11607
+ /** Push ${portionData.title} to ${field.name}${_commentSuffix} */
11608
+ function push${field.methodNameSuffix}(${renderArguments([
11609
+ _typedStore,
11610
+ _typedTableId,
11611
+ _typedKeyArgs,
11612
+ `${portionData.typeWithLocation} ${portionData.name}`
11613
+ ])}) internal {
11614
+ ${_primaryKeysDefinition}
11615
+ ${_store}.pushToField(_tableId, _primaryKeys, ${index}, ${portionData.encoded});
11616
+ }
11617
+ `
11618
+ );
11619
+ }
11620
+ }
11621
+ return result;
11622
+ }
11623
+ function renderEncodeField(field) {
11624
+ let func;
11625
+ if (field.arrayElement) {
11626
+ func = "EncodeArray.encode";
11627
+ } else if (field.isDynamic) {
11628
+ func = "bytes";
11629
+ } else {
11630
+ func = "abi.encodePacked";
11631
+ }
11632
+ return `${func}(${field.typeUnwrap}(${field.name}))`;
11633
+ }
11634
+ function renderDecodeValueType(field, offset) {
11635
+ const { staticByteLength, internalTypeId } = field;
11636
+ const innerSlice = `Bytes.slice${staticByteLength}(_blob, ${offset})`;
11637
+ const bits = staticByteLength * 8;
11638
+ let result;
11639
+ if (internalTypeId.match(/^uint\d{1,3}$/) || internalTypeId === "address") {
11640
+ result = `${internalTypeId}(${innerSlice})`;
11641
+ } else if (internalTypeId.match(/^int\d{1,3}$/)) {
11642
+ result = `${internalTypeId}(uint${bits}(${innerSlice}))`;
11643
+ } else if (internalTypeId.match(/^bytes\d{1,2}$/)) {
11644
+ result = innerSlice;
11645
+ } else if (internalTypeId === "bool") {
11646
+ result = `_toBool(uint8(${innerSlice}))`;
11647
+ } else {
11648
+ throw new Error(`Unknown value type id ${internalTypeId}`);
11649
+ }
11650
+ return `${field.typeWrap}(${result})`;
11651
+ }
11652
+ function fieldPortionData(field) {
11653
+ const methodNameSuffix = "";
11654
+ if (field.arrayElement) {
11655
+ const name = "_element";
11656
+ return {
11657
+ typeWithLocation: field.arrayElement.typeWithLocation,
11658
+ name: "_element",
11659
+ encoded: renderEncodeField({ ...field.arrayElement, arrayElement: void 0, name, methodNameSuffix }),
11660
+ title: "an element"
11661
+ };
11662
+ } else {
11663
+ const name = "_slice";
11664
+ return {
11665
+ typeWithLocation: `${field.typeId} memory`,
11666
+ name,
11667
+ encoded: renderEncodeField({ ...field, name, methodNameSuffix }),
11668
+ title: "a slice"
11669
+ };
11670
+ }
11671
+ }
11672
+ function renderDecodeFieldSingle(field) {
11673
+ const { isDynamic, arrayElement } = field;
11674
+ if (arrayElement) {
11675
+ return `${field.typeWrap}(
11676
+ SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_${arrayElement.internalTypeId}()
11677
+ )`;
11678
+ } else if (isDynamic) {
11679
+ return `${field.typeWrap}(${field.internalTypeId}(_blob))`;
11680
+ } else {
11681
+ return renderDecodeValueType(field, 0);
11682
+ }
11683
+ }
11684
+
11685
+ // src/render-solidity/record.ts
11686
+ function renderRecordMethods(options) {
11687
+ const { structName, storeArgument } = options;
11688
+ const { _tableId, _typedTableId, _keyArgs, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
11689
+ let result = renderWithStore(
11690
+ storeArgument,
11691
+ (_typedStore, _store, _commentSuffix) => `
11692
+ /** Get the full data${_commentSuffix} */
11693
+ function get(${renderArguments([
11694
+ _typedStore,
11695
+ _typedTableId,
11696
+ _typedKeyArgs
11697
+ ])}) internal view returns (${renderDecodedRecord(options)}) {
11698
+ ${_primaryKeysDefinition}
11699
+ bytes memory _blob = ${_store}.getRecord(_tableId, _primaryKeys, getSchema());
11700
+ return decode(_blob);
11701
+ }
11702
+ `
11703
+ );
11704
+ result += renderWithStore(
11705
+ storeArgument,
11706
+ (_typedStore, _store, _commentSuffix) => `
11707
+ /** Set the full data using individual values${_commentSuffix} */
11708
+ function set(${renderArguments([
11709
+ _typedStore,
11710
+ _typedTableId,
11711
+ _typedKeyArgs,
11712
+ renderArguments(options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`))
11713
+ ])}) internal {
11714
+ bytes memory _data = encode(${renderArguments(options.fields.map(({ name }) => name))});
11715
+
11716
+ ${_primaryKeysDefinition}
11717
+
11718
+ ${_store}.setRecord(_tableId, _primaryKeys, _data);
11719
+ }
11720
+ `
11721
+ );
11722
+ if (structName !== void 0) {
11723
+ result += renderWithStore(
11724
+ storeArgument,
11725
+ (_typedStore, _store, _commentSuffix, _untypedStore) => `
11726
+ /** Set the full data using the data struct${_commentSuffix} */
11727
+ function set(${renderArguments([
11728
+ _typedStore,
11729
+ _typedTableId,
11730
+ _typedKeyArgs,
11731
+ `${structName} memory _table`
11732
+ ])}) internal {
11733
+ set(${renderArguments([
11734
+ _untypedStore,
11735
+ _tableId,
11736
+ _keyArgs,
11737
+ renderArguments(options.fields.map(({ name }) => `_table.${name}`))
11738
+ ])});
11739
+ }
11740
+ `
11741
+ );
11742
+ }
11743
+ result += renderDecodeFunction(options);
11744
+ return result;
11745
+ }
11746
+ function renderDecodeFunction({ structName, fields, staticFields, dynamicFields }) {
11747
+ const renderedDecodedRecord = structName ? `${structName} memory _table` : renderArguments(fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
11748
+ const fieldNamePrefix = structName ? "_table." : "";
11749
+ const staticOffsets = staticFields.map(() => 0);
11750
+ let _acc = 0;
11751
+ for (const [index, field] of staticFields.entries()) {
11752
+ staticOffsets[index] = _acc;
11753
+ _acc += field.staticByteLength;
11754
+ }
11755
+ if (dynamicFields.length > 0) {
11756
+ const totalStaticLength = staticFields.reduce((acc, { staticByteLength }) => acc + staticByteLength, 0);
11757
+ return `
11758
+ /** Decode the tightly packed blob using this table's schema */
11759
+ function decode(bytes memory _blob) internal view returns (${renderedDecodedRecord}) {
11760
+ // ${totalStaticLength} is the total byte length of static data
11761
+ PackedCounter _encodedLengths = PackedCounter.wrap(Bytes.slice32(_blob, ${totalStaticLength}));
11762
+
11763
+ ${renderList(
11764
+ staticFields,
11765
+ (field, index) => `
11766
+ ${fieldNamePrefix}${field.name} = ${renderDecodeValueType(field, staticOffsets[index])};
11767
+ `
11768
+ )}
11769
+ uint256 _start;
11770
+ uint256 _end = ${totalStaticLength + 32};
11771
+ ${renderList(
11772
+ dynamicFields,
11773
+ (field, index) => `
11774
+ _start = _end;
11775
+ _end += _encodedLengths.atIndex(${index});
11776
+ ${fieldNamePrefix}${field.name} = ${renderDecodeDynamicFieldPartial(field)};
11777
+ `
11778
+ )}
11779
+ }
11780
+ `;
11781
+ } else {
11782
+ return `
11783
+ /** Decode the tightly packed blob using this table's schema */
11784
+ function decode(bytes memory _blob) internal pure returns (${renderedDecodedRecord}) {
11785
+ ${renderList(
11786
+ staticFields,
11787
+ (field, index) => `
11788
+ ${fieldNamePrefix}${field.name} = ${renderDecodeValueType(field, staticOffsets[index])};
11789
+ `
11790
+ )}
11791
+ }
11792
+ `;
11793
+ }
11794
+ }
11795
+ function renderDecodedRecord({ structName, fields }) {
11796
+ if (structName) {
11797
+ return `${structName} memory _table`;
11798
+ } else {
11799
+ return renderArguments(fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
11800
+ }
11801
+ }
11802
+ function renderDecodeDynamicFieldPartial(field) {
11803
+ const { typeId, arrayElement, typeWrap } = field;
11804
+ if (arrayElement) {
11805
+ return `${typeWrap}(
11806
+ SliceLib.getSubslice(_blob, _start, _end).decodeArray_${arrayElement.typeId}()
11807
+ )`;
11808
+ } else {
11809
+ return `${typeWrap}(
11810
+ ${typeId}(
11811
+ SliceLib.getSubslice(_blob, _start, _end).toBytes()
11812
+ )
11813
+ )`;
11814
+ }
11815
+ }
11816
+
11817
+ // src/render-solidity/renderTypeHelpers.ts
11818
+ function renderTypeHelpers(options) {
11819
+ const { fields, primaryKeys } = options;
11820
+ let result = "";
11821
+ for (const wrappingHelper of getWrappingHelpers([...fields, ...primaryKeys])) {
11822
+ result += wrappingHelper;
11823
+ }
11824
+ if (fields.some(({ typeId }) => typeId === "bool")) {
11825
+ result += `
11826
+ function _toBool(uint8 value) pure returns (bool result) {
11827
+ assembly {
11828
+ result := value
11829
+ }
11830
+ }
11831
+ `;
11832
+ }
11833
+ if (primaryKeys.some(({ typeId }) => typeId === "bool")) {
11834
+ result += `
11835
+ function _boolToBytes32(bool value) pure returns (bytes32 result) {
11836
+ assembly {
11837
+ result := value
11838
+ }
11839
+ }
11840
+ `;
11841
+ }
11842
+ return result;
11843
+ }
11844
+ function getWrappingHelpers(array) {
11845
+ const wrappers = /* @__PURE__ */ new Map();
11846
+ const unwrappers = /* @__PURE__ */ new Map();
11847
+ for (const { typeWrappingData, typeWrap, typeUnwrap, internalTypeId } of array) {
11848
+ if (!typeWrappingData)
11849
+ continue;
11850
+ const { kind } = typeWrappingData;
11851
+ if (kind === "staticArray") {
11852
+ const { elementType, staticLength } = typeWrappingData;
11853
+ wrappers.set(typeWrap, renderWrapperStaticArray(typeWrap, elementType, staticLength, internalTypeId));
11854
+ unwrappers.set(typeUnwrap, renderUnwrapperStaticArray(typeUnwrap, elementType, staticLength, internalTypeId));
11855
+ }
11856
+ }
11857
+ return [...wrappers.values(), ...unwrappers.values()];
11858
+ }
11859
+ function renderWrapperStaticArray(functionName, elementType, staticLength, internalTypeId) {
11860
+ return `
11861
+ function ${functionName}(
11862
+ ${internalTypeId} memory _value
11863
+ ) pure returns (
11864
+ ${elementType}[${staticLength}] memory _result
11865
+ ) {
11866
+ // in memory static arrays are just dynamic arrays without the length byte
11867
+ assembly {
11868
+ _result := add(_value, 0x20)
11869
+ }
11870
+ }
11871
+ `;
11872
+ }
11873
+ function renderUnwrapperStaticArray(functionName, elementType, staticLength, internalTypeId) {
11874
+ const byteLength = staticLength * 32;
11875
+ return `
11876
+ function ${functionName}(
11877
+ ${elementType}[${staticLength}] memory _value
11878
+ ) view returns (
11879
+ ${internalTypeId} memory _result
11880
+ ) {
11881
+ _result = new ${internalTypeId}(${staticLength});
11882
+ uint256 fromPointer;
11883
+ uint256 toPointer;
11884
+ assembly {
11885
+ fromPointer := _value
11886
+ toPointer := add(_result, 0x20)
11887
+ }
11888
+ Memory.copy(fromPointer, toPointer, ${byteLength});
11889
+ }
11890
+ `;
11891
+ }
11892
+
11893
+ // src/render-solidity/renderTable.ts
11894
+ function renderTable(options) {
11895
+ const {
11896
+ imports,
11897
+ libraryName,
11898
+ structName,
11899
+ staticResourceData,
11900
+ storeImportPath,
11901
+ fields,
11902
+ staticFields,
11903
+ dynamicFields,
11904
+ withRecordMethods,
11905
+ storeArgument,
11906
+ primaryKeys
11907
+ } = options;
11908
+ const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
11909
+ return `${renderedSolidityHeader}
11910
+
11911
+ // Import schema type
11912
+ import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol";
11913
+
11914
+ // Import store internals
11915
+ import { IStore } from "${storeImportPath}IStore.sol";
11916
+ import { StoreSwitch } from "${storeImportPath}StoreSwitch.sol";
11917
+ import { StoreCore } from "${storeImportPath}StoreCore.sol";
11918
+ import { Bytes } from "${storeImportPath}Bytes.sol";
11919
+ import { Memory } from "${storeImportPath}Memory.sol";
11920
+ import { SliceLib } from "${storeImportPath}Slice.sol";
11921
+ import { EncodeArray } from "${storeImportPath}tightcoder/EncodeArray.sol";
11922
+ import { Schema, SchemaLib } from "${storeImportPath}Schema.sol";
11923
+ import { PackedCounter, PackedCounterLib } from "${storeImportPath}PackedCounter.sol";
11924
+
11925
+ ${imports.length > 0 ? `
11926
+ // Import user types
11927
+ ${renderImports(imports)}
11928
+ ` : ""}
11929
+
11930
+ ${staticResourceData ? renderTableId(staticResourceData).tableIdDefinition : ""}
11931
+
11932
+ ${!structName ? "" : `
11933
+ struct ${structName} {
11934
+ ${renderList(fields, ({ name, typeId }) => `${typeId} ${name};`)}
11935
+ }
11936
+ `}
11937
+
11938
+ library ${libraryName} {
11939
+ /** Get the table's schema */
11940
+ function getSchema() internal pure returns (Schema) {
11941
+ SchemaType[] memory _schema = new SchemaType[](${fields.length});
11942
+ ${renderList(fields, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)}
11943
+
11944
+ return SchemaLib.encode(_schema);
11945
+ }
11946
+
11947
+ function getKeySchema() internal pure returns (Schema) {
11948
+ SchemaType[] memory _schema = new SchemaType[](${primaryKeys.length});
11949
+ ${renderList(primaryKeys, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)}
11950
+
11951
+ return SchemaLib.encode(_schema);
11952
+ }
11953
+
11954
+ /** Get the table's metadata */
11955
+ function getMetadata() internal pure returns (string memory, string[] memory) {
11956
+ string[] memory _fieldNames = new string[](${fields.length});
11957
+ ${renderList(fields, (field, index) => `_fieldNames[${index}] = "${field.name}";`)}
11958
+ return ("${libraryName}", _fieldNames);
11959
+ }
11960
+
11961
+ ${renderWithStore(
11962
+ storeArgument,
11963
+ (_typedStore, _store, _commentSuffix) => `
11964
+ /** Register the table's schema${_commentSuffix} */
11965
+ function registerSchema(${renderArguments([_typedStore, _typedTableId])}) internal {
11966
+ ${_store}.registerSchema(_tableId, getSchema(), getKeySchema());
11967
+ }
11968
+ `
11969
+ )}
11970
+ ${renderWithStore(
11971
+ storeArgument,
11972
+ (_typedStore, _store, _commentSuffix) => `
11973
+ /** Set the table's metadata${_commentSuffix} */
11974
+ function setMetadata(${renderArguments([_typedStore, _typedTableId])}) internal {
11975
+ (string memory _tableName, string[] memory _fieldNames) = getMetadata();
11976
+ ${_store}.setMetadata(_tableId, _tableName, _fieldNames);
11977
+ }
11978
+ `
11979
+ )}
11980
+
11981
+ ${renderFieldMethods(options)}
11982
+
11983
+ ${withRecordMethods ? renderRecordMethods(options) : ""}
11984
+
11985
+ /** Tightly pack full data using this table's schema */
11986
+ function encode(${renderArguments(
11987
+ options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`)
11988
+ )}) internal view returns (bytes memory) {
11989
+ ${renderEncodedLengths(dynamicFields)}
11990
+ return abi.encodePacked(${renderArguments([
11991
+ renderArguments(staticFields.map(({ name }) => name)),
11992
+ // TODO try gas optimization (preallocate for all, encodePacked statics, and direct encode dynamics)
11993
+ // (see https://github.com/latticexyz/mud/issues/444)
11994
+ ...dynamicFields.length === 0 ? [] : ["_encodedLengths.unwrap()", renderArguments(dynamicFields.map((field) => renderEncodeField(field)))]
11995
+ ])});
11996
+ }
11997
+
11998
+ ${renderWithStore(
11999
+ storeArgument,
12000
+ (_typedStore, _store, _commentSuffix) => `
12001
+ /* Delete all data for given keys${_commentSuffix} */
12002
+ function deleteRecord(${renderArguments([_typedStore, _typedTableId, _typedKeyArgs])}) internal {
12003
+ ${_primaryKeysDefinition}
12004
+ ${_store}.deleteRecord(_tableId, _primaryKeys);
12005
+ }
12006
+ `
12007
+ )}
12008
+ }
12009
+
12010
+ ${renderTypeHelpers(options)}
12011
+
12012
+ `;
12013
+ }
12014
+ function renderEncodedLengths(dynamicFields) {
12015
+ if (dynamicFields.length > 0) {
12016
+ return `
12017
+ uint16[] memory _counters = new uint16[](${dynamicFields.length});
12018
+ ${renderList(dynamicFields, ({ name, arrayElement }, index) => {
12019
+ if (arrayElement) {
12020
+ return `_counters[${index}] = uint16(${name}.length * ${arrayElement.staticByteLength});`;
12021
+ } else {
12022
+ return `_counters[${index}] = uint16(bytes(${name}).length);`;
12023
+ }
12024
+ })}
12025
+ PackedCounter _encodedLengths = PackedCounterLib.pack(_counters);
12026
+ `;
12027
+ } else {
12028
+ return "";
12029
+ }
12030
+ }
11400
12031
 
11401
12032
  // src/render-solidity/renderTypes.ts
11402
12033
  function renderTypes(options) {
@@ -11417,9 +12048,9 @@ ${renderList(
11417
12048
 
11418
12049
  // src/render-solidity/renderTypesFromConfig.ts
11419
12050
  function renderTypesFromConfig(config2) {
11420
- const enums = Object.keys(config2.userTypes.enums).map((name) => ({
12051
+ const enums = Object.keys(config2.enums).map((name) => ({
11421
12052
  name,
11422
- memberNames: config2.userTypes.enums[name]
12053
+ memberNames: config2.enums[name]
11423
12054
  }));
11424
12055
  return renderTypes({
11425
12056
  enums
@@ -11428,24 +12059,24 @@ function renderTypesFromConfig(config2) {
11428
12059
 
11429
12060
  // src/render-solidity/tablegen.ts
11430
12061
  async function tablegen(config2, outputBaseDirectory) {
11431
- const renderedTables = renderTablesFromConfig(config2, outputBaseDirectory);
11432
- for (const { outputDirectory, output, tableName } of renderedTables) {
11433
- const formattedOutput = await formatSolidity(output);
11434
- mkdirSync(outputDirectory, { recursive: true });
11435
- const outputPath = path5.join(outputDirectory, `${tableName}.sol`);
11436
- writeFileSync2(outputPath, formattedOutput);
11437
- console.log(`Generated table: ${outputPath}`);
12062
+ const allTableOptions = getTableOptions(config2);
12063
+ for (const { outputPath, renderOptions } of allTableOptions) {
12064
+ const fullOutputPath = path7.join(outputBaseDirectory, outputPath);
12065
+ const output = renderTable(renderOptions);
12066
+ formatAndWrite(output, fullOutputPath, "Generated table");
11438
12067
  }
11439
- if (Object.keys(config2.userTypes.enums).length > 0) {
11440
- const renderedTypes = renderTypesFromConfig(config2);
11441
- const formattedOutput = await formatSolidity(renderedTypes);
11442
- const outputPath = path5.join(outputBaseDirectory, `${config2.userTypes.path}.sol`);
11443
- const outputDirectory = path5.dirname(outputPath);
11444
- mkdirSync(outputDirectory, { recursive: true });
11445
- writeFileSync2(outputPath, formattedOutput);
11446
- console.log(`Generated types file: ${outputPath}`);
12068
+ if (Object.keys(config2.enums).length > 0) {
12069
+ const fullOutputPath = path7.join(outputBaseDirectory, `${config2.userTypesPath}.sol`);
12070
+ const output = renderTypesFromConfig(config2);
12071
+ formatAndWrite(output, fullOutputPath, "Generated types file");
11447
12072
  }
11448
12073
  }
12074
+ async function formatAndWrite(output, fullOutputPath, logPrefix) {
12075
+ const formattedOutput = await formatSolidity(output);
12076
+ mkdirSync(path7.dirname(fullOutputPath), { recursive: true });
12077
+ writeFileSync2(fullOutputPath, formattedOutput);
12078
+ console.log(`${logPrefix}: ${fullOutputPath}`);
12079
+ }
11449
12080
 
11450
12081
  // src/commands/tablegen.ts
11451
12082
  var commandModule13 = {
@@ -11468,8 +12099,20 @@ var tablegen_default = commandModule13;
11468
12099
  // src/commands/deploy-v2.ts
11469
12100
  import chalk4 from "chalk";
11470
12101
  import glob from "glob";
11471
- import path6, { basename } from "path";
12102
+ import path8, { basename } from "path";
11472
12103
  import { mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
12104
+
12105
+ // src/utils/getChainId.ts
12106
+ import { ethers } from "ethers";
12107
+ async function getChainId(rpc) {
12108
+ const { result: chainId } = await ethers.utils.fetchJson(
12109
+ rpc,
12110
+ '{ "id": 42, "jsonrpc": "2.0", "method": "eth_chainId", "params": [ ] }'
12111
+ );
12112
+ return Number(chainId);
12113
+ }
12114
+
12115
+ // src/commands/deploy-v2.ts
11473
12116
  var commandModule14 = {
11474
12117
  command: "deploy-v2",
11475
12118
  describe: "Deploy MUD v2 contracts",
@@ -11479,6 +12122,7 @@ var commandModule14 = {
11479
12122
  clean: { type: "boolean", desc: "Remove the build forge artifacts and cache directories before building" },
11480
12123
  printConfig: { type: "boolean", desc: "Print the resolved config" },
11481
12124
  profile: { type: "string", desc: "The foundry profile to use" },
12125
+ debug: { type: "boolean", desc: "Print debug logs, like full error messages" },
11482
12126
  priorityFeeMultiplier: {
11483
12127
  type: "number",
11484
12128
  desc: "Multiply the estimated priority fee by the provided factor",
@@ -11500,8 +12144,8 @@ var commandModule14 = {
11500
12144
  if (clean)
11501
12145
  await forge(["clean"], { profile });
11502
12146
  await forge(["build"], { profile });
11503
- const outDir = await getOutDirectory();
11504
- const existingContracts = glob.sync(`${outDir}/*.sol`).map((path7) => basename(path7, ".sol"));
12147
+ const srcDir = await getSrcDirectory();
12148
+ const existingContracts = glob.sync(`${srcDir}/**/*.sol`).map((path11) => basename(path11, ".sol"));
11505
12149
  const worldConfig = await loadWorldConfig(configPath, existingContracts);
11506
12150
  const storeConfig = await loadStoreConfig(configPath);
11507
12151
  const mudConfig = { ...worldConfig, ...storeConfig };
@@ -11512,16 +12156,11 @@ var commandModule14 = {
11512
12156
  if (!privateKey)
11513
12157
  throw new MUDError("Missing PRIVATE_KEY environment variable");
11514
12158
  const deploymentInfo = await deploy(mudConfig, { ...args, rpc, privateKey });
11515
- const outputDir = mudConfig.deploymentInfoDirectory;
12159
+ const chainId = await getChainId(rpc);
12160
+ const outputDir = path8.join(mudConfig.deploysDirectory, chainId.toString());
11516
12161
  mkdirSync2(outputDir, { recursive: true });
11517
- writeFileSync3(
11518
- path6.join(outputDir, deploymentInfoFilenamePrefix + "latest.json"),
11519
- JSON.stringify(deploymentInfo, null, 2)
11520
- );
11521
- writeFileSync3(
11522
- path6.join(outputDir, deploymentInfoFilenamePrefix + Date.now() + ".json"),
11523
- JSON.stringify(deploymentInfo, null, 2)
11524
- );
12162
+ writeFileSync3(path8.join(outputDir, "latest.json"), JSON.stringify(deploymentInfo, null, 2));
12163
+ writeFileSync3(path8.join(outputDir, Date.now() + ".json"), JSON.stringify(deploymentInfo, null, 2));
11525
12164
  console.log(chalk4.bgGreen(chalk4.whiteBright(`
11526
12165
  Deployment result (written to ${outputDir}):
11527
12166
  `)));
@@ -11535,6 +12174,246 @@ var commandModule14 = {
11535
12174
  };
11536
12175
  var deploy_v2_default = commandModule14;
11537
12176
 
12177
+ // src/commands/worldgen.ts
12178
+ import glob2 from "glob";
12179
+ import path10, { basename as basename2 } from "path";
12180
+
12181
+ // src/render-solidity/worldgen.ts
12182
+ import { readFileSync as readFileSync3 } from "fs";
12183
+ import path9 from "path";
12184
+
12185
+ // src/utils/contractToInterface.ts
12186
+ import { parse, visit } from "@solidity-parser/parser";
12187
+ function contractToInterface(data, contractName) {
12188
+ const ast = parse(data);
12189
+ let withContract = false;
12190
+ let symbols = [];
12191
+ const functions = [];
12192
+ visit(ast, {
12193
+ ContractDefinition({ name }) {
12194
+ if (name === contractName) {
12195
+ withContract = true;
12196
+ }
12197
+ },
12198
+ FunctionDefinition({ name, visibility, parameters, returnParameters, isConstructor, isFallback, isReceiveEther }, parent) {
12199
+ if (parent !== void 0 && parent.type === "ContractDefinition" && parent.name === contractName) {
12200
+ try {
12201
+ if (isConstructor || isFallback || isReceiveEther)
12202
+ return;
12203
+ if (visibility === "default")
12204
+ throw new MUDError(`Visibility is not specified`);
12205
+ if (visibility === "external" || visibility === "public") {
12206
+ functions.push({
12207
+ name: name === null ? "" : name,
12208
+ parameters: parameters.map(parseParameter),
12209
+ returnParameters: returnParameters === null ? [] : returnParameters.map(parseParameter)
12210
+ });
12211
+ for (const { typeName } of parameters.concat(returnParameters ?? [])) {
12212
+ symbols = symbols.concat(typeNameToExternalSymbols(typeName));
12213
+ }
12214
+ }
12215
+ } catch (error) {
12216
+ if (error instanceof MUDError) {
12217
+ error.message = `Function "${name}" in contract "${contractName}": ${error.message}`;
12218
+ }
12219
+ throw error;
12220
+ }
12221
+ }
12222
+ }
12223
+ });
12224
+ if (!withContract) {
12225
+ throw new MUDError(`Contract not found: ${contractName}`);
12226
+ }
12227
+ return {
12228
+ functions,
12229
+ symbols
12230
+ };
12231
+ }
12232
+ function parseParameter({ name, typeName, storageLocation }) {
12233
+ let typedNameWithLocation = "";
12234
+ const { name: flattenedTypeName, stateMutability } = flattenTypeName(typeName);
12235
+ typedNameWithLocation += flattenedTypeName;
12236
+ if (stateMutability !== null) {
12237
+ typedNameWithLocation += ` ${stateMutability}`;
12238
+ }
12239
+ if (storageLocation !== null) {
12240
+ typedNameWithLocation += ` ${storageLocation}`;
12241
+ }
12242
+ if (name !== null) {
12243
+ typedNameWithLocation += ` ${name}`;
12244
+ }
12245
+ return typedNameWithLocation;
12246
+ }
12247
+ function flattenTypeName(typeName) {
12248
+ if (typeName === null) {
12249
+ return {
12250
+ name: "",
12251
+ stateMutability: null
12252
+ };
12253
+ }
12254
+ if (typeName.type === "ElementaryTypeName") {
12255
+ return {
12256
+ name: typeName.name,
12257
+ stateMutability: typeName.stateMutability
12258
+ };
12259
+ } else if (typeName.type === "UserDefinedTypeName") {
12260
+ return {
12261
+ name: typeName.namePath,
12262
+ stateMutability: null
12263
+ };
12264
+ } else if (typeName.type === "ArrayTypeName") {
12265
+ const { name, stateMutability } = flattenTypeName(typeName.baseTypeName);
12266
+ return {
12267
+ name: `${name}[]`,
12268
+ stateMutability
12269
+ };
12270
+ } else {
12271
+ throw new MUDError(`Invalid typeName.type ${typeName.type}`);
12272
+ }
12273
+ }
12274
+ function typeNameToExternalSymbols(typeName) {
12275
+ if (typeName?.type === "UserDefinedTypeName") {
12276
+ const symbol = typeName.namePath.split(".")[0];
12277
+ return [symbol];
12278
+ } else if (typeName?.type === "ArrayTypeName") {
12279
+ return typeNameToExternalSymbols(typeName.baseTypeName);
12280
+ } else {
12281
+ return [];
12282
+ }
12283
+ }
12284
+
12285
+ // src/utils/formatAndWrite.ts
12286
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
12287
+ import { dirname } from "path";
12288
+ async function formatAndWrite2(output, fullOutputPath, logPrefix) {
12289
+ const formattedOutput = await formatSolidity(output);
12290
+ mkdirSync3(dirname(fullOutputPath), { recursive: true });
12291
+ writeFileSync4(fullOutputPath, formattedOutput);
12292
+ console.log(`${logPrefix}: ${fullOutputPath}`);
12293
+ }
12294
+
12295
+ // src/render-solidity/renderSystemInterface.ts
12296
+ function renderSystemInterface(options) {
12297
+ const { imports, name, functionPrefix, functions } = options;
12298
+ return `${renderedSolidityHeader}
12299
+
12300
+ ${renderImports(imports)}
12301
+
12302
+ interface ${name} {
12303
+ ${renderList(
12304
+ functions,
12305
+ ({ name: name2, parameters, returnParameters }) => `
12306
+ function ${functionPrefix}${name2}(${renderArguments(parameters)}) external ${renderReturnParameters(
12307
+ returnParameters
12308
+ )};
12309
+ `
12310
+ )}
12311
+ }
12312
+
12313
+ `;
12314
+ }
12315
+ function renderReturnParameters(returnParameters) {
12316
+ if (returnParameters.length > 0) {
12317
+ return `returns (${renderArguments(returnParameters)})`;
12318
+ } else {
12319
+ return "";
12320
+ }
12321
+ }
12322
+
12323
+ // src/render-solidity/renderWorld.ts
12324
+ function renderWorld(options) {
12325
+ const { interfaceName, storeImportPath, worldImportPath, imports } = options;
12326
+ return `${renderedSolidityHeader}
12327
+
12328
+ import { IStore } from "${storeImportPath}IStore.sol";
12329
+
12330
+ import { IWorldCore } from "${worldImportPath}interfaces/IWorldCore.sol";
12331
+
12332
+ ${renderImports(imports)}
12333
+
12334
+ /**
12335
+ * The ${interfaceName} interface includes all systems dynamically added to the World
12336
+ * during the deploy process.
12337
+ */
12338
+ interface ${interfaceName} is ${renderArguments(["IStore", "IWorldCore", ...imports.map(({ symbol }) => symbol)])} {
12339
+
12340
+ }
12341
+
12342
+ `;
12343
+ }
12344
+
12345
+ // src/render-solidity/worldgen.ts
12346
+ async function worldgen(config2, existingContracts, outputBaseDirectory) {
12347
+ const worldgenBaseDirectory = path9.join(outputBaseDirectory, config2.worldgenDirectory);
12348
+ const systems = existingContracts.filter(({ basename: basename3 }) => Object.keys(config2.systems).includes(basename3));
12349
+ const systemInterfaceImports = [];
12350
+ for (const system of systems) {
12351
+ const data = readFileSync3(system.path, "utf8");
12352
+ const { functions, symbols } = contractToInterface(data, system.basename);
12353
+ const imports = symbols.map((symbol) => ({
12354
+ symbol,
12355
+ fromPath: system.path,
12356
+ usedInPath: worldgenBaseDirectory
12357
+ }));
12358
+ const systemInterfaceName = `I${system.basename}`;
12359
+ const { fileSelector } = config2.systems[system.basename];
12360
+ const output2 = renderSystemInterface({
12361
+ name: systemInterfaceName,
12362
+ functionPrefix: config2.namespace === "" ? "" : `${config2.namespace}_${fileSelector}_`,
12363
+ functions,
12364
+ imports
12365
+ });
12366
+ const fullOutputPath2 = path9.join(worldgenBaseDirectory, systemInterfaceName + ".sol");
12367
+ await formatAndWrite2(output2, fullOutputPath2, "Generated system interface");
12368
+ systemInterfaceImports.push({
12369
+ symbol: systemInterfaceName,
12370
+ fromPath: `${systemInterfaceName}.sol`,
12371
+ usedInPath: "./"
12372
+ });
12373
+ }
12374
+ const worldInterfaceName = "IWorld";
12375
+ const output = renderWorld({
12376
+ interfaceName: worldInterfaceName,
12377
+ imports: systemInterfaceImports,
12378
+ storeImportPath: config2.storeImportPath,
12379
+ worldImportPath: config2.worldImportPath
12380
+ });
12381
+ const fullOutputPath = path9.join(worldgenBaseDirectory, worldInterfaceName + ".sol");
12382
+ await formatAndWrite2(output, fullOutputPath, "Generated system interface");
12383
+ }
12384
+
12385
+ // src/commands/worldgen.ts
12386
+ import { rmSync as rmSync3 } from "fs";
12387
+ var commandModule15 = {
12388
+ command: "worldgen",
12389
+ describe: "Autogenerate interfaces for Systems and World based on existing contracts and the config file",
12390
+ builder(yargs2) {
12391
+ return yargs2.options({
12392
+ configPath: { type: "string", desc: "Path to the config file" },
12393
+ clean: { type: "boolean", desc: "Clear the worldgen directory before generating new interfaces" }
12394
+ });
12395
+ },
12396
+ async handler(args) {
12397
+ const { configPath, clean } = args;
12398
+ const srcDir = await getSrcDirectory();
12399
+ const existingContracts = glob2.sync(`${srcDir}/**/*.sol`).map((path11) => ({
12400
+ path: path11,
12401
+ basename: basename2(path11, ".sol")
12402
+ }));
12403
+ const worldConfig = await loadWorldConfig(
12404
+ configPath,
12405
+ existingContracts.map(({ basename: basename3 }) => basename3)
12406
+ );
12407
+ const storeConfig = await loadStoreConfig(configPath);
12408
+ const mudConfig = { ...worldConfig, ...storeConfig };
12409
+ if (clean)
12410
+ rmSync3(path10.join(srcDir, worldConfig.worldgenDirectory), { recursive: true, force: true });
12411
+ await worldgen(mudConfig, existingContracts, srcDir);
12412
+ process.exit(0);
12413
+ }
12414
+ };
12415
+ var worldgen_default = commandModule15;
12416
+
11538
12417
  // src/commands/index.ts
11539
12418
  var commands = [
11540
12419
  bulkupload_default,
@@ -11550,7 +12429,8 @@ var commands = [
11550
12429
  tablegen_default,
11551
12430
  test_default,
11552
12431
  trace_default,
11553
- types_default
12432
+ types_default,
12433
+ worldgen_default
11554
12434
  ];
11555
12435
 
11556
12436
  // src/mud.ts