UNPKG

@tevm/base-bundler

Version:

Internal bundler for Tevm

135 lines (131 loc) 4.74 kB
import { resolveArtifacts } from '@tevm/compiler' import { generateRuntime } from '@tevm/runtime' import { runPromise } from 'effect/Effect' import { readCache } from './readCache.js' import { writeCache } from './writeCache.js' /** * Asynchronously resolves a Solidity module to the specified module format. * * This function is the core of the bundler's module resolution process. It: * 1. Attempts to read from cache first * 2. If not cached, compiles the Solidity source and generates artifacts * 3. Generates code for the requested module type (dts, mjs, etc.) * 4. Writes results to cache (without blocking the resolution) * 5. Returns the bundler result * * @param {import('@tevm/compiler').Logger} logger - Logger for error reporting * @param {import('@tevm/config').ResolvedCompilerConfig} config - Compiler configuration * @param {import('@tevm/compiler').FileAccessObject} fao - File system access object * @param {import('@tevm/solc').Solc} solc - Solidity compiler instance * @param {string} modulePath - Path to the Solidity module * @param {string} basedir - Base directory for resolving relative paths * @param {boolean} includeAst - Whether to include AST in the result * @param {boolean} includeBytecode - Whether to include bytecode in the result * @param {import('@tevm/runtime').ModuleType} moduleType - Type of module to generate ('dts', 'mjs', 'cjs', 'ts') * @param {import('@tevm/bundler-cache').Cache} cache - Cache instance for artifacts * @param {'tevm/contract' | '@tevm/contract'} contractPackage - Contract package name to import in generated code * @returns {Promise<import('./types.js').BundlerResult>} A promise that resolves to a bundler result object * @throws {Error} - Throws if compilation or code generation fails * * @example * ```javascript * import { resolveModuleAsync } from '@tevm/base-bundler' * import { createCache } from '@tevm/bundler-cache' * import { createSolc } from '@tevm/solc' * import { loadConfig } from '@tevm/config' * import { mkdir, readFile, writeFile } from 'fs/promises' * import { existsSync, statSync } from 'fs' * * // Setup dependencies * const config = await loadConfig() * const solc = await createSolc() * const cache = createCache() * const logger = console * * // File access object * const fao = { * readFile: (path, encoding) => readFile(path, { encoding }), * writeFile, * exists: async (path) => existsSync(path), * existsSync, * statSync, * mkdir * // Include other required methods * } * * // Resolve a Solidity file to a TypeScript declaration file * const result = await resolveModuleAsync( * logger, * config, * fao, * solc, * './contracts/Counter.sol', * process.cwd(), * true, // include AST * true, // include bytecode * 'dts', // generate .d.ts file * cache, * '@tevm/contract' * ) * * console.log(result.code) // Generated TypeScript declarations * ``` */ export const resolveModuleAsync = async ( logger, config, fao, solc, modulePath, basedir, includeAst, includeBytecode, moduleType, cache, contractPackage, ) => { const cachedResult = await readCache(logger, cache, modulePath, includeAst, includeBytecode) try { const { solcInput, solcOutput, asts, artifacts, modules } = cachedResult ?? (await resolveArtifacts(modulePath, basedir, logger, config, includeAst, includeBytecode, fao, solc)) let code = '' const artifactsExist = artifacts && Object.keys(artifacts).length > 0 if (artifactsExist) { code = await runPromise(generateRuntime(artifacts, moduleType, includeBytecode, contractPackage)) } else { const message = `there were no artifacts for ${modulePath}. This is likely a bug in tevm` code = `// ${message}` logger.warn(message) } // The `writeCache` function is intentionally not awaited to allow non-blocking cache writes. // This enables the rest of the module resolution to proceed without waiting for the cache operation to complete. writeCache( logger, cache, { solcInput, solcOutput, asts, artifacts, modules }, code, modulePath, moduleType, // This is kinda quick and dirty but works for now // We are skipping writing artifacts if there is an error // But still write dts and mjs files since they always // fall back to generating an empty file with error messages artifactsExist, ).catch((e) => { logger.error(e) logger.error('there was an error writing to the cache. This may cause peformance issues') }) return { solcInput, solcOutput, asts, modules, code, } } catch (e) { logger.error(`there was an error in tevm plugin resolving .${moduleType}`) logger.error(/** @type any */ (e)) throw e } }