diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a7c94549f4..17c98b7474 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,3 +29,10 @@ jobs: - name: Outdated files, run `pnpm build` and commit them uses: ./.github/actions/require-empty-diff + + - name: Build API docs + shell: bash + run: pnpm docs:generate:api + + - name: Outdated files, run `pnpm docs:generate:api` and commit them + uses: ./.github/actions/require-empty-diff diff --git a/next-docs/pages/store/reference.mdx b/next-docs/pages/store/reference.mdx deleted file mode 100644 index cf5aa07416..0000000000 --- a/next-docs/pages/store/reference.mdx +++ /dev/null @@ -1 +0,0 @@ -# Reference diff --git a/next-docs/pages/store/reference/_meta.js b/next-docs/pages/store/reference/_meta.js new file mode 100644 index 0000000000..e8c248aa2c --- /dev/null +++ b/next-docs/pages/store/reference/_meta.js @@ -0,0 +1,5 @@ +export default { + "store-core": "StoreCore (internal)", + store: "IStore (external)", + "store-hook": "StoreHook", +}; diff --git a/next-docs/pages/store/reference/store-core.mdx b/next-docs/pages/store/reference/store-core.mdx new file mode 100644 index 0000000000..bb9c8ba2db --- /dev/null +++ b/next-docs/pages/store/reference/store-core.mdx @@ -0,0 +1,809 @@ +[//]: # "This file is autogenerated, do not change manually" + +## StoreCore + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/StoreCore.sol) + +This library includes implementations for all IStore methods and events related to the store actions. + +### Functions + +### initialize + +Initialize the store address in StoreSwitch. + +_Consumers must call this function in their constructor. +StoreSwitch uses the storeAddress to decide where to write data to. +If StoreSwitch is called in the context of a Store contract (storeAddress == address(this)), +StoreSwitch uses internal methods to write data instead of external calls._ + +```solidity +function initialize() internal; +``` + +### registerCoreTables + +Register core tables in the store. + +_Consumers must call this function in their constructor before setting +any table data to allow indexers to decode table events._ + +```solidity +function registerCoreTables() internal; +``` + +### getFieldLayout + +SCHEMA + +Get the field layout for the given table ID. + +```solidity +function getFieldLayout(ResourceId tableId) internal view returns (FieldLayout); +``` + +**Parameters** + +| Name | Type | Description | +| --------- | ------------ | ------------------------------------------------------ | +| `tableId` | `ResourceId` | The ID of the table for which to get the field layout. | + +**Returns** + +| Name | Type | Description | +| -------- | ------------- | ---------------------------------------- | +| `` | `FieldLayout` | The field layout for the given table ID. | + +### getKeySchema + +Get the key schema for the given table ID. + +_Reverts if the table ID is not registered._ + +```solidity +function getKeySchema(ResourceId tableId) internal view returns (Schema keySchema); +``` + +**Parameters** + +| Name | Type | Description | +| --------- | ------------ | ---------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table for which to get the key schema. | + +**Returns** + +| Name | Type | Description | +| ----------- | -------- | -------------------------------------- | +| `keySchema` | `Schema` | The key schema for the given table ID. | + +### getValueSchema + +Get the value schema for the given table ID. + +_Reverts if the table ID is not registered._ + +```solidity +function getValueSchema(ResourceId tableId) internal view returns (Schema valueSchema); +``` + +**Parameters** + +| Name | Type | Description | +| --------- | ------------ | ------------------------------------------------------ | +| `tableId` | `ResourceId` | The ID of the table for which to get the value schema. | + +**Returns** + +| Name | Type | Description | +| ------------- | -------- | ---------------------------------------- | +| `valueSchema` | `Schema` | The value schema for the given table ID. | + +### registerTable + +Register a new table with the given configuration. + +\*This method reverts if + +- The table ID is not of type RESOURCE_TABLE or RESOURCE_OFFCHAIN_TABLE. +- The field layout is invalid. +- The key schema is invalid. +- The value schema is invalid. +- The number of key names does not match the number of key schema types. +- The number of field names does not match the number of field layout fields.\* + +```solidity +function registerTable( + ResourceId tableId, + FieldLayout fieldLayout, + Schema keySchema, + Schema valueSchema, + string[] memory keyNames, + string[] memory fieldNames +) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to register. | +| `fieldLayout` | `FieldLayout` | The field layout of the table. | +| `keySchema` | `Schema` | The key schema of the table. | +| `valueSchema` | `Schema` | The value schema of the table. | +| `keyNames` | `string[]` | The names of the keys in the table. | +| `fieldNames` | `string[]` | The names of the fields in the table. | + +### registerStoreHook + +REGISTER HOOKS + +Register hooks to be called when a record or field is set or deleted. + +_This method reverts for all resource IDs other than tables. +Hooks are not supported for offchain tables._ + +```solidity +function registerStoreHook(ResourceId tableId, IStoreHook hookAddress, uint8 enabledHooksBitmap) internal; +``` + +**Parameters** + +| Name | Type | Description | +| -------------------- | ------------ | --------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to register the hook for. | +| `hookAddress` | `IStoreHook` | The address of the hook contract to register. | +| `enabledHooksBitmap` | `uint8` | The bitmap of enabled hooks. | + +### unregisterStoreHook + +Unregister a hook from the given table ID. + +```solidity +function unregisterStoreHook(ResourceId tableId, IStoreHook hookAddress) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------ | ------------------------------------------------ | +| `tableId` | `ResourceId` | The ID of the table to unregister the hook from. | +| `hookAddress` | `IStoreHook` | The address of the hook to unregister. | + +### setRecord + +SET DATA + +Set a full record for the given table ID and key tuple. + +_Calling this method emits a Store_SetRecord event. +This method internally calls another overload of setRecord by fetching the field layout for the given table ID. +If the field layout is available to the caller, it is recommended to use the other overload to avoid an additional storage read._ + +```solidity +function setRecord( + ResourceId tableId, + bytes32[] memory keyTuple, + bytes memory staticData, + PackedCounter encodedLengths, + bytes memory dynamicData +) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to set the record for. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `staticData` | `bytes` | The static data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `dynamicData` | `bytes` | The dynamic data of the record. | + +### setRecord + +Set a full data record for the given table ID, key tuple, and field layout. + +_For onchain tables, the method emits a `Store_SetRecord` event, updates the data in storage, +calls `onBeforeSetRecord` hooks before actually modifying the state, and calls `onAfterSetRecord` +hooks after modifying the state. For offchain tables, the method returns early after emitting the +event without calling hooks or modifying the state._ + +```solidity +function setRecord( + ResourceId tableId, + bytes32[] memory keyTuple, + bytes memory staticData, + PackedCounter encodedLengths, + bytes memory dynamicData, + FieldLayout fieldLayout +) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to set the record for. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `staticData` | `bytes` | The static data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `dynamicData` | `bytes` | The dynamic data of the record. | +| `fieldLayout` | `FieldLayout` | The field layout for the record. | + +### spliceStaticData + +Splice the static data for the given table ID and key tuple. + +_This method emits a `Store_SpliceStaticData` event, updates the data in storage, and calls +`onBeforeSpliceStaticData` and `onAfterSpliceStaticData` hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function spliceStaticData(ResourceId tableId, bytes32[] memory keyTuple, uint48 start, bytes memory data) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ------------ | --------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to splice the static data for. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `start` | `uint48` | The start position in bytes for the splice operation. | +| `data` | `bytes` | The data to write to the static data of the record at the start byte. | + +### spliceDynamicData + +Splice the dynamic data for the given table ID, key tuple, and dynamic field index. + +_This method emits a `Store_SpliceDynamicData` event, updates the data in storage, and calls +`onBeforeSpliceDynamicData` and `onAfterSpliceDynamicData` hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function spliceDynamicData( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex, + uint40 startWithinField, + uint40 deleteCount, + bytes memory data +) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | ------------ | ------------------------------------------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to splice the dynamic data for. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `dynamicFieldIndex` | `uint8` | The index of the dynamic field to splice. (Dynamic field index = field index - number of static fields) | +| `startWithinField` | `uint40` | The start position within the field for the splice operation. | +| `deleteCount` | `uint40` | The number of bytes to delete in the splice operation. | +| `data` | `bytes` | The data to insert into the dynamic data of the record at the start byte. | + +### setField + +Set data for a field at the given index in a table with the given tableId, key tuple, and value field layout. + +_This method internally calls another overload of setField by fetching the field layout for the given table ID. +If the field layout is available to the caller, it is recommended to use the other overload to avoid an additional storage read. +This function emits a `Store_SpliceStaticData` or `Store_SpliceDynamicData` event and calls the corresponding hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function setField(ResourceId tableId, bytes32[] memory keyTuple, uint8 fieldIndex, bytes memory data) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | ------------ | --------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to set the field for. | +| `keyTuple` | `bytes32[]` | An array representing the key for the record. | +| `fieldIndex` | `uint8` | The index of the field to set. | +| `data` | `bytes` | The data to set for the field. | + +### setField + +Set data for a field at the given index in a table with the given tableId, key tuple, and value field layout. + +_This method internally calls to `setStaticField` or `setDynamicField` based on the field index and layout. +Calling `setStaticField` or `setDynamicField` directly is recommended if the caller is aware of the field layout. +This function emits a `Store_SpliceStaticData` or `Store_SpliceDynamicData` event, updates the data in storage, +and calls the corresponding hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function setField( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 fieldIndex, + bytes memory data, + FieldLayout fieldLayout +) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to set the field for. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldIndex` | `uint8` | The index of the field to set. | +| `data` | `bytes` | The data to set for the field. | +| `fieldLayout` | `FieldLayout` | The field layout for the record. | + +### setStaticField + +Set a static field for the given table ID, key tuple, field index, and field layout. + +_This method emits a `Store_SpliceStaticData` event, updates the data in storage and calls the +`onBeforeSpliceStaticData` and `onAfterSpliceStaticData` hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function setStaticField( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 fieldIndex, + bytes memory data, + FieldLayout fieldLayout +) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------------------ | +| `tableId` | `ResourceId` | The ID of the table to set the static field for. | +| `keyTuple` | `bytes32[]` | An array representing the key for the record. | +| `fieldIndex` | `uint8` | The index of the field to set. | +| `data` | `bytes` | The data to set for the static field. | +| `fieldLayout` | `FieldLayout` | The field layout for the record. | + +### setDynamicField + +Set a dynamic field for the given table ID, key tuple, and dynamic field index. + +_This method emits a `Store_SpliceDynamicData` event, updates the data in storage and calls the +`onBeforeSpliceDynamicaData` and `onAfterSpliceDynamicData` hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function setDynamicField( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex, + bytes memory data +) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | ------------ | ----------------------------------------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to set the dynamic field for. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `dynamicFieldIndex` | `uint8` | The index of the dynamic field to set. (Dynamic field index = field index - number of static fields). | +| `data` | `bytes` | The data to set for the dynamic field. | + +### deleteRecord + +Delete a record for the given table ID and key tuple. + +_This method internally calls another overload of deleteRecord by fetching the field layout for the given table ID. +This method deletes static data and sets the dynamic data length to 0, but does not +actually modify the dynamic data. It emits a `Store_DeleteRecord` event and emits the +`onBeforeDeleteRecord` and `onAfterDeleteRecord` hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ------------ | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to delete the record from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | + +### deleteRecord + +Delete a record for the given table ID and key tuple. + +_This method deletes static data and sets the dynamic data length to 0, but does not +actually modify the dynamic data. It emits a `Store_DeleteRecord` event and emits the +`onBeforeDeleteRecord` and `onAfterDeleteRecord` hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple, FieldLayout fieldLayout) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to delete the record from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldLayout` | `FieldLayout` | The field layout for the record. | + +### pushToDynamicField + +Push data to a field at the dynamic field index in a table with the given table ID and key tuple. + +_This method emits a `Store_SpliceDynamicData` event, updates the data in storage and calls the +`onBeforeSpliceDynamicData` and `onAfterSpliceDynamicData` hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function pushToDynamicField( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex, + bytes memory dataToPush +) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | ------------ | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to push data to the dynamic field. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `dynamicFieldIndex` | `uint8` | The index of the dynamic field to push data to. | +| `dataToPush` | `bytes` | The data to push to the dynamic field. | + +### popFromDynamicField + +Pop data from a field at the dynamic field index in a table with the given table ID and key tuple. + +_This method emits a `Store_SpliceDynamicData` event, updates the data in storage and calls the +`onBeforeSpliceDynamicData` and `onAfterSpliceDynamicData` hooks. +For offchain tables, it returns early after emitting the event._ + +```solidity +function popFromDynamicField( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex, + uint256 byteLengthToPop +) internal; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | ------------ | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to pop data from the dynamic field. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `dynamicFieldIndex` | `uint8` | The index of the dynamic field to pop data from. | +| `byteLengthToPop` | `uint256` | The byte length to pop from the dynamic field. | + +### getRecord + +GET DATA + +Get the full record (all fields, static and dynamic data) for the given table ID and key tuple. + +_This function internally calls another overload of `getRecord`, loading the field layout from storage. +If the field layout is available to the caller, it is recommended to use the other overload to avoid an additional storage read._ + +```solidity +function getRecord( + ResourceId tableId, + bytes32[] memory keyTuple +) internal view returns (bytes memory staticData, PackedCounter encodedLengths, bytes memory dynamicData); +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ------------ | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the record from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | + +**Returns** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------ | +| `staticData` | `bytes` | The static data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `dynamicData` | `bytes` | The dynamic data of the record. | + +### getRecord + +Get the full record (all fields, static and dynamic data) for the given table ID and key tuple, with the given field layout. + +```solidity +function getRecord( + ResourceId tableId, + bytes32[] memory keyTuple, + FieldLayout fieldLayout +) internal view returns (bytes memory staticData, PackedCounter encodedLengths, bytes memory dynamicData); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the record from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldLayout` | `FieldLayout` | The field layout for the record. | + +**Returns** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------ | +| `staticData` | `bytes` | The static data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `dynamicData` | `bytes` | The dynamic data of the record. | + +### getField + +Get a single field from the given table ID and key tuple. + +_This function internally calls another overload of `getField`, loading the field layout from storage._ + +```solidity +function getField(ResourceId tableId, bytes32[] memory keyTuple, uint8 fieldIndex) internal view returns (bytes memory); +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | ------------ | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the field from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldIndex` | `uint8` | The index of the field to get. | + +**Returns** + +| Name | Type | Description | +| -------- | ------- | ---------------------- | +| `` | `bytes` | The data of the field. | + +### getField + +Get a single field from the given table ID and key tuple, with the given field layout. + +```solidity +function getField( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 fieldIndex, + FieldLayout fieldLayout +) internal view returns (bytes memory); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the field from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldIndex` | `uint8` | The index of the field to get. | +| `fieldLayout` | `FieldLayout` | The field layout for the record. | + +**Returns** + +| Name | Type | Description | +| -------- | ------- | ---------------------- | +| `` | `bytes` | The data of the field. | + +### getStaticField + +Get a single static field from the given table ID and key tuple, with the given value field layout. + +_The field value is left-aligned in the returned bytes32, the rest of the word is not zeroed out. +Consumers are expected to truncate the returned value as needed._ + +```solidity +function getStaticField( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 fieldIndex, + FieldLayout fieldLayout +) internal view returns (bytes32); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the static field from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldIndex` | `uint8` | The index of the field to get. | +| `fieldLayout` | `FieldLayout` | The field layout for the record. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ----------------------------- | +| `` | `bytes32` | The data of the static field. | + +### getDynamicField + +Get a single dynamic field from the given table ID and key tuple. + +```solidity +function getDynamicField( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex +) internal view returns (bytes memory); +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the dynamic field from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `dynamicFieldIndex` | `uint8` | The index of the dynamic field to get, relative to the start of the dynamic fields. (Dynamic field index = field index - number of static fields) | + +**Returns** + +| Name | Type | Description | +| -------- | ------- | ------------------------------ | +| `` | `bytes` | The data of the dynamic field. | + +### getFieldLength + +Get the byte length of a single field from the given table ID and key tuple. + +_This function internally calls another overload of `getFieldLength`, loading the field layout from storage. +If the field layout is available to the caller, it is recommended to use the other overload to avoid an additional storage read._ + +```solidity +function getFieldLength( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 fieldIndex +) internal view returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ------------ | ------------ | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the field length from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldIndex` | `uint8` | The index of the field to get the length for. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ----------------------------- | +| `` | `uint256` | The byte length of the field. | + +### getFieldLength + +Get the byte length of a single field from the given table ID and key tuple. + +```solidity +function getFieldLength( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 fieldIndex, + FieldLayout fieldLayout +) internal view returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the field length from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldIndex` | `uint8` | The index of the field to get the length for. | +| `fieldLayout` | `FieldLayout` | The field layout for the record. | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ----------------------------- | +| `` | `uint256` | The byte length of the field. | + +### getDynamicFieldLength + +Get the byte length of a single dynamic field from the given table ID and key tuple. + +```solidity +function getDynamicFieldLength( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex +) internal view returns (uint256); +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the dynamic field length from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `dynamicFieldIndex` | `uint8` | The index of the dynamic field to get the length for, relative to the start of the dynamic fields. (Dynamic field index = field index - number of static fields) | + +**Returns** + +| Name | Type | Description | +| -------- | --------- | ------------------------------------- | +| `` | `uint256` | The byte length of the dynamic field. | + +### getDynamicFieldSlice + +Get a byte slice (including start, excluding end) of a single dynamic field from the given table ID and key tuple. + +```solidity +function getDynamicFieldSlice( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex, + uint256 start, + uint256 end +) internal view returns (bytes memory); +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table to get the dynamic field slice from. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `dynamicFieldIndex` | `uint8` | The index of the dynamic field to get the slice from, relative to the start of the dynamic fields. (Dynamic field index = field index - number of static fields) | +| `start` | `uint256` | The start index within the dynamic field for the slice operation (inclusive). | +| `end` | `uint256` | The end index within the dynamic field for the slice operation (exclusive). | + +**Returns** + +| Name | Type | Description | +| -------- | ------- | ------------------------------------ | +| `` | `bytes` | The byte slice of the dynamic field. | + +### Events + +### Store_SetRecord + +Emitted when a new record is set in the store. + +```solidity +event Store_SetRecord( + ResourceId indexed tableId, bytes32[] keyTuple, bytes staticData, PackedCounter encodedLengths, bytes dynamicData +); +``` + +### Store_SpliceStaticData + +Emitted when static data in the store is spliced. + +_In static data, data is always overwritten starting at the start position, +so the total length of the data remains the same and no data is shifted._ + +```solidity +event Store_SpliceStaticData(ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, bytes data); +``` + +### Store_SpliceDynamicData + +Emitted when dynamic data in the store is spliced. + +```solidity +event Store_SpliceDynamicData( + ResourceId indexed tableId, + bytes32[] keyTuple, + uint48 start, + uint40 deleteCount, + PackedCounter encodedLengths, + bytes data +); +``` + +### Store_DeleteRecord + +Emitted when a record is deleted from the store. + +```solidity +event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple); +``` diff --git a/next-docs/pages/store/reference/store-hook.mdx b/next-docs/pages/store/reference/store-hook.mdx new file mode 100644 index 0000000000..ba416e2627 --- /dev/null +++ b/next-docs/pages/store/reference/store-hook.mdx @@ -0,0 +1,231 @@ +[//]: # "This file is autogenerated, do not change manually" + +## Constants + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreHook.sol) + +### STORE_HOOK_INTERFACE_ID + +```solidity +bytes4 constant STORE_HOOK_INTERFACE_ID = IStoreHook.onBeforeSetRecord.selector ^ + IStoreHook.onAfterSetRecord.selector ^ + IStoreHook.onBeforeSpliceStaticData.selector ^ + IStoreHook.onAfterSpliceStaticData.selector ^ + IStoreHook.onBeforeSpliceDynamicData.selector ^ + IStoreHook.onAfterSpliceDynamicData.selector ^ + IStoreHook.onBeforeDeleteRecord.selector ^ + IStoreHook.onAfterDeleteRecord.selector ^ + ERC165_INTERFACE_ID; +``` + +## IStoreHook + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreHook.sol) + +### Functions + +### onBeforeSetRecord + +Called before setting a record in the store. + +```solidity +function onBeforeSetRecord( + ResourceId tableId, + bytes32[] memory keyTuple, + bytes memory staticData, + PackedCounter encodedLengths, + bytes memory dynamicData, + FieldLayout fieldLayout +) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the record is to be set. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `staticData` | `bytes` | The static data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `dynamicData` | `bytes` | The dynamic data of the record. | +| `fieldLayout` | `FieldLayout` | The layout of the field, see FieldLayout.sol. | + +### onAfterSetRecord + +Called after setting a record in the store. + +```solidity +function onAfterSetRecord( + ResourceId tableId, + bytes32[] memory keyTuple, + bytes memory staticData, + PackedCounter encodedLengths, + bytes memory dynamicData, + FieldLayout fieldLayout +) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------------- | --------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the record was set. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `staticData` | `bytes` | The static data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `dynamicData` | `bytes` | The dynamic data of the record. | +| `fieldLayout` | `FieldLayout` | The layout of the field, see FieldLayout.sol. | + +### onBeforeSpliceStaticData + +Called before splicing static data in the store. + +_Splice operations in static data always overwrite data starting at the start position, +so the total length of the data remains the same and no data is shifted._ + +```solidity +function onBeforeSpliceStaticData( + ResourceId tableId, + bytes32[] memory keyTuple, + uint48 start, + bytes memory data +) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ------------ | -------------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the data is to be spliced. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `start` | `uint48` | The start byte position for splicing. | +| `data` | `bytes` | The data to be written to the static data of the record at the start byte. | + +### onAfterSpliceStaticData + +Called after splicing static data in the store. + +_Splice operations in static data always overwrite data starting at the start position, +so the total length of the data remains the same and no data is shifted._ + +```solidity +function onAfterSpliceStaticData( + ResourceId tableId, + bytes32[] memory keyTuple, + uint48 start, + bytes memory data +) external; +``` + +**Parameters** + +| Name | Type | Description | +| ---------- | ------------ | -------------------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the data was spliced. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `start` | `uint48` | The start byte position for splicing. | +| `data` | `bytes` | The data written to the static data of the record at the start byte. | + +### onBeforeSpliceDynamicData + +Called before splicing dynamic data in the store. + +_Splice operations in dynamic data always reach the end of the dynamic data +to avoid shifting data after the inserted or deleted data._ + +```solidity +function onBeforeSpliceDynamicData( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex, + uint40 startWithinField, + uint40 deleteCount, + PackedCounter encodedLengths, + bytes memory data +) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | --------------- | ------------------------------------------------------------------------------ | +| `tableId` | `ResourceId` | The ID of the table where the data is to be spliced. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `dynamicFieldIndex` | `uint8` | The index of the dynamic field. | +| `startWithinField` | `uint40` | The start byte position within the field for splicing. | +| `deleteCount` | `uint40` | The number of bytes to delete in the dynamic data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `data` | `bytes` | The data to be inserted into the dynamic data of the record at the start byte. | + +### onAfterSpliceDynamicData + +Called after splicing dynamic data in the store. + +_Splice operations in dynamic data always reach the end of the dynamic data +to avoid shifting data after the inserted or deleted data._ + +```solidity +function onAfterSpliceDynamicData( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex, + uint40 startWithinField, + uint40 deleteCount, + PackedCounter encodedLengths, + bytes memory data +) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------------------- | --------------- | ------------------------------------------------------------------------ | +| `tableId` | `ResourceId` | The ID of the table where the data was spliced. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `dynamicFieldIndex` | `uint8` | The index of the dynamic field. | +| `startWithinField` | `uint40` | The start byte position within the field for splicing. | +| `deleteCount` | `uint40` | The number of bytes deleted in the dynamic data of the record. | +| `encodedLengths` | `PackedCounter` | The encoded lengths of the dynamic data of the record. | +| `data` | `bytes` | The data inserted into the dynamic data of the record at the start byte. | + +### onBeforeDeleteRecord + +Called before deleting a record from the store. + +```solidity +function onBeforeDeleteRecord(ResourceId tableId, bytes32[] memory keyTuple, FieldLayout fieldLayout) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the record is to be deleted. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldLayout` | `FieldLayout` | The layout of the field, see FieldLayout.sol. | + +### onAfterDeleteRecord + +Called after deleting a record from the store. + +```solidity +function onAfterDeleteRecord(ResourceId tableId, bytes32[] memory keyTuple, FieldLayout fieldLayout) external; +``` + +**Parameters** + +| Name | Type | Description | +| ------------- | ------------- | ------------------------------------------------------- | +| `tableId` | `ResourceId` | The ID of the table where the record was deleted. | +| `keyTuple` | `bytes32[]` | An array representing the composite key for the record. | +| `fieldLayout` | `FieldLayout` | The layout of the field, see FieldLayout.sol. | + +### Errors + +### StoreHook_NotImplemented + +Error emitted when a function is not implemented. + +```solidity +error StoreHook_NotImplemented(); +``` diff --git a/next-docs/pages/store/reference/store.mdx b/next-docs/pages/store/reference/store.mdx new file mode 100644 index 0000000000..7f6b1db8ab --- /dev/null +++ b/next-docs/pages/store/reference/store.mdx @@ -0,0 +1,451 @@ +[//]: # "This file is autogenerated, do not change manually" + +## IStore + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStore.sol) + +**Inherits:** +[IStoreData](#istoredata), [IStoreRegistration](#istoreregistration), [IStoreErrors](#istoreerrors) + +## IStoreEvents + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreEvents.sol) + +### Events + +### Store_SetRecord + +Emitted when a new record is set in the store. + +```solidity +event Store_SetRecord( + ResourceId indexed tableId, bytes32[] keyTuple, bytes staticData, PackedCounter encodedLengths, bytes dynamicData +); +``` + +### Store_SpliceStaticData + +Emitted when static data in the store is spliced. + +_In static data, data is always overwritten starting at the start position, +so the total length of the data remains the same and no data is shifted._ + +```solidity +event Store_SpliceStaticData(ResourceId indexed tableId, bytes32[] keyTuple, uint48 start, bytes data); +``` + +### Store_SpliceDynamicData + +Emitted when dynamic data in the store is spliced. + +```solidity +event Store_SpliceDynamicData( + ResourceId indexed tableId, + bytes32[] keyTuple, + uint48 start, + uint40 deleteCount, + PackedCounter encodedLengths, + bytes data +); +``` + +### Store_DeleteRecord + +Emitted when a record is deleted from the store. + +```solidity +event Store_DeleteRecord(ResourceId indexed tableId, bytes32[] keyTuple); +``` + +## IStoreErrors + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreErrors.sol) + +### Errors + +### Store_TableAlreadyExists + +```solidity +error Store_TableAlreadyExists(ResourceId tableId, string tableIdString); +``` + +### Store_TableNotFound + +```solidity +error Store_TableNotFound(ResourceId tableId, string tableIdString); +``` + +### Store_InvalidResourceType + +```solidity +error Store_InvalidResourceType(bytes2 expected, ResourceId resourceId, string resourceIdString); +``` + +### Store_InvalidDynamicDataLength + +```solidity +error Store_InvalidDynamicDataLength(uint256 expected, uint256 received); +``` + +### Store_IndexOutOfBounds + +```solidity +error Store_IndexOutOfBounds(uint256 length, uint256 accessedIndex); +``` + +### Store_InvalidKeyNamesLength + +```solidity +error Store_InvalidKeyNamesLength(uint256 expected, uint256 received); +``` + +### Store_InvalidFieldNamesLength + +```solidity +error Store_InvalidFieldNamesLength(uint256 expected, uint256 received); +``` + +### Store_InvalidValueSchemaLength + +```solidity +error Store_InvalidValueSchemaLength(uint256 expected, uint256 received); +``` + +### Store_InvalidSplice + +```solidity +error Store_InvalidSplice(uint40 startWithinField, uint40 deleteCount, uint40 fieldLength); +``` + +## IStoreData + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreData.sol) + +**Inherits:** +[IStoreRead](#istoreread), [IStoreWrite](#istorewrite) + +The IStoreData interface includes methods for reading and writing table values. + +_These methods are frequently invoked during runtime, so it is essential to prioritize optimizing their gas cost._ + +### Functions + +### storeVersion + +Returns the version of the Store contract. + +```solidity +function storeVersion() external view returns (bytes32 version); +``` + +**Returns** + +| Name | Type | Description | +| --------- | --------- | ---------------------------------- | +| `version` | `bytes32` | The version of the Store contract. | + +### Events + +### HelloStore + +Emitted when the store is initialized. + +```solidity +event HelloStore(bytes32 indexed storeVersion); +``` + +## IStoreRead + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreRead.sol) + +### Functions + +### getFieldLayout + +```solidity +function getFieldLayout(ResourceId tableId) external view returns (FieldLayout fieldLayout); +``` + +### getValueSchema + +```solidity +function getValueSchema(ResourceId tableId) external view returns (Schema valueSchema); +``` + +### getKeySchema + +```solidity +function getKeySchema(ResourceId tableId) external view returns (Schema keySchema); +``` + +### getRecord + +Get full record (all fields, static and dynamic data) for the given tableId and key tuple, loading the field layout from storage + +```solidity +function getRecord( + ResourceId tableId, + bytes32[] calldata keyTuple +) external view returns (bytes memory staticData, PackedCounter encodedLengths, bytes memory dynamicData); +``` + +### getRecord + +Get full record (all fields, static and dynamic data) for the given tableId and key tuple, with the given field layout + +```solidity +function getRecord( + ResourceId tableId, + bytes32[] calldata keyTuple, + FieldLayout fieldLayout +) external view returns (bytes memory staticData, PackedCounter encodedLengths, bytes memory dynamicData); +``` + +### getField + +Get a single field from the given tableId and key tuple, loading the field layout from storage + +```solidity +function getField( + ResourceId tableId, + bytes32[] calldata keyTuple, + uint8 fieldIndex +) external view returns (bytes memory data); +``` + +### getField + +Get a single field from the given tableId and key tuple, with the given field layout + +```solidity +function getField( + ResourceId tableId, + bytes32[] calldata keyTuple, + uint8 fieldIndex, + FieldLayout fieldLayout +) external view returns (bytes memory data); +``` + +### getStaticField + +Get a single static field from the given tableId and key tuple, with the given value field layout. +Note: the field value is left-aligned in the returned bytes32, the rest of the word is not zeroed out. +Consumers are expected to truncate the returned value as needed. + +```solidity +function getStaticField( + ResourceId tableId, + bytes32[] calldata keyTuple, + uint8 fieldIndex, + FieldLayout fieldLayout +) external view returns (bytes32); +``` + +### getDynamicField + +Get a single dynamic field from the given tableId and key tuple at the given dynamic field index. +(Dynamic field index = field index - number of static fields) + +```solidity +function getDynamicField( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex +) external view returns (bytes memory); +``` + +### getFieldLength + +Get the byte length of a single field from the given tableId and key tuple, loading the field layout from storage + +```solidity +function getFieldLength( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 fieldIndex +) external view returns (uint256); +``` + +### getFieldLength + +Get the byte length of a single field from the given tableId and key tuple, with the given value field layout + +```solidity +function getFieldLength( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 fieldIndex, + FieldLayout fieldLayout +) external view returns (uint256); +``` + +### getDynamicFieldLength + +Get the byte length of a single dynamic field from the given tableId and key tuple + +```solidity +function getDynamicFieldLength( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex +) external view returns (uint256); +``` + +### getDynamicFieldSlice + +Get a byte slice (including start, excluding end) of a single dynamic field from the given tableId and key tuple, with the given value field layout. +The slice is unchecked and will return invalid data if `start`:`end` overflow. + +```solidity +function getDynamicFieldSlice( + ResourceId tableId, + bytes32[] memory keyTuple, + uint8 dynamicFieldIndex, + uint256 start, + uint256 end +) external view returns (bytes memory data); +``` + +## IStoreWrite + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreWrite.sol) + +**Inherits:** +[IStoreEvents](#istoreevents) + +### Functions + +### setRecord + +```solidity +function setRecord( + ResourceId tableId, + bytes32[] calldata keyTuple, + bytes calldata staticData, + PackedCounter encodedLengths, + bytes calldata dynamicData +) external; +``` + +### spliceStaticData + +```solidity +function spliceStaticData(ResourceId tableId, bytes32[] calldata keyTuple, uint48 start, bytes calldata data) external; +``` + +### spliceDynamicData + +```solidity +function spliceDynamicData( + ResourceId tableId, + bytes32[] calldata keyTuple, + uint8 dynamicFieldIndex, + uint40 startWithinField, + uint40 deleteCount, + bytes calldata data +) external; +``` + +### setField + +```solidity +function setField(ResourceId tableId, bytes32[] calldata keyTuple, uint8 fieldIndex, bytes calldata data) external; +``` + +### setField + +```solidity +function setField( + ResourceId tableId, + bytes32[] calldata keyTuple, + uint8 fieldIndex, + bytes calldata data, + FieldLayout fieldLayout +) external; +``` + +### setStaticField + +```solidity +function setStaticField( + ResourceId tableId, + bytes32[] calldata keyTuple, + uint8 fieldIndex, + bytes calldata data, + FieldLayout fieldLayout +) external; +``` + +### setDynamicField + +```solidity +function setDynamicField( + ResourceId tableId, + bytes32[] calldata keyTuple, + uint8 dynamicFieldIndex, + bytes calldata data +) external; +``` + +### pushToDynamicField + +```solidity +function pushToDynamicField( + ResourceId tableId, + bytes32[] calldata keyTuple, + uint8 dynamicFieldIndex, + bytes calldata dataToPush +) external; +``` + +### popFromDynamicField + +```solidity +function popFromDynamicField( + ResourceId tableId, + bytes32[] calldata keyTuple, + uint8 dynamicFieldIndex, + uint256 byteLengthToPop +) external; +``` + +### deleteRecord + +```solidity +function deleteRecord(ResourceId tableId, bytes32[] memory keyTuple) external; +``` + +## IStoreRegistration + +[Git Source](https://github.com/latticexyz/mud/blob/main/packages/store/src/IStoreRegistration.sol) + +The IStoreRegistration interface includes methods for managing table field layouts, +metadata, and hooks, which are usually called once in the setup phase of an application, +making them less performance critical than the methods. + +### Functions + +### registerTable + +```solidity +function registerTable( + ResourceId tableId, + FieldLayout fieldLayout, + Schema keySchema, + Schema valueSchema, + string[] calldata keyNames, + string[] calldata fieldNames +) external; +``` + +### registerStoreHook + +```solidity +function registerStoreHook(ResourceId tableId, IStoreHook hookAddress, uint8 enabledHooksBitmap) external; +``` + +### unregisterStoreHook + +```solidity +function unregisterStoreHook(ResourceId tableId, IStoreHook hookAddress) external; +``` diff --git a/package.json b/package.json index 419c584001..c7305a3ea2 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "clean": "turbo run clean", "dev": "turbo run dev --concurrency 100", "dist-tag-rm": "pnpm recursive exec -- sh -c 'npm dist-tag rm $(cat package.json | jq -r \".name\") $TAG || true'", + "docs:generate:api": "pnpx bun@0.7.3 scripts/render-api-docs.ts", "foundryup": "curl -L https://foundry.paradigm.xyz | bash && bash ~/.foundry/bin/foundryup", "gas-report": "pnpm run --recursive --parallel gas-report", "lint": "pnpm prettier:check && eslint . --ext .ts --ext .tsx", diff --git a/scripts/render-api-docs.ts b/scripts/render-api-docs.ts new file mode 100644 index 0000000000..9f11b012e0 --- /dev/null +++ b/scripts/render-api-docs.ts @@ -0,0 +1,161 @@ +/** + * Parse raw `forge doc` output from contract packages, clean it up, and render as markdown in docs. + */ + +import { execa } from "execa"; +import prettier from "prettier"; +import { readFileSync, readdirSync, writeFileSync } from "fs"; +import path from "path"; +import prettierOptions from "../.prettierrc.js"; + +const DOCS_ROOT = "next-docs/pages"; + +// Config for API docs input/output and filter/processing +const PUBLIC_APIS: PublicApis = { + "store/reference/store-core.mdx": { + inputFiles: [ + { + source: "store/src/StoreCore.sol", + filterFiles: (fileName) => !fileName.includes("StoreCoreInternal"), + }, + ], + processContent: (content) => { + content = formatHeadings(content); + content = fixGithubLinks(content); + return content; + }, + }, + "store/reference/store.mdx": { + inputFiles: [ + { source: "store/src/IStore.sol" }, + { source: "store/src/IStoreEvents.sol" }, + { source: "store/src/IStoreErrors.sol" }, + { source: "store/src/IStoreData.sol" }, + { source: "store/src/IStoreRead.sol" }, + { source: "store/src/IStoreWrite.sol" }, + { source: "store/src/IStoreRegistration.sol" }, + ], + processContent: (content) => { + content = formatHeadings(content); + content = fixGithubLinks(content); + return content + .replace("/src/IStoreData.sol/interface.IStoreData.md", "#istoredata") + .replace("/src/IStoreRegistration.sol/interface.IStoreRegistration.md", "#istoreregistration") + .replace("/src/IStoreRead.sol/interface.IStoreRead.md", "#istoreread") + .replace("/src/IStoreWrite.sol/interface.IStoreWrite.md", "#istorewrite") + .replace("/src/IStoreEvents.sol/interface.IStoreEvents.md", "#istoreevents") + .replace("/src/IStoreErrors.sol/interface.IStoreErrors.md", "#istoreerrors"); + }, + }, + "store/reference/store-hook.mdx": { + inputFiles: [ + { + source: "store/src/IStoreHook.sol", + }, + ], + processContent: (content) => { + content = formatHeadings(content); + content = fixGithubLinks(content); + return content.replace(`**Inherits:**\n[IERC165](/src/IERC165.sol/interface.IERC165.md)`, ""); + }, + }, +}; + +function formatHeadings(content: string) { + const h1 = /^# (?=.+)/gm; + const h2 = /^## (?=.+)/gm; + return content.replace(h2, "### ").replace(h1, "## "); +} + +function fixGithubLinks(content: string) { + const pattern = /https:\/\/github.com\/latticexyz\/mud\/blob\/[^/]+\/(.*)/g; + const replacement = "https://github.com/latticexyz/mud/blob/main/packages/store/$1"; + return content.replace(pattern, replacement); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////// +// SHOULDN'T HAVE TO TOUCH CODE BELOW THIS +/////////////////////////////////////////////////////////////////////////////////////////////////////// + +type Input = { + source: string; + filterFiles?: (fileName: string) => boolean; +}; + +type PublicApis = { + [outputFile: string]: { inputFiles: Input[]; processContent?: (content: string) => string }; +}; + +function identity(input: T): T { + return input; +} + +function getPackages() { + return [ + ...new Set( + Object.values(PUBLIC_APIS) + .map(({ inputFiles }) => inputFiles) + .flat() + .map((input) => input.source.split("/")[0]) + ), + ]; +} + +/** + * Generate raw docs using `forge doc` in all relevant contract packages + */ +async function generateDocs() { + const packages = getPackages(); + for (const pkg of packages) { + const { stdout, stderr } = await execa("forge", ["doc", "--build"], { + stdio: "pipe", + cwd: path.join(process.cwd(), "packages", pkg), + }); + if (stderr || stdout) { + console.log(stderr || stdout); + } + } +} + +function getDocsPath(sourceFilePath: string) { + const pkg = sourceFilePath.split("/")[0]; + const relativeFilePath = sourceFilePath.replace(pkg, ""); + return path.join("packages", pkg, "docs", "src", relativeFilePath); +} + +function formatMarkdown(content: string) { + return prettier.format(content, { parser: "markdown", ...prettierOptions }); +} + +/** + * Write output files from array of input files + */ +async function renderDocs() { + for (const [outputFile, { inputFiles, processContent = identity }] of Object.entries(PUBLIC_APIS)) { + // Concat all input files for this output file + const content = + `[//]: # (This file is autogenerated, do not change manually)\n\n` + + processContent( + inputFiles + .map((input) => { + const docsPath = getDocsPath(input.source); + const docsFiles = readdirSync(docsPath); + return docsFiles + .filter(input.filterFiles ?? identity) + .map((fileName) => readFileSync(path.join(docsPath, fileName), { encoding: "utf8" })); + }) + .flat() + .join("\n") + ); + + // Write the output file + writeFileSync(path.join(DOCS_ROOT, outputFile), formatMarkdown(content)); + } +} + +async function run() { + await generateDocs(); + await renderDocs(); +} + +await run();