@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
@@ -0,0 +1,99 @@
1
+ import { RenderTableOptions, RenderTableType } from "./types.js";
2
+
3
+ export function renderTypeHelpers(options: RenderTableOptions) {
4
+ const { fields, primaryKeys } = options;
5
+
6
+ let result = "";
7
+
8
+ for (const wrappingHelper of getWrappingHelpers([...fields, ...primaryKeys])) {
9
+ result += wrappingHelper;
10
+ }
11
+
12
+ // bool is special - it's the only primitive value type that can't be typecasted to/from
13
+ if (fields.some(({ typeId }) => typeId === "bool")) {
14
+ result += `
15
+ function _toBool(uint8 value) pure returns (bool result) {
16
+ assembly {
17
+ result := value
18
+ }
19
+ }
20
+ `;
21
+ }
22
+ if (primaryKeys.some(({ typeId }) => typeId === "bool")) {
23
+ result += `
24
+ function _boolToBytes32(bool value) pure returns (bytes32 result) {
25
+ assembly {
26
+ result := value
27
+ }
28
+ }
29
+ `;
30
+ }
31
+
32
+ return result;
33
+ }
34
+
35
+ function getWrappingHelpers(array: RenderTableType[]) {
36
+ const wrappers = new Map();
37
+ const unwrappers = new Map();
38
+ for (const { typeWrappingData, typeWrap, typeUnwrap, internalTypeId } of array) {
39
+ if (!typeWrappingData) continue;
40
+ const { kind } = typeWrappingData;
41
+
42
+ if (kind === "staticArray") {
43
+ const { elementType, staticLength } = typeWrappingData;
44
+ wrappers.set(typeWrap, renderWrapperStaticArray(typeWrap, elementType, staticLength, internalTypeId));
45
+ unwrappers.set(typeUnwrap, renderUnwrapperStaticArray(typeUnwrap, elementType, staticLength, internalTypeId));
46
+ }
47
+ }
48
+
49
+ return [...wrappers.values(), ...unwrappers.values()];
50
+ }
51
+
52
+ function renderWrapperStaticArray(
53
+ functionName: string,
54
+ elementType: string,
55
+ staticLength: number,
56
+ internalTypeId: string
57
+ ) {
58
+ // WARNING: ensure this still works if changing major solidity versions!
59
+ // (the memory layout for static arrays may change)
60
+ return `
61
+ function ${functionName}(
62
+ ${internalTypeId} memory _value
63
+ ) pure returns (
64
+ ${elementType}[${staticLength}] memory _result
65
+ ) {
66
+ // in memory static arrays are just dynamic arrays without the length byte
67
+ assembly {
68
+ _result := add(_value, 0x20)
69
+ }
70
+ }
71
+ `;
72
+ }
73
+
74
+ function renderUnwrapperStaticArray(
75
+ functionName: string,
76
+ elementType: string,
77
+ staticLength: number,
78
+ internalTypeId: string
79
+ ) {
80
+ // byte length for memory copying (more efficient than a loop)
81
+ const byteLength = staticLength * 32;
82
+ // TODO to optimize memory usage consider generalizing TightEncoder to a render-time utility
83
+ return `
84
+ function ${functionName}(
85
+ ${elementType}[${staticLength}] memory _value
86
+ ) view returns (
87
+ ${internalTypeId} memory _result
88
+ ) {
89
+ _result = new ${internalTypeId}(${staticLength});
90
+ uint256 fromPointer;
91
+ uint256 toPointer;
92
+ assembly {
93
+ fromPointer := _value
94
+ toPointer := add(_result, 0x20)
95
+ }
96
+ Memory.copy(fromPointer, toPointer, ${byteLength});
97
+ }
98
+ `;
99
+ }
@@ -2,9 +2,9 @@ import { StoreConfig } from "../config/parseStoreConfig.js";
2
2
  import { renderTypes } from "./renderTypes.js";
3
3
 
