@latticexyz/cli 1.40.0 → 1.41.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/LICENSE +21 -0
  2. package/dist/chunk-ATAWDHWC.js +67 -0
  3. package/dist/{chunk-6AQ6LFVZ.js → chunk-J4DJQNIC.js} +743 -103
  4. package/dist/chunk-KD354QKC.js +23039 -0
  5. package/dist/{chunk-S3V3XX7N.js → chunk-SLIMIO4Z.js} +1 -1
  6. package/dist/config/index.d.ts +746 -8
  7. package/dist/config/index.js +63 -17
  8. package/dist/index.d.ts +1 -2
  9. package/dist/index.js +14 -10
  10. package/dist/mud.js +1055 -49
  11. package/dist/utils/deprecated/index.js +2 -2
  12. package/dist/utils/index.d.ts +56 -7
  13. package/dist/utils/index.js +17 -3
  14. package/package.json +16 -11
  15. package/src/commands/deploy-v2.ts +96 -0
  16. package/src/commands/deprecated/call-system.ts +1 -1
  17. package/src/commands/deprecated/deploy-contracts.ts +1 -1
  18. package/src/commands/deprecated/test.ts +9 -6
  19. package/src/commands/deprecated/trace.ts +1 -1
  20. package/src/commands/gas-report.ts +1 -1
  21. package/src/commands/index.ts +4 -0
  22. package/src/commands/tablegen.ts +4 -18
  23. package/src/commands/worldgen.ts +55 -0
  24. package/src/config/commonSchemas.ts +19 -5
  25. package/src/config/dynamicResolution.ts +49 -0
  26. package/src/config/index.ts +20 -0
  27. package/src/config/loadStoreConfig.ts +3 -89
  28. package/src/config/parseStoreConfig.test-d.ts +40 -0
  29. package/src/config/parseStoreConfig.ts +314 -0
  30. package/src/config/validation.ts +71 -0
  31. package/src/config/world/index.ts +4 -0
  32. package/src/config/world/loadWorldConfig.test-d.ts +11 -0
  33. package/src/config/world/loadWorldConfig.ts +26 -0
  34. package/src/config/world/parseWorldConfig.ts +55 -0
  35. package/src/config/world/resolveWorldConfig.ts +80 -0
  36. package/src/config/world/userTypes.ts +72 -0
  37. package/src/index.ts +13 -5
  38. package/src/mud.ts +4 -0
  39. package/src/render-solidity/common.ts +138 -0
  40. package/src/render-solidity/field.ts +137 -0
  41. package/src/render-solidity/index.ts +10 -0
  42. package/src/render-solidity/record.ts +154 -0
  43. package/src/render-solidity/renderSystemInterface.ts +31 -0
  44. package/src/render-solidity/renderTable.ts +164 -0
  45. package/src/render-solidity/renderTypeHelpers.ts +99 -0
  46. package/src/render-solidity/renderTypes.ts +19 -0
  47. package/src/render-solidity/renderTypesFromConfig.ts +13 -0
  48. package/src/render-solidity/renderWorld.ts +24 -0
  49. package/src/{render-table/renderTablesFromConfig.ts → render-solidity/tableOptions.ts} +45 -37
  50. package/src/render-solidity/tablegen.ts +33 -0
  51. package/src/render-solidity/types.ts +110 -0
  52. package/src/render-solidity/userType.ts +132 -0
  53. package/src/render-solidity/worldgen.ts +60 -0
  54. package/src/utils/contractToInterface.ts +130 -0
  55. package/src/utils/deploy-v2.ts +512 -0
  56. package/src/utils/deprecated/build.ts +1 -1
  57. package/src/utils/deprecated/typegen.ts +1 -1
  58. package/src/utils/errors.ts +12 -2
  59. package/src/utils/execLog.ts +22 -0
  60. package/src/utils/formatAndWrite.ts +12 -0
  61. package/src/utils/foundry.ts +94 -0
  62. package/src/utils/getChainId.ts +10 -0
  63. package/src/utils/index.ts +2 -1
  64. package/src/utils/typeUtils.ts +17 -0
  65. package/dist/chunk-B6VWCGHZ.js +0 -199
  66. package/dist/chunk-JKAA3WMC.js +0 -55
  67. package/dist/chunk-JNGSW4AP.js +0 -493
  68. package/dist/chunk-PJ6GS2R4.js +0 -22
  69. package/dist/chunk-UC3QPOON.js +0 -35
  70. package/dist/loadStoreConfig-37f99136.d.ts +0 -164
  71. package/dist/render-table/index.d.ts +0 -29
  72. package/dist/render-table/index.js +0 -24
  73. package/dist/renderTable-9e6410c5.d.ts +0 -72
  74. package/src/config/loadStoreConfig.test-d.ts +0 -11
  75. package/src/render-table/common.ts +0 -67
  76. package/src/render-table/field.ts +0 -132
  77. package/src/render-table/index.ts +0 -6
  78. package/src/render-table/record.ts +0 -176
  79. package/src/render-table/renderTable.ts +0 -109
  80. package/src/render-table/types.ts +0 -51
  81. package/src/utils/forgeConfig.ts +0 -45
