From d7eb23bccd4b296cb72eadc65eba3945a82c316f Mon Sep 17 00:00:00 2001 From: Suh Donghwi Date: Thu, 27 Nov 2025 12:44:17 +0900 Subject: [PATCH 1/8] Add before versions of dependency change hooks --- .../plugin-essentials/sources/commands/add.ts | 12 +++++ .../sources/commands/remove.ts | 14 +++++- .../plugin-essentials/sources/commands/up.ts | 12 +++++ packages/plugin-essentials/sources/index.ts | 47 +++++++++++++++++++ 4 files changed, 84 insertions(+), 1 deletion(-) diff --git a/packages/plugin-essentials/sources/commands/add.ts b/packages/plugin-essentials/sources/commands/add.ts index b50def73e0ad..d85f6ae7ca17 100644 --- a/packages/plugin-essentials/sources/commands/add.ts +++ b/packages/plugin-essentials/sources/commands/add.ts @@ -194,6 +194,18 @@ export default class AddCommand extends BaseCommand { }); const results = await Promise.all(targetList.map(async target => { + for (const plugin of configuration.plugins.values()) { + const hooks = plugin.hooks as Hooks; + if (!hooks?.beforeWorkspaceDependencyAddition) + continue; + + await hooks.beforeWorkspaceDependencyAddition( + workspace, + target, + request, + ); + } + const suggestedDescriptors = await suggestUtils.getSuggestedDescriptors(request, {project, workspace, cache, fixed, target, modifier, strategies, maxResults}); return {request, suggestedDescriptors, target}; })); diff --git a/packages/plugin-essentials/sources/commands/remove.ts b/packages/plugin-essentials/sources/commands/remove.ts index 23145c1f20db..2254e8a1fe80 100644 --- a/packages/plugin-essentials/sources/commands/remove.ts +++ b/packages/plugin-essentials/sources/commands/remove.ts @@ -117,7 +117,19 @@ export default class RemoveCommand extends BaseCommand { if (typeof removedDescriptor === `undefined`) throw new Error(`Assertion failed: Expected the descriptor to be registered`); - workspace.manifest[target].delete(identHash); + for (const plugin of configuration.plugins.values()) { + const hooks = plugin.hooks as Hooks; + if (!hooks?.beforeWorkspaceDependencyRemoval) + continue; + + await hooks.beforeWorkspaceDependencyRemoval( + workspace, + target, + removedDescriptor, + ); + } + + workspace.manifest[target].delete(removedDescriptor.identHash); afterWorkspaceDependencyRemovalList.push([ workspace, diff --git a/packages/plugin-essentials/sources/commands/up.ts b/packages/plugin-essentials/sources/commands/up.ts index adc95c12406f..393946195aa9 100644 --- a/packages/plugin-essentials/sources/commands/up.ts +++ b/packages/plugin-essentials/sources/commands/up.ts @@ -211,6 +211,18 @@ export default class UpCommand extends BaseCommand { const request = structUtils.makeDescriptor(ident, pseudoDescriptor.range); allSuggestionsPromises.push(Promise.resolve().then(async () => { + for (const plugin of configuration.plugins.values()) { + const hooks = plugin.hooks as Hooks; + if (!hooks?.beforeWorkspaceDependencyReplacement) + continue; + + await hooks.beforeWorkspaceDependencyReplacement( + workspace, + target, + request, + ); + } + return [ workspace, target, diff --git a/packages/plugin-essentials/sources/index.ts b/packages/plugin-essentials/sources/index.ts index d3a330165791..b884a73d7b81 100644 --- a/packages/plugin-essentials/sources/index.ts +++ b/packages/plugin-essentials/sources/index.ts @@ -121,6 +121,53 @@ export interface Hooks { descriptor: Descriptor, ) => Promise; + /** + * Called before a new dependency is added to a workspace. This hook is + * invoked after the descriptor is parsed but before it is processed by the + * suggestion engine. Plugins can mutate the descriptor (e.g., modify the + * range) to influence what gets added to the manifest. + * + * Note that this hook is only called by the CLI commands like `yarn add` - + * manually adding the dependencies into the manifest and running + * `yarn install` won't trigger it. + */ + beforeWorkspaceDependencyAddition?: ( + workspace: Workspace, + target: suggestUtils.Target, + descriptor: Descriptor, + ) => Promise; + + /** + * Called before a dependency range is replaced inside a workspace. This hook + * is invoked after the new descriptor is parsed but before it is processed + * by the suggestion engine. Plugins can mutate the descriptor (e.g., modify + * the range) to influence what gets added to the manifest. + * + * Note that this hook is only called by the CLI commands like `yarn add` or + * `yarn up` - manually updating the dependencies from the manifest and + * running `yarn install` won't trigger it. + */ + beforeWorkspaceDependencyReplacement?: ( + workspace: Workspace, + target: suggestUtils.Target, + descriptor: Descriptor, + ) => Promise; + + /** + * Called before a dependency is removed from a workspace. This hook receives + * the descriptor that is about to be removed. Plugins can inspect the + * descriptor or throw an error to prevent the removal. + * + * Note that this hook is only called by the CLI commands like `yarn remove` - + * manually removing the dependencies from the manifest and running + * `yarn install` won't trigger it. + */ + beforeWorkspaceDependencyRemoval?: ( + workspace: Workspace, + target: suggestUtils.Target, + descriptor: Descriptor, + ) => Promise; + /** * Called by `yarn info`. The `extra` field is the set of parameters passed * to the `-X,--extra` flag. Calling `registerData` will add a new set of From 217fe06669ba32706affbc5089e7b3c97f6363fe Mon Sep 17 00:00:00 2001 From: Suh Donghwi Date: Thu, 27 Nov 2025 12:59:00 +0900 Subject: [PATCH 2/8] Run replacement hook when yarn add replaces existing dependency --- .../plugin-essentials/sources/commands/add.ts | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/plugin-essentials/sources/commands/add.ts b/packages/plugin-essentials/sources/commands/add.ts index d85f6ae7ca17..5373dcac2c15 100644 --- a/packages/plugin-essentials/sources/commands/add.ts +++ b/packages/plugin-essentials/sources/commands/add.ts @@ -194,16 +194,31 @@ export default class AddCommand extends BaseCommand { }); const results = await Promise.all(targetList.map(async target => { + const current = workspace.manifest[target].get(request.identHash); + const isReplacement = typeof current !== `undefined`; + for (const plugin of configuration.plugins.values()) { const hooks = plugin.hooks as Hooks; - if (!hooks?.beforeWorkspaceDependencyAddition) - continue; - await hooks.beforeWorkspaceDependencyAddition( - workspace, - target, - request, - ); + if (isReplacement) { + if (!hooks?.beforeWorkspaceDependencyReplacement) + continue; + + await hooks.beforeWorkspaceDependencyReplacement( + workspace, + target, + request, + ); + } else { + if (!hooks?.beforeWorkspaceDependencyAddition) + continue; + + await hooks.beforeWorkspaceDependencyAddition( + workspace, + target, + request, + ); + } } const suggestedDescriptors = await suggestUtils.getSuggestedDescriptors(request, {project, workspace, cache, fixed, target, modifier, strategies, maxResults}); From 17f8a02883fc083d6f96a5c7bed45d7786bc22db Mon Sep 17 00:00:00 2001 From: Suh Donghwi Date: Thu, 27 Nov 2025 13:04:43 +0900 Subject: [PATCH 3/8] Replacement hooks receive fromDescriptor and toDescriptor --- packages/plugin-essentials/sources/commands/add.ts | 1 + packages/plugin-essentials/sources/commands/up.ts | 1 + packages/plugin-essentials/sources/index.ts | 5 +++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/plugin-essentials/sources/commands/add.ts b/packages/plugin-essentials/sources/commands/add.ts index 5373dcac2c15..c80ac52a23bb 100644 --- a/packages/plugin-essentials/sources/commands/add.ts +++ b/packages/plugin-essentials/sources/commands/add.ts @@ -207,6 +207,7 @@ export default class AddCommand extends BaseCommand { await hooks.beforeWorkspaceDependencyReplacement( workspace, target, + current, request, ); } else { diff --git a/packages/plugin-essentials/sources/commands/up.ts b/packages/plugin-essentials/sources/commands/up.ts index 393946195aa9..08988456ab5d 100644 --- a/packages/plugin-essentials/sources/commands/up.ts +++ b/packages/plugin-essentials/sources/commands/up.ts @@ -219,6 +219,7 @@ export default class UpCommand extends BaseCommand { await hooks.beforeWorkspaceDependencyReplacement( workspace, target, + existingDescriptor, request, ); } diff --git a/packages/plugin-essentials/sources/index.ts b/packages/plugin-essentials/sources/index.ts index b884a73d7b81..98608c225f4a 100644 --- a/packages/plugin-essentials/sources/index.ts +++ b/packages/plugin-essentials/sources/index.ts @@ -140,7 +140,7 @@ export interface Hooks { /** * Called before a dependency range is replaced inside a workspace. This hook * is invoked after the new descriptor is parsed but before it is processed - * by the suggestion engine. Plugins can mutate the descriptor (e.g., modify + * by the suggestion engine. Plugins can mutate the new descriptor (e.g., modify * the range) to influence what gets added to the manifest. * * Note that this hook is only called by the CLI commands like `yarn add` or @@ -150,7 +150,8 @@ export interface Hooks { beforeWorkspaceDependencyReplacement?: ( workspace: Workspace, target: suggestUtils.Target, - descriptor: Descriptor, + fromDescriptor: Descriptor, + toDescriptor: Descriptor, ) => Promise; /** From 64f81216d5281ea3a08ef75c798c196342b973ad Mon Sep 17 00:00:00 2001 From: Suh Donghwi Date: Thu, 27 Nov 2025 13:07:39 +0900 Subject: [PATCH 4/8] Match docs style with after hooks --- packages/plugin-essentials/sources/index.ts | 35 +++++++-------------- 1 file changed, 12 insertions(+), 23 deletions(-) diff --git a/packages/plugin-essentials/sources/index.ts b/packages/plugin-essentials/sources/index.ts index 98608c225f4a..17d22768e594 100644 --- a/packages/plugin-essentials/sources/index.ts +++ b/packages/plugin-essentials/sources/index.ts @@ -122,14 +122,10 @@ export interface Hooks { ) => Promise; /** - * Called before a new dependency is added to a workspace. This hook is - * invoked after the descriptor is parsed but before it is processed by the - * suggestion engine. Plugins can mutate the descriptor (e.g., modify the - * range) to influence what gets added to the manifest. - * - * Note that this hook is only called by the CLI commands like `yarn add` - - * manually adding the dependencies into the manifest and running - * `yarn install` won't trigger it. + * Called before a new dependency is added to a workspace. Note that this + * hook is only called by the CLI commands like `yarn add` - manually adding + * the dependencies into the manifest and running `yarn install` won't + * trigger it. */ beforeWorkspaceDependencyAddition?: ( workspace: Workspace, @@ -138,14 +134,10 @@ export interface Hooks { ) => Promise; /** - * Called before a dependency range is replaced inside a workspace. This hook - * is invoked after the new descriptor is parsed but before it is processed - * by the suggestion engine. Plugins can mutate the new descriptor (e.g., modify - * the range) to influence what gets added to the manifest. - * - * Note that this hook is only called by the CLI commands like `yarn add` or - * `yarn up` - manually updating the dependencies from the manifest and - * running `yarn install` won't trigger it. + * Called before a dependency range is replaced inside a workspace. Note that + * this hook is only called by the CLI commands like `yarn add` or `yarn up` - + * manually updating the dependencies from the manifest and running + * `yarn install` won't trigger it. */ beforeWorkspaceDependencyReplacement?: ( workspace: Workspace, @@ -155,13 +147,10 @@ export interface Hooks { ) => Promise; /** - * Called before a dependency is removed from a workspace. This hook receives - * the descriptor that is about to be removed. Plugins can inspect the - * descriptor or throw an error to prevent the removal. - * - * Note that this hook is only called by the CLI commands like `yarn remove` - - * manually removing the dependencies from the manifest and running - * `yarn install` won't trigger it. + * Called before a dependency range is removed from a workspace. Note that + * this hook is only called by the CLI commands like `yarn remove` - manually + * removing the dependencies from the manifest and running `yarn install` + * won't trigger it. */ beforeWorkspaceDependencyRemoval?: ( workspace: Workspace, From eaeca5a0239dc29e116ec82ac6e3bcafc0a89154 Mon Sep 17 00:00:00 2001 From: Suh Donghwi Date: Thu, 27 Nov 2025 16:50:45 +0900 Subject: [PATCH 5/8] Add integration tests --- .../sources/features/beforeHooks.test.ts | 223 ++++++++++++++++++ scripts/plugin-before-hooks-test.js | 28 +++ 2 files changed, 251 insertions(+) create mode 100644 packages/acceptance-tests/pkg-tests-specs/sources/features/beforeHooks.test.ts create mode 100644 scripts/plugin-before-hooks-test.js diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/features/beforeHooks.test.ts b/packages/acceptance-tests/pkg-tests-specs/sources/features/beforeHooks.test.ts new file mode 100644 index 000000000000..4fe9bcf4fb87 --- /dev/null +++ b/packages/acceptance-tests/pkg-tests-specs/sources/features/beforeHooks.test.ts @@ -0,0 +1,223 @@ +import {PortablePath, npath, xfs} from '@yarnpkg/fslib'; +import {stringifySyml} from '@yarnpkg/parsers'; + +describe(`Features`, () => { + describe(`Before Hooks`, () => { + describe(`beforeWorkspaceDependencyAddition`, () => { + test( + `it should allow plugins to modify descriptor before addition`, + makeTemporaryEnv({}, async ({path, run}) => { + const pluginPath = npath.toPortablePath(require.resolve(`@yarnpkg/monorepo/scripts/plugin-before-hooks-test.js`)); + const pluginContent = await xfs.readFilePromise(pluginPath); + await xfs.writeFilePromise(`${path}/plugin-before-hooks.js` as PortablePath, pluginContent); + + await xfs.writeFilePromise(`${path}/.yarnrc.yml` as PortablePath, stringifySyml({ + plugins: [`./plugin-before-hooks.js`], + })); + + await run(`add`, `no-deps`); + + await expect(xfs.readJsonPromise(`${path}/package.json` as PortablePath)).resolves.toMatchObject({ + dependencies: { + [`no-deps`]: `^1.0.0`, + }, + }); + }), + ); + + test( + `it should work with dev dependencies`, + makeTemporaryEnv({}, async ({path, run}) => { + const pluginPath = npath.toPortablePath(require.resolve(`@yarnpkg/monorepo/scripts/plugin-before-hooks-test.js`)); + const pluginContent = await xfs.readFilePromise(pluginPath); + await xfs.writeFilePromise(`${path}/plugin-before-hooks.js` as PortablePath, pluginContent); + + await xfs.writeFilePromise(`${path}/.yarnrc.yml` as PortablePath, stringifySyml({ + plugins: [`./plugin-before-hooks.js`], + })); + + await run(`add`, `no-deps`, `-D`); + + await expect(xfs.readJsonPromise(`${path}/package.json` as PortablePath)).resolves.toMatchObject({ + devDependencies: { + [`no-deps`]: `^1.0.0`, + }, + }); + }), + ); + + test( + `it should not affect other packages`, + makeTemporaryEnv({}, async ({path, run}) => { + const pluginPath = npath.toPortablePath(require.resolve(`@yarnpkg/monorepo/scripts/plugin-before-hooks-test.js`)); + const pluginContent = await xfs.readFilePromise(pluginPath); + await xfs.writeFilePromise(`${path}/plugin-before-hooks.js` as PortablePath, pluginContent); + + await xfs.writeFilePromise(`${path}/.yarnrc.yml` as PortablePath, stringifySyml({ + plugins: [`./plugin-before-hooks.js`], + })); + + await run(`add`, `one-fixed-dep`); + + await expect(xfs.readJsonPromise(`${path}/package.json` as PortablePath)).resolves.toMatchObject({ + dependencies: { + [`one-fixed-dep`]: `^2.0.0`, + }, + }); + }), + ); + }); + + describe(`beforeWorkspaceDependencyReplacement`, () => { + test( + `it should allow plugins to modify descriptor before replacement via yarn add`, + makeTemporaryEnv( + { + dependencies: { + 'no-deps': `^1.0.0`, + }, + }, + async ({path, run}) => { + const pluginPath = npath.toPortablePath(require.resolve(`@yarnpkg/monorepo/scripts/plugin-before-hooks-test.js`)); + const pluginContent = await xfs.readFilePromise(pluginPath); + await xfs.writeFilePromise(`${path}/plugin-before-hooks.js` as PortablePath, pluginContent); + + await xfs.writeFilePromise(`${path}/.yarnrc.yml` as PortablePath, stringifySyml({ + plugins: [`./plugin-before-hooks.js`], + })); + + await run(`add`, `no-deps@^1.5.0`); + + await expect(xfs.readJsonPromise(`${path}/package.json` as PortablePath)).resolves.toMatchObject({ + dependencies: { + [`no-deps`]: `^2.0.0`, + }, + }); + }, + ), + ); + + test( + `it should allow plugins to modify descriptor before replacement via yarn up`, + makeTemporaryEnv( + { + dependencies: { + 'no-deps': `^1.0.0`, + }, + }, + async ({path, run}) => { + const pluginPath = npath.toPortablePath(require.resolve(`@yarnpkg/monorepo/scripts/plugin-before-hooks-test.js`)); + const pluginContent = await xfs.readFilePromise(pluginPath); + await xfs.writeFilePromise(`${path}/plugin-before-hooks.js` as PortablePath, pluginContent); + + await xfs.writeFilePromise(`${path}/.yarnrc.yml` as PortablePath, stringifySyml({ + plugins: [`./plugin-before-hooks.js`], + })); + + await run(`up`, `no-deps`); + + await expect(xfs.readJsonPromise(`${path}/package.json` as PortablePath)).resolves.toMatchObject({ + dependencies: { + [`no-deps`]: `^2.0.0`, + }, + }); + }, + ), + ); + }); + + describe(`beforeWorkspaceDependencyRemoval`, () => { + test( + `it should allow plugins to block removal by throwing`, + makeTemporaryEnv( + { + dependencies: { + 'no-deps': `^2.0.0`, + }, + }, + async ({path, run}) => { + const pluginPath = npath.toPortablePath(require.resolve(`@yarnpkg/monorepo/scripts/plugin-before-hooks-test.js`)); + const pluginContent = await xfs.readFilePromise(pluginPath); + await xfs.writeFilePromise(`${path}/plugin-before-hooks.js` as PortablePath, pluginContent); + + await xfs.writeFilePromise(`${path}/.yarnrc.yml` as PortablePath, stringifySyml({ + plugins: [`./plugin-before-hooks.js`], + })); + + await expect(run(`remove`, `no-deps`)).rejects.toThrow(); + + await expect(xfs.readJsonPromise(`${path}/package.json` as PortablePath)).resolves.toMatchObject({ + dependencies: { + 'no-deps': `^2.0.0`, + }, + }); + }, + ), + ); + + test( + `it should allow removal of other packages`, + makeTemporaryEnv( + { + dependencies: { + 'one-fixed-dep': `^1.0.0`, + }, + }, + async ({path, run}) => { + const pluginPath = npath.toPortablePath(require.resolve(`@yarnpkg/monorepo/scripts/plugin-before-hooks-test.js`)); + const pluginContent = await xfs.readFilePromise(pluginPath); + await xfs.writeFilePromise(`${path}/plugin-before-hooks.js` as PortablePath, pluginContent); + + await xfs.writeFilePromise(`${path}/.yarnrc.yml` as PortablePath, stringifySyml({ + plugins: [`./plugin-before-hooks.js`], + })); + + await run(`remove`, `one-fixed-dep`); + + const manifest = await xfs.readJsonPromise(`${path}/package.json` as PortablePath); + expect(manifest.dependencies).toBeUndefined(); + }, + ), + ); + }); + + describe(`Multiple hooks interaction`, () => { + test( + `it should handle both addition and replacement hooks in yarn add`, + makeTemporaryEnv( + { + dependencies: { + 'no-deps': `^1.0.0`, + }, + }, + async ({path, run}) => { + const pluginPath = npath.toPortablePath(require.resolve(`@yarnpkg/monorepo/scripts/plugin-before-hooks-test.js`)); + const pluginContent = await xfs.readFilePromise(pluginPath); + await xfs.writeFilePromise(`${path}/plugin-before-hooks.js` as PortablePath, pluginContent); + + await xfs.writeFilePromise(`${path}/.yarnrc.yml` as PortablePath, stringifySyml({ + plugins: [`./plugin-before-hooks.js`], + })); + + await run(`add`, `no-deps@^1.5.0`); + + await expect(xfs.readJsonPromise(`${path}/package.json` as PortablePath)).resolves.toMatchObject({ + dependencies: { + [`no-deps`]: `^2.0.0`, + }, + }); + + await run(`add`, `one-fixed-dep`); + + await expect(xfs.readJsonPromise(`${path}/package.json` as PortablePath)).resolves.toMatchObject({ + dependencies: { + [`no-deps`]: `^2.0.0`, + [`one-fixed-dep`]: expect.any(String), + }, + }); + }, + ), + ); + }); + }); +}); diff --git a/scripts/plugin-before-hooks-test.js b/scripts/plugin-before-hooks-test.js new file mode 100644 index 000000000000..1064dda30634 --- /dev/null +++ b/scripts/plugin-before-hooks-test.js @@ -0,0 +1,28 @@ +module.exports = { + name: `@yarnpkg/plugin-before-hooks-test`, + factory: require => { + const {structUtils} = require(`@yarnpkg/core`); + + return { + hooks: { + beforeWorkspaceDependencyAddition: async (workspace, target, descriptor) => { + if (descriptor.name === 'no-deps') { + descriptor.range = '^1.0.0'; + } + }, + + beforeWorkspaceDependencyReplacement: async (workspace, target, fromDescriptor, toDescriptor) => { + if (toDescriptor.name === 'no-deps') { + toDescriptor.range = '^2.0.0'; + } + }, + + beforeWorkspaceDependencyRemoval: async (workspace, target, descriptor) => { + if (descriptor.name === 'no-deps') { + throw new Error('Cannot remove no-deps - it is protected'); + } + }, + }, + }; + }, +}; From 97f561f5000181fa82ed8f278072c325c598d678 Mon Sep 17 00:00:00 2001 From: Suh Donghwi Date: Thu, 27 Nov 2025 17:05:26 +0900 Subject: [PATCH 6/8] yarn version check -i --- .yarn/versions/5888d405.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .yarn/versions/5888d405.yml diff --git a/.yarn/versions/5888d405.yml b/.yarn/versions/5888d405.yml new file mode 100644 index 000000000000..4c7483a79ab3 --- /dev/null +++ b/.yarn/versions/5888d405.yml @@ -0,0 +1,2 @@ +releases: + "@yarnpkg/plugin-essentials": minor From 3ba93b2caa8ecd6ff4393d5d1da0b1dfd0e93a4b Mon Sep 17 00:00:00 2001 From: Suh Donghwi Date: Thu, 27 Nov 2025 20:57:09 +0900 Subject: [PATCH 7/8] Fix all lint errors --- .../sources/features/beforeHooks.test.ts | 6 +++--- scripts/plugin-before-hooks-test.js | 16 +++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/features/beforeHooks.test.ts b/packages/acceptance-tests/pkg-tests-specs/sources/features/beforeHooks.test.ts index 4fe9bcf4fb87..bbd28f986b1b 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/features/beforeHooks.test.ts +++ b/packages/acceptance-tests/pkg-tests-specs/sources/features/beforeHooks.test.ts @@ -1,5 +1,5 @@ -import {PortablePath, npath, xfs} from '@yarnpkg/fslib'; -import {stringifySyml} from '@yarnpkg/parsers'; +import {PortablePath, npath, xfs} from '@yarnpkg/fslib'; +import {stringifySyml} from '@yarnpkg/parsers'; describe(`Features`, () => { describe(`Before Hooks`, () => { @@ -61,7 +61,7 @@ describe(`Features`, () => { await expect(xfs.readJsonPromise(`${path}/package.json` as PortablePath)).resolves.toMatchObject({ dependencies: { - [`one-fixed-dep`]: `^2.0.0`, + [`one-fixed-dep`]: `^2.0.0`, }, }); }), diff --git a/scripts/plugin-before-hooks-test.js b/scripts/plugin-before-hooks-test.js index 1064dda30634..726ba3ad2e32 100644 --- a/scripts/plugin-before-hooks-test.js +++ b/scripts/plugin-before-hooks-test.js @@ -1,25 +1,23 @@ module.exports = { name: `@yarnpkg/plugin-before-hooks-test`, - factory: require => { - const {structUtils} = require(`@yarnpkg/core`); - + factory: () => { return { hooks: { beforeWorkspaceDependencyAddition: async (workspace, target, descriptor) => { - if (descriptor.name === 'no-deps') { - descriptor.range = '^1.0.0'; + if (descriptor.name === `no-deps`) { + descriptor.range = `^1.0.0`; } }, beforeWorkspaceDependencyReplacement: async (workspace, target, fromDescriptor, toDescriptor) => { - if (toDescriptor.name === 'no-deps') { - toDescriptor.range = '^2.0.0'; + if (toDescriptor.name === `no-deps`) { + toDescriptor.range = `^2.0.0`; } }, beforeWorkspaceDependencyRemoval: async (workspace, target, descriptor) => { - if (descriptor.name === 'no-deps') { - throw new Error('Cannot remove no-deps - it is protected'); + if (descriptor.name === `no-deps`) { + throw new Error(`Cannot remove no-deps - it is protected`); } }, }, From 14c15bd03aa6ceff8276d960fd6f90ac164111e4 Mon Sep 17 00:00:00 2001 From: Suh Donghwi Date: Thu, 27 Nov 2025 21:05:12 +0900 Subject: [PATCH 8/8] Decline dependent packages update --- .yarn/versions/5888d405.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.yarn/versions/5888d405.yml b/.yarn/versions/5888d405.yml index 4c7483a79ab3..27151cad2ce9 100644 --- a/.yarn/versions/5888d405.yml +++ b/.yarn/versions/5888d405.yml @@ -1,2 +1,7 @@ releases: "@yarnpkg/plugin-essentials": minor + +declined: + - "@yarnpkg/plugin-interactive-tools" + - "@yarnpkg/plugin-typescript" + - "@yarnpkg/cli"