@latticexyz/cli 2.0.0-alpha.0 → 2.0.0-alpha.1

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 (82) hide show
  1. package/dist/chunk-6V563IAZ.js +283 -0
  2. package/dist/{chunk-ATAWDHWC.js → chunk-FPG73MVN.js} +5 -1
  3. package/dist/{chunk-O6HOO6WA.js → chunk-L4YLJHLJ.js} +1 -9
  4. package/dist/{chunk-J4DJQNIC.js → chunk-SKNB74MT.js} +129 -568
  5. package/dist/chunk-VQTZJIFF.js +353 -0
  6. package/dist/chunk-WZFXLDPK.js +761 -0
  7. package/dist/chunk-YL4GJLLL.js +26139 -0
  8. package/dist/chunk-ZSZDPSLH.js +3841 -0
  9. package/dist/index.d.ts +2 -3
  10. package/dist/index.js +0 -21
  11. package/dist/mud.d.ts +1 -1
  12. package/dist/mud.js +326 -4452
  13. package/dist/mud2.d.ts +1 -0
  14. package/dist/mud2.js +25 -0
  15. package/dist/render-solidity/index.d.ts +171 -0
  16. package/dist/render-solidity/index.js +49 -0
  17. package/dist/render-ts/index.d.ts +26 -0
  18. package/dist/render-ts/index.js +14 -0
  19. package/dist/utils/deprecated/index.js +3 -3
  20. package/dist/utils/index.d.ts +13 -18
  21. package/dist/utils/index.js +14 -16
  22. package/package.json +20 -21
  23. package/src/commands/deploy-v2.ts +80 -64
  24. package/src/commands/deprecated/index.ts +22 -0
  25. package/src/commands/deprecated/test.ts +1 -1
  26. package/src/commands/gas-report.ts +54 -55
  27. package/src/commands/index.ts +6 -17
  28. package/src/commands/set-version.ts +172 -0
  29. package/src/commands/tablegen.ts +5 -5
  30. package/src/commands/test-v2.ts +71 -0
  31. package/src/commands/tsgen.ts +33 -0
  32. package/src/commands/worldgen.ts +5 -4
  33. package/src/contracts/BulkUpload.sol +13 -20
  34. package/src/contracts/Deploy.sol +3 -3
  35. package/src/contracts/LibDeploy.sol +1 -1
  36. package/src/contracts/LibDeployStub.sol +1 -1
  37. package/src/index.ts +1 -15
  38. package/src/mud.ts +4 -3
  39. package/src/mud2.ts +29 -0
  40. package/src/render-solidity/common.ts +4 -4
  41. package/src/render-solidity/field.ts +25 -2
  42. package/src/render-solidity/record.ts +14 -10
  43. package/src/render-solidity/renderSystemInterface.ts +4 -4
  44. package/src/render-solidity/renderTableIndex.ts +15 -0
  45. package/src/render-solidity/renderTypesFromConfig.ts +1 -1
  46. package/src/render-solidity/tableOptions.ts +2 -2
  47. package/src/render-solidity/tablegen.ts +15 -13
  48. package/src/render-solidity/types.ts +2 -1
  49. package/src/render-solidity/userType.ts +1 -2
  50. package/src/render-solidity/worldgen.ts +8 -9
  51. package/src/render-ts/index.ts +5 -0
  52. package/src/render-ts/recsV1TableOptions.ts +39 -0
  53. package/src/render-ts/renderRecsV1Tables.ts +31 -0
  54. package/src/render-ts/schemaTypesToRecsTypeStrings.ts +202 -0
  55. package/src/render-ts/tsgen.ts +12 -0
  56. package/src/render-ts/types.ts +13 -0
  57. package/src/utils/contractToInterface.ts +5 -3
  58. package/src/utils/deploy-v2.ts +90 -84
  59. package/src/utils/errors.ts +3 -34
  60. package/src/utils/format.ts +6 -0
  61. package/src/utils/formatAndWrite.ts +11 -2
  62. package/src/utils/foundry.ts +9 -0
  63. package/src/utils/index.ts +1 -0
  64. package/dist/chunk-O57QENJ6.js +0 -23039
  65. package/dist/chunk-SLIMIO4Z.js +0 -14358
  66. package/dist/config/index.d.ts +0 -763
  67. package/dist/config/index.js +0 -83
  68. package/src/config/commonSchemas.ts +0 -34
  69. package/src/config/dynamicResolution.ts +0 -49
  70. package/src/config/index.ts +0 -24
  71. package/src/config/loadConfig.ts +0 -39
  72. package/src/config/loadStoreConfig.ts +0 -18
  73. package/src/config/parseStoreConfig.test-d.ts +0 -40
  74. package/src/config/parseStoreConfig.ts +0 -314
  75. package/src/config/validation.ts +0 -163
  76. package/src/config/world/index.ts +0 -4
  77. package/src/config/world/loadWorldConfig.test-d.ts +0 -11
  78. package/src/config/world/loadWorldConfig.ts +0 -26
  79. package/src/config/world/parseWorldConfig.ts +0 -55
  80. package/src/config/world/resolveWorldConfig.ts +0 -80
  81. package/src/config/world/userTypes.ts +0 -72
  82. package/src/utils/typeUtils.ts +0 -17
