UNPKG

sync-npm-packages

Version:

Sync released npm packages to a mirror site.

128 lines (123 loc) 3.47 kB
import { readFile } from 'node:fs/promises'; import { request } from 'node:https'; import process from 'node:process'; import { glob } from 'tinyglobby'; import { createConfigLoader } from 'unconfig'; function toArray(value) { value ??= []; return Array.isArray(value) ? value : [value]; } function unique(array) { return Array.from(new Set(array)); } function isValidPublicPackage(packageJson) { if (packageJson.private) return false; return !!(packageJson.name && packageJson.version); } const SUPPORTED_TARGETS = ["npmmirror"]; function assertSyncTarget(target) { if (!target || !SUPPORTED_TARGETS.includes(target)) { throw new Error( `Required option target to be one of ${SUPPORTED_TARGETS.join(", ")}` ); } } const IGNORE_NODE_MODULES = "**/node_modules/**"; const DEFAULT_IGNORE = [ IGNORE_NODE_MODULES, "**/.git/**", "**/docs/**", "**/tests/**", "**/examples/**", "**/fixtures/**", "**/playground/**" ]; const GLOB_PACKAGE_JSON = "**/package.json"; async function syncPackage2NpmMirror(packageName) { const p = new Promise((resolve) => { const req = request({ method: "PUT", path: `/${packageName}/sync_upstream=true`, host: "registry-direct.npmmirror.com", protocol: "https:", headers: { "content-length": 0 } }); req.write(""); req.on("close", () => { resolve(); }); req.end(); }); return p; } async function syncNpmPackages(input, options) { const packages = unique(toArray(input)); assertSyncTarget(options.target); return Promise.all(packages.map((v) => syncPackage2NpmMirror(v))); } async function getValidPackageNames(options = {}) { const { cwd = process.cwd(), defaultIgnore: useDefaultIgnore = true, ignore: userIgnore = [], include = [], exclude = [], withOptional = false } = options; const ignore = toArray(userIgnore); if (useDefaultIgnore) { ignore.push(...DEFAULT_IGNORE); } else { ignore.push(IGNORE_NODE_MODULES); } const files = await glob(GLOB_PACKAGE_JSON, { cwd, ignore, absolute: true, onlyFiles: true }); const packages = [...toArray(include)]; for await (const file of files) { const content = await readFile(file, "utf-8"); const packageJson = JSON.parse(content); if (isValidPublicPackage(packageJson)) { packages.push(packageJson.name); if (withOptional) { packages.push(...Object.keys(packageJson.optionalDependencies || {})); } } } return unique(packages.filter((pkg) => !toArray(exclude).includes(pkg))); } async function syncNpmPackagesAuto(options) { assertSyncTarget(options.target); const packages = await getValidPackageNames(options); return syncNpmPackages(packages, options); } function defineConfig(config = {}) { return config; } async function resolveConfig(cliConfig = {}) { const loader = createConfigLoader({ sources: [ { files: ["sync.config"], extensions: ["mts", "cts", "ts", "mjs", "cjs", "js", "json"] }, { files: [".syncrc"], extensions: ["json"] } ], cwd: process.cwd(), merge: false }); const { config = {}, sources = [] } = await loader.load(); return sources.length ? { ...config, ...cliConfig } : cliConfig; } export { syncNpmPackagesAuto as a, assertSyncTarget as b, defineConfig as d, getValidPackageNames as g, resolveConfig as r, syncNpmPackages as s };