@@ -0,0 +1,132 @@
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
+
6
+ export type UserTypeInfo = ReturnType<typeof getUserTypeInfo>;
7
+
8
+ /**
9
+ * Resolve an abi or user type into a SchemaType
10
+ */
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
+ }
34
+ }
35
+ // user types
36
+ return getUserTypeInfo(abiOrUserType, config);
37
+ }
38
+
39
+ /**
40
+ * Get the required import for SchemaType|userType (`undefined` means that no import is required)
41
+ */
42
+ export function importForAbiOrUserType(
43
+ abiOrUserType: string,
44
+ usedInDirectory: string,
45
+ config: StoreConfig
46
+ ): ImportDatum | undefined {
47
+ // abi types which directly mirror a SchemaType
48
+ if (abiOrUserType in AbiTypeToSchemaType) {
49
+ return undefined;
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
+ };
62
+ }
63
+
64
+ export function getSchemaTypeInfo(schemaType: SchemaType): RenderTableType {
65
+ const staticByteLength = getStaticByteLength(schemaType);
66
+ const isDynamic = staticByteLength === 0;
67
+ const typeId = SchemaTypeToAbiType[schemaType];
68
+ return {
69
+ typeId,
70
+ typeWithLocation: isDynamic ? typeId + " memory" : typeId,
71
+ enumName: SchemaType[schemaType],
72
+ staticByteLength,
73
+ isDynamic,
74
+ typeWrap: "",
75
+ typeUnwrap: "",
76
+ internalTypeId: typeId,
77
+ };
78
+ }
79
+
80
+ export function getUserTypeInfo(
81
+ userType: string,
82
+ config: StoreConfig
83
+ ): {
84
+ schemaType: SchemaType;
85
+ renderTableType: RenderTableType;
86
+ } {
87
+ // enums
88
+ if (userType in config.enums) {
89
+ const schemaType = SchemaType.UINT8;
90
+ const staticByteLength = getStaticByteLength(schemaType);
91
+ const isDynamic = staticByteLength === 0;
92
+ const typeId = userType;
93
+ return {
94
+ schemaType,
95
+ renderTableType: {
96
+ typeId,
97
+ typeWithLocation: typeId,
98
+ enumName: SchemaType[schemaType],
99
+ staticByteLength,
100
+ isDynamic,
101
+ typeWrap: `${userType}`,
102
+ typeUnwrap: `uint8`,
103
+ internalTypeId: `${SchemaTypeToAbiType[schemaType]}`,
104
+ },
105
+ };
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;
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
+ }
@@ -0,0 +1,130 @@
1
+ import { parse, visit } from "@solidity-parser/parser";
2
+ import { TypeName, VariableDeclaration } from "@solidity-parser/parser/dist/src/ast-types.js";
3
+ import { RenderSystemInterfaceFunction } from "../render-solidity/types.js";
4
+ import { MUDError } from "./errors.js";
5
+
6
+ /**
7
+ * Parse the contract data to get the functions necessary to generate an interface,
8
+ * and symbols to import from the original contract.
9
+ * @param data contents of a file with the solidity contract
10
+ * @param contractName name of the contract
11
+ * @returns interface data
12
+ */
13
+ export function contractToInterface(data: string, contractName: string) {
14
+ const ast = parse(data);
15
+
16
+ let withContract = false;
17
+ let symbols: string[] = [];
18
+ const functions: RenderSystemInterfaceFunction[] = [];
19
+
20
+ visit(ast, {
21
+ ContractDefinition({ name }) {
22
+ if (name === contractName) {
23
+ withContract = true;
24
+ }
25
+ },
26
+ FunctionDefinition(
27
+ { name, visibility, parameters, returnParameters, isConstructor, isFallback, isReceiveEther },
28
+ parent
29
+ ) {
30
+ if (parent !== undefined && parent.type === "ContractDefinition" && parent.name === contractName) {
31
+ try {
32
+ // skip constructor and fallbacks
33
+ if (isConstructor || isFallback || isReceiveEther) return;
34
+ // forbid default visibility (this check might be unnecessary, modern solidity already disallows this)
35
+ if (visibility === "default") throw new MUDError(`Visibility is not specified`);
36
+
37
+ if (visibility === "external" || visibility === "public") {
38
+ functions.push({
39
+ name: name === null ? "" : name,
40
+ parameters: parameters.map(parseParameter),
41
+ returnParameters: returnParameters === null ? [] : returnParameters.map(parseParameter),
42
+ });
43
+
44
+ for (const { typeName } of parameters.concat(returnParameters ?? [])) {
45
+ symbols = symbols.concat(typeNameToExternalSymbols(typeName));
46
+ }
47
+ }
48
+ } catch (error: unknown) {
49
+ if (error instanceof MUDError) {
50
+ error.message = `Function "${name}" in contract "${contractName}": ${error.message}`;
51
+ }
52
+ throw error;
53
+ }
54
+ }
55
+ },
56
+ });
57
+
58
+ if (!withContract) {
59
+ throw new MUDError(`Contract not found: ${contractName}`);
60
+ }
61
+
62
+ return {
63
+ functions,
64
+ symbols,
65
+ };
66
+ }
67
+
68
+ function parseParameter({ name, typeName, storageLocation }: VariableDeclaration): string {
69
+ let typedNameWithLocation = "";
70
+
71
+ const { name: flattenedTypeName, stateMutability } = flattenTypeName(typeName);
72
+ // type name (e.g. uint256)
73
+ typedNameWithLocation += flattenedTypeName;
74
+ // optional mutability (e.g. address payable)
75
+ if (stateMutability !== null) {
76
+ typedNameWithLocation += ` ${stateMutability}`;
77
+ }
78
+ // location, when relevant (e.g. string memory)
79
+ if (storageLocation !== null) {
80
+ typedNameWithLocation += ` ${storageLocation}`;
81
+ }
82
+ // optional variable name
83
+ if (name !== null) {
84
+ typedNameWithLocation += ` ${name}`;
85
+ }
86
+
87
+ return typedNameWithLocation;
88
+ }
89
+
90
+ function flattenTypeName(typeName: TypeName | null): { name: string; stateMutability: string | null } {
91
+ if (typeName === null) {
92
+ return {
93
+ name: "",
94
+ stateMutability: null,
95
+ };
96
+ }
97
+ if (typeName.type === "ElementaryTypeName") {
98
+ return {
99
+ name: typeName.name,
100
+ stateMutability: typeName.stateMutability,
101
+ };
102
+ } else if (typeName.type === "UserDefinedTypeName") {
103
+ return {
104
+ name: typeName.namePath,
105
+ stateMutability: null,
106
+ };
107
+ } else if (typeName.type === "ArrayTypeName") {
108
+ const { name, stateMutability } = flattenTypeName(typeName.baseTypeName);
109
+ return {
110
+ name: `${name}[]`,
111
+ stateMutability,
112
+ };
113
+ } else {
114
+ // TODO function types are unsupported but could be useful
115
+ throw new MUDError(`Invalid typeName.type ${typeName.type}`);
116
+ }
117
+ }
118
+
119
+ // Get symbols that need to be imported for given typeName
120
+ function typeNameToExternalSymbols(typeName: TypeName | null): string[] {
121
+ if (typeName?.type === "UserDefinedTypeName") {
122
+ // split is needed to get a library, if types are internal to it
123
+ const symbol = typeName.namePath.split(".")[0];
124
+ return [symbol];
125
+ } else if (typeName?.type === "ArrayTypeName") {
126
+ return typeNameToExternalSymbols(typeName.baseTypeName);
127
+ } else {
128
+ return [];
129
+ }
130
+ }