diff --git a/src/index.ts b/src/index.ts index 29f199f..52268a0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import type { CheckOptions } from './types' export { resolvePackage, resolveDependencies, resolveDependency } from './io/resolves' -export { loadPackageJSON as loadPackage, loadPackages, writePackage } from './io/packages' +export { loadPackage, loadPackages, writePackage } from './io/packages' export { dumpDependencies, parseDependencies } from './io/dependencies' export { CheckPackages } from './api/check' export * from './types' diff --git a/src/io/packageJson.ts b/src/io/packageJson.ts new file mode 100644 index 0000000..e21a436 --- /dev/null +++ b/src/io/packageJson.ts @@ -0,0 +1,82 @@ +import path from 'node:path' +import type { CommonOptions, PackageMeta, RawDep } from '../types' +import { dumpDependencies, getByPath, parseDependencies, parseDependency, setByPath } from './dependencies' +import { readJSON, writeJSON } from './packages' + +const depsFields = [ + 'dependencies', + 'devDependencies', + 'optionalDependencies', + 'packageManager', + 'pnpm.overrides', + 'resolutions', + 'overrides', +] as const + +export async function loadPackageJSON( + relative: string, + options: CommonOptions, + shouldUpdate: (name: string) => boolean, +): Promise { + const filepath = path.resolve(options.cwd ?? '', relative) + const raw = await readJSON(filepath) + const deps: RawDep[] = [] + + for (const key of depsFields) { + if (options.depFields?.[key] !== false) { + if (key === 'packageManager') { + if (raw.packageManager) { + const [name, version] = raw.packageManager.split('@') + deps.push(parseDependency(name, `^${version}`, 'packageManager', shouldUpdate)) + } + } + else { + deps.push(...parseDependencies(raw, key, shouldUpdate)) + } + } + } + + return [ + { + name: raw.name, + private: !!raw.private, + version: raw.version, + type: 'package.json', + relative, + filepath, + raw, + deps, + resolved: [], + }, + ] +} + +export async function writePackageJSON( + pkg: PackageMeta, + options: CommonOptions, +) { + const { raw, filepath, resolved } = pkg + + let changed = false + + depsFields.forEach((key) => { + if (options.depFields?.[key] === false) + return + if (key === 'packageManager') { + const value = Object.entries(dumpDependencies(resolved, 'packageManager'))[0] + if (value) { + raw.packageManager = `${value[0]}@${value[1].replace('^', '')}` + changed = true + } + } + else { + if (getByPath(raw, key)) { + setByPath(raw, key, dumpDependencies(resolved, key)) + changed = true + } + } + }) + + if (changed) + await writeJSON(filepath, raw) +} diff --git a/src/io/packages.ts b/src/io/packages.ts index 508b88a..b2cc7db 100644 --- a/src/io/packages.ts +++ b/src/io/packages.ts @@ -1,12 +1,12 @@ import path from 'node:path' import { existsSync, promises as fs } from 'node:fs' import fg from 'fast-glob' -import YAML from 'js-yaml' import detectIndent from 'detect-indent' import type { CommonOptions, PackageMeta, RawDep } from '../types' import { createDependenciesFilter } from '../utils/dependenciesFilter' import { DEFAULT_IGNORE_PATHS } from '../constants' -import { dumpDependencies, getByPath, parseDependencies, parseDependency, setByPath } from './dependencies' +import { loadPackageJSON, writePackageJSON } from './packageJson' +import { loadPnpmWorkspace, writePnpmWorkspace } from './pnpmWorkspaces' export async function readJSON(filepath: string) { return JSON.parse(await fs.readFile(filepath, 'utf-8')) @@ -19,16 +19,6 @@ export async function writeJSON(filepath: string, data: any) { return await fs.writeFile(filepath, `${JSON.stringify(data, null, fileIndent)}\n`, 'utf-8') } -const depsFields = [ - 'dependencies', - 'devDependencies', - 'optionalDependencies', - 'packageManager', - 'pnpm.overrides', - 'resolutions', - 'overrides', -] as const - export async function writePackage( pkg: PackageMeta, options: CommonOptions, @@ -43,102 +33,6 @@ export async function writePackage( } } -export async function writePnpmWorkspace( - pkg: PackageMeta, - _options: CommonOptions, -) { - const catalogName = pkg.name.replace('catalog:', '') - const versions = dumpDependencies(pkg.resolved, 'pnpm:catalog') - - if (!Object.keys(versions).length) - return - - if (catalogName === 'default') { - pkg.raw.catalog = versions - } - else { - pkg.raw.catalogs ??= {} - pkg.raw.catalogs[catalogName] = versions - } - - await fs.writeFile(pkg.filepath, YAML.dump(pkg.raw), 'utf-8') -} - -export async function writePackageJSON( - pkg: PackageMeta, - options: CommonOptions, -) { - const { raw, filepath, resolved } = pkg - - let changed = false - - depsFields.forEach((key) => { - if (options.depFields?.[key] === false) - return - if (key === 'packageManager') { - const value = Object.entries(dumpDependencies(resolved, 'packageManager'))[0] - if (value) { - raw.packageManager = `${value[0]}@${value[1].replace('^', '')}` - changed = true - } - } - else { - if (getByPath(raw, key)) { - setByPath(raw, key, dumpDependencies(resolved, key)) - changed = true - } - } - }) - - if (changed) - await writeJSON(filepath, raw) -} - -export async function loadPnpmWorkspace( - relative: string, - options: CommonOptions, - shouldUpdate: (name: string) => boolean, -): Promise { - const filepath = path.resolve(options.cwd ?? '', relative) - const rawText = await fs.readFile(filepath, 'utf-8') - const raw = YAML.load(rawText) as any - - const catalogs: PackageMeta[] = [] - - function createCatalogFromKeyValue(catalogName: string, map: Record): PackageMeta { - const deps: RawDep[] = Object.entries(map) - .map(([name, version]) => parseDependency(name, version, 'pnpm:catalog', shouldUpdate)) - - return { - name: `catalog:${catalogName}`, - private: true, - version: '', - type: 'pnpm-workspace.yaml', - relative, - filepath, - raw, - deps, - resolved: [], - } - } - - if (raw.catalog) { - catalogs.push( - createCatalogFromKeyValue('default', raw.catalog), - ) - } - - if (raw.catalogs) { - for (const key of Object.keys(raw.catalogs)) { - catalogs.push( - createCatalogFromKeyValue(key, raw.catalogs[key]), - ) - } - } - - return catalogs -} - export async function loadPackage( relative: string, options: CommonOptions, @@ -149,44 +43,6 @@ export async function loadPackage( return loadPackageJSON(relative, options, shouldUpdate) } -export async function loadPackageJSON( - relative: string, - options: CommonOptions, - shouldUpdate: (name: string) => boolean, -): Promise { - const filepath = path.resolve(options.cwd ?? '', relative) - const raw = await readJSON(filepath) - const deps: RawDep[] = [] - - for (const key of depsFields) { - if (options.depFields?.[key] !== false) { - if (key === 'packageManager') { - if (raw.packageManager) { - const [name, version] = raw.packageManager.split('@') - deps.push(parseDependency(name, `^${version}`, 'packageManager', shouldUpdate)) - } - } - else { - deps.push(...parseDependencies(raw, key, shouldUpdate)) - } - } - } - - return [ - { - name: raw.name, - private: !!raw.private, - version: raw.version, - type: 'package.json', - relative, - filepath, - raw, - deps, - resolved: [], - }, - ] -} - export async function loadPackages(options: CommonOptions): Promise { let packagesNames: string[] = [] diff --git a/src/io/pnpmWorkspaces.ts b/src/io/pnpmWorkspaces.ts new file mode 100644 index 0000000..af886a6 --- /dev/null +++ b/src/io/pnpmWorkspaces.ts @@ -0,0 +1,71 @@ +import path from 'node:path' +import fs from 'node:fs/promises' +import YAML from 'js-yaml' +import type { CommonOptions, PackageMeta, RawDep } from '../types' +import { dumpDependencies, parseDependency } from './dependencies' + +export async function loadPnpmWorkspace( + relative: string, + options: CommonOptions, + shouldUpdate: (name: string) => boolean, +): Promise { + const filepath = path.resolve(options.cwd ?? '', relative) + const rawText = await fs.readFile(filepath, 'utf-8') + const raw = YAML.load(rawText) as any + + const catalogs: PackageMeta[] = [] + + function createCatalogFromKeyValue(catalogName: string, map: Record): PackageMeta { + const deps: RawDep[] = Object.entries(map) + .map(([name, version]) => parseDependency(name, version, 'pnpm:catalog', shouldUpdate)) + + return { + name: `catalog:${catalogName}`, + private: true, + version: '', + type: 'pnpm-workspace.yaml', + relative, + filepath, + raw, + deps, + resolved: [], + } + } + + if (raw.catalog) { + catalogs.push( + createCatalogFromKeyValue('default', raw.catalog), + ) + } + + if (raw.catalogs) { + for (const key of Object.keys(raw.catalogs)) { + catalogs.push( + createCatalogFromKeyValue(key, raw.catalogs[key]), + ) + } + } + + return catalogs +} + +export async function writePnpmWorkspace( + pkg: PackageMeta, + _options: CommonOptions, +) { + const catalogName = pkg.name.replace('catalog:', '') + const versions = dumpDependencies(pkg.resolved, 'pnpm:catalog') + + if (!Object.keys(versions).length) + return + + if (catalogName === 'default') { + pkg.raw.catalog = versions + } + else { + pkg.raw.catalogs ??= {} + pkg.raw.catalogs[catalogName] = versions + } + + await fs.writeFile(pkg.filepath, YAML.dump(pkg.raw), 'utf-8') +}