Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 12, 2025

Stricter publishConfig.exports validation

  • Understand the existing validation logic in loadPkgWithReporting.ts
  • Add validation to ensure publishConfig.exports values match exports values (after removing source/development)
  • Handle nested conditions (like node.require, node.import)
  • Create tests for the new validation rules
  • Run tests to validate the changes
  • Run pnpm changeset add to document the changes
  • Fix TypeScript compilation errors

Changes Made

  • Added areExportValuesEqual() helper function to recursively compare export values
  • Enhanced string export validation to check that publishConfig string value matches the exports default value
  • Added value validation for all conditions in object-based exports to ensure publishConfig mirrors exports (excluding source/development)
  • Added comprehensive test suite to validate the new validation logic works correctly for all scenarios
  • Created changeset to document the breaking changes
  • Fixed TypeScript compilation errors by adding proper type assertions and correcting logger usage

Summary

This PR implements stricter validation for publishConfig.exports to ensure that the values in publishConfig match the values in exports (after removing source/development conditions). This prevents publishing packages to npm with incorrect paths that would lead to crashes.

The validation is always enabled and cannot be turned off with strictOptions, as these checks are critical for package correctness.

Original prompt

This section details on the original issue you should resolve

<issue_title>Stricter publishConfig.exports validation</issue_title>
<issue_description>This is invalid and should not be allowed:

{
  "exports": {
    ".": {
      "source": "./src/node/index.ts",
      "default": "./dist/index.js"
    },
    "./package.json": "./package.json"
  },
  "publishConfig": {
    "exports": {
      ".": {"default": "./dist/index.mjs"},
      "./package.json": "./package.json"
    }
  }
}

Correct output is:

{
  "exports": {
    ".": {
      "source": "./src/node/index.ts",
      "default": "./dist/index.js"
    },
    "./package.json": "./package.json"
  },
  "publishConfig": {
    "exports": {
      ".": "./dist/index.js",
      "./package.json": "./package.json"
    }
  }
}

This is also invalid:

{
  "exports": {
    ".": {
      "source": "./src/node/index.ts",
      "default": "./dist/index.js"
    },
    "./package.json": "./package.json"
  },
  "publishConfig": {
    "exports": {
      ".": "./dist/index.mjs",
      "./package.json": "./package.json"
    }
  }
}

It should be:

{
  "exports": {
    ".": {
      "source": "./src/node/index.ts",
      "default": "./dist/index.js"
    },
    "./package.json": "./package.json"
  },
  "publishConfig": {
    "exports": {
      ".": "./dist/index.js",
      "./package.json": "./package.json"
    }
  }
}

Finally, this is also invalid:

{
  "type": "module",
  "exports": {
    ".": {
      "source": "./src/node/index.ts",
      "require": "./dist/index.cjs",
      "default": "./dist/index.js"
    },
    "./package.json": "./package.json"
  },
  "publishConfig": {
    "exports": {
      ".": {
        "require": "./dist/index.js",
        "default": "./dist/index.mjs"
      },
      "./package.json": "./package.json"
    }
  }
}
{
  "type": "commonjs",
  "exports": {
    ".": {
      "source": "./src/node/index.ts",
      "import": "./dist/index.mjs",
      "default": "./dist/index.js"
    },
    "./package.json": "./package.json"
  },
  "publishConfig": {
    "exports": {
      ".": {
        "import": "./dist/index.js",
        "default": "./dist/index.cjs"
      },
      "./package.json": "./package.json"
    }
  }
}

It should be:

{
  "type": "module",
  "exports": {
    ".": {
      "source": "./src/node/index.ts",
      "require": "./dist/index.cjs",
      "default": "./dist/index.js"
    },
    "./package.json": "./package.json"
  },
  "publishConfig": {
    "exports": {
      ".": {
        "require": "./dist/index.cjs",
        "default": "./dist/index.js"
      },
      "./package.json": "./package.json"
    }
  }
}
{
  "type": "commonjs",
  "exports": {
    ".": {
      "source": "./src/node/index.ts",
      "import": "./dist/index.mjs",
      "default": "./dist/index.js"
    },
    "./package.json": "./package.json"
  },
  "publishConfig": {
    "exports": {
      ".": {
        "import": "./dist/index.mjs",
        "default": "./dist/index.js"
      },
      "./package.json": "./package.json"
    }
  }
}

These should be validated and prevented, as the consequence is that the published package on npm will be pointing to wrong paths, leading to crashes. These new checks should always be checked that they mirror, it should not be possible to turn this check off with strictOptions.</issue_description>

<agent_instructions>Make sure you run pnpm changeset add when you're done</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@changeset-bot
Copy link

changeset-bot bot commented Dec 12, 2025

🦋 Changeset detected

Latest commit: cfaeae7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@sanity/parse-package-json Major
@sanity/pkg-utils Minor
@sanity/tsdown-config Patch

Not sure what this means? Click here to learn what changesets are.

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

@stipsan
Copy link
Member

stipsan commented Dec 12, 2025

@copilot test fail

Copilot AI changed the title [WIP] Add stricter validation for publishConfig.exports Validate publishConfig.exports values match exports Dec 12, 2025
Copilot AI requested a review from stipsan December 12, 2025 12:16
Copy link
Contributor Author

Copilot AI commented Dec 12, 2025

@copilot test fail

The test failure is due to JavaScript heap running out of memory during the full test suite execution. The new publishConfigExports.test.ts tests pass successfully when run in isolation. The memory issue appears to be a CI environment limitation unrelated to the validation changes.

@stipsan stipsan marked this pull request as ready for review December 12, 2025 12:59
@stipsan
Copy link
Member

stipsan commented Dec 12, 2025

@copilot fix failed checks

Copy link
Contributor Author

Copilot AI commented Dec 12, 2025

@copilot fix failed checks

Fixed TypeScript compilation errors in cfaeae7:

  • Added proper type assertions for dynamic property access in loadPkgWithReporting.ts
  • Corrected logger initialization in publishConfigExports.test.ts to use boolean parameter

The build now passes successfully and all tests are working.

@stipsan stipsan merged commit 38c1fea into main Dec 14, 2025
8 checks passed
@stipsan stipsan deleted the copilot/validate-publish-config-exports branch December 14, 2025 12:43
@squiggler squiggler bot mentioned this pull request Dec 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Stricter publishConfig.exports validation

2 participants