-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add Yarn plugin enabling dynamic package extensions
- Loading branch information
Showing
60 changed files
with
362 additions
and
383 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@rnx-kit/yarn-plugin-dynamic-extensions": minor | ||
--- | ||
|
||
Added experimental Yarn plugin to enable dynamic package extensions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# @rnx-kit/yarn-plugin-dynamic-extensions | ||
|
||
[](https://github.com/microsoft/rnx-kit/actions/workflows/build.yml) | ||
[](https://www.npmjs.com/package/@rnx-kit/yarn-plugin-dynamic-extensions) | ||
|
||
🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧 | ||
|
||
### THIS TOOL IS EXPERIMENTAL — USE WITH CAUTION | ||
|
||
🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧 | ||
|
||
This is a Yarn plugin that lets you extend the package definitions of your | ||
dependencies, similar to [`packageExtensions`][], but dynamically. | ||
|
||
## Motivation | ||
|
||
Making sure a large number of packages are using the same version of | ||
dependencies, like `eslint` or `typescript`, can involve a lot of manual work. | ||
It is easy to make mistakes, especially if these packages span across multiple | ||
repositories. | ||
|
||
This plugin allows you to manage all dependencies across multiple repositories | ||
from a central location. | ||
|
||
## Installation | ||
|
||
```sh | ||
yarn plugin import https://raw.githubusercontent.com/microsoft/rnx-kit/main/incubator/yarn-plugin-dynamic-extensions/index.js | ||
``` | ||
|
||
## Usage | ||
|
||
Create a module that will return package extensions. In the following example, | ||
we create a module that adds `typescript` to all packages: | ||
|
||
```js | ||
/** | ||
* @param {Object} workspace The package currently being processed | ||
* @param {string} workspace.cwd Path of the current package | ||
* @param {Object} workspace.manifest The content of `package.json` | ||
* @returns {{ | ||
* dependencies?: Record<string, string>; | ||
* peerDependencies?: Record<string, string>; | ||
* peerDependenciesMeta?: Record<string, { optional?: boolean }>; | ||
* }} | ||
*/ | ||
export default function ({ cwd, manifest }) { | ||
return { | ||
dependencies: { | ||
typescript: "^5.0.0", | ||
}, | ||
}; | ||
} | ||
``` | ||
|
||
The function will receive context on the currently processed package, and is | ||
expected to return a map similar to the one for [`packageExtensions`][]. | ||
|
||
For a more complete example, take a look at how we use it in | ||
[`rnx-kit`](https://github.com/microsoft/rnx-kit/blob/main/scripts/dependencies.config.js). | ||
|
||
Add the configuration in your `.yarnrc.yml`: | ||
|
||
```yaml | ||
dynamicPackageExtensions: ./my-dependencies.config.js | ||
``` | ||
If you run `yarn install` now, Yarn will install `typescript` in all your | ||
packages. To verify, try running `tsc`: | ||
|
||
``` | ||
% yarn tsc --version | ||
Version 5.7.3 | ||
``` | ||
|
||
Other Yarn commands will also work as if you had installed dependencies | ||
explicitly as you normally would. For example, `yarn why`: | ||
|
||
``` | ||
% yarn why typescript | ||
└─ @rnx-kit/yarn-plugin-dynamic-extensions@workspace:incubator/yarn-plugin-dynamic-extensions | ||
└─ typescript@npm:5.7.3 (via npm:^5.0.0) | ||
``` | ||
|
||
<!-- References --> | ||
|
||
[`packageExtensions`]: | ||
https://yarnpkg.com/configuration/yarnrc#packageExtensions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
module.exports = require("@rnx-kit/eslint-config"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// @ts-check | ||
|
||
/** | ||
* @import { Configuration, Hooks, Manifest, PackageExtensionData, Plugin } from "@yarnpkg/core"; | ||
* @typedef {{ cwd: string; manifest: Manifest["raw"]; }} Workspace; | ||
*/ | ||
|
||
const DYNAMIC_PACKAGE_EXTENSIONS_KEY = "dynamicPackageExtensions"; | ||
|
||
// This module *must* be CommonJS because `actions/setup-node` (and probably | ||
// other GitHub actions) does not support ESM. Yarn itself does. | ||
exports.name = "@rnx-kit/yarn-plugin-dynamic-extensions"; | ||
|
||
/** @type {(require: NodeJS.Require) => Plugin<Hooks>} */ | ||
exports.factory = (require) => { | ||
const { Project, SettingsType, structUtils } = require("@yarnpkg/core"); | ||
|
||
/** | ||
* @param {Configuration} configuration | ||
* @param {string} projectRoot | ||
* @returns {Promise<((ws: Workspace) => PackageExtensionData | undefined) | void>} | ||
*/ | ||
async function loadUserExtensions(configuration, projectRoot) { | ||
const packageExtensions = configuration.get(DYNAMIC_PACKAGE_EXTENSIONS_KEY); | ||
if ( | ||
typeof packageExtensions !== "string" || | ||
packageExtensions === "false" | ||
) { | ||
return; | ||
} | ||
|
||
const path = require("node:path"); | ||
const { pathToFileURL } = require("node:url"); | ||
|
||
// On Windows, import paths must include the `file:` protocol. | ||
const url = pathToFileURL(path.resolve(projectRoot, packageExtensions)); | ||
const external = await import(url.toString()); | ||
return external?.default ?? external; | ||
} | ||
|
||
/** @type {Plugin<Hooks>["configuration"] & Record<string, unknown>} */ | ||
const configuration = {}; | ||
configuration[DYNAMIC_PACKAGE_EXTENSIONS_KEY] = { | ||
description: "Path to module providing package extensions", | ||
type: SettingsType.STRING, | ||
}; | ||
|
||
return { | ||
configuration, | ||
hooks: { | ||
registerPackageExtensions: async ( | ||
configuration, | ||
registerPackageExtension | ||
) => { | ||
const { projectCwd } = configuration; | ||
if (!projectCwd) { | ||
return; | ||
} | ||
|
||
const { workspace } = await Project.find(configuration, projectCwd); | ||
if (!workspace) { | ||
return; | ||
} | ||
|
||
// @ts-expect-error Cannot find module or its corresponding type declarations | ||
const { npath } = require("@yarnpkg/fslib"); | ||
|
||
const root = npath.fromPortablePath(projectCwd); | ||
const getUserExtensions = await loadUserExtensions(configuration, root); | ||
if (!getUserExtensions) { | ||
return; | ||
} | ||
|
||
workspace.project.workspacesByCwd.forEach(({ cwd, manifest }) => { | ||
const { name, version, raw } = manifest; | ||
if (!name || !version) { | ||
return; | ||
} | ||
|
||
/** @type {Workspace} */ | ||
const workspace = { cwd: npath.fromPortablePath(cwd), manifest: raw }; | ||
const data = getUserExtensions(workspace); | ||
if (!data) { | ||
return; | ||
} | ||
|
||
const descriptor = structUtils.makeDescriptor(name, version); | ||
registerPackageExtension(descriptor, data); | ||
}); | ||
}, | ||
}, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
{ | ||
"name": "@rnx-kit/yarn-plugin-dynamic-extensions", | ||
"version": "0.0.1", | ||
"description": "EXPERIMENTAL - USE WITH CAUTION - yarn-plugin-dynamic-extensions", | ||
"homepage": "https://github.com/microsoft/rnx-kit/tree/main/incubator/yarn-plugin-dynamic-extensions#readme", | ||
"license": "MIT", | ||
"author": { | ||
"name": "Microsoft Open Source", | ||
"email": "[email protected]" | ||
}, | ||
"files": [ | ||
"index.js" | ||
], | ||
"main": "index.js", | ||
"exports": { | ||
".": "./index.js" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/microsoft/rnx-kit", | ||
"directory": "incubator/yarn-plugin-dynamic-extensions" | ||
}, | ||
"engines": { | ||
"node": ">=18.12", | ||
"yarn": ">=4.0" | ||
}, | ||
"scripts": { | ||
"build": "rnx-kit-scripts build", | ||
"format": "rnx-kit-scripts format", | ||
"lint": "rnx-kit-scripts lint", | ||
"test": "rnx-kit-scripts test" | ||
}, | ||
"devDependencies": { | ||
"@rnx-kit/eslint-config": "*", | ||
"@rnx-kit/scripts": "*", | ||
"@rnx-kit/tsconfig": "*", | ||
"@yarnpkg/core": "^4.0.0" | ||
}, | ||
"experimental": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
{ | ||
"extends": "@rnx-kit/tsconfig/tsconfig.esm.json", | ||
"compilerOptions": { | ||
"target": "esnext", | ||
"module": "nodenext", | ||
"moduleResolution": "nodenext", | ||
"allowImportingTsExtensions": true, | ||
"rewriteRelativeImportExtensions": true, | ||
"noEmit": true | ||
}, | ||
"include": ["index.js"] | ||
} |
Oops, something went wrong.