Skip to content

perf: cache more semver ranges #2890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 13, 2021
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
30 changes: 30 additions & 0 deletions .yarn/versions/76e603e2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
releases:
"@yarnpkg/cli": patch
"@yarnpkg/core": patch
"@yarnpkg/plugin-essentials": patch
"@yarnpkg/plugin-git": patch
"@yarnpkg/plugin-npm-cli": patch
"@yarnpkg/plugin-pnp": patch
"@yarnpkg/plugin-typescript": patch

declined:
- "@yarnpkg/plugin-compat"
- "@yarnpkg/plugin-constraints"
- "@yarnpkg/plugin-dlx"
- "@yarnpkg/plugin-exec"
- "@yarnpkg/plugin-file"
- "@yarnpkg/plugin-github"
- "@yarnpkg/plugin-http"
- "@yarnpkg/plugin-init"
- "@yarnpkg/plugin-interactive-tools"
- "@yarnpkg/plugin-link"
- "@yarnpkg/plugin-node-modules"
- "@yarnpkg/plugin-npm"
- "@yarnpkg/plugin-pack"
- "@yarnpkg/plugin-patch"
- "@yarnpkg/plugin-stage"
- "@yarnpkg/plugin-version"
- "@yarnpkg/plugin-workspace-tools"
- "@yarnpkg/builder"
- "@yarnpkg/doctor"
- "@yarnpkg/pnpify"
2 changes: 1 addition & 1 deletion packages/plugin-essentials/sources/commands/set/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export default class SetVersionCommand extends BaseCommand {
bundleUrl = `https://github.com/yarnpkg/berry/raw/%40yarnpkg/cli/${this.version}/packages/yarnpkg-cli/bin/yarn.js`;
else if (semverUtils.satisfiesWithPrereleases(this.version, `^0.x || ^1.x`))
bundleUrl = `https://github.com/yarnpkg/yarn/releases/download/v${this.version}/yarn-${this.version}.js`;
else if (semver.validRange(this.version))
else if (semverUtils.validRange(this.version))
throw new UsageError(`Support for ranges got removed - please use the exact version you want to install, or 'latest' to get the latest build available`);
else
throw new UsageError(`Invalid version descriptor "${this.version}"`);
Expand Down
17 changes: 9 additions & 8 deletions packages/plugin-git/sources/gitUtils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {Configuration, Locator, execUtils, structUtils, httpUtils} from '@yarnpkg/core';
import {npath, xfs} from '@yarnpkg/fslib';
import GitUrlParse from 'git-url-parse';
import querystring from 'querystring';
import semver from 'semver';
import urlLib from 'url';
import {Configuration, Locator, execUtils, structUtils, httpUtils, semverUtils} from '@yarnpkg/core';
import {npath, xfs} from '@yarnpkg/fslib';
import GitUrlParse from 'git-url-parse';
import querystring from 'querystring';
import semver from 'semver';
import urlLib from 'url';

function makeGitEnvironment() {
return {
Expand Down Expand Up @@ -237,7 +237,8 @@ export async function resolveUrl(url: string, configuration: Configuration) {
}

case TreeishProtocols.Semver: {
if (!semver.validRange(request))
const validRange = semverUtils.validRange(request);
if (!validRange)
throw new Error(`Invalid range ("${request}")`);

const semverTags = new Map([...refs.entries()].filter(([ref]) => {
Expand All @@ -248,7 +249,7 @@ export async function resolveUrl(url: string, configuration: Configuration) {
return entry[0] !== null;
}));

const bestVersion = semver.maxSatisfying([...semverTags.keys()], request);
const bestVersion = semver.maxSatisfying([...semverTags.keys()], validRange);
if (bestVersion === null)
throw new Error(`No matching range ("${request}")`);

Expand Down
7 changes: 4 additions & 3 deletions packages/plugin-npm-cli/sources/commands/npm/info.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as npm from '@npm/types';
import {BaseCommand} from '@yarnpkg/cli';
import {Project, Configuration, structUtils, Descriptor} from '@yarnpkg/core';
import {StreamReport, MessageName} from '@yarnpkg/core';
import {StreamReport, MessageName, semverUtils} from '@yarnpkg/core';
import {npmHttpUtils} from '@yarnpkg/plugin-npm';
import {Command, Option, Usage, UsageError} from 'clipanion';
import path from 'path';
Expand Down Expand Up @@ -127,8 +127,9 @@ export default class InfoCommand extends BaseCommand {

// The latest version that satisfies `descriptor.range` (if it is a valid range), else `fallbackVersion`
let version: string = fallbackVersion;
if (semver.validRange(descriptor.range)) {
const maxSatisfyingVersion = semver.maxSatisfying(versions, descriptor.range);
const validRange = semverUtils.validRange(descriptor.range);
if (validRange) {
const maxSatisfyingVersion = semver.maxSatisfying(versions, validRange);

if (maxSatisfyingVersion !== null) {
version = maxSatisfyingVersion;
Expand Down
3 changes: 1 addition & 2 deletions packages/plugin-pnp/sources/commands/unplug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {Cache, Configuration, Project, StreamReport, Package, MessageName, forma
import {structUtils, semverUtils} from '@yarnpkg/core';
import {Command, Option, Usage, UsageError} from 'clipanion';
import micromatch from 'micromatch';
import semver from 'semver';

import * as pnpUtils from '../pnpUtils';

Expand Down Expand Up @@ -85,7 +84,7 @@ export default class UnplugCommand extends BaseCommand {
? patternDescriptor
: structUtils.makeDescriptor(patternDescriptor, `*`);

if (!semver.validRange(pseudoDescriptor.range))
if (!semverUtils.validRange(pseudoDescriptor.range))
throw new UsageError(`The range of the descriptor patterns must be a valid semver range (${structUtils.prettyDescriptor(configuration, pseudoDescriptor)})`);

return (pkg: Package) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-typescript/sources/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Descriptor, Plugin, Workspace, ResolveOptions, Manifest, AllDependencies, DescriptorHash, Package} from '@yarnpkg/core';
import {structUtils, ThrowReport, miscUtils} from '@yarnpkg/core';
import {structUtils, ThrowReport, miscUtils, semverUtils} from '@yarnpkg/core';
import {Hooks as EssentialsHooks} from '@yarnpkg/plugin-essentials';
import {suggestUtils} from '@yarnpkg/plugin-essentials';
import {Hooks as PackHooks} from '@yarnpkg/plugin-pack';
Expand Down Expand Up @@ -41,7 +41,7 @@ const afterWorkspaceDependencyAddition = async (

let range = structUtils.parseRange(descriptor.range).selector;
// If the range is a tag, we have to resolve it into a semver version
if (!semver.validRange(range)) {
if (!semverUtils.validRange(range)) {
const originalCandidates = await resolver.getCandidates(descriptor, new Map<DescriptorHash, Package>(), resolveOptions);
range = structUtils.parseRange(originalCandidates[0].reference).selector;
}
Expand Down
3 changes: 1 addition & 2 deletions packages/yarnpkg-core/sources/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import camelcase
import {isCI} from 'ci-info';
import {UsageError} from 'clipanion';
import pLimit, {Limit} from 'p-limit';
import semver from 'semver';
import {PassThrough, Writable} from 'stream';

import {CorePlugin} from './CorePlugin';
Expand Down Expand Up @@ -1407,7 +1406,7 @@ export class Configuration {
const packageExtensions = this.packageExtensions;

const registerPackageExtension = (descriptor: Descriptor, extensionData: PackageExtensionData, {userProvided = false}: {userProvided?: boolean} = {}) => {
if (!semver.validRange(descriptor.range))
if (!semverUtils.validRange(descriptor.range))
throw new Error(`Only semver ranges are allowed as keys for the lockfileExtensions setting`);

const extension = new Manifest();
Expand Down
4 changes: 2 additions & 2 deletions packages/yarnpkg-core/sources/LegacyMigrationResolver.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {xfs, ppath} from '@yarnpkg/fslib';
import {parseSyml} from '@yarnpkg/parsers';
import semver from 'semver';

import {MessageName} from './MessageName';
import {Project} from './Project';
import {Report} from './Report';
import {Resolver, ResolveOptions, MinimalResolveOptions} from './Resolver';
import * as semverUtils from './semverUtils';
import * as structUtils from './structUtils';
import {DescriptorHash, Descriptor, Locator} from './types';

Expand Down Expand Up @@ -58,7 +58,7 @@ export class LegacyMigrationResolver implements Resolver {
continue;
}

if (semver.validRange(descriptor.range))
if (semverUtils.validRange(descriptor.range))
descriptor = structUtils.makeDescriptor(descriptor, `npm:${descriptor.range}`);

const {version, resolved} = (parsed as any)[key];
Expand Down
9 changes: 5 additions & 4 deletions packages/yarnpkg-core/sources/Workspace.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {PortablePath, npath, ppath, xfs, Filename} from '@yarnpkg/fslib';
import globby from 'globby';
import semver from 'semver';

import {HardDependencies, Manifest} from './Manifest';
import {Project} from './Project';
import {WorkspaceResolver} from './WorkspaceResolver';
import * as hashUtils from './hashUtils';
import * as semverUtils from './semverUtils';
import * as structUtils from './structUtils';
import {IdentHash} from './types';
import {Descriptor, Locator} from './types';
Expand Down Expand Up @@ -101,17 +101,18 @@ export class Workspace {
if (protocol === WorkspaceResolver.protocol && pathname === `*`)
return true;

if (!semver.validRange(pathname))
const semverRange = semverUtils.validRange(pathname);
if (!semverRange)
return false;

if (protocol === WorkspaceResolver.protocol)
return semver.satisfies(this.manifest.version !== null ? this.manifest.version : `0.0.0`, pathname);
return semverRange.test(this.manifest.version ?? `0.0.0`);

if (!this.project.configuration.get(`enableTransparentWorkspaces`))
return false;

if (this.manifest.version !== null)
return semver.satisfies(this.manifest.version, pathname);
return semverRange.test(this.manifest.version);

return false;
}
Expand Down
21 changes: 15 additions & 6 deletions packages/yarnpkg-core/sources/semverUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import semver from 'semver';

export {SemVer} from 'semver';

const satisfiesWithPrereleasesCache = new Map<string, semver.Range | null>();

/**
* Returns whether the given semver version satisfies the given range. Notably
* this supports prerelease versions so that "2.0.0-rc.0" satisfies the range
Expand All @@ -16,15 +18,22 @@ export {SemVer} from 'semver';
* See https://github.com/yarnpkg/berry/issues/575 for more context.
*/
export function satisfiesWithPrereleases(version: string | null, range: string, loose: boolean = false): boolean {
let semverRange;
try {
semverRange = new semver.Range(range, {includePrerelease: true, loose});
} catch (err) {
if (!version)
return false;
}

if (!version)
const key = `${range}${loose}`;
let semverRange = satisfiesWithPrereleasesCache.get(key);
if (typeof semverRange === `undefined`) {
try {
semverRange = new semver.Range(range, {includePrerelease: true, loose});
} catch {
return false;
} finally {
satisfiesWithPrereleasesCache.set(key, semverRange || null);
}
} else if (semverRange === null) {
return false;
}

let semverVersion: semver.SemVer;
try {
Expand Down