@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.
- package/LICENSE +21 -0
- package/dist/chunk-ATAWDHWC.js +67 -0
- package/dist/{chunk-6AQ6LFVZ.js → chunk-J4DJQNIC.js} +743 -103
- package/dist/chunk-KD354QKC.js +23039 -0
- package/dist/{chunk-S3V3XX7N.js → chunk-SLIMIO4Z.js} +1 -1
- package/dist/config/index.d.ts +746 -8
- package/dist/config/index.js +63 -17
- package/dist/index.d.ts +1 -2
- package/dist/index.js +14 -10
- package/dist/mud.js +1055 -49
- package/dist/utils/deprecated/index.js +2 -2
- package/dist/utils/index.d.ts +56 -7
- package/dist/utils/index.js +17 -3
- package/package.json +16 -11
- package/src/commands/deploy-v2.ts +96 -0
- package/src/commands/deprecated/call-system.ts +1 -1
- package/src/commands/deprecated/deploy-contracts.ts +1 -1
- package/src/commands/deprecated/test.ts +9 -6
- package/src/commands/deprecated/trace.ts +1 -1
- package/src/commands/gas-report.ts +1 -1
- package/src/commands/index.ts +4 -0
- package/src/commands/tablegen.ts +4 -18
- package/src/commands/worldgen.ts +55 -0
- package/src/config/commonSchemas.ts +19 -5
- package/src/config/dynamicResolution.ts +49 -0
- package/src/config/index.ts +20 -0
- package/src/config/loadStoreConfig.ts +3 -89
- package/src/config/parseStoreConfig.test-d.ts +40 -0
- package/src/config/parseStoreConfig.ts +314 -0
- package/src/config/validation.ts +71 -0
- package/src/config/world/index.ts +4 -0
- package/src/config/world/loadWorldConfig.test-d.ts +11 -0
- 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 +13 -5
- package/src/mud.ts +4 -0
- package/src/render-solidity/common.ts +138 -0
- package/src/render-solidity/field.ts +137 -0
- package/src/render-solidity/index.ts +10 -0
- package/src/render-solidity/record.ts +154 -0
- package/src/render-solidity/renderSystemInterface.ts +31 -0
- package/src/render-solidity/renderTable.ts +164 -0
- package/src/render-solidity/renderTypeHelpers.ts +99 -0
- package/src/render-solidity/renderTypes.ts +19 -0
- package/src/render-solidity/renderTypesFromConfig.ts +13 -0
- package/src/render-solidity/renderWorld.ts +24 -0
- package/src/{render-table/renderTablesFromConfig.ts → render-solidity/tableOptions.ts} +45 -37
- package/src/render-solidity/tablegen.ts +33 -0
- package/src/render-solidity/types.ts +110 -0
- package/src/render-solidity/userType.ts +132 -0
- package/src/render-solidity/worldgen.ts +60 -0
- package/src/utils/contractToInterface.ts +130 -0
- package/src/utils/deploy-v2.ts +512 -0
- package/src/utils/deprecated/build.ts +1 -1
- package/src/utils/deprecated/typegen.ts +1 -1
- package/src/utils/errors.ts +12 -2
- package/src/utils/execLog.ts +22 -0
- package/src/utils/formatAndWrite.ts +12 -0
- package/src/utils/foundry.ts +94 -0
- package/src/utils/getChainId.ts +10 -0
- package/src/utils/index.ts +2 -1
- package/src/utils/typeUtils.ts +17 -0
- package/dist/chunk-B6VWCGHZ.js +0 -199
- package/dist/chunk-JKAA3WMC.js +0 -55
- package/dist/chunk-JNGSW4AP.js +0 -493
- package/dist/chunk-PJ6GS2R4.js +0 -22
- package/dist/chunk-UC3QPOON.js +0 -35
- package/dist/loadStoreConfig-37f99136.d.ts +0 -164
- package/dist/render-table/index.d.ts +0 -29
- package/dist/render-table/index.js +0 -24
- package/dist/renderTable-9e6410c5.d.ts +0 -72
- package/src/config/loadStoreConfig.test-d.ts +0 -11
- package/src/render-table/common.ts +0 -67
- package/src/render-table/field.ts +0 -132
- package/src/render-table/index.ts +0 -6
- package/src/render-table/record.ts +0 -176
- package/src/render-table/renderTable.ts +0 -109
- package/src/render-table/types.ts +0 -51
- package/src/utils/forgeConfig.ts +0 -45
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import {
|
|
2
|
+
renderArguments,
|
|
3
|
+
renderCommonData,
|
|
4
|
+
renderList,
|
|
5
|
+
renderedSolidityHeader,
|
|
6
|
+
renderImports,
|
|
7
|
+
renderTableId,
|
|
8
|
+
renderWithStore,
|
|
9
|
+
} from "./common.js";
|
|
10
|
+
import { renderEncodeField, renderFieldMethods } from "./field.js";
|
|
11
|
+
import { renderRecordMethods } from "./record.js";
|
|
12
|
+
import { renderTypeHelpers } from "./renderTypeHelpers.js";
|
|
13
|
+
import { RenderTableDynamicField, RenderTableOptions } from "./types.js";
|
|
14
|
+
|
|
15
|
+
export function renderTable(options: RenderTableOptions) {
|
|
16
|
+
const {
|
|
17
|
+
imports,
|
|
18
|
+
libraryName,
|
|
19
|
+
structName,
|
|
20
|
+
staticResourceData,
|
|
21
|
+
storeImportPath,
|
|
22
|
+
fields,
|
|
23
|
+
staticFields,
|
|
24
|
+
dynamicFields,
|
|
25
|
+
withRecordMethods,
|
|
26
|
+
storeArgument,
|
|
27
|
+
primaryKeys,
|
|
28
|
+
} = options;
|
|
29
|
+
|
|
30
|
+
const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
|
|
31
|
+
|
|
32
|
+
return `${renderedSolidityHeader}
|
|
33
|
+
|
|
34
|
+
// Import schema type
|
|
35
|
+
import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol";
|
|
36
|
+
|
|
37
|
+
// Import store internals
|
|
38
|
+
import { IStore } from "${storeImportPath}IStore.sol";
|
|
39
|
+
import { StoreSwitch } from "${storeImportPath}StoreSwitch.sol";
|
|
40
|
+
import { StoreCore } from "${storeImportPath}StoreCore.sol";
|
|
41
|
+
import { Bytes } from "${storeImportPath}Bytes.sol";
|
|
42
|
+
import { Memory } from "${storeImportPath}Memory.sol";
|
|
43
|
+
import { SliceLib } from "${storeImportPath}Slice.sol";
|
|
44
|
+
import { EncodeArray } from "${storeImportPath}tightcoder/EncodeArray.sol";
|
|
45
|
+
import { Schema, SchemaLib } from "${storeImportPath}Schema.sol";
|
|
46
|
+
import { PackedCounter, PackedCounterLib } from "${storeImportPath}PackedCounter.sol";
|
|
47
|
+
|
|
48
|
+
${
|
|
49
|
+
imports.length > 0
|
|
50
|
+
? `
|
|
51
|
+
// Import user types
|
|
52
|
+
${renderImports(imports)}
|
|
53
|
+
`
|
|
54
|
+
: ""
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
${staticResourceData ? renderTableId(staticResourceData).tableIdDefinition : ""}
|
|
58
|
+
|
|
59
|
+
${
|
|
60
|
+
!structName
|
|
61
|
+
? ""
|
|
62
|
+
: `
|
|
63
|
+
struct ${structName} {
|
|
64
|
+
${renderList(fields, ({ name, typeId }) => `${typeId} ${name};`)}
|
|
65
|
+
}
|
|
66
|
+
`
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
library ${libraryName} {
|
|
70
|
+
/** Get the table's schema */
|
|
71
|
+
function getSchema() internal pure returns (Schema) {
|
|
72
|
+
SchemaType[] memory _schema = new SchemaType[](${fields.length});
|
|
73
|
+
${renderList(fields, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)}
|
|
74
|
+
|
|
75
|
+
return SchemaLib.encode(_schema);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function getKeySchema() internal pure returns (Schema) {
|
|
79
|
+
SchemaType[] memory _schema = new SchemaType[](${primaryKeys.length});
|
|
80
|
+
${renderList(primaryKeys, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)}
|
|
81
|
+
|
|
82
|
+
return SchemaLib.encode(_schema);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Get the table's metadata */
|
|
86
|
+
function getMetadata() internal pure returns (string memory, string[] memory) {
|
|
87
|
+
string[] memory _fieldNames = new string[](${fields.length});
|
|
88
|
+
${renderList(fields, (field, index) => `_fieldNames[${index}] = "${field.name}";`)}
|
|
89
|
+
return ("${libraryName}", _fieldNames);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
${renderWithStore(
|
|
93
|
+
storeArgument,
|
|
94
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
95
|
+
/** Register the table's schema${_commentSuffix} */
|
|
96
|
+
function registerSchema(${renderArguments([_typedStore, _typedTableId])}) internal {
|
|
97
|
+
${_store}.registerSchema(_tableId, getSchema(), getKeySchema());
|
|
98
|
+
}
|
|
99
|
+
`
|
|
100
|
+
)}
|
|
101
|
+
${renderWithStore(
|
|
102
|
+
storeArgument,
|
|
103
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
104
|
+
/** Set the table's metadata${_commentSuffix} */
|
|
105
|
+
function setMetadata(${renderArguments([_typedStore, _typedTableId])}) internal {
|
|
106
|
+
(string memory _tableName, string[] memory _fieldNames) = getMetadata();
|
|
107
|
+
${_store}.setMetadata(_tableId, _tableName, _fieldNames);
|
|
108
|
+
}
|
|
109
|
+
`
|
|
110
|
+
)}
|
|
111
|
+
|
|
112
|
+
${renderFieldMethods(options)}
|
|
113
|
+
|
|
114
|
+
${withRecordMethods ? renderRecordMethods(options) : ""}
|
|
115
|
+
|
|
116
|
+
/** Tightly pack full data using this table's schema */
|
|
117
|
+
function encode(${renderArguments(
|
|
118
|
+
options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`)
|
|
119
|
+
)}) internal view returns (bytes memory) {
|
|
120
|
+
${renderEncodedLengths(dynamicFields)}
|
|
121
|
+
return abi.encodePacked(${renderArguments([
|
|
122
|
+
renderArguments(staticFields.map(({ name }) => name)),
|
|
123
|
+
// TODO try gas optimization (preallocate for all, encodePacked statics, and direct encode dynamics)
|
|
124
|
+
// (see https://github.com/latticexyz/mud/issues/444)
|
|
125
|
+
...(dynamicFields.length === 0
|
|
126
|
+
? []
|
|
127
|
+
: ["_encodedLengths.unwrap()", renderArguments(dynamicFields.map((field) => renderEncodeField(field)))]),
|
|
128
|
+
])});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
${renderWithStore(
|
|
132
|
+
storeArgument,
|
|
133
|
+
(_typedStore, _store, _commentSuffix) => `
|
|
134
|
+
/* Delete all data for given keys${_commentSuffix} */
|
|
135
|
+
function deleteRecord(${renderArguments([_typedStore, _typedTableId, _typedKeyArgs])}) internal {
|
|
136
|
+
${_primaryKeysDefinition}
|
|
137
|
+
${_store}.deleteRecord(_tableId, _primaryKeys);
|
|
138
|
+
}
|
|
139
|
+
`
|
|
140
|
+
)}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
${renderTypeHelpers(options)}
|
|
144
|
+
|
|
145
|
+
`;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function renderEncodedLengths(dynamicFields: RenderTableDynamicField[]) {
|
|
149
|
+
if (dynamicFields.length > 0) {
|
|
150
|
+
return `
|
|
151
|
+
uint16[] memory _counters = new uint16[](${dynamicFields.length});
|
|
152
|
+
${renderList(dynamicFields, ({ name, arrayElement }, index) => {
|
|
153
|
+
if (arrayElement) {
|
|
154
|
+
return `_counters[${index}] = uint16(${name}.length * ${arrayElement.staticByteLength});`;
|
|
155
|
+
} else {
|
|
156
|
+
return `_counters[${index}] = uint16(bytes(${name}).length);`;
|
|
157
|
+
}
|
|
158
|
+
})}
|
|
159
|
+
PackedCounter _encodedLengths = PackedCounterLib.pack(_counters);
|
|
160
|
+
`;
|
|
161
|
+
} else {
|
|
162
|
+
return "";
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { renderArguments, renderList, renderedSolidityHeader } from "./common.js";
|
|
2
|
+
import { RenderTypesOptions } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export function renderTypes(options: RenderTypesOptions) {
|
|
5
|
+
const { enums } = options;
|
|
6
|
+
|
|
7
|
+
return `${renderedSolidityHeader}
|
|
8
|
+
|
|
9
|
+
${renderList(
|
|
10
|
+
enums,
|
|
11
|
+
({ name, memberNames }) => `
|
|
12
|
+
enum ${name} {
|
|
13
|
+
${renderArguments(memberNames)}
|
|
14
|
+
}
|
|
15
|
+
`
|
|
16
|
+
)}
|
|
17
|
+
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StoreConfig } from "../config/parseStoreConfig.js";
|
|
2
|
+
import { renderTypes } from "./renderTypes.js";
|
|
3
|
+
|
|
4
|
+
export function renderTypesFromConfig(config: StoreConfig) {
|
|
5
|
+
const enums = Object.keys(config.enums).map((name) => ({
|
|
6
|
+
name,
|
|
7
|
+
memberNames: config.enums[name],
|
|
8
|
+
}));
|
|
9
|
+
|
|
10
|
+
return renderTypes({
|
|
11
|
+
enums,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -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,18 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import { StoreConfig } from "../config/
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { SchemaTypeArrayToElement } from "@latticexyz/schema-type";
|
|
3
|
+
import { StoreConfig } from "../config/parseStoreConfig.js";
|
|
4
4
|
import {
|
|
5
|
+
ImportDatum,
|
|
5
6
|
RenderTableDynamicField,
|
|
6
7
|
RenderTableField,
|
|
8
|
+
RenderTableOptions,
|
|
7
9
|
RenderTablePrimaryKey,
|
|
8
10
|
RenderTableStaticField,
|
|
9
|
-
RenderTableType,
|
|
10
11
|
} from "./types.js";
|
|
12
|
+
import { getSchemaTypeInfo, importForAbiOrUserType, resolveAbiOrUserType } from "./userType.js";
|
|
11
13
|
|
|
12
|
-
export
|
|
14
|
+
export interface TableOptions {
|
|
15
|
+
outputPath: string;
|
|
16
|
+
tableName: string;
|
|
17
|
+
renderOptions: RenderTableOptions;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getTableOptions(config: StoreConfig): TableOptions[] {
|
|
13
21
|
const storeImportPath = config.storeImportPath;
|
|
14
22
|
|
|
15
|
-
const
|
|
23
|
+
const options = [];
|
|
16
24
|
for (const tableName of Object.keys(config.tables)) {
|
|
17
25
|
const tableData = config.tables[tableName];
|
|
18
26
|
|
|
@@ -22,14 +30,21 @@ export function renderTablesFromConfig(config: StoreConfig) {
|
|
|
22
30
|
const withRecordMethods = withStruct || Object.keys(tableData.schema).length > 1;
|
|
23
31
|
// field methods can be simply get/set if there's only 1 field and no record methods
|
|
24
32
|
const noFieldMethodSuffix = !withRecordMethods && Object.keys(tableData.schema).length === 1;
|
|
33
|
+
// list of any symbols that need to be imported
|
|
34
|
+
const imports: ImportDatum[] = [];
|
|
25
35
|
|
|
26
36
|
const primaryKeys = Object.keys(tableData.primaryKeys).map((name) => {
|
|
27
|
-
const
|
|
28
|
-
const
|
|
29
|
-
|
|
37
|
+
const abiOrUserType = tableData.primaryKeys[name];
|
|
38
|
+
const { renderTableType } = resolveAbiOrUserType(abiOrUserType, config);
|
|
39
|
+
|
|
40
|
+
const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config);
|
|
41
|
+
if (importDatum) imports.push(importDatum);
|
|
42
|
+
|
|
43
|
+
if (renderTableType.isDynamic)
|
|
44
|
+
throw new Error(`Parsing error: found dynamic primary key ${name} in table ${tableName}`);
|
|
30
45
|
|
|
31
46
|
const primaryKey: RenderTablePrimaryKey = {
|
|
32
|
-
...
|
|
47
|
+
...renderTableType,
|
|
33
48
|
name,
|
|
34
49
|
isDynamic: false,
|
|
35
50
|
};
|
|
@@ -37,11 +52,16 @@ export function renderTablesFromConfig(config: StoreConfig) {
|
|
|
37
52
|
});
|
|
38
53
|
|
|
39
54
|
const fields = Object.keys(tableData.schema).map((name) => {
|
|
40
|
-
const
|
|
41
|
-
const
|
|
55
|
+
const abiOrUserType = tableData.schema[name];
|
|
56
|
+
const { renderTableType, schemaType } = resolveAbiOrUserType(abiOrUserType, config);
|
|
57
|
+
|
|
58
|
+
const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config);
|
|
59
|
+
if (importDatum) imports.push(importDatum);
|
|
60
|
+
|
|
61
|
+
const elementType = SchemaTypeArrayToElement[schemaType];
|
|
42
62
|
const field: RenderTableField = {
|
|
43
|
-
...
|
|
44
|
-
arrayElement: elementType ? getSchemaTypeInfo(elementType) : undefined,
|
|
63
|
+
...renderTableType,
|
|
64
|
+
arrayElement: elementType !== undefined ? getSchemaTypeInfo(elementType) : undefined,
|
|
45
65
|
name,
|
|
46
66
|
methodNameSuffix: noFieldMethodSuffix ? "" : `${name[0].toUpperCase()}${name.slice(1)}`,
|
|
47
67
|
};
|
|
@@ -52,26 +72,27 @@ export function renderTablesFromConfig(config: StoreConfig) {
|
|
|
52
72
|
const dynamicFields = fields.filter(({ isDynamic }) => isDynamic) as RenderTableDynamicField[];
|
|
53
73
|
|
|
54
74
|
// With tableIdArgument: tableId is a dynamic argument for each method
|
|
55
|
-
// Without tableIdArgument: tableId is a file-level constant generated from `
|
|
56
|
-
const
|
|
75
|
+
// Without tableIdArgument: tableId is a file-level constant generated from `staticResourceData`
|
|
76
|
+
const staticResourceData = (() => {
|
|
57
77
|
if (tableData.tableIdArgument) {
|
|
58
78
|
return;
|
|
59
79
|
} else {
|
|
60
80
|
return {
|
|
61
81
|
tableIdName: tableName + "TableId",
|
|
62
|
-
|
|
63
|
-
|
|
82
|
+
namespace: config.namespace,
|
|
83
|
+
fileSelector: tableData.fileSelector,
|
|
64
84
|
};
|
|
65
85
|
}
|
|
66
86
|
})();
|
|
67
87
|
|
|
68
|
-
|
|
88
|
+
options.push({
|
|
89
|
+
outputPath: path.join(tableData.directory, `${tableName}.sol`),
|
|
69
90
|
tableName,
|
|
70
|
-
|
|
71
|
-
|
|
91
|
+
renderOptions: {
|
|
92
|
+
imports,
|
|
72
93
|
libraryName: tableName,
|
|
73
94
|
structName: withStruct ? tableName + "Data" : undefined,
|
|
74
|
-
|
|
95
|
+
staticResourceData,
|
|
75
96
|
storeImportPath,
|
|
76
97
|
primaryKeys,
|
|
77
98
|
fields,
|
|
@@ -79,21 +100,8 @@ export function renderTablesFromConfig(config: StoreConfig) {
|
|
|
79
100
|
dynamicFields,
|
|
80
101
|
withRecordMethods,
|
|
81
102
|
storeArgument: tableData.storeArgument,
|
|
82
|
-
}
|
|
103
|
+
},
|
|
83
104
|
});
|
|
84
105
|
}
|
|
85
|
-
return
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function getSchemaTypeInfo(schemaType: SchemaType): RenderTableType {
|
|
89
|
-
const staticByteLength = getStaticByteLength(schemaType);
|
|
90
|
-
const isDynamic = staticByteLength === 0;
|
|
91
|
-
const typeId = SchemaTypeId[schemaType];
|
|
92
|
-
return {
|
|
93
|
-
typeId,
|
|
94
|
-
typeWithLocation: isDynamic ? typeId + " memory" : typeId,
|
|
95
|
-
enumName: SchemaType[schemaType],
|
|
96
|
-
staticByteLength,
|
|
97
|
-
isDynamic,
|
|
98
|
-
};
|
|
106
|
+
return options;
|
|
99
107
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { StoreConfig } from "../config/index.js";
|
|
4
|
+
import { formatSolidity } from "../utils/format.js";
|
|
5
|
+
import { getTableOptions } from "./tableOptions.js";
|
|
6
|
+
import { renderTable } from "./renderTable.js";
|
|
7
|
+
import { renderTypesFromConfig } from "./renderTypesFromConfig.js";
|
|
8
|
+
|
|
9
|
+
export async function tablegen(config: StoreConfig, outputBaseDirectory: string) {
|
|
10
|
+
const allTableOptions = getTableOptions(config);
|
|
11
|
+
// write tables to files
|
|
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
|
+
}
|
|
17
|
+
|
|
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");
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function formatAndWrite(output: string, fullOutputPath: string, logPrefix: string) {
|
|
27
|
+
const formattedOutput = await formatSolidity(output);
|
|
28
|
+
|
|
29
|
+
mkdirSync(path.dirname(fullOutputPath), { recursive: true });
|
|
30
|
+
|
|
31
|
+
writeFileSync(fullOutputPath, formattedOutput);
|
|
32
|
+
console.log(`${logPrefix}: ${fullOutputPath}`);
|
|
33
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export interface RenderTableOptions {
|
|
2
|
+
/** List of symbols to import, and their file paths */
|
|
3
|
+
imports: ImportDatum[];
|
|
4
|
+
/** Name of the library to render. */
|
|
5
|
+
libraryName: string;
|
|
6
|
+
/** Name of the struct to render. If undefined, struct and its methods aren't rendered. */
|
|
7
|
+
structName?: string;
|
|
8
|
+
/** Data used to statically registed the table. If undefined, all methods receive `_tableId` as an argument. */
|
|
9
|
+
staticResourceData?: StaticResourceData;
|
|
10
|
+
/** Path for store package imports */
|
|
11
|
+
storeImportPath: string;
|
|
12
|
+
primaryKeys: RenderTablePrimaryKey[];
|
|
13
|
+
fields: RenderTableField[];
|
|
14
|
+
staticFields: RenderTableStaticField[];
|
|
15
|
+
dynamicFields: RenderTableDynamicField[];
|
|
16
|
+
/** Whether to render get/set methods for the whole record */
|
|
17
|
+
withRecordMethods: boolean;
|
|
18
|
+
/** Whether to render additional methods that accept a manual `IStore` argument */
|
|
19
|
+
storeArgument: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ImportDatum {
|
|
23
|
+
symbol: string;
|
|
24
|
+
fromPath: string;
|
|
25
|
+
usedInPath: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export interface StaticResourceData {
|
|
29
|
+
/** Name of the table id constant to render. */
|
|
30
|
+
tableIdName: string;
|
|
31
|
+
namespace: string;
|
|
32
|
+
fileSelector: string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface RenderTableType {
|
|
36
|
+
typeId: string;
|
|
37
|
+
typeWithLocation: string;
|
|
38
|
+
/** The name of the enum element in SchemaType to use for schema registration (e.g. "UINT256_ARRAY") */
|
|
39
|
+
enumName: string;
|
|
40
|
+
staticByteLength: number;
|
|
41
|
+
isDynamic: boolean;
|
|
42
|
+
/** Empty for internal types. Custom `wrap` method for user defined types. */
|
|
43
|
+
typeWrap: string;
|
|
44
|
+
/** Empty for internal types. Custom `unwrap` method for user defined types. */
|
|
45
|
+
typeUnwrap: string;
|
|
46
|
+
/** Data to generate the custom wrapper and unwrapper if necessary. */
|
|
47
|
+
typeWrappingData?: RenderTableTypeWrappingData;
|
|
48
|
+
/** Same as typeId for internal types. The underlying `typeId` for user defined types. */
|
|
49
|
+
internalTypeId: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export type RenderTableTypeWrappingData = {
|
|
53
|
+
kind: "staticArray";
|
|
54
|
+
elementType: string;
|
|
55
|
+
staticLength: number;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export interface RenderTablePrimaryKey extends RenderTableType {
|
|
59
|
+
name: string;
|
|
60
|
+
isDynamic: false;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface RenderTableStaticField extends RenderTableField {
|
|
64
|
+
isDynamic: false;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface RenderTableDynamicField extends RenderTableField {
|
|
68
|
+
isDynamic: true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface RenderTableField extends RenderTableType {
|
|
72
|
+
arrayElement: RenderTableType | undefined;
|
|
73
|
+
name: string;
|
|
74
|
+
methodNameSuffix: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface RenderTypesOptions {
|
|
78
|
+
/** List of enums to render */
|
|
79
|
+
enums: RenderTypesEnum[];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface RenderTypesEnum {
|
|
83
|
+
name: string;
|
|
84
|
+
memberNames: string[];
|
|
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
|
+
}
|