Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
67da7b0
refactor: rename pnpm specific type to reuse it for yarn as well
MKruschke Jul 24, 2025
ab690ff
refactor: use extractCatalogDeps for both cases
MKruschke Jul 24, 2025
fcc0159
feat: extract dependencies for yarn catalogs
MKruschke Jul 24, 2025
d436370
feat: updating dependency
MKruschke Jul 25, 2025
8ca30d5
test: added more tests
MKruschke Aug 3, 2025
7a53772
fix: fix typo
MKruschke Aug 3, 2025
d1874cd
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 3, 2025
350379e
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 3, 2025
fd9bc29
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 4, 2025
4cadc5c
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 4, 2025
04cb16b
fix: remove debugger stmnt and undo line deletion
MKruschke Aug 5, 2025
3e254ee
Merge remote-tracking branch 'origin/main' into feat/yarn-plugin-cata…
MKruschke Aug 6, 2025
6cc85df
fix: remove core file
MKruschke Aug 6, 2025
5ab19aa
fix: fix lint issues
MKruschke Aug 6, 2025
72b6c13
fix: fix lint issues
MKruschke Aug 6, 2025
0c261e7
fix: fix lint issues
MKruschke Aug 6, 2025
8622e23
test: add more tests
MKruschke Aug 7, 2025
c654c2f
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 7, 2025
90437ee
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 7, 2025
bfc0732
test: add more tests
MKruschke Aug 7, 2025
6c77671
test: add test comments
MKruschke Aug 7, 2025
72849f0
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 7, 2025
3ac804d
test: add more tests
MKruschke Aug 8, 2025
a918957
test: add more tests
MKruschke Aug 8, 2025
414f8c3
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 8, 2025
7f20994
fix: remove unused variable
MKruschke Aug 8, 2025
7e38f93
test: add more tests
MKruschke Aug 8, 2025
39dea8d
fix: try to fix istanbul comments
MKruschke Aug 8, 2025
4211ea6
fix: try v8 instead of istanbul
MKruschke Aug 8, 2025
043fd00
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 8, 2025
9a75e30
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 8, 2025
1e69a45
Merge branch 'main' into feat/yarn-plugin-catalogs-support
viceice Aug 8, 2025
adca60c
Merge remote-tracking branch 'origin/main' into feat/yarn-plugin-cata…
MKruschke Aug 15, 2025
8ac44af
chore: remove debugger statement
MKruschke Aug 15, 2025
0046429
chore: fix v8 ignore statements
MKruschke Aug 15, 2025
eb70ee3
fix: remove core file
MKruschke Aug 15, 2025
02ca083
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Aug 25, 2025
ff63e13
fix: applied review suggestions
MKruschke Aug 25, 2025
90ccad6
fix: change to manageFilePattern
MKruschke Sep 14, 2025
693b441
Merge remote-tracking branch 'origin/main' into feat/yarn-plugin-cata…
MKruschke Sep 14, 2025
5f1425f
fix: remove unused import
MKruschke Sep 14, 2025
b95c58f
fix: add return type
MKruschke Sep 15, 2025
216b519
fix: fix tests
MKruschke Sep 15, 2025
91c287d
Merge branch 'main' into feat/yarn-plugin-catalogs-support
MKruschke Sep 15, 2025
3f1aadd
revert: unrelated tests changes
MKruschke Sep 15, 2025
0bfbc90
fix: remove unused code after change the strategy
MKruschke Sep 15, 2025
9ee3c7b
fix: apply review comments
MKruschke Sep 15, 2025
3619d5e
fix: remove imports
MKruschke Sep 15, 2025
bd8a66b
revert: unwanted changes
MKruschke Sep 15, 2025
2a61349
revert: unwanted changes
MKruschke Sep 15, 2025
91bcff6
Merge remote-tracking branch 'origin/main' into feat/yarn-plugin-cata…
MKruschke Sep 19, 2025
6c50ae5
refactore: use loadPackageJson
MKruschke Sep 19, 2025
e66caec
Update lib/modules/manager/npm/extract/common/package-file.spec.ts
MKruschke Sep 19, 2025
8aef009
fix: apply review comments
MKruschke Sep 20, 2025
c681481
fix: remove unused import
MKruschke Sep 20, 2025
7adbb9f
Apply suggestion from @RahulGautamSingh
MKruschke Sep 20, 2025
d73cf56
Apply suggestion from @RahulGautamSingh
MKruschke Sep 20, 2025
bf37bad
fix: apply review comments
MKruschke Sep 20, 2025
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
Empty file added core
Empty file.
37 changes: 37 additions & 0 deletions lib/modules/manager/npm/extract/common/catalogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { PackageDependency } from '../../../types';
import { NpmManagerData } from '../../types';
import { Catalog } from '../types';
import { extractDependency, parseDepName } from './dependency';

