Skip to content

Merge solc output selection config#6605

Closed
ItsNickBarry wants to merge 11 commits intoNomicFoundation:v-nextfrom
ItsNickBarry:output-selection-merge
Closed

Merge solc output selection config#6605
ItsNickBarry wants to merge 11 commits intoNomicFoundation:v-nextfrom
ItsNickBarry:output-selection-merge

Conversation

@ItsNickBarry
Copy link
Contributor

closes #6551

@ItsNickBarry
Copy link
Contributor Author

I suppose the object keys also need to be sorted, but the default is not sorted. "" should come before "*".

@ItsNickBarry
Copy link
Contributor Author

This would be useful as an exported helper function so that plugins can make additions to the output selection without overwriting.

Copy link
Contributor

@zoeyTM zoeyTM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will approve after a couple of minor changes, but this looks great overall. Thanks!

@github-project-automation github-project-automation bot moved this from Backlog to In Review in Hardhat May 1, 2025
Co-authored-by: Zoey <probablyzoey+github@gmail.com>
@changeset-bot
Copy link

changeset-bot bot commented May 1, 2025

⚠️ No Changeset found

Latest commit: 1590d4c

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@ItsNickBarry
Copy link
Contributor Author

@zoeyTM I think this should be exported as a helper function. Plugins often need to add output selection. They could copy/paste this code, but it's ugly and should be hidden behind a function. Otherwise I think they might do it incorrectly and potentially clash with each other. However, I don't know where to put such a function.

const configFileOutputSelection = configOutputSelection[fileKey] ?? {};
outputSelection[fileKey] ??= {};

for (const contractKey of Object.keys(configFileOutputSelection).sort()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think sorting the keys is strictly necessary because they order of keys isn't expected to change, but it's better to keep the object in a normalized state.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe not, actually. I can't quite contrive a situation in which a plugin would reasonably change key order without adding or removing keys.

@ItsNickBarry
Copy link
Contributor Author

ItsNickBarry commented May 1, 2025

@zoeyTM What do you think of this? Everything is sorted and empty entries are ignored.

const configOutputSelection = settings.outputSelection ?? {};
const outputSelection: typeof defaultOutputSelection = {};

const fileKeys = Array.from(
  new Set([
    ...Object.keys(defaultOutputSelection),
    ...Object.keys(configOutputSelection),
  ]),
).sort();

for (const fileKey of fileKeys) {
  const contractKeys = Array.from(
    new Set([
      ...Object.keys(defaultOutputSelection[fileKey] ?? {}),
      ...Object.keys(configOutputSelection[fileKey] ?? {}),
    ]),
  ).sort();

  for (const contractKey of contractKeys) {
    const values = Array.from(
      new Set([
        ...(defaultOutputSelection[fileKey]?.[contractKey] ?? []),
        ...(configOutputSelection[fileKey]?.[contractKey] ?? []),
      ]),
    ).sort();

    if (values.length > 0) {
      outputSelection[fileKey] = {};
      outputSelection[fileKey][contractKey] = values;
    }
  }
}

@ItsNickBarry
Copy link
Contributor Author

Shouldn't all of this go in the config hook?

@alcuadrado
Copy link
Member

alcuadrado commented May 5, 2025

I think this can be simplified, and @zoeyTM should have some time to do it now.

The reason that I think this could be simpler that all we need from Hardhat's point of view is ensure that these are set, as both Hardhat and EDR need them:

"*": {
        "": ["ast"],
        "*": [
          "abi",
          "evm.bytecode",
          "evm.deployedBytecode",
          "evm.methodIdentifiers",
          "metadata",
        ],
      },

So we can just clone whatever the user provides, and add those selectors if not present.

If that's the case, do you think you'd need a helper? can you explain the use case? Wouldn't just getting the build project from hre.solidity be enough?

@ItsNickBarry
Copy link
Contributor Author

I was thinking that both users and plugin developers would expect to be able to pass in an output selection object with the same standard structure. The object isn't even documented (argotorg/solidity#15744), so it's uncomfortable to manipulate directly.

The HH solidity module is also a plugin, and doesn't need to behave any differently. Isn't this a config resolution problem that should be done in the resolveConfig hook?

This is what the code looks like without a helper:

const settings = compiler.settings;
settings.outputSelection ??= {};
settings.outputSelection['*'] ??= {};
settings.outputSelection['*']['*'] ??= [];

if (!settings.outputSelection['*']['*'].includes('storageLayout')) {
  settings.outputSelection['*']['*'].push('storageLayout');
}

It's not that bad, but needs to be duplicated in at least 4 places:

  • builtin:solidity
  • hardhat-docgen
  • hardhat-storage-layout-diff (in two places)

I'd rather do something like this:

const STORAGE_LAYOUT_OUTPUT_SELECTION = { '*': { '*': ['storageLayout'] } };

settings.outputSelection = mergeOutputSelection(settings.outputSelection, STORAGE_LAYOUT_OUTPUT_SELECTION);

Then, nobody has to think about any of these issues:

  • overwriting other plugins' entries
  • nonexistent entries (especially if Hardhat waits until just before compilation to add the "*" defaults)
  • duplicate entries
  • changes in sort order leading to unnecessary recompilation

@kanej
Copy link
Member

kanej commented May 15, 2025

I am closing this PR, thanks @ItsNickBarry, the approach was encoded in these two PRs:

The discussion around exposing the helper function to plugin authors I am going to capture in a separate issue: #6704.

@kanej kanej closed this May 15, 2025
@github-project-automation github-project-automation bot moved this from In Review to Done in Hardhat May 15, 2025
@kanej kanej linked an issue May 15, 2025 that may be closed by this pull request
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 14, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Cannot add storageLayout to compiler output selection

4 participants