From c10c9fb2dacc93bc58d013e74509180f90ac5b5a Mon Sep 17 00:00:00 2001 From: Kevin Ingersoll Date: Thu, 23 May 2024 11:22:31 +0100 Subject: [PATCH] feat(store,world): add option to codegen tables into namespace dirs (#2840) --- .changeset/eleven-lobsters-play.md | 5 + .changeset/great-ducks-search.md | 8 ++ packages/cli/scripts/generate-test-tables.ts | 10 +- packages/cli/src/build.ts | 17 ++-- packages/cli/src/commands/build.ts | 7 +- packages/cli/src/commands/tablegen.ts | 11 +-- packages/cli/src/runDeploy.ts | 7 +- packages/store/mud.config.ts | 2 +- .../store/test/codegen/tables/Callbacks.sol | 4 +- .../store/test/codegen/tables/KeyEncoding.sol | 4 +- packages/store/test/codegen/tables/Mixed.sol | 4 +- .../store/test/codegen/tables/Vector2.sol | 4 +- packages/store/ts/codegen/tableOptions.ts | 83 +++++++++-------- packages/store/ts/codegen/tablegen.ts | 27 ++++-- packages/store/ts/config/storeConfig.ts | 2 +- packages/store/ts/config/v2/compat.ts | 2 +- packages/store/ts/config/v2/defaults.ts | 17 ++-- packages/store/ts/config/v2/input.ts | 18 +++- packages/store/ts/config/v2/output.ts | 27 ++++++ packages/store/ts/config/v2/store.test.ts | 91 +++++++++++++++++++ packages/store/ts/config/v2/store.ts | 24 ++++- .../ts/config/v2/storeWithShorthands.test.ts | 4 + packages/store/ts/config/v2/table.ts | 2 +- .../store/ts/scripts/generate-test-tables.ts | 12 +-- packages/store/ts/scripts/tablegen.ts | 15 +-- packages/world-modules/ts/scripts/tablegen.ts | 15 +-- packages/world-modules/tsconfig.json | 2 +- packages/world/mud.config.ts | 6 +- packages/world/ts/config/v2/defaults.ts | 12 ++- packages/world/ts/config/v2/input.ts | 3 + packages/world/ts/config/v2/output.ts | 5 +- packages/world/ts/config/v2/world.test.ts | 9 +- .../ts/config/v2/worldWithShorthands.test.ts | 5 +- .../world/ts/scripts/generate-test-tables.ts | 25 +++-- packages/world/ts/scripts/tablegen.ts | 15 +-- 35 files changed, 365 insertions(+), 139 deletions(-) create mode 100644 .changeset/eleven-lobsters-play.md create mode 100644 .changeset/great-ducks-search.md diff --git a/.changeset/eleven-lobsters-play.md b/.changeset/eleven-lobsters-play.md new file mode 100644 index 0000000000..6958792d5e --- /dev/null +++ b/.changeset/eleven-lobsters-play.md @@ -0,0 +1,5 @@ +--- +"@latticexyz/store": patch +--- + +Internal `tablegen` function (exported from `@latticexyz/store/codegen`) now expects an object of options with a `configPath` to use as a base path to resolve other relative paths from. diff --git a/.changeset/great-ducks-search.md b/.changeset/great-ducks-search.md new file mode 100644 index 0000000000..73ed17d071 --- /dev/null +++ b/.changeset/great-ducks-search.md @@ -0,0 +1,8 @@ +--- +"@latticexyz/store": patch +"@latticexyz/world": patch +--- + +Added `sourceDirectory` as a top-level config option for specifying contracts source (i.e. Solidity) directory relative to the MUD config. This is used to resolve other paths in the config, like codegen and user types. Like `foundry.toml`, this defaults to `src` and should be kept in sync with `foundry.toml`. + +Also added a `codegen.namespaceDirectories` option to organize codegen output (table libraries, etc.) into directories by namespace. For example, a `Counter` table in the `app` namespace will have codegen at `codegen/app/tables/Counter.sol`. If not set, defaults to `true` when using top-level `namespaces` key, `false` otherwise. diff --git a/packages/cli/scripts/generate-test-tables.ts b/packages/cli/scripts/generate-test-tables.ts index 7c541ae54c..8274f805e9 100644 --- a/packages/cli/scripts/generate-test-tables.ts +++ b/packages/cli/scripts/generate-test-tables.ts @@ -1,12 +1,15 @@ -import path from "path"; import { tablegen } from "@latticexyz/store/codegen"; import { defineStore } from "@latticexyz/store"; -import { getRemappings, getSrcDirectory } from "@latticexyz/common/foundry"; +import { getRemappings } from "@latticexyz/common/foundry"; +import { fileURLToPath } from "node:url"; + +const configPath = fileURLToPath(import.meta.url); // This config is used only for tests. // Aside from avoiding `mud.config.ts` in cli package (could cause issues), // this also tests that mudConfig and tablegen can work as standalone functions const config = defineStore({ + sourceDirectory: "../contracts/src", enums: { Enum1: ["E1", "E2", "E3"], Enum2: ["E1"], @@ -92,7 +95,6 @@ const config = defineStore({ }, }); -const srcDirectory = await getSrcDirectory(); const remappings = await getRemappings(); -await tablegen(config, path.join(srcDirectory, config.codegen.outputDirectory), remappings); +await tablegen({ configPath, config, remappings }); diff --git a/packages/cli/src/build.ts b/packages/cli/src/build.ts index 77a010ebaf..9b8fda5f1c 100644 --- a/packages/cli/src/build.ts +++ b/packages/cli/src/build.ts @@ -2,7 +2,6 @@ import path from "node:path"; import { tablegen } from "@latticexyz/store/codegen"; import { worldgen } from "@latticexyz/world/node"; import { World as WorldConfig } from "@latticexyz/world"; -import { worldToV1 } from "@latticexyz/world/config/v2"; import { forge, getRemappings } from "@latticexyz/common/foundry"; import { getExistingContracts } from "./utils/getExistingContracts"; import { execa } from "execa"; @@ -10,21 +9,27 @@ import { execa } from "execa"; type BuildOptions = { foundryProfile?: string; srcDir: string; + /** + * Path to `mud.config.ts`. We use this as the "project root" to resolve other relative paths. + * + * Defaults to finding the nearest `mud.config.ts`, looking in `process.cwd()` and moving up the directory tree. + */ + configPath: string; config: WorldConfig; }; export async function build({ - config: configV2, + configPath, + config, srcDir, foundryProfile = process.env.FOUNDRY_PROFILE, }: BuildOptions): Promise { - const config = worldToV1(configV2); - const outPath = path.join(srcDir, config.codegenDirectory); + const outPath = path.join(srcDir, config.codegen.outputDirectory); const remappings = await getRemappings(foundryProfile); await Promise.all([ - tablegen(configV2, outPath, remappings), - worldgen(configV2, getExistingContracts(srcDir), outPath), + tablegen({ configPath, config, remappings }), + worldgen(config, getExistingContracts(srcDir), outPath), ]); await forge(["build"], { profile: foundryProfile }); diff --git a/packages/cli/src/commands/build.ts b/packages/cli/src/commands/build.ts index 39dee7e71c..abc37486f4 100644 --- a/packages/cli/src/commands/build.ts +++ b/packages/cli/src/commands/build.ts @@ -1,5 +1,5 @@ import type { CommandModule } from "yargs"; -import { loadConfig } from "@latticexyz/config/node"; +import { loadConfig, resolveConfigPath } from "@latticexyz/config/node"; import { World as WorldConfig } from "@latticexyz/world"; import { getSrcDirectory } from "@latticexyz/common/foundry"; @@ -22,11 +22,12 @@ const commandModule: CommandModule = { }); }, - async handler({ configPath, profile }) { + async handler(opts) { + const configPath = await resolveConfigPath(opts.configPath); const config = (await loadConfig(configPath)) as WorldConfig; const srcDir = await getSrcDirectory(); - await build({ config, srcDir, foundryProfile: profile }); + await build({ configPath, config, srcDir, foundryProfile: opts.profile }); process.exit(0); }, diff --git a/packages/cli/src/commands/tablegen.ts b/packages/cli/src/commands/tablegen.ts index bf237e99dc..210b2885f2 100644 --- a/packages/cli/src/commands/tablegen.ts +++ b/packages/cli/src/commands/tablegen.ts @@ -1,9 +1,8 @@ -import path from "path"; import type { CommandModule } from "yargs"; -import { loadConfig } from "@latticexyz/config/node"; +import { loadConfig, resolveConfigPath } from "@latticexyz/config/node"; import { Store as StoreConfig } from "@latticexyz/store"; import { tablegen } from "@latticexyz/store/codegen"; -import { getRemappings, getSrcDirectory } from "@latticexyz/common/foundry"; +import { getRemappings } from "@latticexyz/common/foundry"; type Options = { configPath?: string; @@ -20,12 +19,12 @@ const commandModule: CommandModule = { }); }, - async handler({ configPath }) { + async handler(opts) { + const configPath = await resolveConfigPath(opts.configPath); const config = (await loadConfig(configPath)) as StoreConfig; - const srcDir = await getSrcDirectory(); const remappings = await getRemappings(); - await tablegen(config, path.join(srcDir, config.codegen.outputDirectory), remappings); + await tablegen({ configPath, config, remappings }); process.exit(0); }, diff --git a/packages/cli/src/runDeploy.ts b/packages/cli/src/runDeploy.ts index e9619fd6a3..ce9f48fb75 100644 --- a/packages/cli/src/runDeploy.ts +++ b/packages/cli/src/runDeploy.ts @@ -4,7 +4,7 @@ import { InferredOptionTypes, Options } from "yargs"; import { deploy } from "./deploy/deploy"; import { createWalletClient, http, Hex, isHex } from "viem"; import { privateKeyToAccount } from "viem/accounts"; -import { loadConfig } from "@latticexyz/config/node"; +import { loadConfig, resolveConfigPath } from "@latticexyz/config/node"; import { World as WorldConfig } from "@latticexyz/world"; import { worldToV1 } from "@latticexyz/world/config/v2"; import { getOutDirectory, getRpcUrl, getSrcDirectory } from "@latticexyz/common/foundry"; @@ -64,7 +64,8 @@ export async function runDeploy(opts: DeployOptions): Promise { const profile = opts.profile ?? process.env.FOUNDRY_PROFILE; - const configV2 = (await loadConfig(opts.configPath)) as WorldConfig; + const configPath = await resolveConfigPath(opts.configPath); + const configV2 = (await loadConfig(configPath)) as WorldConfig; const config = worldToV1(configV2); if (opts.printConfig) { console.log(chalk.green("\nResolved config:\n"), JSON.stringify(config, null, 2)); @@ -82,7 +83,7 @@ export async function runDeploy(opts: DeployOptions): Promise { // Run build if (!opts.skipBuild) { - await build({ config: configV2, srcDir, foundryProfile: profile }); + await build({ configPath, config: configV2, srcDir, foundryProfile: profile }); } const resolvedConfig = resolveConfig({ config, forgeSourceDir: srcDir, forgeOutDir: outDir }); diff --git a/packages/store/mud.config.ts b/packages/store/mud.config.ts index c5fd5335e1..5c779cd700 100644 --- a/packages/store/mud.config.ts +++ b/packages/store/mud.config.ts @@ -4,7 +4,7 @@ export default defineStore({ codegen: { storeImportPath: "../../", }, - namespace: "store" as const, + namespace: "store", userTypes: { ResourceId: { filePath: "./src/ResourceId.sol", type: "bytes32" }, FieldLayout: { filePath: "./src/FieldLayout.sol", type: "bytes32" }, diff --git a/packages/store/test/codegen/tables/Callbacks.sol b/packages/store/test/codegen/tables/Callbacks.sol index 07425feccf..3def318d75 100644 --- a/packages/store/test/codegen/tables/Callbacks.sol +++ b/packages/store/test/codegen/tables/Callbacks.sol @@ -17,8 +17,8 @@ import { EncodedLengths, EncodedLengthsLib } from "../../../src/EncodedLengths.s import { ResourceId } from "../../../src/ResourceId.sol"; library Callbacks { - // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "store", name: "Callbacks", typeId: RESOURCE_TABLE });` - ResourceId constant _tableId = ResourceId.wrap(0x746273746f726500000000000000000043616c6c6261636b7300000000000000); + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "Callbacks", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x7462000000000000000000000000000043616c6c6261636b7300000000000000); FieldLayout constant _fieldLayout = FieldLayout.wrap(0x0000000100000000000000000000000000000000000000000000000000000000); diff --git a/packages/store/test/codegen/tables/KeyEncoding.sol b/packages/store/test/codegen/tables/KeyEncoding.sol index 649ad7f52a..6252ff5200 100644 --- a/packages/store/test/codegen/tables/KeyEncoding.sol +++ b/packages/store/test/codegen/tables/KeyEncoding.sol @@ -20,8 +20,8 @@ import { ResourceId } from "../../../src/ResourceId.sol"; import { ExampleEnum } from "./../common.sol"; library KeyEncoding { - // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "store", name: "KeyEncoding", typeId: RESOURCE_TABLE });` - ResourceId constant _tableId = ResourceId.wrap(0x746273746f72650000000000000000004b6579456e636f64696e670000000000); + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "KeyEncoding", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x746200000000000000000000000000004b6579456e636f64696e670000000000); FieldLayout constant _fieldLayout = FieldLayout.wrap(0x0001010001000000000000000000000000000000000000000000000000000000); diff --git a/packages/store/test/codegen/tables/Mixed.sol b/packages/store/test/codegen/tables/Mixed.sol index 2d3116a9e4..c94148c914 100644 --- a/packages/store/test/codegen/tables/Mixed.sol +++ b/packages/store/test/codegen/tables/Mixed.sol @@ -24,8 +24,8 @@ struct MixedData { } library Mixed { - // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "store", name: "Mixed", typeId: RESOURCE_TABLE });` - ResourceId constant _tableId = ResourceId.wrap(0x746273746f72650000000000000000004d697865640000000000000000000000); + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "Mixed", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x746200000000000000000000000000004d697865640000000000000000000000); FieldLayout constant _fieldLayout = FieldLayout.wrap(0x0014020204100000000000000000000000000000000000000000000000000000); diff --git a/packages/store/test/codegen/tables/Vector2.sol b/packages/store/test/codegen/tables/Vector2.sol index e52a8a1585..661678874b 100644 --- a/packages/store/test/codegen/tables/Vector2.sol +++ b/packages/store/test/codegen/tables/Vector2.sol @@ -22,8 +22,8 @@ struct Vector2Data { } library Vector2 { - // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "store", name: "Vector2", typeId: RESOURCE_TABLE });` - ResourceId constant _tableId = ResourceId.wrap(0x746273746f7265000000000000000000566563746f7232000000000000000000); + // Hex below is the result of `WorldResourceIdLib.encode({ namespace: "", name: "Vector2", typeId: RESOURCE_TABLE });` + ResourceId constant _tableId = ResourceId.wrap(0x74620000000000000000000000000000566563746f7232000000000000000000); FieldLayout constant _fieldLayout = FieldLayout.wrap(0x0008020004040000000000000000000000000000000000000000000000000000); diff --git a/packages/store/ts/codegen/tableOptions.ts b/packages/store/ts/codegen/tableOptions.ts index 208fc42e6e..2922f1d2f2 100644 --- a/packages/store/ts/codegen/tableOptions.ts +++ b/packages/store/ts/codegen/tableOptions.ts @@ -9,8 +9,10 @@ import { SolidityUserDefinedType, } from "@latticexyz/common/codegen"; import { RenderTableOptions } from "./types"; -import { StoreConfig } from "../config"; import { getSchemaTypeInfo, importForAbiOrUserType, resolveAbiOrUserType } from "./userType"; +import { Store as StoreConfig } from "../config/v2/output"; +import { storeToV1 } from "../config/v2/compat"; +import { getKeySchema, getValueSchema } from "@latticexyz/protocol-parser/internal"; export interface TableOptions { /** Path where the file is expected to be written (relative to project root) */ @@ -28,52 +30,58 @@ export function getTableOptions( config: StoreConfig, solidityUserTypes: Record, ): TableOptions[] { - const storeImportPath = config.storeImportPath; + const configV1 = storeToV1(config); - const options = []; - for (const tableName of Object.keys(config.tables)) { - const tableData = config.tables[tableName]; + const options = Object.values(config.tables).map((table): TableOptions => { + const keySchema = getKeySchema(table); + const valueSchema = getValueSchema(table); // struct adds methods to get/set all values at once - const withStruct = tableData.dataStruct; + const withStruct = table.codegen.dataStruct; // operate on all fields at once; always render for offchain tables; for only 1 field keep them if struct is also kept - const withRecordMethods = withStruct || tableData.offchainOnly || Object.keys(tableData.valueSchema).length > 1; + const withRecordMethods = withStruct || table.type === "offchainTable" || Object.keys(valueSchema).length > 1; // field methods can include simply get/set if there's only 1 field and no record methods - const withSuffixlessFieldMethods = !withRecordMethods && Object.keys(tableData.valueSchema).length === 1; + const withSuffixlessFieldMethods = !withRecordMethods && Object.keys(valueSchema).length === 1; // list of any symbols that need to be imported const imports: ImportDatum[] = []; - const keyTuple = Object.keys(tableData.keySchema).map((name) => { - const abiOrUserType = tableData.keySchema[name]; - const { renderType } = resolveAbiOrUserType(abiOrUserType, config, solidityUserTypes); + const keyTuple = Object.entries(keySchema).map(([name, field]): RenderKeyTuple => { + const abiOrUserType = field.internalType; + const { renderType } = resolveAbiOrUserType(abiOrUserType, configV1, solidityUserTypes); - const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config, solidityUserTypes); + const importDatum = importForAbiOrUserType( + abiOrUserType, + table.codegen.outputDirectory, + configV1, + solidityUserTypes, + ); if (importDatum) imports.push(importDatum); - if (renderType.isDynamic) throw new Error(`Parsing error: found dynamic key ${name} in table ${tableName}`); - - const keyTuple: RenderKeyTuple = { + return { ...renderType, name, isDynamic: false, }; - return keyTuple; }); - const fields = Object.keys(tableData.valueSchema).map((name) => { - const abiOrUserType = tableData.valueSchema[name]; - const { renderType, schemaType } = resolveAbiOrUserType(abiOrUserType, config, solidityUserTypes); + const fields = Object.entries(valueSchema).map(([name, field]): RenderField => { + const abiOrUserType = field.internalType; + const { renderType, schemaType } = resolveAbiOrUserType(abiOrUserType, configV1, solidityUserTypes); - const importDatum = importForAbiOrUserType(abiOrUserType, tableData.directory, config, solidityUserTypes); + const importDatum = importForAbiOrUserType( + abiOrUserType, + table.codegen.outputDirectory, + configV1, + solidityUserTypes, + ); if (importDatum) imports.push(importDatum); const elementType = SchemaTypeArrayToElement[schemaType]; - const field: RenderField = { + return { ...renderType, arrayElement: elementType !== undefined ? getSchemaTypeInfo(elementType) : undefined, name, }; - return field; }); const staticFields = fields.filter(({ isDynamic }) => !isDynamic) as RenderStaticField[]; @@ -81,34 +89,35 @@ export function getTableOptions( // With tableIdArgument: tableId is a dynamic argument for each method // Without tableIdArgument: tableId is a file-level constant generated from `staticResourceData` - const staticResourceData = tableData.tableIdArgument + const staticResourceData = table.codegen.tableIdArgument ? undefined : { - namespace: config.namespace, - name: tableData.name, - offchainOnly: tableData.offchainOnly, + namespace: table.namespace, + name: table.name, + offchainOnly: table.type === "offchainTable", }; - options.push({ - outputPath: path.join(tableData.directory, `${tableName}.sol`), - tableName, + return { + outputPath: path.join(table.codegen.outputDirectory, `${table.name}.sol`), + tableName: table.name, renderOptions: { imports, - libraryName: tableName, - structName: withStruct ? tableName + "Data" : undefined, + libraryName: table.name, + structName: withStruct ? table.name + "Data" : undefined, staticResourceData, - storeImportPath, + storeImportPath: config.codegen.storeImportPath, keyTuple, fields, staticFields, dynamicFields, - withGetters: !tableData.offchainOnly, + withGetters: table.type === "table", withRecordMethods, - withDynamicFieldMethods: !tableData.offchainOnly, + withDynamicFieldMethods: table.type === "table", withSuffixlessFieldMethods, - storeArgument: tableData.storeArgument, + storeArgument: table.codegen.storeArgument, }, - }); - } + }; + }); + return options; } diff --git a/packages/store/ts/codegen/tablegen.ts b/packages/store/ts/codegen/tablegen.ts index baa78e8bd1..95c337b5f8 100644 --- a/packages/store/ts/codegen/tablegen.ts +++ b/packages/store/ts/codegen/tablegen.ts @@ -1,4 +1,4 @@ -import path from "path"; +import path from "node:path"; import { formatAndWriteSolidity, loadAndExtractUserTypes } from "@latticexyz/common/codegen"; import { getTableOptions } from "./tableOptions"; import { renderTable } from "./renderTable"; @@ -8,22 +8,29 @@ import { rm } from "fs/promises"; import { Store as StoreConfig } from "../config/v2/output"; import { storeToV1 } from "../config/v2/compat"; -export async function tablegen(configV2: StoreConfig, outputBaseDirectory: string, remappings: [string, string][]) { - const config = storeToV1(configV2); - const solidityUserTypes = loadAndExtractUserTypes(config.userTypes, outputBaseDirectory, remappings); +export type TablegenOptions = { + configPath: string; + config: StoreConfig; + remappings: [string, string][]; +}; + +export async function tablegen({ configPath, config, remappings }: TablegenOptions) { + const outputDirectory = path.join(path.dirname(configPath), config.sourceDirectory, config.codegen.outputDirectory); + const configV1 = storeToV1(config); + const solidityUserTypes = loadAndExtractUserTypes(configV1.userTypes, outputDirectory, remappings); const allTableOptions = getTableOptions(config, solidityUserTypes); const uniqueTableDirectories = Array.from(new Set(allTableOptions.map(({ outputPath }) => path.dirname(outputPath)))); await Promise.all( uniqueTableDirectories.map(async (tableDir) => { - await rm(path.join(outputBaseDirectory, tableDir), { recursive: true, force: true }); + await rm(path.join(outputDirectory, tableDir), { recursive: true, force: true }); }), ); // write tables to files await Promise.all( allTableOptions.map(async ({ outputPath, renderOptions }) => { - const fullOutputPath = path.join(outputBaseDirectory, outputPath); + const fullOutputPath = path.join(outputDirectory, outputPath); const output = renderTable(renderOptions); await formatAndWriteSolidity(output, fullOutputPath, "Generated table"); }), @@ -31,15 +38,15 @@ export async function tablegen(configV2: StoreConfig, outputBaseDirectory: strin // write table index if (allTableOptions.length > 0) { - const fullOutputPath = path.join(outputBaseDirectory, config.codegenIndexFilename); + const fullOutputPath = path.join(outputDirectory, configV1.codegenIndexFilename); const output = renderTableIndex(allTableOptions); await formatAndWriteSolidity(output, fullOutputPath, "Generated table index"); } // write types to file - if (Object.keys(config.enums).length > 0) { - const fullOutputPath = path.join(outputBaseDirectory, config.userTypesFilename); - const output = renderTypesFromConfig(config); + if (Object.keys(configV1.enums).length > 0) { + const fullOutputPath = path.join(outputDirectory, configV1.userTypesFilename); + const output = renderTypesFromConfig(configV1); await formatAndWriteSolidity(output, fullOutputPath, "Generated types file"); } } diff --git a/packages/store/ts/config/storeConfig.ts b/packages/store/ts/config/storeConfig.ts index 9f73ebf54a..2a93de70b3 100644 --- a/packages/store/ts/config/storeConfig.ts +++ b/packages/store/ts/config/storeConfig.ts @@ -145,7 +145,7 @@ export interface ExpandTableConfig, TableN extends OrDefaults< T, { - directory: typeof TABLE_DEFAULTS.directory; + directory: string; name: TableName; tableIdArgument: typeof TABLE_DEFAULTS.tableIdArgument; storeArgument: typeof TABLE_DEFAULTS.storeArgument; diff --git a/packages/store/ts/config/v2/compat.ts b/packages/store/ts/config/v2/compat.ts index 185e0a0744..3bd1a80449 100644 --- a/packages/store/ts/config/v2/compat.ts +++ b/packages/store/ts/config/v2/compat.ts @@ -27,7 +27,7 @@ export type storeToV1 = store extends Store type schemaToV1 = { [key in keyof schema]: schema[key]["internalType"] }; export type tableToV1 = { - directory: table["codegen"]["outputDirectory"]; + directory: string; dataStruct: table["codegen"]["dataStruct"]; tableIdArgument: table["codegen"]["tableIdArgument"]; storeArgument: table["codegen"]["storeArgument"]; diff --git a/packages/store/ts/config/v2/defaults.ts b/packages/store/ts/config/v2/defaults.ts index a5499144fd..9c1899f343 100644 --- a/packages/store/ts/config/v2/defaults.ts +++ b/packages/store/ts/config/v2/defaults.ts @@ -1,35 +1,40 @@ +import { CodegenInput, StoreInput, TableCodegenInput, TableDeployInput, TableInput } from "./input"; + export const CODEGEN_DEFAULTS = { storeImportPath: "@latticexyz/store/src/", userTypesFilename: "common.sol", outputDirectory: "codegen", + // TODO: default to true if using top-level `namespaces` key (once its migrated to store) + namespaceDirectories: false, indexFilename: "index.sol", -} as const; +} as const satisfies CodegenInput; export type CODEGEN_DEFAULTS = typeof CODEGEN_DEFAULTS; export const TABLE_CODEGEN_DEFAULTS = { - outputDirectory: "tables", + outputDirectory: "tables" as string, tableIdArgument: false, storeArgument: false, -} as const; +} as const satisfies TableCodegenInput; export type TABLE_CODEGEN_DEFAULTS = typeof TABLE_CODEGEN_DEFAULTS; export const TABLE_DEPLOY_DEFAULTS = { disabled: false, -} as const; +} as const satisfies TableDeployInput; export type TABLE_DEPLOY_DEFAULTS = typeof TABLE_DEPLOY_DEFAULTS; export const TABLE_DEFAULTS = { namespace: "", type: "table", -} as const; +} as const satisfies Pick; export type TABLE_DEFAULTS = typeof TABLE_DEFAULTS; export const CONFIG_DEFAULTS = { + sourceDirectory: "src", namespace: "", -} as const; +} as const satisfies StoreInput; export type CONFIG_DEFAULTS = typeof CONFIG_DEFAULTS; diff --git a/packages/store/ts/config/v2/input.ts b/packages/store/ts/config/v2/input.ts index 89fa9c0cb8..60c6b2dbad 100644 --- a/packages/store/ts/config/v2/input.ts +++ b/packages/store/ts/config/v2/input.ts @@ -15,6 +15,9 @@ export type ScopedSchemaInput = { readonly [key: string]: keyof scope["types"]; }; +export type TableCodegenInput = Partial; +export type TableDeployInput = Partial; + export type TableInput = { readonly schema: SchemaInput; readonly key: readonly string[]; @@ -22,20 +25,29 @@ export type TableInput = { readonly name: string; readonly namespace?: string; readonly type?: "table" | "offchainTable"; - readonly codegen?: Partial; - readonly deploy?: Partial; + readonly codegen?: TableCodegenInput; + readonly deploy?: TableDeployInput; }; export type TablesInput = { readonly [key: string]: Omit; }; +export type CodegenInput = Partial; + export type StoreInput = { + /** + * Directory of Solidity source relative to the MUD config. + * This is used to resolve other paths in the config, like codegen and user types. + * + * Defaults to `src` to match `foundry.toml`'s default. If you change this from the default, you may also need to configure foundry with the same source directory. + */ + readonly sourceDirectory?: string; readonly namespace?: string; readonly tables?: TablesInput; readonly userTypes?: UserTypes; readonly enums?: EnumsInput; - readonly codegen?: Partial; + readonly codegen?: CodegenInput; }; /******** Variations with shorthands ********/ diff --git a/packages/store/ts/config/v2/output.ts b/packages/store/ts/config/v2/output.ts index 2d13f56677..9db233f7d6 100644 --- a/packages/store/ts/config/v2/output.ts +++ b/packages/store/ts/config/v2/output.ts @@ -18,6 +18,11 @@ export type EnumValues = { }; export type TableCodegen = { + /** + * Directory to output codegenerated files relative to config's `codegen.outputDirectory`. + * + * Defaults to `tables`. + */ readonly outputDirectory: string; readonly tableIdArgument: boolean; readonly storeArgument: boolean; @@ -36,13 +41,35 @@ export type Table = evaluate< >; export type Codegen = { + /** @internal */ readonly storeImportPath: string; readonly userTypesFilename: string; + /** + * Directory to output codegenerated files relative to config's `sourceDirectory`. + * + * Defaults to `codegen`. + */ readonly outputDirectory: string; + /** + * Whether or not to organize codegen output (table libraries, etc.) into directories by namespace. + * + * For example, a `Counter` table in the `app` namespace will have codegen at `codegen/app/tables/Counter.sol`. + * + * Defaults to `true` when using top-level `namespaces` key, `false` otherwise. + */ + // TODO: move `namespaces` key handling into store so we can conditionally turn this on/off + readonly namespaceDirectories: boolean; readonly indexFilename: string; }; export type Store = { + /** + * Directory of contracts source (i.e. Solidity) relative to the MUD config. + * This is used to resolve other paths in the config, like codegen and user types. + * + * Defaults to `src` to match `foundry.toml`'s default. If you change this from the default, you may also need to configure foundry with the same source directory. + */ + readonly sourceDirectory: string; readonly tables: { readonly [namespacedTableName: string]: Table; }; diff --git a/packages/store/ts/config/v2/store.test.ts b/packages/store/ts/config/v2/store.test.ts index d89baccf70..ade2f1809d 100644 --- a/packages/store/ts/config/v2/store.test.ts +++ b/packages/store/ts/config/v2/store.test.ts @@ -17,6 +17,7 @@ describe("defineStore", () => { }); const expected = { + sourceDirectory: "src", tables: { Example: { tableId: resourceToHex({ type: "table", namespace: "", name: "Example" }), @@ -67,6 +68,7 @@ describe("defineStore", () => { }); const expected = { + sourceDirectory: "src", tables: { Example: { tableId: resourceToHex({ type: "table", namespace: "", name: "Example" }), @@ -116,6 +118,7 @@ describe("defineStore", () => { }); const expected = { + sourceDirectory: "src", tables: { Example: { tableId: resourceToHex({ type: "table", namespace: "", name: "Example" }), @@ -166,6 +169,7 @@ describe("defineStore", () => { }); const expected = { + sourceDirectory: "src", tables: { First: { tableId: resourceToHex({ type: "table", namespace: "", name: "First" }), @@ -243,6 +247,7 @@ describe("defineStore", () => { }); const expected = { + sourceDirectory: "src", tables: { First: { tableId: resourceToHex({ type: "table", namespace: "", name: "First" }), @@ -376,6 +381,7 @@ describe("defineStore", () => { }, }); const expected = { + sourceDirectory: "src", tables: { Example: { tableId: resourceToHex({ type: "table", namespace: "", name: "Example" }), @@ -545,4 +551,89 @@ describe("defineStore", () => { }), ).type.errors("`invalidOption` is not a valid Store config option."); }); + + it("should namespace output directories for tables", () => { + const config = defineStore({ + namespace: "app", + codegen: { + namespaceDirectories: true, + }, + tables: { + NamespaceDir: { + schema: { name: "string" }, + key: [], + }, + NotNamespaceDir: { + schema: { name: "string" }, + key: [], + codegen: { + outputDirectory: "tables", + }, + }, + }, + }); + + const expected = { + sourceDirectory: "src", + tables: { + app__NamespaceDir: { + tableId: resourceToHex({ type: "table", namespace: "app", name: "NamespaceDir" }), + schema: { + name: { + type: "string", + internalType: "string", + }, + }, + key: [], + name: "NamespaceDir", + namespace: "app", + codegen: { + ...TABLE_CODEGEN_DEFAULTS, + dataStruct: false as boolean, + outputDirectory: "app/tables" as string, + }, + type: "table", + deploy: TABLE_DEPLOY_DEFAULTS, + }, + app__NotNamespaceDir: { + tableId: resourceToHex({ type: "table", namespace: "app", name: "NotNamespaceDir" }), + schema: { + name: { + type: "string", + internalType: "string", + }, + }, + key: [], + name: "NotNamespaceDir", + namespace: "app", + codegen: { + ...TABLE_CODEGEN_DEFAULTS, + dataStruct: false as boolean, + outputDirectory: "tables", + }, + type: "table", + deploy: TABLE_DEPLOY_DEFAULTS, + }, + }, + userTypes: {}, + enums: {}, + enumValues: {}, + namespace: "app", + codegen: { + ...CODEGEN_DEFAULTS, + namespaceDirectories: true, + }, + } as const; + + // Running attest on the whole object is hard to parse when it fails, so test the inner objects first + attest(config.codegen).equals(expected.codegen); + attest(config.tables.app__NamespaceDir.codegen).equals( + expected.tables.app__NamespaceDir.codegen, + ); + attest(config.tables.app__NotNamespaceDir.codegen).equals( + expected.tables.app__NotNamespaceDir.codegen, + ); + + attest(config).equals(expected); + }); }); diff --git a/packages/store/ts/config/v2/store.ts b/packages/store/ts/config/v2/store.ts index c9312c6093..1337a38286 100644 --- a/packages/store/ts/config/v2/store.ts +++ b/packages/store/ts/config/v2/store.ts @@ -44,6 +44,9 @@ type keyPrefix = store extends { namespace: infer namespace extends strin : ""; export type resolveStore = { + readonly sourceDirectory: "sourceDirectory" extends keyof store + ? store["sourceDirectory"] + : CONFIG_DEFAULTS["sourceDirectory"]; readonly tables: "tables" extends keyof store ? resolveTables< { @@ -63,11 +66,24 @@ export type resolveStore = { }; export function resolveStore(store: store): resolveStore { + // TODO: default `namespaceDirectories` to true if using top-level `namespaces` key (once its migrated to store) + const codegen = resolveCodegen(store.codegen); return { + sourceDirectory: store.sourceDirectory ?? CONFIG_DEFAULTS["sourceDirectory"], tables: resolveTables( - flatMorph(store.tables ?? {}, (tableKey, table) => { - const key = store.namespace ? `${store.namespace}__${tableKey}` : tableKey; - return [key, mergeIfUndefined(table, { namespace: store.namespace, name: tableKey })]; + flatMorph(store.tables ?? {}, (name, table) => { + const namespace = store.namespace; + const key = namespace ? `${namespace}__${name}` : name; + return [ + key, + mergeIfUndefined(table, { + namespace: namespace, + name, + codegen: mergeIfUndefined(table.codegen ?? {}, { + outputDirectory: codegen.namespaceDirectories && namespace?.length ? `${namespace}/tables` : "tables", + }), + }), + ]; }), extendedScope(store), ), @@ -75,7 +91,7 @@ export function resolveStore(store: store): reso enums: resolveEnums(store.enums ?? {}), enumValues: mapEnums(store.enums ?? {}), namespace: store.namespace ?? CONFIG_DEFAULTS["namespace"], - codegen: resolveCodegen(store.codegen), + codegen, } as never; } diff --git a/packages/store/ts/config/v2/storeWithShorthands.test.ts b/packages/store/ts/config/v2/storeWithShorthands.test.ts index 831c3454c8..ce0a07de1a 100644 --- a/packages/store/ts/config/v2/storeWithShorthands.test.ts +++ b/packages/store/ts/config/v2/storeWithShorthands.test.ts @@ -9,6 +9,7 @@ describe("defineStoreWithShorthands", () => { it("should accept a shorthand store config as input and expand it", () => { const config = defineStoreWithShorthands({ tables: { Name: "address" } }); const expected = { + sourceDirectory: "src", tables: { Name: { tableId: resourceToHex({ type: "table", namespace: "", name: "Name" }), @@ -46,6 +47,7 @@ describe("defineStoreWithShorthands", () => { userTypes: { CustomType: { type: "address", filePath: "path/to/file" } }, }); const expected = { + sourceDirectory: "src", tables: { Name: { tableId: resourceToHex({ type: "table", namespace: "", name: "Name" }), @@ -83,6 +85,7 @@ describe("defineStoreWithShorthands", () => { tables: { Example: { id: "address", name: "string", age: "uint256" } }, }); const expected = { + sourceDirectory: "src", tables: { Example: { tableId: resourceToHex({ type: "table", namespace: "", name: "Example" }), @@ -124,6 +127,7 @@ describe("defineStoreWithShorthands", () => { }); const expected = { + sourceDirectory: "src", tables: { Example: { tableId: resourceToHex({ type: "table", namespace: "", name: "Example" }), diff --git a/packages/store/ts/config/v2/table.ts b/packages/store/ts/config/v2/table.ts index cd5f59003b..e07ef4863d 100644 --- a/packages/store/ts/config/v2/table.ts +++ b/packages/store/ts/config/v2/table.ts @@ -126,7 +126,7 @@ export function resolveTableCodegen(input: input): res storeArgument: get(options, "storeArgument") ?? TABLE_CODEGEN_DEFAULTS.storeArgument, // dataStruct is true if there are at least 2 value fields dataStruct: get(options, "dataStruct") ?? Object.keys(input.schema).length - input.key.length > 1, - } satisfies TableCodegen as resolveTableCodegen; + } satisfies TableCodegen as never; } export type resolveTable = input extends TableInput diff --git a/packages/store/ts/scripts/generate-test-tables.ts b/packages/store/ts/scripts/generate-test-tables.ts index b54bd841cf..5d7683d71f 100644 --- a/packages/store/ts/scripts/generate-test-tables.ts +++ b/packages/store/ts/scripts/generate-test-tables.ts @@ -1,14 +1,15 @@ -import path from "path"; -import { getRemappings, getSrcDirectory } from "@latticexyz/common/foundry"; +import { getRemappings } from "@latticexyz/common/foundry"; import { tablegen } from "../codegen"; import { defineStore } from "../config/v2/store"; +import { fileURLToPath } from "node:url"; + +const configPath = fileURLToPath(import.meta.url); const config = defineStore({ + sourceDirectory: "../../test", codegen: { storeImportPath: "../../../src/", - outputDirectory: "../test/codegen", }, - namespace: "store", enums: { ExampleEnum: ["None", "First", "Second", "Third"], }, @@ -50,7 +51,6 @@ const config = defineStore({ }, }); -const srcDir = await getSrcDirectory(); const remappings = await getRemappings(); -await tablegen(config, path.join(srcDir, config.codegen.outputDirectory), remappings); +await tablegen({ configPath, config, remappings }); diff --git a/packages/store/ts/scripts/tablegen.ts b/packages/store/ts/scripts/tablegen.ts index a0a413b894..7a255b21f1 100644 --- a/packages/store/ts/scripts/tablegen.ts +++ b/packages/store/ts/scripts/tablegen.ts @@ -1,11 +1,14 @@ -import path from "path"; -import { loadConfig } from "@latticexyz/config/node"; -import { getRemappings, getSrcDirectory } from "@latticexyz/common/foundry"; +import { loadConfig, resolveConfigPath } from "@latticexyz/config/node"; +import { getRemappings } from "@latticexyz/common/foundry"; import { tablegen } from "../codegen"; import { Store as StoreConfig } from "../config/v2/output"; -const config = (await loadConfig()) as StoreConfig; -const srcDir = await getSrcDirectory(); +const configPath = await resolveConfigPath(undefined); +const config = (await loadConfig(configPath)) as StoreConfig; const remappings = await getRemappings(); -await tablegen(config, path.join(srcDir, config.codegen.outputDirectory), remappings); +await tablegen({ + configPath, + config, + remappings, +}); diff --git a/packages/world-modules/ts/scripts/tablegen.ts b/packages/world-modules/ts/scripts/tablegen.ts index eff4998f7e..bac85728d6 100644 --- a/packages/world-modules/ts/scripts/tablegen.ts +++ b/packages/world-modules/ts/scripts/tablegen.ts @@ -1,11 +1,14 @@ -import path from "path"; -import { loadConfig } from "@latticexyz/config/node"; -import { getRemappings, getSrcDirectory } from "@latticexyz/common/foundry"; +import { loadConfig, resolveConfigPath } from "@latticexyz/config/node"; +import { getRemappings } from "@latticexyz/common/foundry"; import { Store as StoreConfig } from "@latticexyz/store"; import { tablegen } from "@latticexyz/store/codegen"; -const config = (await loadConfig()) as StoreConfig; -const srcDir = await getSrcDirectory(); +const configPath = await resolveConfigPath(undefined); +const config = (await loadConfig(configPath)) as StoreConfig; const remappings = await getRemappings(); -await tablegen(config, path.join(srcDir, config.codegen.outputDirectory), remappings); +await tablegen({ + configPath, + config, + remappings, +}); diff --git a/packages/world-modules/tsconfig.json b/packages/world-modules/tsconfig.json index e8a23b77e4..9060822400 100644 --- a/packages/world-modules/tsconfig.json +++ b/packages/world-modules/tsconfig.json @@ -15,5 +15,5 @@ "strict": true, "skipLibCheck": true }, - "include": ["mud.config.ts"] + "include": ["mud.config.ts", "ts"] } diff --git a/packages/world/mud.config.ts b/packages/world/mud.config.ts index 882c4599a3..6ce75e044f 100644 --- a/packages/world/mud.config.ts +++ b/packages/world/mud.config.ts @@ -6,7 +6,7 @@ export default defineWorld({ worldgenDirectory: "interfaces", worldInterfaceName: "IBaseWorld", }, - namespace: "world" as const, // NOTE: this namespace is only used for tables, the core system is deployed in the root namespace. + namespace: "world", // NOTE: this namespace is only used for tables, the core system is deployed in the root namespace. userTypes: { ResourceId: { filePath: "@latticexyz/store/src/ResourceId.sol", type: "bytes32" }, }, @@ -88,7 +88,9 @@ export default defineWorld({ systemFunctionSelector: "bytes4", }, key: ["worldFunctionSelector"], - codegen: { dataStruct: false }, + codegen: { + dataStruct: false, + }, }, FunctionSignatures: { type: "offchainTable", diff --git a/packages/world/ts/config/v2/defaults.ts b/packages/world/ts/config/v2/defaults.ts index 8e6297f552..48fadb1af1 100644 --- a/packages/world/ts/config/v2/defaults.ts +++ b/packages/world/ts/config/v2/defaults.ts @@ -1,8 +1,10 @@ +import { CodegenInput, DeployInput, ModuleInput, SystemInput, WorldInput } from "./input"; + export const SYSTEM_DEFAULTS = { registerFunctionSelectors: true, openAccess: true, accessList: [], -} as const; +} as const satisfies SystemInput; export type SYSTEM_DEFAULTS = typeof SYSTEM_DEFAULTS; @@ -10,7 +12,7 @@ export const MODULE_DEFAULTS = { root: false, args: [], artifactPath: undefined, -} as const; +} as const satisfies Pick; export type MODULE_DEFAULTS = typeof MODULE_DEFAULTS; @@ -18,7 +20,7 @@ export const CODEGEN_DEFAULTS = { worldInterfaceName: "IWorld", worldgenDirectory: "world", worldImportPath: "@latticexyz/world/src/", -} as const; +} as const satisfies CodegenInput; export type CODEGEN_DEFAULTS = typeof CODEGEN_DEFAULTS; @@ -28,7 +30,7 @@ export const DEPLOY_DEFAULTS = { deploysDirectory: "./deploys", worldsFile: "./worlds.json", upgradeableWorldImplementation: false, -} as const; +} as const satisfies DeployInput; export type DEPLOY_DEFAULTS = typeof DEPLOY_DEFAULTS; @@ -39,6 +41,6 @@ export const CONFIG_DEFAULTS = { modules: [], codegen: CODEGEN_DEFAULTS, deploy: DEPLOY_DEFAULTS, -} as const; +} as const satisfies WorldInput; export type CONFIG_DEFAULTS = typeof CONFIG_DEFAULTS; diff --git a/packages/world/ts/config/v2/input.ts b/packages/world/ts/config/v2/input.ts index 6e784cabfc..f8e8927047 100644 --- a/packages/world/ts/config/v2/input.ts +++ b/packages/world/ts/config/v2/input.ts @@ -54,6 +54,9 @@ export type ModuleInput = ModuleInputArtifactPath & { }; export type DeployInput = { + /** The name of a custom World contract to deploy. If no name is provided, a default MUD World is deployed. */ + // TODO: implement + customWorldContract?: never; /** * Script to execute after the deployment is complete (Default "PostDeploy"). * Script must be placed in the forge scripts directory (see foundry.toml) and have a ".s.sol" extension. diff --git a/packages/world/ts/config/v2/output.ts b/packages/world/ts/config/v2/output.ts index 618d55002c..72f2354019 100644 --- a/packages/world/ts/config/v2/output.ts +++ b/packages/world/ts/config/v2/output.ts @@ -63,7 +63,10 @@ export type Codegen = { readonly worldInterfaceName: string; /** Directory to output system and world interfaces of `worldgen` (Default "world") */ readonly worldgenDirectory: string; - /** Path for world package imports. Default is "@latticexyz/world/src/" */ + /** + * Path for world package imports. Default is "@latticexyz/world/src/" + * @internal + */ readonly worldImportPath: string; }; diff --git a/packages/world/ts/config/v2/world.test.ts b/packages/world/ts/config/v2/world.test.ts index 31f91920a3..ccc069c855 100644 --- a/packages/world/ts/config/v2/world.test.ts +++ b/packages/world/ts/config/v2/world.test.ts @@ -3,12 +3,19 @@ import { defineWorld } from "./world"; import { attest } from "@arktype/attest"; import { resourceToHex } from "@latticexyz/common"; import { + CONFIG_DEFAULTS as STORE_CONFIG_DEFAULTS, TABLE_CODEGEN_DEFAULTS, CODEGEN_DEFAULTS as STORE_CODEGEN_DEFAULTS, TABLE_DEPLOY_DEFAULTS, } from "@latticexyz/store/config/v2"; -import { CODEGEN_DEFAULTS as WORLD_CODEGEN_DEFAULTS, DEPLOY_DEFAULTS, CONFIG_DEFAULTS } from "./defaults"; +import { + CODEGEN_DEFAULTS as WORLD_CODEGEN_DEFAULTS, + DEPLOY_DEFAULTS, + CONFIG_DEFAULTS as WORLD_CONFIG_DEFAULTS, +} from "./defaults"; import { World } from "./output"; + +const CONFIG_DEFAULTS = { ...STORE_CONFIG_DEFAULTS, ...WORLD_CONFIG_DEFAULTS }; const CODEGEN_DEFAULTS = { ...STORE_CODEGEN_DEFAULTS, ...WORLD_CODEGEN_DEFAULTS }; describe("defineWorld", () => { diff --git a/packages/world/ts/config/v2/worldWithShorthands.test.ts b/packages/world/ts/config/v2/worldWithShorthands.test.ts index d7910cce59..c7ec8e2be7 100644 --- a/packages/world/ts/config/v2/worldWithShorthands.test.ts +++ b/packages/world/ts/config/v2/worldWithShorthands.test.ts @@ -3,11 +3,14 @@ import { defineWorldWithShorthands } from "./worldWithShorthands"; import { attest } from "@arktype/attest"; import { resourceToHex } from "@latticexyz/common"; import { + CONFIG_DEFAULTS as STORE_CONFIG_DEFAULTS, TABLE_CODEGEN_DEFAULTS, CODEGEN_DEFAULTS as STORE_CODEGEN_DEFAULTS, TABLE_DEPLOY_DEFAULTS, } from "@latticexyz/store/config/v2"; -import { CODEGEN_DEFAULTS as WORLD_CODEGEN_DEFAULTS, CONFIG_DEFAULTS } from "./defaults"; +import { CODEGEN_DEFAULTS as WORLD_CODEGEN_DEFAULTS, CONFIG_DEFAULTS as WORLD_CONFIG_DEFAULTS } from "./defaults"; + +const CONFIG_DEFAULTS = { ...STORE_CONFIG_DEFAULTS, ...WORLD_CONFIG_DEFAULTS }; const CODEGEN_DEFAULTS = { ...STORE_CODEGEN_DEFAULTS, ...WORLD_CODEGEN_DEFAULTS }; describe("defineWorldWithShorthands", () => { diff --git a/packages/world/ts/scripts/generate-test-tables.ts b/packages/world/ts/scripts/generate-test-tables.ts index 8c70024133..4f310140a6 100644 --- a/packages/world/ts/scripts/generate-test-tables.ts +++ b/packages/world/ts/scripts/generate-test-tables.ts @@ -1,19 +1,21 @@ -import path from "path"; -import { getRemappings, getSrcDirectory } from "@latticexyz/common/foundry"; +import { getRemappings } from "@latticexyz/common/foundry"; import { tablegen } from "@latticexyz/store/codegen"; import { defineWorld } from "../config/v2/world"; +import { fileURLToPath } from "node:url"; + +const configPath = fileURLToPath(import.meta.url); const config = defineWorld({ - codegen: { - outputDirectory: "../test/codegen", - }, + sourceDirectory: "../../test", tables: { Bool: { schema: { value: "bool", }, key: [], - codegen: { tableIdArgument: true }, + codegen: { + tableIdArgument: true, + }, }, TwoFields: { schema: { @@ -21,7 +23,9 @@ const config = defineWorld({ value2: "bool", }, key: [], - codegen: { tableIdArgument: true }, + codegen: { + tableIdArgument: true, + }, }, AddressArray: { schema: { @@ -29,12 +33,13 @@ const config = defineWorld({ value: "address[]", }, key: ["key"], - codegen: { tableIdArgument: true }, + codegen: { + tableIdArgument: true, + }, }, }, }); -const srcDir = await getSrcDirectory(); const remappings = await getRemappings(); -await tablegen(config, path.join(srcDir, config.codegen.outputDirectory), remappings); +await tablegen({ configPath, config, remappings }); diff --git a/packages/world/ts/scripts/tablegen.ts b/packages/world/ts/scripts/tablegen.ts index eff4998f7e..bac85728d6 100644 --- a/packages/world/ts/scripts/tablegen.ts +++ b/packages/world/ts/scripts/tablegen.ts @@ -1,11 +1,14 @@ -import path from "path"; -import { loadConfig } from "@latticexyz/config/node"; -import { getRemappings, getSrcDirectory } from "@latticexyz/common/foundry"; +import { loadConfig, resolveConfigPath } from "@latticexyz/config/node"; +import { getRemappings } from "@latticexyz/common/foundry"; import { Store as StoreConfig } from "@latticexyz/store"; import { tablegen } from "@latticexyz/store/codegen"; -const config = (await loadConfig()) as StoreConfig; -const srcDir = await getSrcDirectory(); +const configPath = await resolveConfigPath(undefined); +const config = (await loadConfig(configPath)) as StoreConfig; const remappings = await getRemappings(); -await tablegen(config, path.join(srcDir, config.codegen.outputDirectory), remappings); +await tablegen({ + configPath, + config, + remappings, +});