Skip to content

Commit

Permalink
feat: update package constraints to allow multiple files. (#4611)
Browse files Browse the repository at this point in the history
## Explanation

Currently the only accepted path is `/dist`, this ensures that other
files outside of dist can be included

This will allow support for multiple files, which can be used for
[subpath exports](https://nodejs.org/api/packages.html#subpath-exports).

For example if a package wants to export `@metamask/my-controller/foo`,
they will need to update the `exports` field **and the `files` field.**

Real world examples:
- Snaps Controller Package -
[here](https://github.com/MetaMask/snaps/blob/main/packages/snaps-controllers/package.json#L31-L35)
- Redux Toolkit -
[here](https://github.com/reduxjs/redux-toolkit/blob/master/packages/toolkit/package.json#L117-L122)
- Our team is exploring subpath exports too -
[here](https://github.com/MetaMask/core/pull/4604/files#diff-7855eaf5406cbf1191aed59d02f2fd928544f17eefcf527a8d0feb7811032b5fR55-R57)

## References

N/A

<!--
Are there any issues that this pull request is tied to? Are there other
links that reviewers should consult to understand these changes better?

For example:

* Fixes #12345
* Related to #67890
-->

## Changelog

N/A

<!--
If you're making any consumer-facing changes, list those changes here as
if you were updating a changelog, using the template below as a guide.

(CATEGORY is one of BREAKING, ADDED, CHANGED, DEPRECATED, REMOVED, or
FIXED. For security-related issues, follow the Security Advisory
process.)

Please take care to name the exact pieces of the API you've added or
changed (e.g. types, interfaces, functions, or methods).

If there are any breaking changes, make sure to offer a solution for
consumers to follow once they upgrade to the changes.

Finally, if you're only making changes to development scripts or tests,
you may replace the template below with "None".

### `@metamask/package-a`

- **<CATEGORY>**: Your change here
- **<CATEGORY>**: Your change here

### `@metamask/package-b`

- **<CATEGORY>**: Your change here
- **<CATEGORY>**: Your change here
-->

## Checklist

- [x] I've updated the test suite for new or updated code as appropriate
- [x] I've updated documentation (JSDoc, Markdown, etc.) for new or
updated code as appropriate
- [x] I've highlighted breaking changes using the "BREAKING" category
above as appropriate
  • Loading branch information
Prithpal-Sooriya authored Aug 29, 2024
1 parent e77a5b5 commit 65a2ecb
Showing 1 changed file with 41 additions and 5 deletions.
46 changes: 41 additions & 5 deletions yarn.config.cjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @ts-check
// This file is used to define, among other configuration, rules that Yarn will
// execute when you run `yarn constraints`. These rules primarily check the
// manifests of each package in the monorepo to ensure they follow a standard
Expand All @@ -14,7 +15,7 @@ const { inspect } = require('util');
/**
* Aliases for the Yarn type definitions, to make the code more readable.
*
* @typedef {import('@yarnpkg/types').Yarn} Yarn
* @typedef {import('@yarnpkg/types').Yarn.Constraints.Yarn} Yarn
* @typedef {import('@yarnpkg/types').Yarn.Constraints.Workspace} Workspace
* @typedef {import('@yarnpkg/types').Yarn.Constraints.Dependency} Dependency
* @typedef {import('@yarnpkg/types').Yarn.Constraints.DependencyType} DependencyType
Expand Down Expand Up @@ -166,7 +167,7 @@ module.exports = defineConfig({
if (isChildWorkspace) {
// The list of files included in all non-root packages must only include
// files generated during the build process.
expectWorkspaceField(workspace, 'files', ['dist/']);
expectWorkspaceArrayField(workspace, 'files', 'dist/');
} else {
// The root package must specify an empty set of published files. (This
// is required in order to be able to import anything in
Expand Down Expand Up @@ -349,7 +350,7 @@ async function getWorkspaceFile(workspace, path) {
*
* @param {Workspace} workspace - The workspace.
* @param {string} path - The path to the file, relative to the workspace root.
* @returns {boolean} True if the file exists, false otherwise.
* @returns {Promise<boolean>} True if the file exists, false otherwise.
*/
async function workspaceFileExists(workspace, path) {
try {
Expand Down Expand Up @@ -385,6 +386,37 @@ function expectWorkspaceField(workspace, fieldName, expectedValue = undefined) {
}
}

/**
* Expect that the workspace has the given field, and that it is an array-like
* property containing the specified value. If the field is not present, is not
* an array, or does not contain the value, this will log an error, and cause
* the constraint to fail.
*
* @param {Workspace} workspace - The workspace to check.
* @param {string} fieldName - The field to check.
* @param {unknown} expectedValue - The value that should be contained in the array.
*/
function expectWorkspaceArrayField(
workspace,
fieldName,
expectedValue = undefined,
) {
let fieldValue = get(workspace.manifest, fieldName);

if (expectedValue) {
if (!Array.isArray(fieldValue)) {
fieldValue = [];
}

if (!fieldValue.includes(expectedValue)) {
fieldValue.push(expectedValue);
workspace.set(fieldName, fieldValue);
}
} else if (fieldValue === undefined || fieldValue === null) {
workspace.error(`Missing required field "${fieldName}".`);
}
}

/**
* Expect that the workspace has a description, and that it is a non-empty
* string. If the description is not present, or is null, this will log an
Expand Down Expand Up @@ -487,8 +519,12 @@ function expectCorrectWorkspaceExports(workspace) {
* @param {Workspace} workspace - The workspace to check.
*/
function expectCorrectWorkspaceChangelogScripts(workspace) {
/**
* @type {Record<string, { expectedStartString: string, script: string, match: RegExpMatchArray | null }>}
*/
const scripts = ['update', 'validate'].reduce((obj, variant) => {
const expectedStartString = `../../scripts/${variant}-changelog.sh ${workspace.manifest.name}`;
/** @type {string} */
const script = workspace.manifest.scripts[`changelog:${variant}`] ?? '';
const match = script.match(new RegExp(`^${expectedStartString}(.*)$`, 'u'));
return { ...obj, [variant]: { expectedStartString, script, match } };
Expand Down Expand Up @@ -583,7 +619,7 @@ function expectUpToDateWorkspacePeerDependencies(Yarn, workspace) {
* `dependencies` and `devDependencies`.
*
* @param {Workspace} workspace - The workspace to check.
* @param {Map<string, Dependency>} dependenciesByIdentAndType - Map of
* @param {Map<string, Map<DependencyType, Dependency>>} dependenciesByIdentAndType - Map of
* dependency ident to dependency type and dependency.
*/
function expectDependenciesNotInBothProdAndDev(
Expand Down Expand Up @@ -621,7 +657,7 @@ function expectDependenciesNotInBothProdAndDev(
*
* @param {Yarn} Yarn - The Yarn "global".
* @param {Workspace} workspace - The workspace to check.
* @param {Map<string, Dependency>} dependenciesByIdentAndType - Map of
* @param {Map<string, Map<DependencyType, Dependency>>} dependenciesByIdentAndType - Map of
* dependency ident to dependency type and dependency.
*/
function expectControllerDependenciesListedAsPeerDependencies(
Expand Down

0 comments on commit 65a2ecb

Please sign in to comment.