@tevm/config
npm install --save-dev @tevm/configOne place decides what a project's Solidity setup looks like. The bundlers, the TypeScript plugin and the language server all call into here, which is why they never disagree about where an import points.
For the file format itself, see Configuration.
loadConfig(configFilePath)
import { loadConfig } from '@tevm/config'
import { runPromise } from 'effect/Effect'
const config = await runPromise(loadConfig(process.cwd()))
console.log(config.cacheDir) // '.tevm'
console.log(config.libs) // ['lib', 'node_modules']
console.log(config.remappings) // { '@openzeppelin/': 'node_modules/@openzeppelin/' }Parameters — configFilePath: string, the directory to resolve from
(normally your project root).
Returns Effect<ResolvedCompilerConfig, LoadConfigError, never>.
Throws (as an Effect failure) LoadConfigError, whose _tag names the
underlying cause:
_tag | Meaning |
|---|---|
FailedToReadConfigError | No tevm.config.json and no Tevm plugin entry in tsconfig.json |
InvalidJsonConfigError | tevm.config.json is not valid JSON |
InvalidConfigError | The config parsed but failed validation |
FoundryNotFoundError | foundryProject set but forge config --json could not run |
FoundryConfigError | forge ran but its output could not be parsed |
InvalidRemappingsError | Remappings were not in prefix=target form |
FailedToReadConfigError is not fatal in practice — every plugin catches it and
falls back to defaults:
import { defaultConfig, loadConfig } from '@tevm/config'
import { catchTag, logWarning, map, runPromise } from 'effect/Effect'
const config = await runPromise(
loadConfig(process.cwd()).pipe(
catchTag('FailedToReadConfigError', () =>
logWarning('No tevm.config.json found, using defaults').pipe(map(() => defaultConfig)),
),
),
)What it merges
tevm.config.json, or the@tevm/ts-pluginentry intsconfig.jsonas a fallback — including convertingcompilerOptions.pathsinto Solidity remappings, honouringbaseUrl;remappings.txt, if present;forge config --json, whenfoundryProjectis truthy;- defaults, for anything still unset.
defaultConfig
import { defaultConfig } from '@tevm/config'
// {
// jsonAsConst: [],
// foundryProject: false,
// remappings: {},
// libs: [],
// debug: false,
// cacheDir: '.tevm',
// }defineConfig(configFactory)
Type-safe authoring of a config from JavaScript rather than JSON.
import { defineConfig } from '@tevm/config'
export default defineConfig(() => ({
foundryProject: true,
libs: ['lib'],
remappings: {
'@openzeppelin/': 'node_modules/@openzeppelin/',
},
}))Parameters — configFactory: () => CompilerConfig. A function, so config can
be computed at load time.
Returns { configFn: (configFilePath: string) => Effect<ResolvedCompilerConfig, DefineConfigError, never> }.
Throws (as an Effect failure) DefineConfigError, wrapping either
ConfigFnThrowError (your factory threw) or InvalidConfigError (the object it
returned failed validation).
Types
CompilerConfig
What a user writes. Every field optional.
type CompilerConfig = {
jsonAsConst?: string | readonly string[]
foundryProject?: boolean | string
libs?: readonly string[]
remappings?: Record<string, string>
debug?: boolean
cacheDir?: string
}ResolvedCompilerConfig
What the pipeline consumes. Defaults filled in, so only debug stays optional.
type ResolvedCompilerConfig = {
jsonAsConst: readonly string[]
foundryProject: boolean | string
libs: readonly string[]
remappings: Record<string, string>
debug?: boolean
cacheDir: string
}ConfigFactory
type ConfigFactory = () => CompilerConfig
