UNPKG

pncat

Version:

A unified cli tool that enhances package managers catalogs feature.

609 lines (608 loc) 19.5 kB
import { PnpmWorkspaceYaml, PnpmWorkspaceYamlSchema } from "pnpm-workspace-yaml"; //#region src/workspace-manager.d.ts declare class Workspace { catalog: CatalogHandler; private loaded; private loadTask; private options; private packages; private packageRegistry; private catalogRegistry; private packageDepIndex; private catalogDepIndex; private depUsageIndex; constructor(options: CatalogOptions); /** * Reset the catalog manager, clear all indexes and loaded packages */ reset(): void; /** * Get the catalog options */ getOptions(): CatalogOptions; /** * Get the current working directory */ getCwd(): string; /** * Load packages from the current working directory */ loadPackages(): Promise<PackageMeta[]>; /** * Get the names of monorepo packages */ getWorkspacePackages(): string[]; /** * Get the dependencies of a package */ getPackageDeps(pkgName: string): RawDep[]; /** * Get a dependency of a package */ getPackageDep(depName: string, pkgName: string): RawDep | null; /** * Remove a dependency from a package */ removePackageDep(depName: string, catalogName: string, isRecursive?: boolean, updatedPackages?: Map<string, PackageJsonMeta>): Promise<{ updatedPackages: Map<string, PackageJsonMeta>; catalogDeletable: boolean; }>; /** * Get a dependency of a catalog */ getCatalogDep(depName: string, catalogName: string): RawDep | null; /** * Get the dependencies of a catalog */ getCatalogDeps(catalogName: string): RawDep[]; /** * Get the packages that use a dependency */ getDepPackages(depName: string): string[]; /** * Infer the catalog name for a dependency */ inferCatalogName(dep: Omit<RawDep, 'catalogName'>): string; /** * Check if a package is a catalog package */ isCatalogPackage(pkg: PackageMeta): pkg is WorkspacePackageMeta; /** * Extract the catalog name from a specifier */ extractCatalogName(specifier: string): string; /** * Extract the catalog name from a package name */ extractCatalogNameFromPkgName(pkgName: string): string; /** * Normalize a dependency, update the catalog name if needed */ resolveDep(dep: RawDep, force?: boolean): RawDep; /** * Get the specifier from the workspace catalog */ resolveCatalogSpecifier(dep: RawDep): RawDep | null; /** * Check if a catalog dependency is in a package */ isDepInPackage(catalogDep: RawDep): boolean; /** * Check if a package dependency is in a catalog */ isDepInCatalog(pkgDep: RawDep): boolean; /** * Check if a catalog dependency is in pnpm overrides */ isDepInPnpmOverrides(catalogDep: RawDep): boolean; /** * Get the names of dependencies */ getDepNames(): string[]; /** * Create indexes for the loaded packages */ private createIndexes; /** * Set the package dependency index */ private setPackageDepIndex; /** * Set the workspace dependency index */ private setCatalogDepIndex; /** * Set the dependency usage index */ private setDepUsageIndex; } //#endregion //#region src/constants.d.ts declare const MODE_CHOICES: readonly ["init", "detect", "migrate", "add", "remove", "clean", "revert"]; declare const AGENTS: readonly ["pnpm", "yarn", "bun", "vlt"]; declare const DEPS_FIELDS: readonly ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies", "pnpm.overrides", "resolutions", "overrides", "pnpm-workspace", "yarn-workspace", "bun-workspace", "vlt-workspace"]; //#endregion //#region src/types/rules.d.ts interface CatalogRule { name: string; match: string | RegExp | (string | RegExp)[]; depFields?: DepType[]; priority?: number; specifierRules?: SpecifierRule[]; } interface SpecifierRule { /** * Semver range, e.g., ">=3.0.0", "<3.0.0" */ specifier: string; /** * Specific packages this version range applies to. * If not specified, applies to all packages matched by the parent CatalogRule. */ match?: string | RegExp | (string | RegExp)[]; /** * Complete catalog name, takes priority over suffix */ name?: string; /** * Catalog suffix, e.g., "v3", "v2" */ suffix?: string; } interface SpecifierOptions { /** * Whether to skip complex version ranges (e.g., "||", "-", ">=16.0.0") * @default true */ skipComplexRanges?: boolean; /** * List of specific range types to skip (overrides skipComplexRanges) * Example: ["||", "-", ">=", "<", "x", "*", "pre-release"] */ skipRangeTypes?: SpecifierRangeType[]; /** * Whether to allow pre-release versions (e.g., "4.0.0-beta") * @default true */ allowPreReleases?: boolean; /** * Whether to allow wildcard versions (e.g., "3.x", "*") * @default false */ allowWildcards?: boolean; } type SpecifierRangeType = '||' | '-' | '>=' | '<=' | '>' | '<' | 'x' | '*' | 'pre-release'; //#endregion //#region src/types/core.d.ts type RangeMode = typeof MODE_CHOICES[number]; type DepType = typeof DEPS_FIELDS[number]; type Agent = typeof AGENTS[number]; type DepFieldOptions = Partial<Record<DepType, boolean>>; type DepFilter = (name: string, specifier: string) => boolean; interface CommandOptions { cwd?: string; mode?: RangeMode; /** * Recursively search for package.json in subdirectories * @default true */ recursive?: boolean; /** * Force the execution of the command * @default false */ force?: boolean; /** * Install from a specific catalog, auto detect if not provided */ catalog?: string; /** * Prompt for confirmation * @default true */ yes?: boolean; /** * Run install after command * @default true */ install?: boolean; /** * Show complete catalogs instead of only the diff * @default false */ verbose?: boolean; } interface ConfigOptions { agent?: Agent; /** * Only included dependencies will be checked for catalog */ include?: string | string[]; /** * Exclude dependencies to be checked, will override --include options */ exclude?: string | string[]; /** * Paths to ignore */ ignorePaths?: string | string[]; /** * Ignore other workspaces * @default true */ ignoreOtherWorkspaces?: boolean; /** * Fields in package.json to be checked * By default check `dependencies`, `devDependencies` and `peerDependencies` */ depFields?: DepFieldOptions; /** * Allowed protocols in specifier to not be converted to catalog */ allowedProtocols?: string[]; /** * Save exact version of the dependency * @default false */ saveExact?: boolean; /** * Hook to run after command completion * Can be a shell command string or a function */ postRun?: string | HookFunction | Array<string | HookFunction>; } interface CatalogOptions extends CommandOptions, ConfigOptions { /** * Rules to group and name dependencies in the catalog output */ catalogRules?: CatalogRule[]; /** * Options to control how specifier ranges are processed */ specifierOptions?: SpecifierOptions; } type HookFunction = () => Promise<void> | void; //#endregion //#region src/types/package-json.d.ts interface PackageJson { /** * The name is what your thing is called. * Some rules: * - The name must be less than or equal to 214 characters. This includes the scope for scoped packages. * - The name can’t start with a dot or an underscore. * - New packages must not have uppercase letters in the name. * - The name ends up being part of a URL, an argument on the command line, and a folder name. Therefore, the name can’t contain any non-URL-safe characters. */ name?: string; /** * Version must be parseable by `node-semver`, which is bundled with npm as a dependency. (`npm install semver` to use it yourself.) */ version?: string; /** * Put a description in it. It’s a string. This helps people discover your package, as it’s listed in `npm search`. */ description?: string; /** * Dependencies are specified in a simple object that maps a package name to a version range. The version range is a string which has one or more space-separated descriptors. Dependencies can also be identified with a tarball or git URL. */ dependencies?: Record<string, string>; /** * If someone is planning on downloading and using your module in their program, then they probably don’t want or need to download and build the external test or documentation framework that you use. * In this case, it’s best to map these additional items in a `devDependencies` object. */ devDependencies?: Record<string, string>; /** * If a dependency can be used, but you would like npm to proceed if it cannot be found or fails to install, then you may put it in the `optionalDependencies` object. This is a map of package name to version or url, just like the `dependencies` object. The difference is that build failures do not cause installation to fail. */ optionalDependencies?: Record<string, string>; /** * In some cases, you want to express the compatibility of your package with a host tool or library, while not necessarily doing a `require` of this host. This is usually referred to as a plugin. Notably, your module may be exposing a specific interface, expected and specified by the host documentation. */ peerDependencies?: Record<string, string>; /** * The field is used to define a set of sub-packages (or workspaces) within a monorepo. * * This field is an array of glob patterns or an object with specific configurations for managing * multiple packages in a single repository. */ workspaces?: string[] | { /** * Workspace package paths. Glob patterns are supported. */ packages?: string[]; /** * Packages to block from hoisting to the workspace root. * Uses glob patterns to match module paths in the dependency tree. * * Docs: * - https://classic.yarnpkg.com/blog/2018/02/15/nohoist/ */ nohoist?: string[]; /** * Docs: * - https://bun.sh/docs/install/catalogs */ catalog?: Record<string, string>; catalogs?: Record<string, Record<string, string>>; }; /** * Docs: * - https://code.visualstudio.com/api/references/extension-manifest */ engines?: { vscode?: string; }; [key: string]: any; } //#endregion //#region src/types/meta.d.ts type WorkspaceYaml = PnpmWorkspaceYaml; type WorkspaceSchema = PnpmWorkspaceYamlSchema; interface RawDep { name: string; specifier: string; source: DepType; /** * Path of dependency in the package.json */ parents?: string[]; /** * Is the dependency a catalog */ catalog: boolean; /** * Is the dependency can be cataloged */ catalogable: boolean; /** * Inference catalog name by catalog rules */ catalogName: string; /** * Is the dependency updated by catalog rules */ update?: boolean; } interface BasePackageMeta { /** * Package name */ name: string; /** * Is private package */ private?: boolean; /** * Package version */ version?: string; /** * Absolute filepath */ filepath: string; /** * Relative filepath to the root project */ relative: string; /** * Dependencies */ deps: RawDep[]; } interface PackageJsonMeta extends BasePackageMeta { /** * Package type */ type: 'package.json'; /** * Raw package.json Object */ raw: PackageJson; } interface PnpmWorkspaceMeta extends BasePackageMeta { type: 'pnpm-workspace.yaml'; raw: WorkspaceSchema; context: WorkspaceYaml; } interface YarnWorkspaceMeta extends Omit<PnpmWorkspaceMeta, 'type'> { type: '.yarnrc.yml'; } interface BunWorkspaceMeta extends BasePackageMeta { type: 'bun-workspace'; raw: PackageJson; } interface VltWorkspaceMeta extends BasePackageMeta { type: 'vlt.json'; raw: WorkspaceSchema; } type WorkspacePackageMeta = PnpmWorkspaceMeta | YarnWorkspaceMeta | BunWorkspaceMeta | VltWorkspaceMeta; type PackageMeta = PackageJsonMeta | WorkspacePackageMeta; interface ParsedSpec { name: string; specifier?: string; catalogName?: string; specifierSource?: 'user' | 'catalog' | 'workspace' | 'npm'; } interface AgentConfig { type: WorkspacePackageMeta['type']; depType: DepType; filename: string; locks: string | string[]; defaultContent: string; } //#endregion //#region src/types/catalog.d.ts interface CatalogHandler { readonly workspace: Workspace; readonly options: CatalogOptions; /** * Find the workspace file */ findWorkspaceFile: () => Promise<string | undefined>; /** * Ensure the workspace file exists */ ensureWorkspace: () => Promise<void>; /** * Convert the workspace to a JSON object */ toJSON: () => Promise<WorkspaceSchema>; /** * Convert the workspace to a string */ toString: () => Promise<string>; /** * Set a package to catalog */ setPackage: (catalog: 'default' | (string & {}), packageName: string, specifier: string) => Promise<void>; /** * Remove packages from the workspace */ removePackages: (deps: RawDep[]) => Promise<void>; /** * Get the catalogs for a package */ getPackageCatalogs: (name: string) => Promise<string[]>; /** * Generate the catalogs for a package */ generateCatalogs: (deps: RawDep[]) => Promise<void>; /** * Cleanup the catalogs */ cleanupCatalogs: () => Promise<void>; /** * Clear the catalogs */ clearCatalogs: () => Promise<void>; /** * Get the workspace path */ getWorkspacePath: () => Promise<string>; /** * Write the workspace */ writeWorkspace: () => Promise<void>; /** * Update the workspace overrides */ updateWorkspaceOverrides?: () => Promise<void>; } //#endregion //#region src/types/resolver.d.ts interface ResolverContext { args?: string[]; options: CatalogOptions; workspace: Workspace; } interface ResolverResult { isDev?: boolean; isPeer?: boolean; isOptional?: boolean; isRevertAll?: boolean; dependencies?: RawDep[]; updatedPackages?: Record<string, PackageJsonMeta>; } //#endregion //#region src/catalog-handler/json-workspace.d.ts declare class JsonCatalog implements CatalogHandler { workspace: Workspace; options: CatalogOptions; agent: 'bun' | 'vlt'; workspaceJson: WorkspaceSchema | null; workspaceJsonPath: string | null; constructor(workspace: Workspace); findWorkspaceFile(): Promise<string | undefined>; ensureWorkspace(): Promise<void>; toJSON(): Promise<WorkspaceSchema>; toString(): Promise<string>; setPackage(catalog: 'default' | (string & {}), packageName: string, specifier: string): Promise<void>; removePackages(deps: RawDep[]): Promise<void>; getPackageCatalogs(name: string): Promise<string[]>; generateCatalogs(deps: RawDep[]): Promise<void>; cleanupCatalogs(): Promise<void>; clearCatalogs(): Promise<void>; getWorkspacePath(): Promise<string>; writeWorkspace(): Promise<void>; getWorkspaceJson(): Promise<WorkspaceSchema>; } //#endregion //#region src/catalog-handler/bun-workspace.d.ts declare class BunCatalog extends JsonCatalog { static loadWorkspace(relative: string, options: CatalogOptions, shouldCatalog: DepFilter): Promise<BunWorkspaceMeta[]>; findWorkspaceFile(): Promise<string | undefined>; ensureWorkspace(): Promise<void>; private findBunWorkspace; } //#endregion //#region src/catalog-handler/yaml-workspace.d.ts declare class YamlCatalog implements CatalogHandler { workspace: Workspace; options: CatalogOptions; agent: 'pnpm' | 'yarn'; workspaceYaml: WorkspaceYaml | null; workspaceYamlPath: string | null; constructor(workspace: Workspace); static loadWorkspace(relative: string, options: CatalogOptions, shouldCatalog: DepFilter): Promise<WorkspacePackageMeta[]>; findWorkspaceFile(): Promise<string | undefined>; ensureWorkspace(): Promise<void>; toJSON(): Promise<WorkspaceSchema>; toString(): Promise<string>; setPackage(catalog: 'default' | (string & {}), packageName: string, specifier: string): Promise<void>; removePackages(deps: RawDep[]): Promise<void>; getPackageCatalogs(name: string): Promise<string[]>; generateCatalogs(deps: RawDep[]): Promise<void>; cleanupCatalogs(): Promise<void>; clearCatalogs(): Promise<void>; getWorkspacePath(): Promise<string>; writeWorkspace(): Promise<void>; getWorkspaceYaml(): Promise<WorkspaceYaml>; } //#endregion //#region src/catalog-handler/pnpm-workspace.d.ts declare class PnpmCatalog extends YamlCatalog { static loadWorkspace(relative: string, options: CatalogOptions, shouldCatalog: DepFilter): Promise<PnpmWorkspaceMeta[]>; updateWorkspaceOverrides(): Promise<void>; } //#endregion //#region src/catalog-handler/vlt-workspace.d.ts declare class VltCatalog extends JsonCatalog { static loadWorkspace(relative: string, options: CatalogOptions, shouldCatalog: DepFilter): Promise<VltWorkspaceMeta[]>; } //#endregion //#region src/catalog-handler/yarn-workspace.d.ts declare class YarnCatalog extends YamlCatalog { static loadWorkspace(relative: string, options: CatalogOptions, shouldCatalog: DepFilter): Promise<YarnWorkspaceMeta[]>; } //#endregion //#region src/catalog-handler/index.d.ts declare function createCatalogHandler(workspace: Workspace): CatalogHandler; //#endregion //#region src/rules.d.ts declare const DEFAULT_CATALOG_RULES: CatalogRule[]; //#endregion //#region src/utils/catalog.d.ts declare function isCatalogWorkspace(type: DepType): type is "pnpm-workspace" | "yarn-workspace" | "bun-workspace" | "vlt-workspace"; declare function isCatalogPackageName(name: string): boolean; declare function extractCatalogName(name: string): string; declare function isCatalogSpecifier(specifier: string): boolean; declare function normalizeCatalogName(catalogName: string): string; declare function isDepMatched(depName: string, match: string | RegExp | (string | RegExp)[]): boolean; declare function inferCatalogName(dep: Omit<RawDep, 'catalogName'>, options: CatalogOptions): string; declare function createDepCatalogIndex(workspaceJson?: WorkspaceSchema): Map<string, { catalogName: string; specifier: string; }[]>; //#endregion //#region src/utils/merge.d.ts interface MergeOptions { mergeDefaults?: boolean; arrayMerge?: (target: CatalogRule[], source: CatalogRule[]) => CatalogRule[]; } declare function mergeCatalogRules(options: MergeOptions, ...rules: CatalogRule[][]): CatalogRule[]; declare function mergeCatalogRules(...rules: CatalogRule[][]): CatalogRule[]; //#endregion //#region src/index.d.ts declare function defineConfig(config: Partial<CatalogOptions>): Partial<CatalogOptions>; //#endregion export { Agent, AgentConfig, BasePackageMeta, BunCatalog, BunWorkspaceMeta, CatalogHandler, CatalogOptions, CatalogRule, CommandOptions, ConfigOptions, DEFAULT_CATALOG_RULES, DepFieldOptions, DepFilter, DepType, HookFunction, MergeOptions, PackageJson, PackageJsonMeta, PackageMeta, ParsedSpec, PnpmCatalog, PnpmWorkspaceMeta, RangeMode, RawDep, ResolverContext, ResolverResult, SpecifierOptions, SpecifierRangeType, SpecifierRule, VltCatalog, VltWorkspaceMeta, Workspace, WorkspacePackageMeta, WorkspaceSchema, WorkspaceYaml, YarnCatalog, YarnWorkspaceMeta, createCatalogHandler, createDepCatalogIndex, defineConfig, extractCatalogName, inferCatalogName, isCatalogPackageName, isCatalogSpecifier, isCatalogWorkspace, isDepMatched, mergeCatalogRules, normalizeCatalogName };