@latticexyz/cli 1.40.0 → 2.0.0-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-O57QENJ6.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
@@ -1,164 +0,0 @@
1
- import { SchemaType } from '@latticexyz/schema-type';
2
- import { z } from 'zod';
3
-
4
- interface StoreUserConfig {
5
- /** The base route prefix for table ids. Default is "" (empty string) */
6
- baseRoute?: string;
7
- /** Path for store package imports. Default is "@latticexyz/store/src/" */
8
- storeImportPath?: string;
9
- /**
10
- * Configuration for each table.
11
- *
12
- * The key is the table name (capitalized).
13
- *
14
- * The value:
15
- * - SchemaType for a single-value table (aka ECS component).
16
- * - FullTableConfig object for multi-value tables (or for customizable options).
17
- */
18
- tables: Record<string, SchemaType | FullTableConfig>;
19
- }
20
- interface FullTableConfig {
21
- /** Output path for the file, and relevant for the table id. The table id will be keccak256(concat(baseRoute,route,tableName)). Default is "tables/" */
22
- route?: string;
23
- /** Make methods accept `tableId` argument instead of it being a hardcoded constant. Default is false */
24
- tableIdArgument?: boolean;
25
- /** Include methods that accept a manual `IStore` argument. Default is false. */
26
- storeArgument?: boolean;
27
- /** Include a data struct and methods for it. Default is false for 1-column tables; true for multi-column tables. */
28
- dataStruct?: boolean;
29
- /** Table's primary key names mapped to their types. Default is `{ key: SchemaType.BYTES32 }` */
30
- primaryKeys?: Record<string, SchemaType>;
31
- /** Table's column names mapped to their types. Table name's 1st letter should be lowercase. */
32
- schema: Record<string, SchemaType>;
33
- }
34
- declare const StoreConfig: z.ZodObject<{
35
- baseRoute: z.ZodDefault<z.ZodEffects<z.ZodString, string, string>>;
36
- storeImportPath: z.ZodDefault<z.ZodString>;
37
- tables: z.ZodRecord<z.ZodEffects<z.ZodString, string, string>, z.ZodUnion<[z.ZodEffects<z.ZodNativeEnum<typeof SchemaType>, Omit<{
38
- dataStruct?: boolean | undefined;
39
- route: string;
40
- tableIdArgument: boolean;
41
- storeArgument: boolean;
42
- primaryKeys: Record<string, SchemaType>;
43
- schema: Record<string, SchemaType>;
44
- }, "dataStruct"> & Required<Pick<{
45
- dataStruct?: boolean | undefined;
46
- route: string;
47
- tableIdArgument: boolean;
48
- storeArgument: boolean;
49
- primaryKeys: Record<string, SchemaType>;
50
- schema: Record<string, SchemaType>;
51
- }, "dataStruct">>, SchemaType>, z.ZodEffects<z.ZodObject<{
52
- route: z.ZodDefault<z.ZodEffects<z.ZodString, string, string>>;
53
- tableIdArgument: z.ZodDefault<z.ZodBoolean>;
54
- storeArgument: z.ZodDefault<z.ZodBoolean>;
55
- primaryKeys: z.ZodDefault<z.ZodRecord<z.ZodEffects<z.ZodString, string, string>, z.ZodEffects<z.ZodNativeEnum<typeof SchemaType>, SchemaType, SchemaType>>>;
56
- schema: z.ZodEffects<z.ZodRecord<z.ZodEffects<z.ZodString, string, string>, z.ZodNativeEnum<typeof SchemaType>>, Record<string, SchemaType>, Record<string, SchemaType>>;
57
- dataStruct: z.ZodOptional<z.ZodBoolean>;
58
- }, "strip", z.ZodTypeAny, {
59
- dataStruct?: boolean | undefined;
60
- route: string;
61
- tableIdArgument: boolean;
62
- storeArgument: boolean;
63
- primaryKeys: Record<string, SchemaType>;
64
- schema: Record<string, SchemaType>;
65
- }, {
66
- route?: string | undefined;
67
- tableIdArgument?: boolean | undefined;
68
- storeArgument?: boolean | undefined;
69
- primaryKeys?: Record<string, SchemaType> | undefined;
70
- dataStruct?: boolean | undefined;
71
- schema: Record<string, SchemaType>;
72
- }>, Omit<{
73
- dataStruct?: boolean | undefined;
74
- route: string;
75
- tableIdArgument: boolean;
76
- storeArgument: boolean;
77
- primaryKeys: Record<string, SchemaType>;
78
- schema: Record<string, SchemaType>;
79
- }, "dataStruct"> & Required<Pick<{
80
- dataStruct?: boolean | undefined;
81
- route: string;
82
- tableIdArgument: boolean;
83
- storeArgument: boolean;
84
- primaryKeys: Record<string, SchemaType>;
85
- schema: Record<string, SchemaType>;
86
- }, "dataStruct">>, {
87
- route?: string | undefined;
88
- tableIdArgument?: boolean | undefined;
89
- storeArgument?: boolean | undefined;
90
- primaryKeys?: Record<string, SchemaType> | undefined;
91
- dataStruct?: boolean | undefined;
92
- schema: Record<string, SchemaType>;
93
- }>]>>;
94
- }, "strip", z.ZodTypeAny, {
95
- baseRoute: string;
96
- storeImportPath: string;
97
- tables: Record<string, Omit<{
98
- dataStruct?: boolean | undefined;
99
- route: string;
100
- tableIdArgument: boolean;
101
- storeArgument: boolean;
102
- primaryKeys: Record<string, SchemaType>;
103
- schema: Record<string, SchemaType>;
104
- }, "dataStruct"> & Required<Pick<{
105
- dataStruct?: boolean | undefined;
106
- route: string;
107
- tableIdArgument: boolean;
108
- storeArgument: boolean;
109
- primaryKeys: Record<string, SchemaType>;
110
- schema: Record<string, SchemaType>;
111
- }, "dataStruct">>>;
112
- }, {
113
- baseRoute?: string | undefined;
114
- storeImportPath?: string | undefined;
115
- tables: Record<string, SchemaType | {
116
- route?: string | undefined;
117
- tableIdArgument?: boolean | undefined;
118
- storeArgument?: boolean | undefined;
119
- primaryKeys?: Record<string, SchemaType> | undefined;
120
- dataStruct?: boolean | undefined;
121
- schema: Record<string, SchemaType>;
122
- }>;
123
- }>;
124
- type StoreConfig = z.output<typeof StoreConfig>;
125
- declare function loadStoreConfig(configPath?: string): Promise<{
126
- baseRoute: string;
127
- storeImportPath: string;
128
- tables: Record<string, Omit<{
129
- dataStruct?: boolean | undefined;
130
- route: string;
131
- tableIdArgument: boolean;
132
- storeArgument: boolean;
133
- primaryKeys: Record<string, SchemaType>;
134
- schema: Record<string, SchemaType>;
135
- }, "dataStruct"> & Required<Pick<{
136
- dataStruct?: boolean | undefined;
137
- route: string;
138
- tableIdArgument: boolean;
139
- storeArgument: boolean;
140
- primaryKeys: Record<string, SchemaType>;
141
- schema: Record<string, SchemaType>;
142
- }, "dataStruct">>>;
143
- }>;
144
- declare function parseStoreConfig(config: unknown): Promise<{
145
- baseRoute: string;
146
- storeImportPath: string;
147
- tables: Record<string, Omit<{
148
- dataStruct?: boolean | undefined;
149
- route: string;
150
- tableIdArgument: boolean;
151
- storeArgument: boolean;
152
- primaryKeys: Record<string, SchemaType>;
153
- schema: Record<string, SchemaType>;
154
- }, "dataStruct"> & Required<Pick<{
155
- dataStruct?: boolean | undefined;
156
- route: string;
157
- tableIdArgument: boolean;
158
- storeArgument: boolean;
159
- primaryKeys: Record<string, SchemaType>;
160
- schema: Record<string, SchemaType>;
161
- }, "dataStruct">>>;
162
- }>;
163
-
164
- export { StoreUserConfig as S, StoreConfig as a, loadStoreConfig as l, parseStoreConfig as p };
@@ -1,29 +0,0 @@
1
- import { R as RenderTableOptions, b as RenderTableField } from '../renderTable-9e6410c5.js';
2
- export { f as RenderTableDynamicField, b as RenderTableField, R as RenderTableOptions, d as RenderTablePrimaryKey, e as RenderTableStaticField, c as RenderTableType, S as StaticRouteData, a as renderTable, r as renderTablesFromConfig } from '../renderTable-9e6410c5.js';
3
- import '@latticexyz/schema-type';
4
- import '../loadStoreConfig-37f99136.js';
5
- import 'zod';
6
-
7
- /**
8
- * Renders a list of lines
9
- */
10
- declare function renderList<T>(list: T[], renderItem: (item: T, index: number) => string): string;
11
- /**
12
- * Renders a comma-separated list of arguments for solidity functions, ignoring empty and undefined ones
13
- */
14
- declare function renderArguments(args: (string | undefined)[]): string;
15
- declare function renderCommonData({ staticRouteData, primaryKeys }: RenderTableOptions): {
16
- _tableId: string;
17
- _typedTableId: string;
18
- _keyArgs: string;
19
- _typedKeyArgs: string;
20
- _primaryKeysDefinition: string;
21
- };
22
-
23
- declare function renderFieldMethods(options: RenderTableOptions): string;
24
- declare function renderEncodeField(field: RenderTableField): string;
25
- declare function renderDecodeValueType(typeId: string, staticByteLength: number, offset: number): string;
26
-
27
- declare function renderRecordMethods(options: RenderTableOptions): string;
28
-
29
- export { renderArguments, renderCommonData, renderDecodeValueType, renderEncodeField, renderFieldMethods, renderList, renderRecordMethods };
@@ -1,24 +0,0 @@
1
- import {
2
- renderArguments,
3
- renderCommonData,
4
- renderDecodeValueType,
5
- renderEncodeField,
6
- renderFieldMethods,
7
- renderList,
8
- renderRecordMethods,
9
- renderTable,
10
- renderTablesFromConfig
11
- } from "../chunk-JNGSW4AP.js";
12
- import "../chunk-6AQ6LFVZ.js";
13
- import "../chunk-O6HOO6WA.js";
14
- export {
15
- renderArguments,
16
- renderCommonData,
17
- renderDecodeValueType,
18
- renderEncodeField,
19
- renderFieldMethods,
20
- renderList,
21
- renderRecordMethods,
22
- renderTable,
23
- renderTablesFromConfig
24
- };
@@ -1,72 +0,0 @@
1
- import { SchemaType } from '@latticexyz/schema-type';
2
- import { a as StoreConfig } from './loadStoreConfig-37f99136.js';
3
-
4
- declare function renderTablesFromConfig(config: StoreConfig): {
5
- tableName: string;
6
- tableData: Omit<{
7
- dataStruct?: boolean | undefined;
8
- route: string;
9
- tableIdArgument: boolean;
10
- storeArgument: boolean;
11
- primaryKeys: Record<string, SchemaType>;
12
- schema: Record<string, SchemaType>;
13
- }, "dataStruct"> & Required<Pick<{
14
- dataStruct?: boolean | undefined;
15
- route: string;
16
- tableIdArgument: boolean;
17
- storeArgument: boolean;
18
- primaryKeys: Record<string, SchemaType>;
19
- schema: Record<string, SchemaType>;
20
- }, "dataStruct">>;
21
- output: string;
22
- }[];
23
-
24
- interface RenderTableOptions {
25
- /** Name of the library to render. */
26
- libraryName: string;
27
- /** Name of the struct to render. If undefined, struct and its methods aren't rendered. */
28
- structName?: string;
29
- /** Data used to statically registed the table. If undefined, all methods receive `_tableId` as an argument. */
30
- staticRouteData?: StaticRouteData;
31
- storeImportPath: string;
32
- primaryKeys: RenderTablePrimaryKey[];
33
- fields: RenderTableField[];
34
- staticFields: RenderTableStaticField[];
35
- dynamicFields: RenderTableDynamicField[];
36
- /** Whether to render get/set methods for the whole record */
37
- withRecordMethods: boolean;
38
- /** Whether to render additional methods that accept a manual `IStore` argument */
39
- storeArgument: boolean;
40
- }
41
- interface StaticRouteData {
42
- /** Name of the table id constant to render. */
43
- tableIdName: string;
44
- baseRoute: string;
45
- subRoute: string;
46
- }
47
- interface RenderTableType {
48
- typeId: string;
49
- typeWithLocation: string;
50
- enumName: string;
51
- staticByteLength: number;
52
- isDynamic: boolean;
53
- }
54
- interface RenderTablePrimaryKey extends RenderTableType {
55
- name: string;
56
- isDynamic: false;
57
- }
58
- interface RenderTableStaticField extends RenderTableField {
59
- isDynamic: false;
60
- }
61
- interface RenderTableDynamicField extends RenderTableField {
62
- isDynamic: true;
63
- }
64
- interface RenderTableField extends RenderTableType {
65
- arrayElement: RenderTableType | undefined;
66
- name: string;
67
- methodNameSuffix: string;
68
- }
69
-
70
- declare function renderTable(options: RenderTableOptions): string;
71
-
72
- export { RenderTableOptions as R, StaticRouteData as S, renderTable as a, RenderTableField as b, RenderTableType as c, RenderTablePrimaryKey as d, RenderTableStaticField as e, RenderTableDynamicField as f, renderTablesFromConfig as r };
@@ -1,11 +0,0 @@
1
- import { describe, expectTypeOf } from "vitest";
2
- import { z } from "zod";
3
- import { StoreConfig, StoreUserConfig } from "./loadStoreConfig.js";
4
-
5
- describe("loadStoreConfig", () => {
6
- // Typecheck manual interfaces against zod
7
- expectTypeOf<StoreUserConfig>().toEqualTypeOf<z.input<typeof StoreConfig>>();
8
- // type equality isn't deep for optionals
9
- expectTypeOf<StoreUserConfig["tables"][string]>().toEqualTypeOf<z.input<typeof StoreConfig>["tables"][string]>();
10
- // TODO If more nested schemas are added, provide separate tests for them
11
- });
@@ -1,67 +0,0 @@
1
- import { RenderTableOptions } from "./types.js";
2
-
3
- /**
4
- * Renders a list of lines
5
- */
6
- export function renderList<T>(list: T[], renderItem: (item: T, index: number) => string) {
7
- return internalRenderList("", list, renderItem);
8
- }
9
-
10
- /**
11
- * Renders a comma-separated list of arguments for solidity functions, ignoring empty and undefined ones
12
- */
13
- export function renderArguments(args: (string | undefined)[]) {
14
- const filteredArgs = args.filter((arg) => arg !== undefined && arg !== "") as string[];
15
- return internalRenderList(",", filteredArgs, (arg) => arg);
16
- }
17
-
18
- export function renderCommonData({ staticRouteData, primaryKeys }: RenderTableOptions) {
19
- // static route means static tableId as well, and no tableId arguments
20
- const _tableId = staticRouteData ? "" : "_tableId";
21
- const _typedTableId = staticRouteData ? "" : "uint256 _tableId";
22
-
23
- const _keyArgs = renderArguments(primaryKeys.map(({ name }) => name));
24
- const _typedKeyArgs = renderArguments(primaryKeys.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
25
-
26
- const _primaryKeysDefinition = `
27
- bytes32[] memory _primaryKeys = new bytes32[](${primaryKeys.length});
28
- ${renderList(
29
- primaryKeys,
30
- ({ name, typeId, staticByteLength }, index) => `
31
- _primaryKeys[${index}] = ${renderValueTypeToBytes32(name, typeId, staticByteLength)};
32
- `
33
- )}
34
- `;
35
-
36
- return {
37
- _tableId,
38
- _typedTableId,
39
- _keyArgs,
40
- _typedKeyArgs,
41
- _primaryKeysDefinition,
42
- };
43
- }
44
-
45
- function renderValueTypeToBytes32(innerText: string, typeId: string, staticByteLength: number) {
46
- const bits = staticByteLength * 8;
47
-
48
- if (typeId.match(/^uint\d{1,3}$/)) {
49
- return `bytes32(uint256(${innerText}))`;
50
- } else if (typeId.match(/^int\d{1,3}$/)) {
51
- return `bytes32(uint256(uint${bits}(${innerText})))`;
52
- } else if (typeId.match(/^bytes\d{1,2}$/)) {
53
- return `bytes32(${innerText})`;
54
- } else if (typeId === "address") {
55
- return `bytes32(bytes20(${innerText}))`;
56
- } else if (typeId === "bool") {
57
- return `_boolToBytes32(${innerText})`;
58
- } else {
59
- throw new Error(`Unknown value type id ${typeId}`);
60
- }
61
- }
62
-
63
- function internalRenderList<T>(lineTerminator: string, list: T[], renderItem: (item: T, index: number) => string) {
64
- return list
65
- .map((item, index) => renderItem(item, index) + (index === list.length - 1 ? "" : lineTerminator))
66
- .join("\n");
67
- }
@@ -1,132 +0,0 @@
1
- import { renderArguments, renderCommonData } from "./common.js";
2
- import { RenderTableField, RenderTableOptions } from "./types.js";
3
-
4
- export function renderFieldMethods(options: RenderTableOptions) {
5
- const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
6
-
7
- let result = "";
8
- for (const [index, field] of options.fields.entries()) {
9
- const _typedFieldName = `${field.typeWithLocation} ${field.name}`;
10
-
11
- result += `
12
- /** Get ${field.name} */
13
- function get${field.methodNameSuffix}(${renderArguments([
14
- _typedTableId,
15
- _typedKeyArgs,
16
- ])}) internal view returns (${_typedFieldName}) {
17
- ${_primaryKeysDefinition}
18
- bytes memory _blob = StoreSwitch.getField(_tableId, _primaryKeys, ${index});
19
- return ${renderDecodeFieldSingle(field)};
20
- }
21
- `;
22
-
23
- if (options.storeArgument) {
24
- result += `
25
- /** Get ${field.name} from the specified store */
26
- function get${field.methodNameSuffix}(${renderArguments([
27
- _typedTableId,
28
- `IStore _store`,
29
- _typedKeyArgs,
30
- ])}) internal view returns (${_typedFieldName}) {
31
- ${_primaryKeysDefinition}
32
- bytes memory _blob = _store.getField(_tableId, _primaryKeys, ${index});
33
- return ${renderDecodeFieldSingle(field)};
34
- }
35
- `;
36
- }
37
-
38
- result += `
39
- /** Set ${field.name} */
40
- function set${field.methodNameSuffix}(${renderArguments([
41
- _typedTableId,
42
- _typedKeyArgs,
43
- _typedFieldName,
44
- ])}) internal {
45
- ${_primaryKeysDefinition}
46
- StoreSwitch.setField(_tableId, _primaryKeys, ${index}, ${renderEncodeField(field)});
47
- }
48
- `;
49
-
50
- // TODO: this is super inefficient right now, need to add support for pushing to arrays to the store core library to avoid reading/writing the entire array
51
- // (see https://github.com/latticexyz/mud/issues/438)
52
- if (field.isDynamic) {
53
- const portionData = fieldPortionData(field);
54
-
55
- result += `
56
- /** Push ${portionData.title} to ${field.name} */
57
- function push${field.methodNameSuffix}(${renderArguments([
58
- _typedTableId,
59
- _typedKeyArgs,
60
- `${portionData.typeWithLocation} ${portionData.name}`,
61
- ])}) internal {
62
- ${_primaryKeysDefinition}
63
- bytes memory _blob = StoreSwitch.getField(_tableId, _primaryKeys, ${index});
64
- bytes memory _newBlob = abi.encodePacked(_blob, ${portionData.encodeFunc}(${portionData.name}));
65
- StoreSwitch.setField(_tableId, _primaryKeys, ${index}, _newBlob);
66
- }
67
- `;
68
- }
69
- }
70
- return result;
71
- }
72
-
73
- export function renderEncodeField(field: RenderTableField) {
74
- let func;
75
- if (field.arrayElement) {
76
- func = "EncodeArray.encode";
77
- } else if (field.isDynamic) {
78
- func = "bytes";
79
- } else {
80
- func = "abi.encodePacked";
81
- }
82
- return `${func}(${field.name})`;
83
- }
84
-
85
- export function renderDecodeValueType(typeId: string, staticByteLength: number, offset: number) {
86
- const innerSlice = `Bytes.slice${staticByteLength}(_blob, ${offset})`;
87
- const bits = staticByteLength * 8;
88
-
89
- if (typeId.match(/^uint\d{1,3}$/) || typeId === "address") {
90
- return `${typeId}(${innerSlice})`;
91
- } else if (typeId.match(/^int\d{1,3}$/)) {
92
- return `${typeId}(uint${bits}(${innerSlice}))`;
93
- } else if (typeId.match(/^bytes\d{1,2}$/)) {
94
- return innerSlice;
95
- } else if (typeId === "bool") {
96
- return `_toBool(uint8(${innerSlice}))`;
97
- } else {
98
- throw new Error(`Unknown value type id ${typeId}`);
99
- }
100
- }
101
-
102
- /** bytes/string are dynamic, but aren't really arrays */
103
- function fieldPortionData(field: RenderTableField) {
104
- if (field.arrayElement) {
105
- return {
106
- typeWithLocation: field.arrayElement.typeWithLocation,
107
- name: "_element",
108
- encodeFunc: "abi.encodePacked",
109
- title: "an element",
110
- };
111
- } else {
112
- return {
113
- typeWithLocation: `${field.typeId} memory`,
114
- name: "_slice",
115
- encodeFunc: "bytes",
116
- title: "a slice",
117
- };
118
- }
119
- }
120
-
121
- function renderDecodeFieldSingle(field: RenderTableField) {
122
- const { typeId, isDynamic, arrayElement } = field;
123
- if (arrayElement) {
124
- // arrays
125
- return `SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_${arrayElement.typeId}()`;
126
- } else if (isDynamic) {
127
- // bytes/string
128
- return `${typeId}(_blob)`;
129
- } else {
130
- return renderDecodeValueType(typeId, field.staticByteLength, 0);
131
- }
132
- }
@@ -1,6 +0,0 @@
1
- export * from "./common.js";
2
- export * from "./field.js";
3
- export * from "./record.js";
4
- export * from "./renderTable.js";
5
- export * from "./renderTablesFromConfig.js";
6
- export * from "./types.js";
@@ -1,176 +0,0 @@
1
- import { renderList, renderArguments, renderCommonData } from "./common.js";
2
- import { renderDecodeValueType, renderEncodeField } from "./field.js";
3
- import { RenderTableDynamicField, RenderTableOptions, RenderTableStaticField } from "./types.js";
4
-
5
- export function renderRecordMethods(options: RenderTableOptions) {
6
- const { staticFields, dynamicFields, structName, storeArgument } = options;
7
- const { _tableId, _typedTableId, _keyArgs, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
8
-
9
- let result = `
10
- /** Get the full data */
11
- function get(${renderArguments([_typedTableId, _typedKeyArgs])}) internal view returns (${renderDecodedRecord(
12
- options
13
- )}) {
14
- ${_primaryKeysDefinition}
15
- bytes memory _blob = StoreSwitch.getRecord(_tableId, _primaryKeys, getSchema());
16
- return decode(_blob);
17
- }
18
- `;
19
-
20
- if (storeArgument) {
21
- result += `
22
- /** Get the full data from the specified store */
23
- function get(${renderArguments([
24
- _typedTableId,
25
- `IStore _store`,
26
- _typedKeyArgs,
27
- ])}) internal view returns (${renderDecodedRecord(options)}) {
28
- ${_primaryKeysDefinition}
29
- bytes memory _blob = _store.getRecord(_tableId, _primaryKeys);
30
- return decode(_blob);
31
- }
32
- `;
33
- }
34
-
35
- result += `
36
- /** Set the full data using individual values */
37
- function set(${renderArguments([
38
- _typedTableId,
39
- _typedKeyArgs,
40
- renderArguments(options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`)),
41
- ])}) internal {
42
- ${renderEncodedLengths(dynamicFields)}
43
- bytes memory _data = abi.encodePacked(${renderArguments([
44
- renderArguments(staticFields.map(({ name }) => name)),
45
- // TODO try gas optimization (preallocate for all, encodePacked statics, and direct encode dynamics)
46
- // (see https://github.com/latticexyz/mud/issues/444)
47
- ...(dynamicFields.length === 0
48
- ? []
49
- : ["_encodedLengths.unwrap()", renderArguments(dynamicFields.map((field) => renderEncodeField(field)))]),
50
- ])});
51
-
52
- ${_primaryKeysDefinition}
53
-
54
- StoreSwitch.setRecord(_tableId, _primaryKeys, _data);
55
- }
56
- `;
57
-
58
- if (structName !== undefined) {
59
- result += `
60
- /** Set the full data using the data struct */
61
- function set(${renderArguments([_typedTableId, _typedKeyArgs, `${structName} memory _table`])}) internal {
62
- set(${renderArguments([
63
- _tableId,
64
- _keyArgs,
65
- renderArguments(options.fields.map(({ name }) => `_table.${name}`)),
66
- ])});
67
- }
68
- `;
69
- }
70
-
71
- result += renderDecodeFunction(options);
72
-
73
- return result;
74
- }
75
-
76
- // Renders the `decode` function that parses a bytes blob into the table data
77
- function renderDecodeFunction({ structName, fields, staticFields, dynamicFields }: RenderTableOptions) {
78
- // either set struct properties, or just variables
79
- const renderedDecodedRecord = structName
80
- ? `${structName} memory _table`
81
- : renderArguments(fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
82
- const fieldNamePrefix = structName ? "_table." : "";
83
-
84
- // Static field offsets
85
- const staticOffsets = staticFields.map(() => 0);
86
- let _acc = 0;
87
- for (const [index, field] of staticFields.entries()) {
88
- staticOffsets[index] = _acc;
89
- _acc += field.staticByteLength;
90
- }
91
-
92
- if (dynamicFields.length > 0) {
93
- const totalStaticLength = staticFields.reduce((acc, { staticByteLength }) => acc + staticByteLength, 0);
94
- // decode static (optionally) and dynamic data
95
- return `
96
- /** Decode the tightly packed blob using this table's schema */
97
- function decode(bytes memory _blob) internal view returns (${renderedDecodedRecord}) {
98
- // ${totalStaticLength} is the total byte length of static data
99
- PackedCounter _encodedLengths = PackedCounter.wrap(Bytes.slice32(_blob, ${totalStaticLength}));
100
-
101
- ${renderList(
102
- staticFields,
103
- (field, index) => `
104
- ${fieldNamePrefix}${field.name} = ${renderDecodeStaticFieldPartial(field, staticOffsets[index])};
105
- `
106
- )}
107
- uint256 _start;
108
- uint256 _end = ${totalStaticLength + 32};
109
- ${renderList(
110
- dynamicFields,
111
- (field, index) => `
112
- _start = _end;
113
- _end += _encodedLengths.atIndex(${index});
114
- ${fieldNamePrefix}${field.name} = ${renderDecodeDynamicFieldPartial(field)};
115
- `
116
- )}
117
- }
118
- `;
119
- } else {
120
- // decode only static data
121
- return `
122
- /** Decode the tightly packed blob using this table's schema */
123
- function decode(bytes memory _blob) internal pure returns (${renderedDecodedRecord}) {
124
- ${renderList(
125
- staticFields,
126
- (field, index) => `
127
- ${fieldNamePrefix}${field.name} = ${renderDecodeStaticFieldPartial(field, staticOffsets[index])};
128
- `
129
- )}
130
- }
131
- `;
132
- }
133
- }
134
-
135
- // contents of `returns (...)` for record getter/decoder
136
- function renderDecodedRecord({ structName, fields }: RenderTableOptions) {
137
- if (structName) {
138
- return `${structName} memory _table`;
139
- } else {
140
- return renderArguments(fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
141
- }
142
- }
143
-
144
- function renderDecodeDynamicFieldPartial(field: RenderTableDynamicField) {
145
- const { typeId, arrayElement } = field;
146
- if (arrayElement) {
147
- // arrays
148
- return `SliceLib.getSubslice(_blob, _start, _end).decodeArray_${arrayElement.typeId}()`;
149
- } else {
150
- // bytes/string
151
- return `${typeId}(SliceLib.getSubslice(_blob, _start, _end).toBytes())`;
152
- }
153
- }
154
-
155
- function renderDecodeStaticFieldPartial(field: RenderTableStaticField, start: number) {
156
- const { typeId, staticByteLength } = field;
157
- return renderDecodeValueType(typeId, staticByteLength, start);
158
- }
159
-
160
- function renderEncodedLengths(dynamicFields: RenderTableDynamicField[]) {
161
- if (dynamicFields.length > 0) {
162
- return `
163
- uint16[] memory _counters = new uint16[](${dynamicFields.length});
164
- ${renderList(dynamicFields, ({ name, arrayElement }, index) => {
165
- if (arrayElement) {
166
- return `_counters[${index}] = uint16(${name}.length * ${arrayElement.staticByteLength});`;
167
- } else {
168
- return `_counters[${index}] = uint16(bytes(${name}).length);`;
169
- }
170
- })}
171
- PackedCounter _encodedLengths = PackedCounterLib.pack(_counters);
172
- `;
173
- } else {
174
- return "";
175
- }
176
- }