export const PNPM_CATALOG_DEPENDENCY = 'pnpm.catalog';
export const YARN_CATALOG_DEPENDENCY = 'yarn.catalog';

/**
* In order to facilitate matching on specific catalogs, we structure the
* depType as `[pnpm|yarn].catalog.default`, `[pnpm|yarn].catalog.react17`, and so on.
*/
function getCatalogDepType(name: string, npmManager: 'pnpm' | 'yarn'): string {
return `${npmManager === 'pnpm' ? PNPM_CATALOG_DEPENDENCY : YARN_CATALOG_DEPENDENCY}.${name}`;
}
export function extractCatalogDeps(
catalogs: Catalog[],
npmManager: 'pnpm' | 'yarn' = 'pnpm',
): PackageDependency<NpmManagerData>[] {
const deps: PackageDependency<NpmManagerData>[] = [];

for (const catalog of catalogs) {
for (const [key, val] of Object.entries(catalog.dependencies)) {
const depType = getCatalogDepType(catalog.name, npmManager);
const depName = parseDepName(depType, key);
const dep: PackageDependency<NpmManagerData> = {
depType,
depName,
...extractDependency(depType, depName, val!),
prettyDepType: depType,
};
deps.push(dep);
}
}

return deps;
}
126 changes: 126 additions & 0 deletions lib/modules/manager/npm/extract/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ const defaultExtractConfig = {

const input01Content = Fixtures.get('inputs/01.json', '..');
const input02Content = Fixtures.get('inputs/02.json', '..');
const input01PackageManager = Fixtures.get(
'inputs/01-package-manager.json',
'..',
);
const input01GlobContent = Fixtures.get('inputs/01-glob.json', '..');
const workspacesContent = Fixtures.get('inputs/workspaces.json', '..');
const vendorisedContent = Fixtures.get('is-object.json', '..');
Expand Down Expand Up @@ -1267,6 +1271,128 @@ describe('modules/manager/npm/extract/index', () => {
},
]);
});

it('extracts yarnrc.yml and adds it as packageFile', async () => {
const yarnrc = codeBlock`
nodeLinker: node-modules

plugins:
- checksum: 4cb9601cfc0c71e5b0ffd0a85b78e37430b62257040714c2558298ce1fc058f4e918903f0d1747a4fef3f58e15722c35bd76d27492d9d08aa5b04e235bf43b22
path: .yarn/plugins/@yarnpkg/plugin-catalogs.cjs
spec: 'https://raw.githubusercontent.com/toss/yarn-plugin-catalogs/main/bundles/%40yarnpkg/plugin-catalogs.js'

catalogs:
list:
is-positive: 1.0.0
`;
fs.findLocalSiblingOrParent.mockResolvedValue('.yarnrc.yml');

fs.readLocalFile.mockResolvedValueOnce(input02Content);
fs.readLocalFile.mockResolvedValue(yarnrc);

const res = await extractAllPackageFiles(defaultExtractConfig, [
'package.json',
]);

expect(res).toEqual([
{
deps: [
{
currentValue: '7.0.0',
datasource: 'npm',
depName: '@babel/core',
depType: 'dependencies',
prettyDepType: 'dependency',
},
{
currentValue: '1.21.0',
datasource: 'npm',
depName: 'config',
depType: 'dependencies',
prettyDepType: 'dependency',
},
{
currentValue: '0.7.0',
datasource: 'npm',
depName: 'express>cookie',
packageName: 'cookie',
depType: 'pnpm.overrides',
prettyDepType: 'overrides',
},
],
extractedConstraints: {},
managerData: {
hasPackageManager: false,
npmLock: undefined,
packageJsonName: 'renovate',
pnpmShrinkwrap: undefined,
workspacesPackages: undefined,
workspaces: undefined,
yarnLock: undefined,
npmrcFileName: '.yarnrc.yml',
yarnZeroInstall: false,
},
npmrc: yarnrc,
packageFile: 'package.json',
packageFileVersion: '1.0.0',
skipInstalls: true,
},
{
deps: [
{
currentValue: '1.0.0',
datasource: 'npm',
depName: 'is-positive',
depType: 'yarn.catalog.default',
prettyDepType: 'yarn.catalog.default',
},
],
managerData: {
hasPackageManager: false,
},
packageFile: '.yarnrc.yml',
},
]);
});

