Skip to content

Commit

Permalink
feat(store): add internalType property to user types config for typ…
Browse files Browse the repository at this point in the history
…e inference (#1587)
  • Loading branch information
alvrs committed Sep 24, 2023
1 parent 0b8ce3f commit 24a6cd5
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 13 deletions.
7 changes: 7 additions & 0 deletions .changeset/thin-chairs-compare.md
@@ -0,0 +1,7 @@
---
"@latticexyz/cli": patch
"@latticexyz/common": patch
"@latticexyz/store": major
---

Changed the `userTypes` property to accept `{ filePath: string, internalType: SchemaAbiType }` to enable strong type inference from the config.
10 changes: 5 additions & 5 deletions packages/cli/scripts/generate-test-tables.ts
Expand Up @@ -83,11 +83,11 @@ try {
},

userTypes: {
TestTypeAddress: "./contracts/src/types.sol",
TestTypeInt64: "./contracts/src/types.sol",
TestTypeBool: "./contracts/src/types.sol",
TestTypeUint128: "./contracts/src/types.sol",
ResourceId: "@latticexyz/store/src/ResourceId.sol",
TestTypeAddress: { filePath: "./contracts/src/types.sol", internalType: "address" },
TestTypeInt64: { filePath: "./contracts/src/types.sol", internalType: "int64" },
TestTypeBool: { filePath: "./contracts/src/types.sol", internalType: "bool" },
TestTypeUint128: { filePath: "./contracts/src/types.sol", internalType: "uint128" },
ResourceId: { filePath: "@latticexyz/store/src/ResourceId.sol", internalType: "bytes32" },
},
});
} catch (error: unknown) {
Expand Down
23 changes: 20 additions & 3 deletions packages/common/src/codegen/utils/loadUserTypesFile.ts
@@ -1,14 +1,20 @@
import { readFileSync } from "fs";
import path from "path";
import { SolidityUserDefinedType, extractUserTypes } from "./extractUserTypes";
import { MUDError } from "../../errors";

export type UserType = {
filePath: string;
internalType: string;
};

export function loadAndExtractUserTypes(
userTypes: Record<string, string>,
userTypes: Record<string, UserType>,
outputBaseDirectory: string,
remappings: [string, string][]
): Record<string, SolidityUserDefinedType> {
const userTypesPerFile: Record<string, string[]> = {};
for (const [userTypeName, unresolvedFilePath] of Object.entries(userTypes)) {
for (const [userTypeName, { filePath: unresolvedFilePath }] of Object.entries(userTypes)) {
if (!(unresolvedFilePath in userTypesPerFile)) {
userTypesPerFile[unresolvedFilePath] = [];
}
Expand All @@ -17,7 +23,18 @@ export function loadAndExtractUserTypes(
let extractedUserTypes: Record<string, SolidityUserDefinedType> = {};
for (const [unresolvedFilePath, userTypeNames] of Object.entries(userTypesPerFile)) {
const { filePath, data } = loadUserTypesFile(outputBaseDirectory, unresolvedFilePath, remappings);
extractedUserTypes = Object.assign(userTypes, extractUserTypes(data, userTypeNames, filePath));
const userTypesInFile = extractUserTypes(data, userTypeNames, filePath);

// Verify the actual user type matches the internalType specified in the config
for (const [userTypeName, userType] of Object.entries(userTypesInFile)) {
if (userType.internalTypeId !== userTypes[userTypeName].internalType) {
throw new MUDError(
`User type "${userTypeName}" has internal type "${userType.internalTypeId}" but config specifies "${userTypes[userTypeName].internalType}"`
);
}
}

extractedUserTypes = Object.assign(extractedUserTypes, userTypesInFile);
}
return extractedUserTypes;
}
Expand Down
16 changes: 11 additions & 5 deletions packages/store/ts/config/storeConfig.ts
Expand Up @@ -22,6 +22,7 @@ import {
zName,
} from "@latticexyz/config";
import { DEFAULTS, PATH_DEFAULTS, TABLE_DEFAULTS } from "./defaults";
import { UserType } from "@latticexyz/common/codegen";

const zTableName = zObjectName;
const zKeyName = zValueName;
Expand Down Expand Up @@ -241,7 +242,7 @@ export const zEnumsConfig = z.object({
*
************************************************************************/

export type UserTypesConfig<UserTypeNames extends StringForUnion> = never extends UserTypeNames
export type UserTypesConfig<UserTypeNames extends StringForUnion = StringForUnion> = never extends UserTypeNames
? {
/**
* User types mapped to file paths from which to import them.
Expand All @@ -250,7 +251,7 @@ export type UserTypesConfig<UserTypeNames extends StringForUnion> = never extend
*
* (user types are inferred to be absent)
*/
userTypes?: Record<UserTypeNames, string>;
userTypes?: Record<UserTypeNames, UserType>;
}
: StringForUnion extends UserTypeNames
? {
Expand All @@ -261,7 +262,7 @@ export type UserTypesConfig<UserTypeNames extends StringForUnion> = never extend
*
* (user types aren't inferred - use `mudConfig` or `storeConfig` helper, and `as const` for variables)
*/
userTypes?: Record<UserTypeNames, string>;
userTypes?: Record<UserTypeNames, UserType>;
}
: {
/**
Expand All @@ -271,15 +272,20 @@ export type UserTypesConfig<UserTypeNames extends StringForUnion> = never extend
*
* User types defined here can be used as types in table schemas/keys
*/
userTypes: Record<UserTypeNames, string>;
userTypes: Record<UserTypeNames, UserType>;
};

export type FullUserTypesConfig<UserTypeNames extends StringForUnion> = {
userTypes: Record<UserTypeNames, string>;
};

const zUserTypeConfig = z.object({
filePath: z.string(),
internalType: z.string(),
});

export const zUserTypesConfig = z.object({
userTypes: z.record(zUserTypeName, z.string()).default(DEFAULTS.userTypes),
userTypes: z.record(zUserTypeName, zUserTypeConfig).default(DEFAULTS.userTypes),
});

/************************************************************************
Expand Down

0 comments on commit 24a6cd5

Please sign in to comment.