4
4
  export function renderTypesFromConfig(config: StoreConfig) {
5
- const enums = Object.keys(config.userTypes.enums).map((name) => ({
5
+ const enums = Object.keys(config.enums).map((name) => ({
6
6
  name,
7
- memberNames: config.userTypes.enums[name],
7
+ memberNames: config.enums[name],
8
8
  }));
9
9
 
10
10
  return renderTypes({
@@ -0,0 +1,24 @@
1
+ import { renderArguments, renderedSolidityHeader, renderImports } from "./common.js";
2
+ import { RenderWorldOptions } from "./types.js";
3
+
4
+ export function renderWorld(options: RenderWorldOptions) {
5
+ const { interfaceName, storeImportPath, worldImportPath, imports } = options;
6
+
7
+ return `${renderedSolidityHeader}
8
+
9
+ import { IStore } from "${storeImportPath}IStore.sol";
10
+
11
+ import { IWorldCore } from "${worldImportPath}interfaces/IWorldCore.sol";
12
+
13
+ ${renderImports(imports)}
14
+
15
+ /**
16
+ * The ${interfaceName} interface includes all systems dynamically added to the World
17
+ * during the deploy process.
18
+ */
19
+ interface ${interfaceName} is ${renderArguments(["IStore", "IWorldCore", ...imports.map(({ symbol }) => symbol)])} {
20
+
21
+ }
22
+
23
+ `;
24
+ }
@@ -1,23 +1,28 @@
1
1
  import path from "path";
2
- import { renderTable } from "./renderTable.js";
3
2
  import { SchemaTypeArrayToElement } from "@latticexyz/schema-type";
4
3
  import { StoreConfig } from "../config/parseStoreConfig.js";
5
4
  import {
6
5
  ImportDatum,
7
6
  RenderTableDynamicField,
8
7
  RenderTableField,
8
+ RenderTableOptions,
9
9
  RenderTablePrimaryKey,
10
10
  RenderTableStaticField,
11
11
  } from "./types.js";
12
- import { getSchemaTypeInfo, resolveSchemaOrUserType } from "./userType.js";
12
+ import { getSchemaTypeInfo, importForAbiOrUserType, resolveAbiOrUserType } from "./userType.js";
13
13
 
14
- export function renderTablesFromConfig(config: StoreConfig, srcDirectory: string) {
14
+ export interface TableOptions {
15
+ outputPath: string;
16
+ tableName: string;
17
+ renderOptions: RenderTableOptions;
18
+ }
19
+
20
+ export function getTableOptions(config: StoreConfig): TableOptions[] {
15
21
  const storeImportPath = config.storeImportPath;
16
22
 
17
- const renderedTables = [];
23
+ const options = [];
18
24
  for (const tableName of Object.keys(config.tables)) {
19
25
  const tableData = config.tables[tableName];
20
- const outputDirectory = path.join(srcDirectory, tableData.directory);
21
26
 
22
27
  // struct adds methods to get/set all values at once
23
28
  const withStruct = tableData.dataStruct;
@@ -29,13 +34,10 @@ export function renderTablesFromConfig(config: StoreConfig, srcDirectory: string
29
34
  const imports: ImportDatum[] = [];
30
35
 
31
36
  const primaryKeys = Object.keys(tableData.primaryKeys).map((name) => {
32
- const schemaOrUserType = tableData.primaryKeys[name];
33
- const { renderTableType, importDatum } = resolveSchemaOrUserType(
34
- schemaOrUserType,
35
- srcDirectory,
36
- outputDirectory,
37
- config.userTypes
38
- );
37
+ const abiOrUserType = tableData.primaryKeys[name];
38
+ const { renderTableType } = resolveAbiOrUserType(abiOrUserType, config);
39
+
40
+ const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config);
39
41
  if (importDatum) imports.push(importDatum);
40
42
 
41
43
  if (renderTableType.isDynamic)
@@ -50,13 +52,10 @@ export function renderTablesFromConfig(config: StoreConfig, srcDirectory: string
50
52
  });
51
53
 
52
54
  const fields = Object.keys(tableData.schema).map((name) => {
53
- const schemaOrUserType = tableData.schema[name];
54
- const { renderTableType, importDatum, schemaType } = resolveSchemaOrUserType(
55
- schemaOrUserType,
56
- srcDirectory,
57
- outputDirectory,
58
- config.userTypes
59
- );
55
+ const abiOrUserType = tableData.schema[name];
56
+ const { renderTableType, schemaType } = resolveAbiOrUserType(abiOrUserType, config);
57
+
58
+ const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config);
60
59
  if (importDatum) imports.push(importDatum);
61
60
 
62
61
  const elementType = SchemaTypeArrayToElement[schemaType];
@@ -73,28 +72,27 @@ export function renderTablesFromConfig(config: StoreConfig, srcDirectory: string
73
72
  const dynamicFields = fields.filter(({ isDynamic }) => isDynamic) as RenderTableDynamicField[];
74
73
 
75
74
  // With tableIdArgument: tableId is a dynamic argument for each method
76
- // Without tableIdArgument: tableId is a file-level constant generated from `staticRouteData`
77
- const staticRouteData = (() => {
75
+ // Without tableIdArgument: tableId is a file-level constant generated from `staticResourceData`
76
+ const staticResourceData = (() => {
78
77
  if (tableData.tableIdArgument) {
79
78
  return;
80
79
  } else {
81
80
  return {
82
81
  tableIdName: tableName + "TableId",
83
- baseRoute: config.baseRoute,
84
- subRoute: tableData.route,
82
+ namespace: config.namespace,
83
+ fileSelector: tableData.fileSelector,
85
84
  };
86
85
  }
87
86
  })();
88
87
 
89
- renderedTables.push({
90
- outputDirectory,
88
+ options.push({
89
+ outputPath: path.join(tableData.directory, `${tableName}.sol`),
91
90
  tableName,
92
- tableData,
93
- output: renderTable({
91
+ renderOptions: {
94
92
  imports,
95
93
  libraryName: tableName,
96
94
  structName: withStruct ? tableName + "Data" : undefined,
97
- staticRouteData,
95
+ staticResourceData,
98
96
  storeImportPath,
99
97
  primaryKeys,
100
98
  fields,
@@ -102,8 +100,8 @@ export function renderTablesFromConfig(config: StoreConfig, srcDirectory: string
102
100
  dynamicFields,
103
101
  withRecordMethods,
104
102
  storeArgument: tableData.storeArgument,
105
- }),
103
+ },
106
104
  });
107
105
  }
108
- return renderedTables;
106
+ return options;
109
107
  }
@@ -1,35 +1,33 @@
1
1
  import { mkdirSync, writeFileSync } from "fs";
2
2
  import path from "path";
3
- import { StoreConfig } from "../index.js";
3
+ import { StoreConfig } from "../config/index.js";
4
4
  import { formatSolidity } from "../utils/format.js";
5
- import { renderTablesFromConfig } from "./renderTablesFromConfig.js";
5
+ import { getTableOptions } from "./tableOptions.js";
6
+ import { renderTable } from "./renderTable.js";
6
7
  import { renderTypesFromConfig } from "./renderTypesFromConfig.js";
7
8
 
8
9
  export async function tablegen(config: StoreConfig, outputBaseDirectory: string) {
9
- // render tables
10
- const renderedTables = renderTablesFromConfig(config, outputBaseDirectory);
10
+ const allTableOptions = getTableOptions(config);
11
11
  // write tables to files
12
- for (const { outputDirectory, output, tableName } of renderedTables) {
13
- const formattedOutput = await formatSolidity(output);
14
-
15
- mkdirSync(outputDirectory, { recursive: true });
12
+ for (const { outputPath, renderOptions } of allTableOptions) {
13
+ const fullOutputPath = path.join(outputBaseDirectory, outputPath);
14
+ const output = renderTable(renderOptions);
15
+ formatAndWrite(output, fullOutputPath, "Generated table");
16
+ }
16
17
 
17
- const outputPath = path.join(outputDirectory, `${tableName}.sol`);
18
- writeFileSync(outputPath, formattedOutput);
19
- console.log(`Generated table: ${outputPath}`);
18
+ // write types to file
19
+ if (Object.keys(config.enums).length > 0) {
20
+ const fullOutputPath = path.join(outputBaseDirectory, `${config.userTypesPath}.sol`);
21
+ const output = renderTypesFromConfig(config);
22
+ formatAndWrite(output, fullOutputPath, "Generated types file");
20
23
  }
24
+ }
21
25
 
22
- // render types
23
- if (Object.keys(config.userTypes.enums).length > 0) {
24
- const renderedTypes = renderTypesFromConfig(config);
25
- // write types to file
26
- const formattedOutput = await formatSolidity(renderedTypes);
26
+ async function formatAndWrite(output: string, fullOutputPath: string, logPrefix: string) {
27
+ const formattedOutput = await formatSolidity(output);
27
28
 
28
- const outputPath = path.join(outputBaseDirectory, `${config.userTypes.path}.sol`);
29
- const outputDirectory = path.dirname(outputPath);
30
- mkdirSync(outputDirectory, { recursive: true });
29
+ mkdirSync(path.dirname(fullOutputPath), { recursive: true });
31
30
 
32
- writeFileSync(outputPath, formattedOutput);
33
- console.log(`Generated types file: ${outputPath}`);
34
- }
31
+ writeFileSync(fullOutputPath, formattedOutput);
32
+ console.log(`${logPrefix}: ${fullOutputPath}`);
35
33
  }
@@ -6,7 +6,7 @@ export interface RenderTableOptions {
6
6
  /** Name of the struct to render. If undefined, struct and its methods aren't rendered. */
7
7
  structName?: string;
8
8
  /** Data used to statically registed the table. If undefined, all methods receive `_tableId` as an argument. */
9
- staticRouteData?: StaticRouteData;
9
+ staticResourceData?: StaticResourceData;
10
10
  /** Path for store package imports */
11
11
  storeImportPath: string;
12
12
  primaryKeys: RenderTablePrimaryKey[];
@@ -21,14 +21,15 @@ export interface RenderTableOptions {
21
21
 
22
22
  export interface ImportDatum {
23
23
  symbol: string;
24
- path: string;
24
+ fromPath: string;
25
+ usedInPath: string;
25
26
  }
26
27
 
27
- export interface StaticRouteData {
28
+ export interface StaticResourceData {
28
29
  /** Name of the table id constant to render. */
29
30
  tableIdName: string;
30
- baseRoute: string;
31
- subRoute: string;
31
+ namespace: string;
32
+ fileSelector: string;
32
33
  }
33
34
 
34
35
  export interface RenderTableType {
@@ -42,10 +43,18 @@ export interface RenderTableType {
42
43
  typeWrap: string;
43
44
  /** Empty for internal types. Custom `unwrap` method for user defined types. */
44
45
  typeUnwrap: string;
46
+ /** Data to generate the custom wrapper and unwrapper if necessary. */
47
+ typeWrappingData?: RenderTableTypeWrappingData;
45
48
  /** Same as typeId for internal types. The underlying `typeId` for user defined types. */
46
49
  internalTypeId: string;
47
50
  }
48
51
 
52
+ export type RenderTableTypeWrappingData = {
53
+ kind: "staticArray";
54
+ elementType: string;
55
+ staticLength: number;
56
+ };
57
+
49
58
  export interface RenderTablePrimaryKey extends RenderTableType {
50
59
  name: string;
51
60
  isDynamic: false;
@@ -74,3 +83,28 @@ export interface RenderTypesEnum {
74
83
  name: string;
75
84
  memberNames: string[];
76
85
  }
86
+
87
+ export interface RenderSystemInterfaceOptions {
88
+ /** List of symbols to import, and their file paths */
89
+ imports: ImportDatum[];
90
+ name: string;
91
+ functionPrefix: string;
92
+ functions: RenderSystemInterfaceFunction[];
93
+ }
94
+
95
+ export interface RenderSystemInterfaceFunction {
96
+ name: string;
97
+ parameters: string[];
98
+ returnParameters: string[];
99
+ }
100
+
101
+ export interface RenderWorldOptions {
102
+ /** List of symbols to import, and their file paths */
103
+ imports: ImportDatum[];
104
+ /** Name of the interface to render */
105
+ interfaceName: string;
106
+ /** Path for store package imports */
107
+ storeImportPath: string;
108
+ /** Path for world package imports */
109
+ worldImportPath: string;
110
+ }
@@ -1,62 +1,70 @@
1
- import { getStaticByteLength, SchemaType, SchemaTypeId } from "@latticexyz/schema-type";
2
- import path from "path";
3
- import { StoreConfig } from "../index.js";
4
- import { RenderTableType } from "./types.js";
1
+ import { AbiTypeToSchemaType, getStaticByteLength, SchemaType, SchemaTypeToAbiType } from "@latticexyz/schema-type";
2
+ import { StoreConfig } from "../config/index.js";
3
+ import { ImportDatum, RenderTableType } from "./types.js";
4
+ import { parseStaticArray } from "../config/validation.js";
5
5
 
6
6
  export type UserTypeInfo = ReturnType<typeof getUserTypeInfo>;
7
7
 
8
8
  /**
9
- * Resolve a SchemaType|userType into a SchemaType
9
+ * Resolve an abi or user type into a SchemaType
10
10
  */
11
- export function resolveSchemaOrUserTypeSimple(
12
- schemaOrUserType: SchemaType | string,
13
- userTypesConfig: StoreConfig["userTypes"]
14
- ) {
15
- if (typeof schemaOrUserType === "string") {
16
- const { schemaType } = getUserTypeInfo(schemaOrUserType, userTypesConfig);
17
- return schemaType;
18
- } else {
19
- return schemaOrUserType;
11
+ export function resolveAbiOrUserType(
12
+ abiOrUserType: string,
13
+ config: StoreConfig
14
+ ): {
15
+ schemaType: SchemaType;
16
+ renderTableType: RenderTableType;
17
+ } {
18
+ // abi types which directly mirror a SchemaType
19
+ if (abiOrUserType in AbiTypeToSchemaType) {
20
+ const schemaType = AbiTypeToSchemaType[abiOrUserType];
21
+ return {
22
+ schemaType,
23
+ renderTableType: getSchemaTypeInfo(schemaType),
24
+ };
25
+ }
26
+ // static arrays
27
+ const staticArray = parseStaticArray(abiOrUserType);
28
+ if (staticArray) {
29
+ if (staticArray.elementType in AbiTypeToSchemaType) {
30
+ return getStaticArrayTypeInfo(abiOrUserType, staticArray.elementType, staticArray.staticLength);
31
+ } else {
32
+ throw new Error("Static arrays of user types are not supported");
33
+ }
20
34
  }
35
+ // user types
36
+ return getUserTypeInfo(abiOrUserType, config);
21
37
  }
22
38
 
23
39
  /**
24
- * Resolve a SchemaType|userType into RenderTableType, required import, and internal SchemaType
40
+ * Get the required import for SchemaType|userType (`undefined` means that no import is required)
25
41
  */
26
- export function resolveSchemaOrUserType(
27
- schemaOrUserType: SchemaType | string,
28
- srcDirectory: string,
42
+ export function importForAbiOrUserType(
43
+ abiOrUserType: string,
29
44
  usedInDirectory: string,
30
- userTypesConfig: StoreConfig["userTypes"]
31
- ) {
32
- if (typeof schemaOrUserType === "string") {
33
- // Relative import path for this type.
34
- // "./" must be added because path stripts it,
35
- // but solidity expects it unless there's "../" ("./../" is fine)
36
- const importedFromPath = path.join(srcDirectory, userTypesConfig.path);
37
- const importDatum = {
38
- symbol: schemaOrUserType,
39
- path: "./" + path.relative(usedInDirectory, importedFromPath) + ".sol",
40
- };
41
- const { schemaType, renderTableType } = getUserTypeInfo(schemaOrUserType, userTypesConfig);
42
- return {
43
- importDatum,
44
- renderTableType,
45
- schemaType,
46
- };
47
- } else {
48
- return {
49
- importDatum: undefined,
50
- renderTableType: getSchemaTypeInfo(schemaOrUserType),
51
- schemaType: schemaOrUserType,
52
- };
45
+ config: StoreConfig
46
+ ): ImportDatum | undefined {
47
+ // abi types which directly mirror a SchemaType
48
+ if (abiOrUserType in AbiTypeToSchemaType) {
49
+ return undefined;
53
50
  }
51
+ // static arrays
52
+ const staticArray = parseStaticArray(abiOrUserType);
53
+ if (staticArray) {
54
+ return undefined;
55
+ }
56
+ // user types
57
+ return {
58
+ symbol: abiOrUserType,
59
+ fromPath: config.userTypesPath + ".sol",
60
+ usedInPath: usedInDirectory,
61
+ };
54
62
  }
55
63
 
56
64
  export function getSchemaTypeInfo(schemaType: SchemaType): RenderTableType {
57
65
  const staticByteLength = getStaticByteLength(schemaType);
58
66
  const isDynamic = staticByteLength === 0;
59
- const typeId = SchemaTypeId[schemaType];
67
+ const typeId = SchemaTypeToAbiType[schemaType];
60
68
  return {
61
69
  typeId,
62
70
  typeWithLocation: isDynamic ? typeId + " memory" : typeId,
@@ -71,12 +79,13 @@ export function getSchemaTypeInfo(schemaType: SchemaType): RenderTableType {
71
79
 
72
80
  export function getUserTypeInfo(
73
81
  userType: string,
74
- userTypesConfig: StoreConfig["userTypes"]
82
+ config: StoreConfig
75
83
  ): {
76
84
  schemaType: SchemaType;
77
85
  renderTableType: RenderTableType;
78
86
  } {
79
- if (userType in userTypesConfig.enums) {
87
+ // enums
88
+ if (userType in config.enums) {
80
89
  const schemaType = SchemaType.UINT8;
81
90
  const staticByteLength = getStaticByteLength(schemaType);
82
91
  const isDynamic = staticByteLength === 0;
@@ -90,11 +99,34 @@ export function getUserTypeInfo(
90
99
  staticByteLength,
91
100
  isDynamic,
92
101
  typeWrap: `${userType}`,
93
- typeUnwrap: `${userType}`,
94
- internalTypeId: `${SchemaTypeId[schemaType]}`,
102
+ typeUnwrap: `uint8`,
103
+ internalTypeId: `${SchemaTypeToAbiType[schemaType]}`,
95
104
  },
96
105
  };
97
- } else {
98
- throw new Error(`User type "${userType}" does not exist`);
99
106
  }
107
+ // invalid
108
+ throw new Error(`User type "${userType}" does not exist`);
109
+ }
110
+
111
+ function getStaticArrayTypeInfo(abiType: string, elementType: string, staticLength: number) {
112
+ const internalTypeId = elementType + "[]";
113
+ const schemaType = AbiTypeToSchemaType[internalTypeId];
114
+ return {
115
+ schemaType,
116
+ renderTableType: {
117
+ typeId: abiType,
118
+ typeWithLocation: `${abiType} memory`,
119
+ enumName: SchemaType[schemaType],
120
+ staticByteLength: 0,
121
+ isDynamic: true,
122
+ typeWrap: `toStaticArray_${elementType}_${staticLength}`,
123
+ typeUnwrap: `fromStaticArray_${elementType}_${staticLength}`,
124
+ typeWrappingData: {
125
+ kind: "staticArray",
126
+ elementType,
127
+ staticLength,
128
+ },
129
+ internalTypeId,
130
+ },
131
+ } as const;
100
132
  }
@@ -0,0 +1,60 @@
1
+ import { readFileSync } from "fs";
2
+ import path from "path";
3
+ import { MUDConfig } from "../config/index.js";
4
+ import { contractToInterface } from "../utils/contractToInterface.js";
5
+ import { formatAndWrite } from "../utils/formatAndWrite.js";
6
+ import { renderSystemInterface } from "./renderSystemInterface.js";
7
+ import { renderWorld } from "./renderWorld.js";
8
+ import { ImportDatum } from "./types.js";
9
+
10
+ export async function worldgen(
11
+ config: MUDConfig,
12
+ existingContracts: { path: string; basename: string }[],
13
+ outputBaseDirectory: string
14
+ ) {
15
+ const worldgenBaseDirectory = path.join(outputBaseDirectory, config.worldgenDirectory);
16
+ const systems = existingContracts.filter(({ basename }) => Object.keys(config.systems).includes(basename));
17
+
18
+ const systemInterfaceImports: ImportDatum[] = [];
19
+ for (const system of systems) {
20
+ const data = readFileSync(system.path, "utf8");
21
+ // get external funcions from a contract
22
+ const { functions, symbols } = contractToInterface(data, system.basename);
23
+ const imports = symbols.map((symbol) => ({
24
+ symbol,
25
+ fromPath: system.path,
26
+ usedInPath: worldgenBaseDirectory,
27
+ }));
28
+ const systemInterfaceName = `I${system.basename}`;
29
+ // create an interface using the external functions and imports
30
+ const { fileSelector } = config.systems[system.basename];
31
+ const output = renderSystemInterface({
32
+ name: systemInterfaceName,
33
+ functionPrefix: config.namespace === "" ? "" : `${config.namespace}_${fileSelector}_`,
34
+ functions,
35
+ imports,
36
+ });
37
+ // write to file
38
+ const fullOutputPath = path.join(worldgenBaseDirectory, systemInterfaceName + ".sol");
39
+ await formatAndWrite(output, fullOutputPath, "Generated system interface");
40
+
41
+ // prepare imports for IWorld
42
+ systemInterfaceImports.push({
43
+ symbol: systemInterfaceName,
44
+ fromPath: `${systemInterfaceName}.sol`,
45
+ usedInPath: "./",
46
+ });
47
+ }
48
+
49
+ // render IWorld
50
+ const worldInterfaceName = "IWorld";
51
+ const output = renderWorld({
52
+ interfaceName: worldInterfaceName,
53
+ imports: systemInterfaceImports,
54
+ storeImportPath: config.storeImportPath,
55
+ worldImportPath: config.worldImportPath,
56
+ });
57
+ // write to file
58
+ const fullOutputPath = path.join(worldgenBaseDirectory, worldInterfaceName + ".sol");
59
+ await formatAndWrite(output, fullOutputPath, "Generated system interface");
60
+ }