Skip to content
Open
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
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20.15.0
node-version: 22.20.0

- run: npm ci
- run: npm test
Expand Down
6 changes: 3 additions & 3 deletions src/lib/cli-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export function getCliOptions() {
)
.option(
"--filter <FILTER>",
"filter packages by wildcard pattern matching from package.json file",
"filter packages by regex pattern matching from package.json file",
)
.option(
"--warn-days <NUMBER>",
Expand All @@ -62,8 +62,8 @@ export function getCliOptions() {
Examples:
$ npm-check-last-publish --sort name --order asc
$ npm-check-last-publish --sort average
$ npm-check-last-publish --filter "@types/*"
$ npm-check-last-publish --filter "react-*"
$ npm-check-last-publish --filter @types
$ npm-check-last-publish --filter "^react.*s$"
$ npm-check-last-publish --warn-days 60 --error-days 120
$ npm-check-last-publish --output json > report.json
$ npm-check-last-publish --output csv > report.csv
Expand Down
8 changes: 2 additions & 6 deletions src/lib/expand-package-patterns.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import { globRegex } from "./glob-regex.ts";

export function expandPackagePatterns(
pattern: string,
allNames: string[],
): string[] {
if (!pattern.includes("*")) return [pattern];

const regex = globRegex(pattern);
const matched = allNames.filter((pkg) => {
return regex.test(pkg);
return new RegExp(pattern).test(pkg);
});

return [...new Set(matched)];
}
75 changes: 18 additions & 57 deletions src/lib/fetch-packages.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,37 @@
import { styleText } from "node:util";
import type { PackagePublishInfo } from "../types.ts";
import { expandPackagePatterns } from "./expand-package-patterns.ts";
import { getPackagePublishDate } from "./get-package-publish-date.ts";
import { progressBar } from "./progress-bar.ts";
import { readPackageJson } from "./read-package-json.ts";

type PackageInfoResult = {
results: (PackagePublishInfo | null)[];
errors: { package: string; error: Error }[];
};
export class NoPackageFoundError extends Error {
constructor() {
super("No packages found to check.");
this.name = "NoPackageFoundError";
}
}

export async function fetchPackageInfoList(
inputPackages: string[],
filter: string,
): Promise<PackageInfoResult> {
): Promise<string[]> {
let packagesToCheck: string[];

const shouldReadFromPackage = inputPackages.length === 0 || filter;
if (shouldReadFromPackage) {
try {
const packageJSON = await readPackageJson();
const allDependencies = {
...packageJSON.dependencies,
...packageJSON.devDependencies,
};
packagesToCheck = Object.keys(allDependencies);
packagesToCheck = filter
? expandPackagePatterns(filter, packagesToCheck)
: packagesToCheck;
} catch (e) {
if (e instanceof Error && e.message === "FILE_NOT_FOUND") {
console.error(
styleText(
"redBright",
`[ERROR]: Cannot find ${styleText(
"bold",
"package.json",
)}. Please ensure that the file exists in your current working directory. \n`,
),
);
process.exit(1);
}

throw e;
}
const packageJSON = await readPackageJson();
const allDependencies = {
...packageJSON.dependencies,
...packageJSON.devDependencies,
};
packagesToCheck = Object.keys(allDependencies);
packagesToCheck = filter
? expandPackagePatterns(filter, packagesToCheck)
: packagesToCheck;
} else {
packagesToCheck = inputPackages.map((p) => p.toLowerCase());
}

if (packagesToCheck.length === 0) {
throw new Error("No matching packages found for given patterns.");
}

const errors: { package: string; error: Error }[] = [];
const results: (PackagePublishInfo | null)[] = [];

progressBar.start(packagesToCheck.length, 0);

for (const pkgName of packagesToCheck) {
try {
const info = await getPackagePublishDate(pkgName);
results.push(info);
} catch (err) {
const message =
err instanceof Error ? err.message.split("\n")[0] : String(err);
errors.push({ package: pkgName, error: new Error(message) });
results.push(null);
}
progressBar.increment();
throw new NoPackageFoundError();
}

progressBar.stop();

return { results, errors };
return packagesToCheck;
}
13 changes: 9 additions & 4 deletions src/lib/format-package-info.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import type { PackageInfo, PackagePublishInfo, Thresholds } from "../types.ts";
import { errorPackageInfo, type PackageInfo } from "../models/package-info.ts";
import type { PackagePublishInfo } from "../models/package-publish-info.ts";
import type { Thresholds } from "../types.ts";
import { getAveragePublishDays } from "./get-average-publish-days.ts";
import { getColorArea } from "./get-color-area.ts";

interface FormatPackageOptions {
pkg: PackagePublishInfo;
publishInfo: PackagePublishInfo;
thresholds: Thresholds;
}

export function formatPackageInfo({
pkg,
publishInfo,
thresholds,
}: FormatPackageOptions): PackageInfo {
if (publishInfo.tag === "Error")
return errorPackageInfo(publishInfo.packageName);

const { packageName, packagePublishDate, packageVersion, publishedTimes } =
pkg;
publishInfo;

const averagePublishDays = getAveragePublishDays(publishedTimes);

Expand Down
27 changes: 15 additions & 12 deletions src/lib/get-package-publish-date.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import type { PackagePublishInfo } from "../models/package-publish-info.ts";
import { getPackageVersionsDetail } from "./get-package-versions-detail.ts";

export const getPackagePublishDate = async (packageName: string) => {
try {
const { packageVersion, publishedTimes } =
await getPackageVersionsDetail(packageName);
const packagePublishDate = new Date(publishedTimes[packageVersion]);
return { packagePublishDate, packageVersion, packageName, publishedTimes };
} catch (error: unknown) {
const e = error as Error;
throw new Error(
`Failed to fetch package info for "${packageName}": ${e.message}`,
);
}
export const getPackagePublishDate = async (
packageName: string,
): Promise<PackagePublishInfo> => {
const { packageVersion, publishedTimes } =
await getPackageVersionsDetail(packageName);
const packagePublishDate = new Date(publishedTimes[packageVersion]);

return {
tag: "OK",
packagePublishDate,
packageVersion,
packageName,
publishedTimes,
};
};
31 changes: 23 additions & 8 deletions src/lib/get-package-versions-detail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,28 @@ type PackageVersionsDetail = {

const execPromise = util.promisify(exec);

export class PackageNotFoundError extends Error {
public packageName: string;

constructor(packageName: string) {
super(`Package "${packageName}" not found on npm registry.`);
this.name = "PackageNotFoundError";
this.packageName = packageName;
}
}

export const getPackageVersionsDetail = async (packageName: string) => {
const { stdout: packageInfoStdout } = await execPromise(
`npm view ${packageName} time version --json`,
);
const packageInfo: PackageVersionsDetail = JSON.parse(packageInfoStdout);
return {
packageVersion: packageInfo.version,
publishedTimes: packageInfo.time,
};
try {
const { stdout: packageInfoStdout } = await execPromise(
`npm view ${packageName} time version --json`,
);

const packageInfo: PackageVersionsDetail = JSON.parse(packageInfoStdout);
return {
packageVersion: packageInfo.version,
publishedTimes: packageInfo.time,
};
} catch {
throw new PackageNotFoundError(packageName);
}
};
33 changes: 0 additions & 33 deletions src/lib/glob-regex.ts

This file was deleted.

32 changes: 0 additions & 32 deletions src/lib/process-packages.ts

This file was deleted.

20 changes: 19 additions & 1 deletion src/lib/sort-packages.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { PackageInfo, SortBy, SortOrder } from "../types.js";
import type { PackageInfo } from "../models/package-info.ts";
import type { SortBy, SortOrder } from "../types.js";

export function sortPackages(
list: PackageInfo[],
Expand All @@ -13,9 +14,26 @@ export function sortPackages(
result = a.name.localeCompare(b.name);
break;
case "average":
if (a.averagePublishDays == null) {
result = -1;
break;
}
if (b.averagePublishDays == null) {
result = 1;
break;
}

result = a.averagePublishDays - b.averagePublishDays;
break;
default:
if (a.date == null) {
result = -1;
break;
}
if (b.date == null) {
result = 1;
break;
}
result = a.date.getTime() - b.date.getTime();
}

Expand Down
Loading