Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .yarn/versions/f352ecbe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
releases:
"@yarnpkg/cli": patch
"@yarnpkg/plugin-catalog": patch

declined:
- "@yarnpkg/plugin-compat"
- "@yarnpkg/plugin-constraints"
- "@yarnpkg/plugin-dlx"
- "@yarnpkg/plugin-essentials"
- "@yarnpkg/plugin-init"
- "@yarnpkg/plugin-interactive-tools"
- "@yarnpkg/plugin-nm"
- "@yarnpkg/plugin-npm-cli"
- "@yarnpkg/plugin-pack"
- "@yarnpkg/plugin-patch"
- "@yarnpkg/plugin-pnp"
- "@yarnpkg/plugin-pnpm"
- "@yarnpkg/plugin-stage"
- "@yarnpkg/plugin-typescript"
- "@yarnpkg/plugin-version"
- "@yarnpkg/plugin-workspace-tools"
- "@yarnpkg/builder"
- "@yarnpkg/core"
- "@yarnpkg/doctor"
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
import {PortablePath, xfs} from '@yarnpkg/fslib';
import {yarn, fs as fsUtils} from 'pkg-tests-core';

const CUSTOM_PROTOCOL_PLUGIN = `
module.exports = {
name: 'plugin-custom-protocol',
factory: function(require) {
const {structUtils} = require('@yarnpkg/core');

return {
default: {
hooks: {
reduceDependency(dependency, project) {
if (!dependency.range.startsWith('custom-protocol:')) {
return dependency;
}

const version = dependency.range.slice('custom-protocol:'.length);

return structUtils.makeDescriptor(
structUtils.makeIdent(dependency.scope, dependency.name),
\`npm:\${version}\`
);
}
}
}
};
}
};
`;

describe(`Features`, () => {
describe(`Catalogs`, () => {
test(
Expand Down Expand Up @@ -213,6 +241,34 @@ describe(`Features`, () => {
),
);

test(
`it should handle custom descriptor supported by a plugin without a resolver`,
makeTemporaryEnv(
{
dependencies: {
[`no-deps`]: `catalog:`,
},
},
async ({path, run, source}) => {
await xfs.writeFilePromise(`${path}/plugin-custom-protocol.js` as PortablePath, CUSTOM_PROTOCOL_PLUGIN);

await yarn.writeConfiguration(path, {
plugins: [`./plugin-custom-protocol.js`],
catalog: {
[`no-deps`]: `custom-protocol:2.0.0`,
},
});

await run(`install`);

await expect(source(`require('no-deps')`)).resolves.toMatchObject({
name: `no-deps`,
version: `2.0.0`,
});
},
),
);

test(
`it should throw an error when catalog is not found`,
makeTemporaryEnv(
Expand Down Expand Up @@ -271,6 +327,26 @@ describe(`Features`, () => {
),
);

test(
`it should throw an error when protocol in catalog isn't supported by any resolver`,
makeTemporaryEnv(
{
dependencies: {
[`no-deps`]: `catalog:`,
},
},
async ({path, run, source}) => {
await yarn.writeConfiguration(path, {
catalog: {
[`no-deps`]: `unknown-protocol:2.0.0`,
},
});

await expect(run(`install`)).rejects.toThrow();
},
),
);

test(
`it should work with file: protocol ranges in catalogs`,
makeTemporaryEnv(
Expand Down
4 changes: 4 additions & 0 deletions packages/plugin-catalog/sources/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export const resolveDescriptorFromCatalog = (project: Project, dependency: Descr
structUtils.makeDescriptor(dependency, resolvedRange),
);

// If the descriptor isn't supported by any available resolver, return it as is
if (!resolver.supportsDescriptor(normalizedDescriptor, resolveOptions))
return normalizedDescriptor;

// Bind the descriptor to the project's top level workspace (which should match the project root),
// addressing issues with relative file paths when using `file:` protocol
const boundDescriptor = resolver.bindDescriptor(normalizedDescriptor, project.topLevelWorkspace.anchoredLocator, resolveOptions);
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-catalog/tests/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ describe(`utils`, () => {
// Create mock resolver with bindDescriptor method
mockResolver = {
bindDescriptor: jest.fn(descriptor => descriptor),
supportsDescriptor: jest.fn(() => true),
} as any;

resolveOptions = {
Expand Down