Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: yarnpkg/berry
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: d2afdfcf8819c449dc9784959ab5beb1389a4b26
Choose a base ref
...
head repository: yarnpkg/berry
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 68e10d099fb6bee03e4450bc516c0c04e24bcb96
Choose a head ref
  • 10 commits
  • 21 files changed
  • 9 contributors

Commits on Aug 24, 2024

  1. Sync master with the changes from master

    yarnbot committed Aug 24, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    Copy the full SHA
    d12fd9b View commit details

Commits on Aug 25, 2024

  1. feat(builder): transform node: imports as needed (#6356)

    ## What's the problem this PR addresses?
    
    <!-- Describe the rationale of your PR. -->
    <!-- Link all issues that it closes. (Closes/Resolves #xxxx.) -->
    
    Yarn plugins used to be forbidden to import/require built-in modules
    prefixed with `node:`.
    see #6135
    see #5417
    Fixes #5637
    
    The yarn plugin builder should be aware of this fact and produce bundled
    code, that does not contain any `node:` prefixed import/require.
    
    This is especially important when building plugins with 3rd party
    dependencies, where the plugin author cannot "fix" the imports to yarn's
    needs.
    
    ## How did you fix it?
    
    <!-- A detailed description of your implementation. -->
    
    I enabled the plugin-compiler to generate the plugin-code as needed:
    
    I utilized the capability of `esbuild` to strip these `node:` prefixes
    from import/require instructions.
    Therefore, I added config options to the plugin build process to
    instruct `esbuild` to do so.
    
    This is a fix of the plugin builder, which enables plugin authors to
    compile their work in a backwards-compatible way, so that the build
    result is runnable in old/unpatched versions of yarn. Unpatched
    regarding #5997
    
    ## Related
    
    The #5997 tries to address the issue from the plugin-runtime side.
    This would enable "broken" plugins to be runnable in all future/patched
    versions of yarn-core.
    
    ## Additionally
    
    This very PR aims to enable plugin authors to create plugins that are
    runnable with unpatched versions of yarn-core.
    It is considered a friction-free backwards-compatible solution on all
    ends. Yet it does not replace #5997.
    
    
    ## Checklist
    
    <!--- Don't worry if you miss something, chores are automatically
    tested. -->
    <!--- This checklist exists to help you remember doing the chores when
    you submit a PR. -->
    <!--- Put an `x` in all the boxes that apply. -->
    - [x] I have read the [Contributing
    Guide](https://yarnpkg.com/advanced/contributing).
    
    <!-- See
    https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released
    for more details. -->
    <!-- Check with `yarn version check` and fix with `yarn version check
    -i` -->
    - [x] I have set the packages that need to be released for my changes to
    be effective.
    
    <!-- The "Testing chores" workflow validates that your PR follows our
    guidelines. -->
    <!-- If it doesn't pass, click on it to see details as to what your PR
    might be missing. -->
    - [x] I will check that all automated PR checks pass before the PR gets
    reviewed.
    
    ---------
    
    Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
    Co-authored-by: MaΓ«l Nison <nison.mael@gmail.com>
    jkowalleck and arcanis authored Aug 25, 2024
    Copy the full SHA
    b2f315f View commit details
  2. Releasing one new package

    | Package name | Version |
    | --- | --- |
    | `@yarnpkg/builder` | `4.2.0` |
    yarnbot committed Aug 25, 2024
    Copy the full SHA
    50ac1e4 View commit details
  3. Sync master with the changes from master

    yarnbot committed Aug 25, 2024
    Copy the full SHA
    cadd19e View commit details
  4. fix(core): determine if a module is a builtin using module.isBuiltin (

    #5997)
    
    **What's the problem this PR addresses?**
    <!-- Describe the rationale of your PR. -->
    `builder plugin` may output `node:process` instead of `process` in the
    generated file.
    When executing `yarn.`, it will report an error like:
    ```
    This plugin cannot access the package referenced via node:process which is neither a builtin, nor an exposed entry
    ```
    
    ** Environment
    ```
    ❯ yarn tsc --version
    Version 5.3.2
    ```
    <!-- Link all issues that it closes. (Closes/Resolves #xxxx.) -->
    
    ...
    
    **How did you fix it?**
    <!-- A detailed description of your implementation. -->
    
    **Checklist**
    <!--- Don't worry if you miss something, chores are automatically
    tested. -->
    <!--- This checklist exists to help you remember doing the chores when
    you submit a PR. -->
    <!--- Put an `x` in all the boxes that apply. -->
    - [x] I have read the [Contributing
    Guide](https://yarnpkg.com/advanced/contributing).
    
    <!-- See
    https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released
    for more details. -->
    <!-- Check with `yarn version check` and fix with `yarn version check
    -i` -->
    - [x] I have set the packages that need to be released for my changes to
    be effective.
    
    <!-- The "Testing chores" workflow validates that your PR follows our
    guidelines. -->
    <!-- If it doesn't pass, click on it to see details as to what your PR
    might be missing. -->
    - [x] I will check that all automated PR checks pass before the PR gets
    reviewed.
    
    ---------
    
    Co-authored-by: MaΓ«l Nison <nison.mael@gmail.com>
    Co-authored-by: Kristoffer K. <merceyz@users.noreply.github.com>
    3 people authored Aug 25, 2024
    Copy the full SHA
    3b156c9 View commit details
  5. feat(shell): add unset command (#6430)

    ## What's the problem this PR addresses?
    
    <!-- Describe the rationale of your PR. -->
    <!-- Link all issues that it closes. (Closes/Resolves #xxxx.) -->
    
    Fixes #4447.
    
    ## How did you fix it?
    
    <!-- A detailed description of your implementation. -->
    
    I fixed it by adding an `unset` built-in.
    
    ## Checklist
    
    <!--- Don't worry if you miss something, chores are automatically
    tested. -->
    <!--- This checklist exists to help you remember doing the chores when
    you submit a PR. -->
    <!--- Put an `x` in all the boxes that apply. -->
    - [x] I have read the [Contributing
    Guide](https://yarnpkg.com/advanced/contributing).
    
    <!-- See
    https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released
    for more details. -->
    <!-- Check with `yarn version check` and fix with `yarn version check
    -i` -->
    - [x] I have set the packages that need to be released for my changes to
    be effective.
    
    <!-- The "Testing chores" workflow validates that your PR follows our
    guidelines. -->
    <!-- If it doesn't pass, click on it to see details as to what your PR
    might be missing. -->
    - [x] I will check that all automated PR checks pass before the PR gets
    reviewed.
    
    ---------
    
    Co-authored-by: merceyz <merceyz@users.noreply.github.com>
    tthijm and merceyz authored Aug 25, 2024
    Copy the full SHA
    10d16c3 View commit details

Commits on Sep 12, 2024

  1. fix(nm): Stop hoisting rounds only when nothing were hoisted (#6495)

    ## What's the problem this PR addresses?
    
    <!-- Describe the rationale of your PR. -->
    <!-- Link all issues that it closes. (Closes/Resolves #xxxx.) -->
    
    Fixes #6493
    Fixes #6494
    
    ## How did you fix it?
    
    <!-- A detailed description of your implementation. -->
    
    Issue: #6493. Sometimes hoisting algorithm was stopped too early,
    because it wasn't able to determine correctly stop condition. I made it
    safer but possibly one round slower by stopping only when nothing was
    hoisted during the last round.
    
    Issue: #6494. Hoisting avoided hoisting to non-root workspace
    previously, I have removed this limitation, because it made inner
    workspaces meaningless.
    
    ## Checklist
    
    <!--- Don't worry if you miss something, chores are automatically
    tested. -->
    <!--- This checklist exists to help you remember doing the chores when
    you submit a PR. -->
    <!--- Put an `x` in all the boxes that apply. -->
    - [x] I have read the [Contributing
    Guide](https://yarnpkg.com/advanced/contributing).
    
    <!-- See
    https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released
    for more details. -->
    <!-- Check with `yarn version check` and fix with `yarn version check
    -i` -->
    - [x] I have set the packages that need to be released for my changes to
    be effective.
    
    <!-- The "Testing chores" workflow validates that your PR follows our
    guidelines. -->
    <!-- If it doesn't pass, click on it to see details as to what your PR
    might be missing. -->
    - [x] I will check that all automated PR checks pass before the PR gets
    reviewed.
    larixer authored Sep 12, 2024
    Copy the full SHA
    a22486f View commit details

Commits on Sep 13, 2024

  1. Avoid crash in simplifyRanges by removing subsets up front (#6459)

    ## What's the problem this PR addresses?
    
    Resolves #6373. The problem is that `simplifyRanges` doesn't correctly
    reduce redundant OR ranges. For example, `~1.0.1 || ~1.0.2` should be
    simplified to `~1.0.1`. As the algorithm runs, it will effectively
    calculate every _combination_ of terms in such ranges. For example,
    given two ranges like `~1.0.1 || ~1.0.2`, the `nextAlternatives` array
    will end up with 2*2 = 4 entries; if you have 100 such ranges you'll end
    up with 2^100 entries. Growing exponentially like this it's not hard to
    crash the process.
    
    Arguably packages should not specify peer deps with this sort of
    redundant range, but sometimes they do (I'm working on cleaning up my
    project now that I know what the problem is!) Regardless, yarn shouldn't
    crash when it happens.
    
    ## How did you fix it?
    
    At the beginning of `simplifyRanges`, I reduce any range of this sort by
    splitting it apart and using `sember.subset` to check if one part of the
    range is a subset of another, in which case it can be excluded from the
    simplified range. I short circuit if the range only has one term, to
    avoid any excess parsing.
    
    I think this is the right fix, but I'm happy to take feedback or hand it
    off if someone knows better. (Maybe @arcanis as author of this code?)
    
    ## Checklist
    
    <!--- Don't worry if you miss something, chores are automatically
    tested. -->
    <!--- This checklist exists to help you remember doing the chores when
    you submit a PR. -->
    <!--- Put an `x` in all the boxes that apply. -->
    - [x] I have read the [Contributing
    Guide](https://yarnpkg.com/advanced/contributing).
    
    <!-- See
    https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released
    for more details. -->
    <!-- Check with `yarn version check` and fix with `yarn version check
    -i` -->
    - [x] I have set the packages that need to be released for my changes to
    be effective.
    
    <!-- The "Testing chores" workflow validates that your PR follows our
    guidelines. -->
    <!-- If it doesn't pass, click on it to see details as to what your PR
    might be missing. -->
    - [x] I will check that all automated PR checks pass before the PR gets
    reviewed.
    smikula authored Sep 13, 2024
    Copy the full SHA
    758a8be View commit details
  2. fix(ci): add workaround for Parcel not working with Yarn PnP (#6447)

    ## What's the problem this PR addresses?
    
    It seems like the issue
    (parcel-bundler/parcel#9114) is stuck on
    Parcel's side with no interest of it being fixed.
    
    ## How did you fix it?
    
    While this is not ideal, that leaves us with two choices: add a
    workaround and continue testing Parcel, or remove E2E tests for Parcel
    altogether. I chose the former.
    
    ## Checklist
    
    <!--- Don't worry if you miss something, chores are automatically
    tested. -->
    <!--- This checklist exists to help you remember doing the chores when
    you submit a PR. -->
    <!--- Put an `x` in all the boxes that apply. -->
    - [x] I have read the [Contributing
    Guide](https://yarnpkg.com/advanced/contributing).
    
    <!-- See
    https://yarnpkg.com/advanced/contributing#preparing-your-pr-to-be-released
    for more details. -->
    <!-- Check with `yarn version check` and fix with `yarn version check
    -i` -->
    - [x] I have set the packages that need to be released for my changes to
    be effective.
    
    <!-- The "Testing chores" workflow validates that your PR follows our
    guidelines. -->
    <!-- If it doesn't pass, click on it to see details as to what your PR
    might be missing. -->
    - [x] I will check that all automated PR checks pass before the PR gets
    reviewed.
    wojtekmaj authored Sep 13, 2024
    Copy the full SHA
    58475b9 View commit details

Commits on Sep 14, 2024

  1. Releasing 6 new packages

    | Package name | Version |
    | --- | --- |
    | `@yarnpkg/cli` | `4.5.0` |
    | `@yarnpkg/shell` | `4.1.0` |
    | `@yarnpkg/nm` | `4.0.3` |
    | `@yarnpkg/plugin-nm` | `4.0.4` |
    | `@yarnpkg/pnpify` | `4.1.2` |
    | `@yarnpkg/core` | `4.1.3` |
    yarnbot committed Sep 14, 2024
    Copy the full SHA
    68e10d0 View commit details
7 changes: 7 additions & 0 deletions .github/workflows/e2e-parcel-workflow.yml
Original file line number Diff line number Diff line change
@@ -29,6 +29,13 @@ jobs:
yarn init -p
yarn add -D parcel@nightly lodash @babel/core
# See https://github.com/parcel-bundler/parcel/issues/9114
echo "packageExtensions:
\"@parcel/fs@*\":
dependencies:
\"@parcel/core\": '*'" > .yarnrc.yml
# JavaScript
echo "import _ from 'lodash';function printHello() { console.log(_.join(['Hello', 'JS'], ' '))}; printHello();" | tee index.js
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -10,6 +10,8 @@ Features in `master` can be tried out by running `yarn set version from sources`

- Fixes `preferInteractive` forcing interactive mode in non-TTY environments.
- `node-modules` linker now honors user-defined symlinks for `<workspace>/node_modules` directories
- `node-modules` linker supports hoisting into inner workspaces that are parents of other workspaces
- `node-modules` linker attemps to hoist tree more exhaustivel until nothing can be hoisted

## 4.1.0

Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import {mockPluginServer} from './plugins.utility';
const COMMANDS_PLUGIN = (name: string, {async = false, printOnBoot = false, thirdParty = false} = {}) => `
const factory = ${async ? `async` : ``} r => {
const {Command} = r('clipanion');
const path = r('node:path');
if (${printOnBoot})
console.log('Booting ${name.toUpperCase()}');
@@ -22,6 +23,14 @@ const factory = ${async ? `async` : ``} r => {
this.context.stdout.write('Executing ${name.toUpperCase()}\\n');
}
},
class MyCommandPath extends Command {
static paths = [['${name}', 'path']];
async execute() {
this.context.stdout.write(path.posix.join('a', 'b') + '\\n');
}
},
],
},
};
@@ -77,6 +86,19 @@ describe(`Features`, () => {
});
}));

test(`it should support plugins using builtin modules`, makeTemporaryEnv({
}, async ({path, run, source}) => {
await xfs.writeFilePromise(`${path}/plugin-a.js` as PortablePath, COMMANDS_PLUGIN(`a`));

await xfs.writeFilePromise(`${path}/.yarnrc.yml` as PortablePath, stringifySyml({
plugins: [`./plugin-a.js`],
}));

await expect(run(`a`, `path`)).resolves.toMatchObject({
stdout: `a/b\n`,
});
}));

test(`it should accept asynchronous plugins`, makeTemporaryEnv({
}, async ({path, run, source}) => {
await xfs.writeFilePromise(`${path}/plugin-a.js` as PortablePath, COMMANDS_PLUGIN(`a`, {async: true}));
324 changes: 162 additions & 162 deletions packages/berry-cli/bin/berry.js

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion packages/plugin-compat/package.json
Original file line number Diff line number Diff line change
@@ -49,5 +49,6 @@
],
"engines": {
"node": ">=18.12.0"
}
},
"stableVersion": "4.0.8"
}
2 changes: 1 addition & 1 deletion packages/plugin-nm/package.json
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@
"@yarnpkg/cli": "workspace:^",
"@yarnpkg/core": "workspace:^"
},
"version": "4.0.3",
"version": "4.0.4",
"nextVersion": {
"semver": "2.0.0-rc.5",
"nonce": "1989925236539513"
4 changes: 2 additions & 2 deletions packages/yarnpkg-builder/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yarnpkg/builder",
"version": "4.1.2",
"version": "4.2.0",
"license": "BSD-2-Clause",
"bin": "./sources/boot-cli-dev.js",
"exports": {
@@ -47,5 +47,5 @@
"engines": {
"node": ">=18.12.0"
},
"stableVersion": "4.1.2"
"stableVersion": "4.2.0"
}
9 changes: 9 additions & 0 deletions packages/yarnpkg-builder/sources/commands/build/plugin.ts
Original file line number Diff line number Diff line change
@@ -128,6 +128,15 @@ export default class BuildPluginCommand extends Command {
minify: !this.noMinify,
sourcemap: this.sourceMap ? `inline` : false,
target: `node${semver.minVersion(pkg.engines.node)!.version}`,
supported: {
/*
Yarn plugin-runtime did not support builtin modules prefixed with "node:".
See https://github.com/yarnpkg/berry/pull/5997
As a solution, and for backwards compatibility, esbuild should strip these prefixes.
*/
'node-colon-prefix-import': false,
'node-colon-prefix-require': false,
},
});

for (const warning of res.warnings) {
324 changes: 162 additions & 162 deletions packages/yarnpkg-cli/bin/yarn.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/yarnpkg-cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yarnpkg/cli",
"version": "4.4.1",
"version": "4.5.0",
"license": "BSD-2-Clause",
"main": "./sources/index.ts",
"exports": {
5 changes: 2 additions & 3 deletions packages/yarnpkg-core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yarnpkg/core",
"version": "4.1.2",
"version": "4.1.3",
"license": "BSD-2-Clause",
"main": "./sources/index.ts",
"exports": {
@@ -82,6 +82,5 @@
},
"engines": {
"node": ">=18.12.0"
},
"stableVersion": "4.1.2"
}
}
8 changes: 5 additions & 3 deletions packages/yarnpkg-core/sources/Configuration.ts
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import camelcase
import {isCI, isPR, GITHUB_ACTIONS} from 'ci-info';
import {UsageError} from 'clipanion';
import {parse as parseDotEnv} from 'dotenv';
import {builtinModules} from 'module';
import {isBuiltin} from 'module';
import pLimit, {Limit} from 'p-limit';
import {PassThrough, Writable} from 'stream';
import {WriteStream} from 'tty';
@@ -1265,8 +1265,7 @@ export class Configuration {
const thirdPartyPlugins = new Map<string, Plugin>([]);
if (pluginConfiguration !== null) {
const requireEntries = new Map();
for (const request of builtinModules)
requireEntries.set(request, () => miscUtils.dynamicRequire(request));

for (const [request, embedModule] of pluginConfiguration.modules)
requireEntries.set(request, () => embedModule);

@@ -1284,6 +1283,9 @@ export class Configuration {

const pluginRequireEntries = new Map(requireEntries);
const pluginRequire = (request: string) => {
if (isBuiltin(request))
return miscUtils.dynamicRequire(request);

if (pluginRequireEntries.has(request)) {
return pluginRequireEntries.get(request)();
} else {
21 changes: 20 additions & 1 deletion packages/yarnpkg-core/sources/semverUtils.ts
Original file line number Diff line number Diff line change
@@ -204,7 +204,7 @@ export function stringifyComparator(comparator: Comparator) {
}

export function simplifyRanges(ranges: Array<string>) {
const parsedRanges = ranges.map(range => validRange(range)!.set.map(comparators => comparators.map(comparator => getComparator(comparator))));
const parsedRanges = ranges.map(removeSubsets).map(range => validRange(range)!.set.map(comparators => comparators.map(comparator => getComparator(comparator))));

let alternatives = parsedRanges.shift()!.map(comparators => mergeComparators(comparators))
.filter((range): range is Comparator => range !== null);
@@ -233,3 +233,22 @@ export function simplifyRanges(ranges: Array<string>) {

return alternatives.map(comparator => stringifyComparator(comparator)).join(` || `);
}

function removeSubsets(rangeString: string) {
const parts = rangeString.split(`||`);
if (parts.length > 1) {
const newParts: Set<string> = new Set();
for (const potentialSubset of parts) {
if (!parts.some(part => part !== potentialSubset && semver.subset(potentialSubset, part))) {
newParts.add(potentialSubset);
}
}

if (newParts.size < parts.length) {
const newRange = [...newParts].join(` || `);
return newRange;
}
}

return rangeString;
}
3 changes: 3 additions & 0 deletions packages/yarnpkg-core/tests/semverUtils.test.ts
Original file line number Diff line number Diff line change
@@ -112,6 +112,9 @@ describe(`semverUtils`, () => {
[[`<=1.5.3`, `1.5.3`], `1.5.3`],
[[`1.5.3`, `1.5.3`], `1.5.3`],
[[`1.5.0`, `1.5.3`], null],
[[`~1.0.1 || ~1.0.2`], `~1.0.1`],
[[`~1.0.1 || ~1.0.2`, `~1.0.1 || ~1.0.2`], `~1.0.1`],
[(new Array(1000)).fill(`~1.0.1 || ~1.0.2`), `~1.0.1`],
])(`should simplify %s into %s`, (ranges, expected) => {
expect(semverUtils.simplifyRanges(ranges)).toEqual(expected);
});
5 changes: 2 additions & 3 deletions packages/yarnpkg-nm/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yarnpkg/nm",
"version": "4.0.2",
"version": "4.0.3",
"license": "BSD-2-Clause",
"main": "./sources/index.ts",
"exports": {
@@ -36,6 +36,5 @@
},
"engines": {
"node": ">=18.12.0"
},
"stableVersion": "4.0.2"
}
}
21 changes: 2 additions & 19 deletions packages/yarnpkg-nm/sources/hoist.ts
Original file line number Diff line number Diff line change
@@ -132,7 +132,8 @@ export const hoist = (tree: HoisterTree, opts: HoistOptions = {}): HoisterResult
let anotherRoundNeeded = false;
let round = 0;
do {
anotherRoundNeeded = hoistTo(treeCopy, [treeCopy], new Set([treeCopy.locator]), new Map(), options).anotherRoundNeeded;
const result = hoistTo(treeCopy, [treeCopy], new Set([treeCopy.locator]), new Map(), options);
anotherRoundNeeded = result.anotherRoundNeeded || result.isGraphChanged;
options.fastLookupPossible = false;
round++;
} while (anotherRoundNeeded);
@@ -480,24 +481,6 @@ const getNodeHoistInfo = (rootNode: HoisterWorkTree, rootNodePathLocators: Set<L
}
}

if (isHoistable) {
// Direct workspace dependencies must be hoisted to any common ancestor workspace of all the
// graph paths that include the dependency, because otherwise running app with
// `--preserve-symlinks` will become broken (without this flag the Node.js will pick dependency
// from the ancestor on the file system and with this flag it will pick ancestor from the graph
// and if these ancestors are different, the behavious of the application will be different).
// Another problem, which is prevented - is a creation of multiple hoisting layouts
// for the same workspace, because different dependencies of the same workspace might be hoisted
// differently, depending on the recepient workspace.
// It is difficult to find all common ancestors, but there is one easy to find common ancestor -
// the root workspace, so, for now, we either hoist direct dependencies into the root workspace, or we keep them
// unhoisted, thus we are safe from various pathological cases with `--preserve-symlinks`
isHoistable = parentNode.dependencyKind !== HoisterDependencyKind.WORKSPACE || parentNode.hoistedFrom.has(node.name) || rootNodePathLocators.size === 1;
if (outputReason && !isHoistable) {
reason = parentNode.reasons.get(node.name)!;
}
}

if (isHoistable) {
isHoistable = !rootNode.peerNames.has(node.name);
if (outputReason && !isHoistable) {
40 changes: 35 additions & 5 deletions packages/yarnpkg-nm/tests/hoist.test.ts
Original file line number Diff line number Diff line change
@@ -534,22 +534,52 @@ describe(`hoist`, () => {
expect(getTreeHeight(hoist(toTree(tree), {check: true}))).toEqual(2);
});

it(`should avoid hoisting direct workspace dependencies into non-root workspace`, () => {
it(`should hoist direct workspace dependencies into non-root workspace`, () => {
// . -> W1(w) -> W2(w) -> W3(w)-> A@X
// -> A@Y
// -> W3
// -> A@Z
// The A@X must not be hoisted into W2(w)
// otherwise accessing A via . -> W3 with --preserve-symlinks will result in A@Z,
// but accessing it via W3(w) will result in A@Y
// The A@X must be hoisted into W2(w)
// Accessing A via . -> W3 with --preserve-symlinks will result in A@Z,
// but accessing it via W3(w) will result in A@Y, however if we don't do it,
// inner workspaces will have multiple unexpected copies of dependencies
const tree = {
'.': {dependencies: [`W1(w)`, `W3`, `A@Z`], dependencyKind: HoisterDependencyKind.WORKSPACE},
'W1(w)': {dependencies: [`W2(w)`, `A@Y`], dependencyKind: HoisterDependencyKind.WORKSPACE},
'W2(w)': {dependencies: [`W3(w)`], dependencyKind: HoisterDependencyKind.WORKSPACE},
'W3(w)': {dependencies: [`A@X`], dependencyKind: HoisterDependencyKind.WORKSPACE},
};

expect(getTreeHeight(hoist(toTree(tree), {check: true}))).toEqual(5);
expect(getTreeHeight(hoist(toTree(tree), {check: true}))).toEqual(4);
});

it(`should hoist dependencies to the top from workspaces that have no hoist borders given there is workspace with hoist borders`, () => {
// . -> W1(w)| -> A@X --> B
// -> B@X
// -> W2(w) -> A@Y --> B
// -> B@Y
// should be hoisted to:
// . -> W1(w)| -> A@X -->B
// -> B@X
// -> W2(w)
// -> A@Y --> B
// -> B@Y

const tree = {
'.': {dependencies: [`W1(w)`, `W2(w)`], dependencyKind: HoisterDependencyKind.WORKSPACE},
'W1(w)': {dependencies: [`A@X`, `B@X`], dependencyKind: HoisterDependencyKind.WORKSPACE},
'A@X': {dependencies: [`B@X`], peerNames: [`B`]},
'A@Y': {dependencies: [`B@Y`], peerNames: [`B`]},
'W2(w)': {dependencies: [`A@Y`, `B@Y`], dependencyKind: HoisterDependencyKind.WORKSPACE},
};

const hoistingLimits = new Map([
[`.@`, new Set([`W1(w)`])],
]);

const hoistedTree = hoist(toTree(tree), {check: true, hoistingLimits});
const W2 = Array.from(Array.from(hoistedTree.dependencies).filter(x => x.name === `W2(w)`)[0].dependencies);
expect(W2).toEqual([]);
});

it(`should hoist aliased packages`, () => {
5 changes: 2 additions & 3 deletions packages/yarnpkg-pnpify/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yarnpkg/pnpify",
"version": "4.1.1",
"version": "4.1.2",
"license": "BSD-2-Clause",
"main": "./sources/index.ts",
"bin": "./sources/boot-cli-dev.js",
@@ -49,6 +49,5 @@
},
"engines": {
"node": ">=18.12.0"
},
"stableVersion": "4.1.1"
}
}
5 changes: 2 additions & 3 deletions packages/yarnpkg-shell/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@yarnpkg/shell",
"version": "4.0.2",
"version": "4.1.0",
"license": "BSD-2-Clause",
"main": "./sources/index.ts",
"bin": "./sources/boot-cli-dev.js",
@@ -50,6 +50,5 @@
},
"engines": {
"node": ">=18.12.0"
},
"stableVersion": "4.0.2"
}
}
9 changes: 9 additions & 0 deletions packages/yarnpkg-shell/sources/index.ts
Original file line number Diff line number Diff line change
@@ -166,6 +166,15 @@ const BUILTINS = new Map<string, ShellBuiltin>([
return await setTimeout(1000 * seconds, 0);
}],

[`unset`, async (args: Array<string>, opts: ShellOptions, state: ShellState) => {
for (const name of args) {
delete state.environment[name];
delete state.variables[name];
}

return 0;
}],

[`__ysh_run_procedure`, async (args: Array<string>, opts: ShellOptions, state: ShellState) => {
const procedure = state.procedures[args[0]];

20 changes: 20 additions & 0 deletions packages/yarnpkg-shell/tests/shell.test.ts
Original file line number Diff line number Diff line change
@@ -2094,5 +2094,25 @@ describe(`Shell`, () => {
});
});
});

describe(`unset`, () => {
it(`should unset one variable`, async () => {
await expectResult(bufferResult(
`FOO=bar; unset FOO; echo $FOO`,
), {
exitCode: 1,
stderr: `Unbound variable "FOO"\n`,
});
});

it(`should unset multiple variables`, async () => {
await expectResult(bufferResult(
`A=1 B=2; unset A B; echo $A; echo $B`,
), {
exitCode: 1,
stderr: `Unbound variable "A"\nUnbound variable "B"\n`,
});
});
});
});
});