mirror of https://github.com/renovatebot/renovate
224 lines
7.0 KiB
TypeScript
224 lines
7.0 KiB
TypeScript
import is from '@sindresorhus/is';
|
|
import validateNpmPackageName from 'validate-npm-package-name';
|
|
import { logger } from '../../../../../logger';
|
|
import { regEx } from '../../../../../util/regex';
|
|
import { GithubTagsDatasource } from '../../../../datasource/github-tags';
|
|
import { NodeVersionDatasource } from '../../../../datasource/node-version';
|
|
import { NpmDatasource } from '../../../../datasource/npm';
|
|
import {
|
|
api,
|
|
isValid,
|
|
isVersion,
|
|
id as npmVersioningId,
|
|
} from '../../../../versioning/npm';
|
|
import type { PackageDependency } from '../../../types';
|
|
|
|
const RE_REPOSITORY_GITHUB_SSH_FORMAT = regEx(
|
|
/(?:git@)github.com:([^/]+)\/([^/.]+)(?:\.git)?/,
|
|
);
|
|
|
|
export function parseDepName(depType: string, key: string): string {
|
|
if (depType !== 'resolutions') {
|
|
return key;
|
|
}
|
|
|
|
const [, depName] = regEx(/((?:@[^/]+\/)?[^/@]+)$/).exec(key) ?? [];
|
|
return depName;
|
|
}
|
|
|
|
export function extractDependency(
|
|
depType: string,
|
|
depName: string,
|
|
input: string,
|
|
): PackageDependency {
|
|
const dep: PackageDependency = {};
|
|
if (!validateNpmPackageName(depName).validForOldPackages) {
|
|
dep.skipReason = 'invalid-name';
|
|
return dep;
|
|
}
|
|
if (typeof input !== 'string') {
|
|
dep.skipReason = 'invalid-value';
|
|
return dep;
|
|
}
|
|
dep.currentValue = input.trim();
|
|
if (depType === 'engines' || depType === 'packageManager') {
|
|
if (depName === 'node') {
|
|
dep.datasource = NodeVersionDatasource.id;
|
|
} else if (depName === 'yarn') {
|
|
dep.datasource = NpmDatasource.id;
|
|
dep.commitMessageTopic = 'Yarn';
|
|
const major =
|
|
isVersion(dep.currentValue) && api.getMajor(dep.currentValue);
|
|
if (major && major > 1) {
|
|
dep.packageName = '@yarnpkg/cli';
|
|
}
|
|
} else if (depName === 'npm') {
|
|
dep.datasource = NpmDatasource.id;
|
|
dep.commitMessageTopic = 'npm';
|
|
} else if (depName === 'pnpm') {
|
|
dep.datasource = NpmDatasource.id;
|
|
dep.commitMessageTopic = 'pnpm';
|
|
} else if (depName === 'vscode') {
|
|
dep.datasource = GithubTagsDatasource.id;
|
|
dep.packageName = 'microsoft/vscode';
|
|
dep.versioning = npmVersioningId;
|
|
} else {
|
|
dep.skipReason = 'unknown-engines';
|
|
}
|
|
if (!isValid(dep.currentValue)) {
|
|
dep.skipReason = 'unspecified-version';
|
|
}
|
|
return dep;
|
|
}
|
|
|
|
// support for volta
|
|
if (depType === 'volta') {
|
|
if (depName === 'node') {
|
|
dep.datasource = NodeVersionDatasource.id;
|
|
} else if (depName === 'yarn') {
|
|
dep.datasource = NpmDatasource.id;
|
|
dep.commitMessageTopic = 'Yarn';
|
|
const major =
|
|
isVersion(dep.currentValue) && api.getMajor(dep.currentValue);
|
|
if (major && major > 1) {
|
|
dep.packageName = '@yarnpkg/cli';
|
|
}
|
|
} else if (depName === 'npm') {
|
|
dep.datasource = NpmDatasource.id;
|
|
} else if (depName === 'pnpm') {
|
|
dep.datasource = NpmDatasource.id;
|
|
dep.commitMessageTopic = 'pnpm';
|
|
} else {
|
|
dep.skipReason = 'unknown-volta';
|
|
}
|
|
if (!isValid(dep.currentValue)) {
|
|
dep.skipReason = 'unspecified-version';
|
|
}
|
|
return dep;
|
|
}
|
|
|
|
if (dep.currentValue.startsWith('npm:')) {
|
|
dep.npmPackageAlias = true;
|
|
const valSplit = dep.currentValue.replace('npm:', '').split('@');
|
|
if (valSplit.length === 1) {
|
|
dep.packageName = depName;
|
|
dep.currentValue = valSplit[0];
|
|
} else if (valSplit.length === 2) {
|
|
dep.packageName = valSplit[0];
|
|
dep.currentValue = valSplit[1];
|
|
} else if (valSplit.length === 3) {
|
|
dep.packageName = valSplit[0] + '@' + valSplit[1];
|
|
dep.currentValue = valSplit[2];
|
|
} else {
|
|
logger.debug(
|
|
`Invalid npm package alias for dependency: "${depName}":"${dep.currentValue}"`,
|
|
);
|
|
}
|
|
}
|
|
if (dep.currentValue.startsWith('file:')) {
|
|
dep.skipReason = 'file';
|
|
return dep;
|
|
}
|
|
|
|
if (isValid(dep.currentValue)) {
|
|
dep.datasource = NpmDatasource.id;
|
|
if (dep.currentValue === '') {
|
|
dep.skipReason = 'empty';
|
|
}
|
|
return dep;
|
|
}
|
|
const hashSplit = dep.currentValue.split('#');
|
|
if (hashSplit.length !== 2) {
|
|
dep.skipReason = 'unspecified-version';
|
|
return dep;
|
|
}
|
|
const [depNamePart, depRefPart] = hashSplit;
|
|
|
|
let githubOwnerRepo: string;
|
|
let githubOwner: string;
|
|
let githubRepo: string;
|
|
const matchUrlSshFormat = RE_REPOSITORY_GITHUB_SSH_FORMAT.exec(depNamePart);
|
|
if (matchUrlSshFormat === null) {
|
|
githubOwnerRepo = depNamePart
|
|
.replace(regEx(/^github:/), '')
|
|
.replace(regEx(/^git\+/), '')
|
|
.replace(regEx(/^https:\/\/github\.com\//), '')
|
|
.replace(regEx(/\.git$/), '');
|
|
const githubRepoSplit = githubOwnerRepo.split('/');
|
|
if (githubRepoSplit.length !== 2) {
|
|
dep.skipReason = 'unspecified-version';
|
|
return dep;
|
|
}
|
|
[githubOwner, githubRepo] = githubRepoSplit;
|
|
} else {
|
|
githubOwner = matchUrlSshFormat[1];
|
|
githubRepo = matchUrlSshFormat[2];
|
|
githubOwnerRepo = `${githubOwner}/${githubRepo}`;
|
|
}
|
|
const githubValidRegex = /^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i; // TODO #12872 lookahead
|
|
if (
|
|
!githubValidRegex.test(githubOwner) ||
|
|
!githubValidRegex.test(githubRepo)
|
|
) {
|
|
dep.skipReason = 'unspecified-version';
|
|
return dep;
|
|
}
|
|
if (isVersion(depRefPart)) {
|
|
dep.currentRawValue = dep.currentValue;
|
|
dep.currentValue = depRefPart;
|
|
dep.datasource = GithubTagsDatasource.id;
|
|
dep.versioning = npmVersioningId;
|
|
dep.packageName = githubOwnerRepo;
|
|
dep.pinDigests = false;
|
|
} else if (
|
|
regEx(/^[0-9a-f]{7}$/).test(depRefPart) ||
|
|
regEx(/^[0-9a-f]{40}$/).test(depRefPart)
|
|
) {
|
|
dep.currentRawValue = dep.currentValue;
|
|
dep.currentValue = null;
|
|
dep.currentDigest = depRefPart;
|
|
dep.datasource = GithubTagsDatasource.id;
|
|
dep.versioning = npmVersioningId;
|
|
dep.packageName = githubOwnerRepo;
|
|
} else {
|
|
// <protocol>://[<user>[:<password>]@]<hostname>[:<port>][:][/]<path>[#<commit-ish> | #semver:<semver>]
|
|
// https://docs.npmjs.com/cli/v10/configuring-npm/package-json#git-urls-as-dependencies
|
|
const len = 7; // length of 'semver:'
|
|
const maybeVersion = depRefPart.substring(len);
|
|
|
|
if (depRefPart.startsWith('semver:') && isValid(maybeVersion)) {
|
|
dep.currentRawValue = dep.currentValue;
|
|
dep.currentValue = maybeVersion;
|
|
dep.datasource = GithubTagsDatasource.id;
|
|
dep.versioning = npmVersioningId;
|
|
dep.packageName = githubOwnerRepo;
|
|
dep.pinDigests = false;
|
|
} else {
|
|
dep.skipReason = 'unversioned-reference';
|
|
return dep;
|
|
}
|
|
}
|
|
dep.sourceUrl = `https://github.com/${githubOwnerRepo}`;
|
|
dep.gitRef = true;
|
|
return dep;
|
|
}
|
|
|
|
export function getExtractedConstraints(
|
|
deps: PackageDependency[],
|
|
): Record<string, string> {
|
|
const extractedConstraints: Record<string, string> = {};
|
|
const constraints = ['node', 'yarn', 'npm', 'pnpm', 'vscode'];
|
|
for (const dep of deps) {
|
|
if (
|
|
!dep.skipReason &&
|
|
(dep.depType === 'engines' || dep.depType === 'packageManager') &&
|
|
dep.depName &&
|
|
constraints.includes(dep.depName) &&
|
|
is.string(dep.currentValue)
|
|
) {
|
|
extractedConstraints[dep.depName] = dep.currentValue;
|
|
}
|
|
}
|
|
return extractedConstraints;
|
|
}
|