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
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/npm-check-fork",
"comment": "Remove dependencies on throat and package-json",
"type": "patch"
}
],
"packageName": "@rushstack/npm-check-fork"
}
256 changes: 5 additions & 251 deletions common/config/subspaces/build-tests-subspace/pnpm-lock.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.
{
"pnpmShrinkwrapHash": "da80c128380df78244e113861884b5e6a38ad7c5",
"pnpmShrinkwrapHash": "5d9bc6eee5c9d99eb1d47a58664f6c7488199d42",
"preferredVersionsHash": "550b4cee0bef4e97db6c6aad726df5149d20e7d9",
"packageJsonInjectedDependenciesHash": "1c312688ef85bfdb64079cc271a46b18d816d411"
"packageJsonInjectedDependenciesHash": "88585d29209a34b4908b0928fd68566f978c2bca"
}
14 changes: 3 additions & 11 deletions common/config/subspaces/default/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion common/config/subspaces/default/repo-state.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.
{
"pnpmShrinkwrapHash": "aebea9e28d4e012d8a37fc57c92bd28eb386df5b",
"pnpmShrinkwrapHash": "b0dbc9dd6df6e790055edb199b9d85eb3a0f200f",
"preferredVersionsHash": "a9b67c38568259823f9cfb8270b31bf6d8470b27"
}
3 changes: 1 addition & 2 deletions libraries/npm-check-fork/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@
"dependencies": {
"giturl": "^2.0.0",
"lodash": "~4.17.15",
"package-json": "^10.0.1",
"semver": "~7.5.4",
"throat": "^6.0.2"
"@rushstack/node-core-library": "workspace:*"
},
"devDependencies": {
"@rushstack/heft": "workspace:*",
Expand Down
120 changes: 86 additions & 34 deletions libraries/npm-check-fork/src/GetLatestFromRegistry.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,97 @@
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.

import os from 'node:os';

import _ from 'lodash';
import semver from 'semver';
import packageJson from 'package-json';
import throat from 'throat';

import { Async } from '@rushstack/node-core-library';

import bestGuessHomepage from './BestGuessHomepage';
import type { INpmRegistryInfo } from './interfaces/INpmCheckRegistry';
import { NpmRegistryClient, type INpmRegistryClientResult } from './NpmRegistryClient';
import type {
INpmRegistryInfo,
INpmCheckRegistryData,
INpmRegistryPackageResponse
} from './interfaces/INpmCheckRegistry';

const cpuCount: number = os.cpus().length;
// Module-level registry client instance (lazy initialized)
let _registryClient: NpmRegistryClient | undefined;

/**
* Gets or creates the shared registry client instance.
*/
function getRegistryClient(): NpmRegistryClient {
if (!_registryClient) {
_registryClient = new NpmRegistryClient();
}
return _registryClient;
}

/**
* Fetches package information from the npm registry.
*
* @param packageName - The name of the package to fetch
* @returns A promise that resolves to the package registry info
*/
export default async function getNpmInfo(packageName: string): Promise<INpmRegistryInfo> {
const limit: () => Promise<packageJson.FullMetadata> = throat(cpuCount, () =>
packageJson(packageName, { fullMetadata: true, allVersions: true })
const client: NpmRegistryClient = getRegistryClient();
const result: INpmRegistryClientResult = await client.fetchPackageMetadataAsync(packageName);

if (result.error) {
return {
error: `Registry error ${result.error}`
};
}

const rawData: INpmRegistryPackageResponse = result.data!;
const CRAZY_HIGH_SEMVER: string = '8000.0.0';
const sortedVersions: string[] = _(rawData.versions)
.keys()
.remove(_.partial(semver.gt, CRAZY_HIGH_SEMVER))
.sort(semver.compare)
.valueOf();

const latest: string = rawData['dist-tags'].latest;
const next: string = rawData['dist-tags'].next;
const latestStableRelease: string | undefined = semver.satisfies(latest, '*')
? latest
: semver.maxSatisfying(sortedVersions, '*') || '';

// Cast to INpmCheckRegistryData for bestGuessHomepage compatibility
// INpmRegistryPackageResponse is a superset of INpmCheckRegistryData
const registryData: INpmCheckRegistryData = rawData as unknown as INpmCheckRegistryData;

return {
latest: latestStableRelease,
next: next,
versions: sortedVersions,
homepage: bestGuessHomepage(registryData) || ''
};
}

/**
* Fetches package information for multiple packages concurrently.
*
* @param packageNames - Array of package names to fetch
* @param concurrency - Maximum number of concurrent requests (defaults to CPU count)
* @returns A promise that resolves to a Map of package name to registry info
*/
export async function getNpmInfoBatch(
packageNames: string[],
concurrency: number = os.cpus().length
): Promise<Map<string, INpmRegistryInfo>> {
const results: Map<string, INpmRegistryInfo> = new Map();

// TODO: Refactor createPackageSummary to use this batch function to reduce registry requests
await Async.forEachAsync(
packageNames,
async (packageName: string) => {
results.set(packageName, await getNpmInfo(packageName));
},
{ concurrency }
);
return limit()
.then((rawData: packageJson.FullMetadata) => {
const CRAZY_HIGH_SEMVER: string = '8000.0.0';
const sortedVersions: string[] = _(rawData.versions)
.keys()
.remove(_.partial(semver.gt, CRAZY_HIGH_SEMVER))
.sort(semver.compare)
.valueOf();

const latest: string = rawData['dist-tags'].latest;
const next: string = rawData['dist-tags'].next;
const latestStableRelease: string | undefined = semver.satisfies(latest, '*')
? latest
: semver.maxSatisfying(sortedVersions, '*') || '';

return {
latest: latestStableRelease,
next: next,
versions: sortedVersions,
homepage: bestGuessHomepage(rawData) || ''
};
})
.catch((error) => {
const errorMessage: string = `Registry error ${error.message}`;
return {
error: errorMessage
};
});

return results;
}
Loading