it('extracts yarnrc.yml and adds it as packageFile and sets pacakgeManager', async () => {
const yarnrc = codeBlock`
nodeLinker: node-modules

plugins:
- checksum: 4cb9601cfc0c71e5b0ffd0a85b78e37430b62257040714c2558298ce1fc058f4e918903f0d1747a4fef3f58e15722c35bd76d27492d9d08aa5b04e235bf43b22
path: .yarn/plugins/@yarnpkg/plugin-catalogs.cjs
spec: 'https://raw.githubusercontent.com/toss/yarn-plugin-catalogs/main/bundles/%40yarnpkg/plugin-catalogs.js'

catalogs:
list:
is-positive: 1.0.0
`;
fs.findLocalSiblingOrParent.mockResolvedValue('.yarnrc.yml');

fs.readLocalFile.mockResolvedValueOnce(input01PackageManager);
fs.readLocalFile.mockResolvedValue(yarnrc);

const res = await extractAllPackageFiles(defaultExtractConfig, [
'package.json',
]);

expect(res[1]).toEqual({
deps: [
{
currentValue: '1.0.0',
datasource: 'npm',
depName: 'is-positive',
depType: 'yarn.catalog.default',
prettyDepType: 'yarn.catalog.default',
},
],
managerData: {
hasPackageManager: true,
},
packageFile: '.yarnrc.yml',
});
});
});

describe('.postExtract()', () => {
Expand Down
38 changes: 28 additions & 10 deletions lib/modules/manager/npm/extract/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import { extractPackageJson } from './common/package-file';
import { extractPnpmWorkspaceFile, tryParsePnpmWorkspaceYaml } from './pnpm';
import { postExtract } from './post';
import type { NpmPackage } from './types';
import { isZeroInstall } from './yarn';
import { extractYarnCatalogsFromYml, isZeroInstall } from './yarn';
import type { YarnConfig } from './yarnrc';
import {
loadConfigFromLegacyYarnrc,
loadConfigFromYarnrcYml,
loadYarnRcYml,
resolveRegistryUrl,
} from './yarnrc';

Expand Down Expand Up @@ -137,13 +137,7 @@ export async function extractPackageFile(
? await isZeroInstall(yarnrcYmlFileName)
: false;

let yarnConfig: YarnConfig | null = null;
const repoYarnrcYml = yarnrcYmlFileName
? await readLocalFile(yarnrcYmlFileName, 'utf8')
: null;
if (is.string(repoYarnrcYml) && repoYarnrcYml.trim().length > 0) {
yarnConfig = loadConfigFromYarnrcYml(repoYarnrcYml);
}
let yarnConfig: YarnConfig | null = await loadYarnRcYml(yarnrcYmlFileName);

const legacyYarnrcFileName = await findLocalSiblingOrParent(
packageFile,
Expand Down Expand Up @@ -252,6 +246,7 @@ export async function extractAllPackageFiles(
});
}
} else {
debugger;
logger.trace({ packageFile }, `Extracting as a package.json file`);
const deps = await extractPackageFile(content, packageFile, config);
if (deps) {
Expand All @@ -260,12 +255,35 @@ export async function extractAllPackageFiles(
packageFile,
});
}

if (packageFile === 'package.json') {
const yarnrcYmlFileName = await findLocalSiblingOrParent(
packageFile,
'.yarnrc.yml',
);

const yarnConfig: YarnConfig | null =
await loadYarnRcYml(yarnrcYmlFileName);

if (yarnConfig?.catalogs) {
const catalogsDeps = await extractYarnCatalogsFromYml(
yarnConfig.catalogs,
packageFile,
deps?.managerData?.hasPackageManager ?? false,
);
if (catalogsDeps) {
npmFiles.push({
...catalogsDeps,
packageFile: '.yarnrc.yml',
});
}
}
}
}
} else {
logger.debug({ packageFile }, `No content found`);
}
}

