@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.
- package/dist/{chunk-GR245KYP.js → chunk-J4DJQNIC.js} +679 -133
- package/dist/chunk-O57QENJ6.js +23039 -0
- package/dist/config/index.d.ts +610 -296
- package/dist/config/index.js +49 -26
- package/dist/index.d.ts +2 -110
- package/dist/index.js +9 -50
- package/dist/mud.js +937 -57
- package/dist/utils/index.d.ts +92 -4
- package/dist/utils/index.js +2 -3
- package/package.json +10 -9
- package/src/commands/deploy-v2.ts +11 -15
- package/src/commands/index.ts +2 -0
- package/src/commands/worldgen.ts +55 -0
- package/src/config/commonSchemas.ts +11 -13
- package/src/config/dynamicResolution.ts +49 -0
- package/src/config/index.ts +15 -3
- package/src/config/loadStoreConfig.ts +1 -1
- package/src/config/parseStoreConfig.test-d.ts +31 -5
- package/src/config/parseStoreConfig.ts +218 -78
- package/src/config/validation.ts +25 -0
- package/src/config/world/index.ts +4 -0
- package/src/config/{loadWorldConfig.test-d.ts → world/loadWorldConfig.test-d.ts} +3 -3
- package/src/config/world/loadWorldConfig.ts +26 -0
- package/src/config/world/parseWorldConfig.ts +55 -0
- package/src/config/world/resolveWorldConfig.ts +80 -0
- package/src/config/world/userTypes.ts +72 -0
- package/src/index.ts +4 -6
- package/src/render-solidity/common.ts +51 -6
- package/src/render-solidity/field.ts +40 -44
- package/src/render-solidity/index.ts +5 -1
- package/src/render-solidity/record.ts +56 -73
- package/src/render-solidity/renderSystemInterface.ts +31 -0
- package/src/render-solidity/renderTable.ts +98 -70
- package/src/render-solidity/renderTypeHelpers.ts +99 -0
- package/src/render-solidity/renderTypesFromConfig.ts +2 -2
- package/src/render-solidity/renderWorld.ts +24 -0
- package/src/render-solidity/{renderTablesFromConfig.ts → tableOptions.ts} +28 -30
- package/src/render-solidity/tablegen.ts +20 -22
- package/src/render-solidity/types.ts +39 -5
- package/src/render-solidity/userType.ts +80 -48
- package/src/render-solidity/worldgen.ts +60 -0
- package/src/utils/contractToInterface.ts +130 -0
- package/src/utils/deploy-v2.ts +268 -101
- package/src/utils/formatAndWrite.ts +12 -0
- package/src/utils/getChainId.ts +10 -0
- package/src/utils/typeUtils.ts +17 -0
- package/dist/chunk-AER7UDD4.js +0 -0
- package/dist/chunk-XRS7KWBZ.js +0 -547
- package/dist/chunk-YZATC2M3.js +0 -397
- package/dist/chunk-ZYDMYSTH.js +0 -1178
- package/dist/deploy-v2-b7b3207d.d.ts +0 -92
- package/src/config/loadWorldConfig.ts +0 -178
- 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.
|
|
5
|
+
const enums = Object.keys(config.enums).map((name) => ({
|
|
6
6
|
name,
|
|
7
|
-
memberNames: config.
|
|
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,
|
|
12
|
+
import { getSchemaTypeInfo, importForAbiOrUserType, resolveAbiOrUserType } from "./userType.js";
|
|
13
13
|
|
|
14
|
-
export
|
|
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
|
|
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
|
|
33
|
-
const { renderTableType
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
54
|
-
const { renderTableType,
|
|
55
|
-
|
|
56
|
-
|
|
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 `
|
|
77
|
-
const
|
|
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
|
-
|
|
84
|
-
|
|
82
|
+
namespace: config.namespace,
|
|
83
|
+
fileSelector: tableData.fileSelector,
|
|
85
84
|
};
|
|
86
85
|
}
|
|
87
86
|
})();
|
|
88
87
|
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
options.push({
|
|
89
|
+
outputPath: path.join(tableData.directory, `${tableName}.sol`),
|
|
91
90
|
tableName,
|
|
92
|
-
|
|
93
|
-
output: renderTable({
|
|
91
|
+
renderOptions: {
|
|
94
92
|
imports,
|
|
95
93
|
libraryName: tableName,
|
|
96
94
|
structName: withStruct ? tableName + "Data" : undefined,
|
|
97
|
-
|
|
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
|
|
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 {
|
|
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
|
-
|
|
10
|
-
const renderedTables = renderTablesFromConfig(config, outputBaseDirectory);
|
|
10
|
+
const allTableOptions = getTableOptions(config);
|
|
11
11
|
// write tables to files
|
|
12
|
-
for (const {
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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
|
-
|
|
29
|
-
const outputDirectory = path.dirname(outputPath);
|
|
30
|
-
mkdirSync(outputDirectory, { recursive: true });
|
|
29
|
+
mkdirSync(path.dirname(fullOutputPath), { recursive: true });
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
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
|
-
|
|
24
|
+
fromPath: string;
|
|
25
|
+
usedInPath: string;
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
export interface
|
|
28
|
+
export interface StaticResourceData {
|
|
28
29
|
/** Name of the table id constant to render. */
|
|
29
30
|
tableIdName: string;
|
|
30
|
-
|
|
31
|
-
|
|
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,
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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
|
|
9
|
+
* Resolve an abi or user type into a SchemaType
|
|
10
10
|
*/
|
|
11
|
-
export function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
*
|
|
40
|
+
* Get the required import for SchemaType|userType (`undefined` means that no import is required)
|
|
25
41
|
*/
|
|
26
|
-
export function
|
|
27
|
-
|
|
28
|
-
srcDirectory: string,
|
|
42
|
+
export function importForAbiOrUserType(
|
|
43
|
+
abiOrUserType: string,
|
|
29
44
|
usedInDirectory: string,
|
|
30
|
-
|
|
31
|
-
) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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 =
|
|
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
|
-
|
|
82
|
+
config: StoreConfig
|
|
75
83
|
): {
|
|
76
84
|
schemaType: SchemaType;
|
|
77
85
|
renderTableType: RenderTableType;
|
|
78
86
|
} {
|
|
79
|
-
|
|
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:
|
|
94
|
-
internalTypeId: `${
|
|
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
|
+
}
|