Skip to content
Draft
11 changes: 11 additions & 0 deletions .changeset/config-mapped-arguments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@mysten/codegen': minor
---

Add `configArguments` codegen option for mapping function parameters and package addresses to a
runtime config object. Matched parameters become optional in generated `arguments` and are resolved
from a typed optional `config` object instead, with per-function minimal config slices, resolver
functions for generic types (receiving the matched parameter's normalized instantiation and
call-site metadata), and a generated per-package config interface in `config-arguments.ts`.
Misconfigured matchers are surfaced at generation time. Also treat
`0x2::accumulator::AccumulatorRoot` as a well-known object that is auto-injected like `Clock`.
36 changes: 35 additions & 1 deletion packages/codegen/src/cli/commands/generate/impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import type { LocalContext } from '../../context.js';
import { generateFromPackageSummary } from '../../../index.js';
import { generateFromPackageSummary, resolvePackageRootAddress } from '../../../index.js';
import { loadConfig, type GenerateBase, type PackageGenerate } from '../../../config.js';
import { isValidNamedPackage, isValidSuiObjectId } from '@mysten/sui/utils';
import { execSync } from 'node:child_process';
Expand Down Expand Up @@ -49,6 +49,24 @@ export default async function generate(
})
: config.packages;

// Package entries in any configArguments block must reference a package in this run — a typo'd
// name would otherwise silently never apply.
const knownPackageNames = new Set(normalizedPackages.map((p) => p.package));
const configArgumentBlocks = [
config.configArguments ?? {},
...normalizedPackages.map((p) => ('configArguments' in p ? (p.configArguments ?? {}) : {})),
];
for (const block of configArgumentBlocks) {
for (const [key, matcher] of Object.entries(block)) {
if ('package' in matcher && !knownPackageNames.has(matcher.package)) {
throw new Error(
`configArguments.${key} references package "${matcher.package}", which is not part of ` +
`this codegen run (packages: ${[...knownPackageNames].join(', ')})`,
);
}
}
}

const generateSummaries =
flags.noSummaries === undefined ? config.generateSummaries : !flags.noSummaries;

Expand Down Expand Up @@ -81,6 +99,8 @@ export default async function generate(
}
: undefined;

// First ensure summaries exist for every package, then resolve each package's root address so
// configArguments matchers can reference any package in the run by its identifier.
for (const pkg of normalizedPackages) {
// Detect on-chain packages: they have 'network' field and no 'path'
const isOnChainPackage =
Expand Down Expand Up @@ -108,6 +128,18 @@ export default async function generate(
stdio: 'inherit',
});
}
}

const packageAddresses: Record<string, string> = {};
for (const pkg of normalizedPackages) {
if (!pkg.path) continue;
const address = await resolvePackageRootAddress(pkg.path);
if (address !== undefined) {
packageAddresses[pkg.package] = address;
}
}

for (const pkg of normalizedPackages) {
const importExtension =
flags.importExtension === undefined
? config.importExtension
Expand Down Expand Up @@ -149,6 +181,8 @@ export default async function generate(
importExtension,
includePhantomTypeParameters: config.includePhantomTypeParameters,
errorClass: config.errorClass,
configArguments: config.configArguments,
packageAddresses,
});
}
}
Loading
Loading