await postExtract(npmFiles);
return npmFiles;
}
47 changes: 6 additions & 41 deletions lib/modules/manager/npm/extract/pnpm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@ import {
readLocalFile,
} from '../../../../util/fs';
import { parseSingleYaml } from '../../../../util/yaml';
import type {
PackageDependency,
PackageFile,
PackageFileContent,
} from '../../types';
import type { PackageFile, PackageFileContent } from '../../types';
import type { PnpmDependencySchema, PnpmLockFile } from '../post-update/types';
import type { PnpmCatalogsSchema } from '../schema';
import { PnpmWorkspaceFileSchema } from '../schema';
import type { NpmManagerData } from '../types';
import { extractDependency, parseDepName } from './common/dependency';
import type { LockFile, PnpmCatalog, PnpmWorkspaceFile } from './types';
import { extractCatalogDeps } from './common/catalogs';
import type { Catalog, LockFile, PnpmWorkspaceFile } from './types';

function isPnpmLockfile(obj: any): obj is PnpmLockFile {
return is.plainObject(obj) && 'lockfileVersion' in obj;
Expand Down Expand Up @@ -279,7 +275,7 @@ export async function extractPnpmWorkspaceFile(

const pnpmCatalogs = pnpmCatalogsToArray(catalogs);

const deps = extractPnpmCatalogDeps(pnpmCatalogs);
const deps = extractCatalogDeps(pnpmCatalogs);

let pnpmShrinkwrap;
const filePath = getSiblingFileName(packageFile, 'pnpm-lock.yaml');
Expand All @@ -296,42 +292,11 @@ export async function extractPnpmWorkspaceFile(
};
}

/**
* In order to facilitate matching on specific catalogs, we structure the
* depType as `pnpm.catalog.default`, `pnpm.catalog.react17`, and so on.
*/
function getCatalogDepType(name: string): string {
const CATALOG_DEPENDENCY = 'pnpm.catalog';
return `${CATALOG_DEPENDENCY}.${name}`;
}

function extractPnpmCatalogDeps(
catalogs: PnpmCatalog[],
): PackageDependency<NpmManagerData>[] {
const deps: PackageDependency<NpmManagerData>[] = [];

for (const catalog of catalogs) {
for (const [key, val] of Object.entries(catalog.dependencies)) {
const depType = getCatalogDepType(catalog.name);
const depName = parseDepName(depType, key);
const dep: PackageDependency<NpmManagerData> = {
depType,
depName,
...extractDependency(depType, depName, val!),
prettyDepType: depType,
};
deps.push(dep);
}
}

return deps;
}

function pnpmCatalogsToArray({
catalog: defaultCatalogDeps,
catalogs: namedCatalogs,
}: PnpmCatalogs): PnpmCatalog[] {
const result: PnpmCatalog[] = [];
}: PnpmCatalogs): Catalog[] {
const result: Catalog[] = [];

if (defaultCatalogDeps !== undefined) {
result.push({ name: 'default', dependencies: defaultCatalogDeps });
Expand Down
2 changes: 1 addition & 1 deletion lib/modules/manager/npm/extract/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export interface PnpmWorkspaceFile {
* A pnpm catalog is either the default catalog (catalog:, catalogs:default), or
* a named one (catalogs:<name>)
*/
export interface PnpmCatalog {
export interface Catalog {
name: string;
dependencies: NpmPackageDependency;
}
Expand Down
Loading