@@ -0,0 +1,761 @@
1
+ import {
2
+ SchemaTypeArrayToElement,
3
+ formatAndWriteSolidity,
4
+ getSchemaTypeInfo,
5
+ importForAbiOrUserType,
6
+ resolveAbiOrUserType
7
+ } from "./chunk-SKNB74MT.js";
8
+
9
+ // src/render-solidity/tableOptions.ts
10
+ import path from "path";
11
+ function getTableOptions(config) {
12
+ const storeImportPath = config.storeImportPath;
13
+ const options = [];
14
+ for (const tableName of Object.keys(config.tables)) {
15
+ const tableData = config.tables[tableName];
16
+ const withStruct = tableData.dataStruct;
17
+ const withRecordMethods = withStruct || Object.keys(tableData.schema).length > 1;
18
+ const noFieldMethodSuffix = !withRecordMethods && Object.keys(tableData.schema).length === 1;
19
+ const imports = [];
20
+ const primaryKeys = Object.keys(tableData.primaryKeys).map((name) => {
21
+ const abiOrUserType = tableData.primaryKeys[name];
22
+ const { renderTableType } = resolveAbiOrUserType(abiOrUserType, config);
23
+ const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config);
24
+ if (importDatum)
25
+ imports.push(importDatum);
26
+ if (renderTableType.isDynamic)
27
+ throw new Error(`Parsing error: found dynamic primary key ${name} in table ${tableName}`);
28
+ const primaryKey = {
29
+ ...renderTableType,
30
+ name,
31
+ isDynamic: false
32
+ };
33
+ return primaryKey;
34
+ });
35
+ const fields = Object.keys(tableData.schema).map((name) => {
36
+ const abiOrUserType = tableData.schema[name];
37
+ const { renderTableType, schemaType } = resolveAbiOrUserType(abiOrUserType, config);
38
+ const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config);
39
+ if (importDatum)
40
+ imports.push(importDatum);
41
+ const elementType = SchemaTypeArrayToElement[schemaType];
42
+ const field = {
43
+ ...renderTableType,
44
+ arrayElement: elementType !== void 0 ? getSchemaTypeInfo(elementType) : void 0,
45
+ name,
46
+ methodNameSuffix: noFieldMethodSuffix ? "" : `${name[0].toUpperCase()}${name.slice(1)}`
47
+ };
48
+ return field;
49
+ });
50
+ const staticFields = fields.filter(({ isDynamic }) => !isDynamic);
51
+ const dynamicFields = fields.filter(({ isDynamic }) => isDynamic);
52
+ const staticResourceData = (() => {
53
+ if (tableData.tableIdArgument) {
54
+ return;
55
+ } else {
56
+ return {
57
+ tableIdName: tableName + "TableId",
58
+ namespace: config.namespace,
59
+ name: tableData.name
60
+ };
61
+ }
62
+ })();
63
+ options.push({
64
+ outputPath: path.join(tableData.directory, `${tableName}.sol`),
65
+ tableName,
66
+ renderOptions: {
67
+ imports,
68
+ libraryName: tableName,
69
+ structName: withStruct ? tableName + "Data" : void 0,
70
+ staticResourceData,
71
+ storeImportPath,
72
+ primaryKeys,
73
+ fields,
74
+ staticFields,
75
+ dynamicFields,
76
+ withRecordMethods,
77
+ storeArgument: tableData.storeArgument
78
+ }
79
+ });
80
+ }
81
+ return options;
82
+ }
83
+
84
+ // src/render-solidity/common.ts
85
+ import path2 from "path";
86
+ var renderedSolidityHeader = `// SPDX-License-Identifier: MIT
87
+ pragma solidity >=0.8.0;
88
+
89
+ /* Autogenerated file. Do not edit manually. */`;
90
+ function renderList(list, renderItem) {
91
+ return internalRenderList("", list, renderItem);
92
+ }
93
+ function renderArguments(args) {
94
+ const filteredArgs = args.filter((arg) => arg !== void 0 && arg !== "");
95
+ return internalRenderList(",", filteredArgs, (arg) => arg);
96
+ }
97
+ function renderCommonData({
98
+ staticResourceData,
99
+ primaryKeys
100
+ }) {
101
+ const _tableId = staticResourceData ? "" : "_tableId";
102
+ const _typedTableId = staticResourceData ? "" : "bytes32 _tableId";
103
+ const _keyArgs = renderArguments(primaryKeys.map(({ name }) => name));
104
+ const _typedKeyArgs = renderArguments(primaryKeys.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
105
+ const _primaryKeysDefinition = `
106
+ bytes32[] memory _primaryKeys = new bytes32[](${primaryKeys.length});
107
+ ${renderList(
108
+ primaryKeys,
109
+ (primaryKey, index) => `_primaryKeys[${index}] = ${renderValueTypeToBytes32(primaryKey.name, primaryKey)};`
110
+ )}
111
+ `;
112
+ return {
113
+ _tableId,
114
+ _typedTableId,
115
+ _keyArgs,
116
+ _typedKeyArgs,
117
+ _primaryKeysDefinition
118
+ };
119
+ }
120
+ function solidityRelativeImportPath(fromPath, usedInPath) {
121
+ return "./" + path2.relative("./" + usedInPath, "./" + fromPath);
122
+ }
123
+ function renderImports(imports) {
124
+ const aggregatedImports = /* @__PURE__ */ new Map();
125
+ for (const { symbol, fromPath, usedInPath } of imports) {
126
+ const path4 = solidityRelativeImportPath(fromPath, usedInPath);
127
+ if (!aggregatedImports.has(path4)) {
128
+ aggregatedImports.set(path4, /* @__PURE__ */ new Set());
129
+ }
130
+ aggregatedImports.get(path4)?.add(symbol);
131
+ }
132
+ const renderedImports = [];
133
+ for (const [path4, symbols] of aggregatedImports) {
134
+ const renderedSymbols = [...symbols].join(", ");
135
+ renderedImports.push(`import { ${renderedSymbols} } from "${path4}";`);
136
+ }
137
+ return renderedImports.join("\n");
138
+ }
139
+ function renderWithStore(storeArgument, callback) {
140
+ let result = "";
141
+ result += callback(void 0, "StoreSwitch", "", void 0);
142
+ if (storeArgument) {
143
+ result += "\n" + callback("IStore _store", "_store", " (using the specified store)", "_store");
144
+ }
145
+ return result;
146
+ }
147
+ function renderTableId(staticResourceData) {
148
+ const hardcodedTableId = `bytes32(abi.encodePacked(bytes16("${staticResourceData.namespace}"), bytes16("${staticResourceData.name}")))`;
149
+ const tableIdDefinition = `
150
+ bytes32 constant _tableId = ${hardcodedTableId};
151
+ bytes32 constant ${staticResourceData.tableIdName} = _tableId;
152
+ `;
153
+ return {
154
+ hardcodedTableId,
155
+ tableIdDefinition
156
+ };
157
+ }
158
+ function renderValueTypeToBytes32(name, { staticByteLength, typeUnwrap, internalTypeId }) {
159
+ const bits = staticByteLength * 8;
160
+ const innerText = `${typeUnwrap}(${name})`;
161
+ if (internalTypeId.match(/^uint\d{1,3}$/)) {
162
+ return `bytes32(uint256(${innerText}))`;
163
+ } else if (internalTypeId.match(/^int\d{1,3}$/)) {
164
+ return `bytes32(uint256(uint${bits}(${innerText})))`;
165
+ } else if (internalTypeId.match(/^bytes\d{1,2}$/)) {
166
+ return `bytes32(${innerText})`;
167
+ } else if (internalTypeId === "address") {
168
+ return `bytes32(bytes20(${innerText}))`;
169
+ } else if (internalTypeId === "bool") {
170
+ return `_boolToBytes32(${innerText})`;
171
+ } else {
172
+ throw new Error(`Unknown value type id ${internalTypeId}`);
173
+ }
174
+ }
175
+ function internalRenderList(lineTerminator, list, renderItem) {
176
+ return list.map((item, index) => renderItem(item, index) + (index === list.length - 1 ? "" : lineTerminator)).join("\n");
177
+ }
178
+
179
+ // src/render-solidity/field.ts
180
+ function renderFieldMethods(options) {
181
+ const storeArgument = options.storeArgument;
182
+ const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
183
+ let result = "";
184
+ for (const [index, field] of options.fields.entries()) {
185
+ const _typedFieldName = `${field.typeWithLocation} ${field.name}`;
186
+ result += renderWithStore(
187
+ storeArgument,
188
+ (_typedStore, _store, _commentSuffix) => `
189
+ /** Get ${field.name}${_commentSuffix} */
190
+ function get${field.methodNameSuffix}(${renderArguments([
191
+ _typedStore,
192
+ _typedTableId,
193
+ _typedKeyArgs
194
+ ])}) internal view returns (${_typedFieldName}) {
195
+ ${_primaryKeysDefinition}
196
+ bytes memory _blob = ${_store}.getField(_tableId, _primaryKeys, ${index});
197
+ return ${renderDecodeFieldSingle(field)};
198
+ }
199
+ `
200
+ );
201
+ result += renderWithStore(
202
+ storeArgument,
203
+ (_typedStore, _store, _commentSuffix) => `
204
+ /** Set ${field.name}${_commentSuffix} */
205
+ function set${field.methodNameSuffix}(${renderArguments([
206
+ _typedStore,
207
+ _typedTableId,
208
+ _typedKeyArgs,
209
+ _typedFieldName
210
+ ])}) internal {
211
+ ${_primaryKeysDefinition}
212
+ ${_store}.setField(_tableId, _primaryKeys, ${index}, ${renderEncodeField(field)});
213
+ }
214
+ `
215
+ );
216
+ if (field.isDynamic) {
217
+ const portionData = fieldPortionData(field);
218
+ result += renderWithStore(
219
+ storeArgument,
220
+ (_typedStore, _store, _commentSuffix) => `
221
+ /** Push ${portionData.title} to ${field.name}${_commentSuffix} */
222
+ function push${field.methodNameSuffix}(${renderArguments([
223
+ _typedStore,
224
+ _typedTableId,
225
+ _typedKeyArgs,
226
+ `${portionData.typeWithLocation} ${portionData.name}`
227
+ ])}) internal {
228
+ ${_primaryKeysDefinition}
229
+ ${_store}.pushToField(_tableId, _primaryKeys, ${index}, ${portionData.encoded});
230
+ }
231
+ `
232
+ );
233
+ result += renderWithStore(
234
+ storeArgument,
235
+ (_typedStore, _store, _commentSuffix) => `
236
+ /** Update ${portionData.title} of ${field.name}${_commentSuffix} at \`_index\` */
237
+ function update${field.methodNameSuffix}(${renderArguments([
238
+ _typedStore,
239
+ _typedTableId,
240
+ _typedKeyArgs,
241
+ "uint256 _index",
242
+ `${portionData.typeWithLocation} ${portionData.name}`
243
+ ])}) internal {
244
+ ${_primaryKeysDefinition}
245
+ ${_store}.updateInField(
246
+ _tableId,
247
+ _primaryKeys,
248
+ ${index},
249
+ _index * ${portionData.elementLength},
250
+ ${portionData.encoded}
251
+ );
252
+ }
253
+ `
254
+ );
255
+ }
256
+ }
257
+ return result;
258
+ }
259
+ function renderEncodeField(field) {
260
+ let func;
261
+ if (field.arrayElement) {
262
+ func = "EncodeArray.encode";
263
+ } else if (field.isDynamic) {
264
+ func = "bytes";
265
+ } else {
266
+ func = "abi.encodePacked";
267
+ }
268
+ return `${func}(${field.typeUnwrap}(${field.name}))`;
269
+ }
270
+ function renderDecodeValueType(field, offset) {
271
+ const { staticByteLength, internalTypeId } = field;
272
+ const innerSlice = `Bytes.slice${staticByteLength}(_blob, ${offset})`;
273
+ const bits = staticByteLength * 8;
274
+ let result;
275
+ if (internalTypeId.match(/^uint\d{1,3}$/) || internalTypeId === "address") {
276
+ result = `${internalTypeId}(${innerSlice})`;
277
+ } else if (internalTypeId.match(/^int\d{1,3}$/)) {
278
+ result = `${internalTypeId}(uint${bits}(${innerSlice}))`;
279
+ } else if (internalTypeId.match(/^bytes\d{1,2}$/)) {
280
+ result = innerSlice;
281
+ } else if (internalTypeId === "bool") {
282
+ result = `_toBool(uint8(${innerSlice}))`;
283
+ } else {
284
+ throw new Error(`Unknown value type id ${internalTypeId}`);
285
+ }
286
+ return `${field.typeWrap}(${result})`;
287
+ }
288
+ function fieldPortionData(field) {
289
+ const methodNameSuffix = "";
290
+ if (field.arrayElement) {
291
+ const name = "_element";
292
+ return {
293
+ typeWithLocation: field.arrayElement.typeWithLocation,
294
+ name: "_element",
295
+ encoded: renderEncodeField({ ...field.arrayElement, arrayElement: void 0, name, methodNameSuffix }),
296
+ title: "an element",
297
+ elementLength: field.arrayElement.staticByteLength
298
+ };
299
+ } else {
300
+ const name = "_slice";
301
+ return {
302
+ typeWithLocation: `${field.typeId} memory`,
303
+ name,
304
+ encoded: renderEncodeField({ ...field, name, methodNameSuffix }),
305
+ title: "a slice",
306
+ elementLength: 1
307
+ };
308
+ }
309
+ }
310
+ function renderDecodeFieldSingle(field) {
311
+ const { isDynamic, arrayElement } = field;
312
+ if (arrayElement) {
313
+ return `${field.typeWrap}(
314
+ SliceLib.getSubslice(_blob, 0, _blob.length).decodeArray_${arrayElement.internalTypeId}()
315
+ )`;
316
+ } else if (isDynamic) {
317
+ return `${field.typeWrap}(${field.internalTypeId}(_blob))`;
318
+ } else {
319
+ return renderDecodeValueType(field, 0);
320
+ }
321
+ }
322
+
323
+ // src/render-solidity/record.ts
324
+ function renderRecordMethods(options) {
325
+ const { structName, storeArgument } = options;
326
+ const { _tableId, _typedTableId, _keyArgs, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
327
+ let result = renderWithStore(
328
+ storeArgument,
329
+ (_typedStore, _store, _commentSuffix) => `
330
+ /** Get the full data${_commentSuffix} */
331
+ function get(${renderArguments([
332
+ _typedStore,
333
+ _typedTableId,
334
+ _typedKeyArgs
335
+ ])}) internal view returns (${renderDecodedRecord(options)}) {
336
+ ${_primaryKeysDefinition}
337
+ bytes memory _blob = ${_store}.getRecord(_tableId, _primaryKeys, getSchema());
338
+ return decode(_blob);
339
+ }
340
+ `
341
+ );
342
+ result += renderWithStore(
343
+ storeArgument,
344
+ (_typedStore, _store, _commentSuffix) => `
345
+ /** Set the full data using individual values${_commentSuffix} */
346
+ function set(${renderArguments([
347
+ _typedStore,
348
+ _typedTableId,
349
+ _typedKeyArgs,
350
+ renderArguments(options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`))
351
+ ])}) internal {
352
+ bytes memory _data = encode(${renderArguments(options.fields.map(({ name }) => name))});
353
+
354
+ ${_primaryKeysDefinition}
355
+
356
+ ${_store}.setRecord(_tableId, _primaryKeys, _data);
357
+ }
358
+ `
359
+ );
360
+ if (structName !== void 0) {
361
+ result += renderWithStore(
362
+ storeArgument,
363
+ (_typedStore, _store, _commentSuffix, _untypedStore) => `
364
+ /** Set the full data using the data struct${_commentSuffix} */
365
+ function set(${renderArguments([
366
+ _typedStore,
367
+ _typedTableId,
368
+ _typedKeyArgs,
369
+ `${structName} memory _table`
370
+ ])}) internal {
371
+ set(${renderArguments([
372
+ _untypedStore,
373
+ _tableId,
374
+ _keyArgs,
375
+ renderArguments(options.fields.map(({ name }) => `_table.${name}`))
376
+ ])});
377
+ }
378
+ `
379
+ );
380
+ }
381
+ result += renderDecodeFunction(options);
382
+ return result;
383
+ }
384
+ function renderDecodeFunction({ structName, fields, staticFields, dynamicFields }) {
385
+ const renderedDecodedRecord = structName ? `${structName} memory _table` : renderArguments(fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
386
+ const fieldNamePrefix = structName ? "_table." : "";
387
+ const staticOffsets = staticFields.map(() => 0);
388
+ let _acc = 0;
389
+ for (const [index, field] of staticFields.entries()) {
390
+ staticOffsets[index] = _acc;
391
+ _acc += field.staticByteLength;
392
+ }
393
+ if (dynamicFields.length > 0) {
394
+ const totalStaticLength = staticFields.reduce((acc, { staticByteLength }) => acc + staticByteLength, 0);
395
+ return `
396
+ /** Decode the tightly packed blob using this table's schema */
397
+ function decode(bytes memory _blob) internal view returns (${renderedDecodedRecord}) {
398
+ // ${totalStaticLength} is the total byte length of static data
399
+ PackedCounter _encodedLengths = PackedCounter.wrap(Bytes.slice32(_blob, ${totalStaticLength}));
400
+
401
+ ${renderList(
402
+ staticFields,
403
+ (field, index) => `
404
+ ${fieldNamePrefix}${field.name} = ${renderDecodeValueType(field, staticOffsets[index])};
405
+ `
406
+ )}
407
+ // Store trims the blob if dynamic fields are all empty
408
+ if (_blob.length > ${totalStaticLength}) {
409
+ uint256 _start;
410
+ // skip static data length + dynamic lengths word
411
+ uint256 _end = ${totalStaticLength + 32};
412
+ ${renderList(
413
+ dynamicFields,
414
+ (field, index) => `
415
+ _start = _end;
416
+ _end += _encodedLengths.atIndex(${index});
417
+ ${fieldNamePrefix}${field.name} = ${renderDecodeDynamicFieldPartial(field)};
418
+ `
419
+ )}
420
+ }
421
+ }
422
+ `;
423
+ } else {
424
+ return `
425
+ /** Decode the tightly packed blob using this table's schema */
426
+ function decode(bytes memory _blob) internal pure returns (${renderedDecodedRecord}) {
427
+ ${renderList(
428
+ staticFields,
429
+ (field, index) => `
430
+ ${fieldNamePrefix}${field.name} = ${renderDecodeValueType(field, staticOffsets[index])};
431
+ `
432
+ )}
433
+ }
434
+ `;
435
+ }
436
+ }
437
+ function renderDecodedRecord({ structName, fields }) {
438
+ if (structName) {
439
+ return `${structName} memory _table`;
440
+ } else {
441
+ return renderArguments(fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`));
442
+ }
443
+ }
444
+ function renderDecodeDynamicFieldPartial(field) {
445
+ const { typeId, arrayElement, typeWrap } = field;
446
+ if (arrayElement) {
447
+ return `${typeWrap}(
448
+ SliceLib.getSubslice(_blob, _start, _end).decodeArray_${arrayElement.typeId}()
449
+ )`;
450
+ } else {
451
+ return `${typeWrap}(
452
+ ${typeId}(
453
+ SliceLib.getSubslice(_blob, _start, _end).toBytes()
454
+ )
455
+ )`;
456
+ }
457
+ }
458
+
459
+ // src/render-solidity/renderTypeHelpers.ts
460
+ function renderTypeHelpers(options) {
461
+ const { fields, primaryKeys } = options;
462
+ let result = "";
463
+ for (const wrappingHelper of getWrappingHelpers([...fields, ...primaryKeys])) {
464
+ result += wrappingHelper;
465
+ }
466
+ if (fields.some(({ typeId }) => typeId === "bool")) {
467
+ result += `
468
+ function _toBool(uint8 value) pure returns (bool result) {
469
+ assembly {
470
+ result := value
471
+ }
472
+ }
473
+ `;
474
+ }
475
+ if (primaryKeys.some(({ typeId }) => typeId === "bool")) {
476
+ result += `
477
+ function _boolToBytes32(bool value) pure returns (bytes32 result) {
478
+ assembly {
479
+ result := value
480
+ }
481
+ }
482
+ `;
483
+ }
484
+ return result;
485
+ }
486
+ function getWrappingHelpers(array) {
487
+ const wrappers = /* @__PURE__ */ new Map();
488
+ const unwrappers = /* @__PURE__ */ new Map();
489
+ for (const { typeWrappingData, typeWrap, typeUnwrap, internalTypeId } of array) {
490
+ if (!typeWrappingData)
491
+ continue;
492
+ const { kind } = typeWrappingData;
493
+ if (kind === "staticArray") {
494
+ const { elementType, staticLength } = typeWrappingData;
495
+ wrappers.set(typeWrap, renderWrapperStaticArray(typeWrap, elementType, staticLength, internalTypeId));
496
+ unwrappers.set(typeUnwrap, renderUnwrapperStaticArray(typeUnwrap, elementType, staticLength, internalTypeId));
497
+ }
498
+ }
499
+ return [...wrappers.values(), ...unwrappers.values()];
500
+ }
501
+ function renderWrapperStaticArray(functionName, elementType, staticLength, internalTypeId) {
502
+ return `
503
+ function ${functionName}(
504
+ ${internalTypeId} memory _value
505
+ ) pure returns (
506
+ ${elementType}[${staticLength}] memory _result
507
+ ) {
508
+ // in memory static arrays are just dynamic arrays without the length byte
509
+ assembly {
510
+ _result := add(_value, 0x20)
511
+ }
512
+ }
513
+ `;
514
+ }
515
+ function renderUnwrapperStaticArray(functionName, elementType, staticLength, internalTypeId) {
516
+ const byteLength = staticLength * 32;
517
+ return `
518
+ function ${functionName}(
519
+ ${elementType}[${staticLength}] memory _value
520
+ ) view returns (
521
+ ${internalTypeId} memory _result
522
+ ) {
523
+ _result = new ${internalTypeId}(${staticLength});
524
+ uint256 fromPointer;
525
+ uint256 toPointer;
526
+ assembly {
527
+ fromPointer := _value
528
+ toPointer := add(_result, 0x20)
529
+ }
530
+ Memory.copy(fromPointer, toPointer, ${byteLength});
531
+ }
532
+ `;
533
+ }
534
+
535
+ // src/render-solidity/renderTable.ts
536
+ function renderTable(options) {
537
+ const {
538
+ imports,
539
+ libraryName,
540
+ structName,
541
+ staticResourceData,
542
+ storeImportPath,
543
+ fields,
544
+ staticFields,
545
+ dynamicFields,
546
+ withRecordMethods,
547
+ storeArgument,
548
+ primaryKeys
549
+ } = options;
550
+ const { _typedTableId, _typedKeyArgs, _primaryKeysDefinition } = renderCommonData(options);
551
+ return `${renderedSolidityHeader}
552
+
553
+ // Import schema type
554
+ import { SchemaType } from "@latticexyz/schema-type/src/solidity/SchemaType.sol";
555
+
556
+ // Import store internals
557
+ import { IStore } from "${storeImportPath}IStore.sol";
558
+ import { StoreSwitch } from "${storeImportPath}StoreSwitch.sol";
559
+ import { StoreCore } from "${storeImportPath}StoreCore.sol";
560
+ import { Bytes } from "${storeImportPath}Bytes.sol";
561
+ import { Memory } from "${storeImportPath}Memory.sol";
562
+ import { SliceLib } from "${storeImportPath}Slice.sol";
563
+ import { EncodeArray } from "${storeImportPath}tightcoder/EncodeArray.sol";
564
+ import { Schema, SchemaLib } from "${storeImportPath}Schema.sol";
565
+ import { PackedCounter, PackedCounterLib } from "${storeImportPath}PackedCounter.sol";
566
+
567
+ ${imports.length > 0 ? `
568
+ // Import user types
569
+ ${renderImports(imports)}
570
+ ` : ""}
571
+
572
+ ${staticResourceData ? renderTableId(staticResourceData).tableIdDefinition : ""}
573
+
574
+ ${!structName ? "" : `
575
+ struct ${structName} {
576
+ ${renderList(fields, ({ name, typeId }) => `${typeId} ${name};`)}
577
+ }
578
+ `}
579
+
580
+ library ${libraryName} {
581
+ /** Get the table's schema */
582
+ function getSchema() internal pure returns (Schema) {
583
+ SchemaType[] memory _schema = new SchemaType[](${fields.length});
584
+ ${renderList(fields, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)}
585
+
586
+ return SchemaLib.encode(_schema);
587
+ }
588
+
589
+ function getKeySchema() internal pure returns (Schema) {
590
+ SchemaType[] memory _schema = new SchemaType[](${primaryKeys.length});
591
+ ${renderList(primaryKeys, ({ enumName }, index) => `_schema[${index}] = SchemaType.${enumName};`)}
592
+
593
+ return SchemaLib.encode(_schema);
594
+ }
595
+
596
+ /** Get the table's metadata */
597
+ function getMetadata() internal pure returns (string memory, string[] memory) {
598
+ string[] memory _fieldNames = new string[](${fields.length});
599
+ ${renderList(fields, (field, index) => `_fieldNames[${index}] = "${field.name}";`)}
600
+ return ("${libraryName}", _fieldNames);
601
+ }
602
+
603
+ ${renderWithStore(
604
+ storeArgument,
605
+ (_typedStore, _store, _commentSuffix) => `
606
+ /** Register the table's schema${_commentSuffix} */
607
+ function registerSchema(${renderArguments([_typedStore, _typedTableId])}) internal {
608
+ ${_store}.registerSchema(_tableId, getSchema(), getKeySchema());
609
+ }
610
+ `
611
+ )}
612
+ ${renderWithStore(
613
+ storeArgument,
614
+ (_typedStore, _store, _commentSuffix) => `
615
+ /** Set the table's metadata${_commentSuffix} */
616
+ function setMetadata(${renderArguments([_typedStore, _typedTableId])}) internal {
617
+ (string memory _tableName, string[] memory _fieldNames) = getMetadata();
618
+ ${_store}.setMetadata(_tableId, _tableName, _fieldNames);
619
+ }
620
+ `
621
+ )}
622
+
623
+ ${renderFieldMethods(options)}
624
+
625
+ ${withRecordMethods ? renderRecordMethods(options) : ""}
626
+
627
+ /** Tightly pack full data using this table's schema */
628
+ function encode(${renderArguments(
629
+ options.fields.map(({ name, typeWithLocation }) => `${typeWithLocation} ${name}`)
630
+ )}) internal view returns (bytes memory) {
631
+ ${renderEncodedLengths(dynamicFields)}
632
+ return abi.encodePacked(${renderArguments([
633
+ renderArguments(staticFields.map(({ name }) => name)),
634
+ // TODO try gas optimization (preallocate for all, encodePacked statics, and direct encode dynamics)
635
+ // (see https://github.com/latticexyz/mud/issues/444)
636
+ ...dynamicFields.length === 0 ? [] : ["_encodedLengths.unwrap()", renderArguments(dynamicFields.map((field) => renderEncodeField(field)))]
637
+ ])});
638
+ }
639
+
640
+ ${renderWithStore(
641
+ storeArgument,
642
+ (_typedStore, _store, _commentSuffix) => `
643
+ /* Delete all data for given keys${_commentSuffix} */
644
+ function deleteRecord(${renderArguments([_typedStore, _typedTableId, _typedKeyArgs])}) internal {
645
+ ${_primaryKeysDefinition}
646
+ ${_store}.deleteRecord(_tableId, _primaryKeys);
647
+ }
648
+ `
649
+ )}
650
+ }
651
+
652
+ ${renderTypeHelpers(options)}
653
+
654
+ `;
655
+ }
656
+ function renderEncodedLengths(dynamicFields) {
657
+ if (dynamicFields.length > 0) {
658
+ return `
659
+ uint16[] memory _counters = new uint16[](${dynamicFields.length});
660
+ ${renderList(dynamicFields, ({ name, arrayElement }, index) => {
661
+ if (arrayElement) {
662
+ return `_counters[${index}] = uint16(${name}.length * ${arrayElement.staticByteLength});`;
663
+ } else {
664
+ return `_counters[${index}] = uint16(bytes(${name}).length);`;
665
+ }
666
+ })}
667
+ PackedCounter _encodedLengths = PackedCounterLib.pack(_counters);
668
+ `;
669
+ } else {
670
+ return "";
671
+ }
672
+ }
673
+
674
+ // src/render-solidity/renderTypes.ts
675
+ function renderTypes(options) {
676
+ const { enums } = options;
677
+ return `${renderedSolidityHeader}
678
+
679
+ ${renderList(
680
+ enums,
681
+ ({ name, memberNames }) => `
682
+ enum ${name} {
683
+ ${renderArguments(memberNames)}
684
+ }
685
+ `
686
+ )}
687
+
688
+ `;
689
+ }
690
+
691
+ // src/render-solidity/renderTypesFromConfig.ts
692
+ function renderTypesFromConfig(config) {
693
+ const enums = Object.keys(config.enums).map((name) => ({
694
+ name,
695
+ memberNames: config.enums[name]
696
+ }));
697
+ return renderTypes({
698
+ enums
699
+ });
700
+ }
701
+
702
+ // src/render-solidity/tablegen.ts
703
+ import path3 from "path";
704
+
705
+ // src/render-solidity/renderTableIndex.ts
706
+ function renderTableIndex(options) {
707
+ return `${renderedSolidityHeader}
708
+
709
+ ${renderList(options, ({ outputPath, tableName, renderOptions: { structName, staticResourceData } }) => {
710
+ const imports = [tableName];
711
+ if (structName)
712
+ imports.push(structName);
713
+ if (staticResourceData)
714
+ imports.push(`${tableName}TableId`);
715
+ return `import { ${imports.join(", ")} } from "./${outputPath}";`;
716
+ })}
717
+ `;
718
+ }
719
+
720
+ // src/render-solidity/tablegen.ts
721
+ import { rmSync } from "fs";
722
+ async function tablegen(config, outputBaseDirectory) {
723
+ const allTableOptions = getTableOptions(config);
724
+ const uniqueTableDirectories = new Set(allTableOptions.map(({ outputPath }) => path3.dirname(outputPath)));
725
+ for (const tableDir of uniqueTableDirectories) {
726
+ rmSync(path3.join(outputBaseDirectory, tableDir), { recursive: true, force: true });
727
+ }
728
+ for (const { outputPath, renderOptions } of allTableOptions) {
729
+ const fullOutputPath2 = path3.join(outputBaseDirectory, outputPath);
730
+ const output2 = renderTable(renderOptions);
731
+ formatAndWriteSolidity(output2, fullOutputPath2, "Generated table");
732
+ }
733
+ if (Object.keys(config.enums).length > 0) {
734
+ const fullOutputPath2 = path3.join(outputBaseDirectory, `${config.userTypesPath}.sol`);
735
+ const output2 = renderTypesFromConfig(config);
736
+ formatAndWriteSolidity(output2, fullOutputPath2, "Generated types file");
737
+ }
738
+ const fullOutputPath = path3.join(outputBaseDirectory, `Tables.sol`);
739
+ const output = renderTableIndex(allTableOptions);
740
+ formatAndWriteSolidity(output, fullOutputPath, "Generated table index");
741
+ }
742
+
743
+ export {
744
+ getTableOptions,
745
+ renderedSolidityHeader,
746
+ renderList,
747
+ renderArguments,
748
+ renderCommonData,
749
+ solidityRelativeImportPath,
750
+ renderImports,
751
+ renderWithStore,
752
+ renderTableId,
753
+ renderFieldMethods,
754
+ renderEncodeField,
755
+ renderDecodeValueType,
756
+ renderRecordMethods,
757
+ renderTable,
758
+ renderTypes,
759
+ renderTypesFromConfig,
760
+ tablegen
761
+ };