Find all packages inside a directory with customizable pattern matching for monorepos
npx @tessl/cli install tessl/npm-pnpm--fs--find-packages@1000.0.0@pnpm/fs.find-packages provides functionality to find all packages inside a directory with customizable pattern matching. It's designed for working with monorepos and workspaces, allowing developers to discover package.json, package.yaml, and package.json5 files across complex directory structures.
pnpm add @pnpm/fs.find-packagesCommonJS (primary):
const { findPackages } = require("@pnpm/fs.find-packages");TypeScript:
import { findPackages, type Options } from "@pnpm/fs.find-packages";import { findPackages } from "@pnpm/fs.find-packages";
import path from "path";
// Find all packages in a directory with default patterns
const packages = await findPackages(path.join(__dirname, "my-monorepo"));
// Each package contains:
// - rootDir: path to package directory
// - rootDirRealPath: resolved real path
// - manifest: parsed package.json/yaml/json5 content
// - writeProjectManifest: function to write manifest changes
console.log(packages[0].manifest.name); // package name
console.log(packages[0].rootDir); // package directoryAsynchronously finds all packages in a directory based on configurable glob patterns and ignore rules.
/**
* Find all packages in a directory
* @param root - Root directory to search in
* @param opts - Optional configuration for search behavior
* @returns Promise resolving to array of discovered projects
*/
function findPackages(root: string, opts?: Options): Promise<Project[]>;
interface Options {
/** Patterns to ignore when searching (default: node_modules, bower_components, test, tests) */
ignore?: string[];
/** Whether to include the workspace root package (default: false) */
includeRoot?: boolean;
/**
* Glob patterns for package locations (default: ['.', '**'])
* Supports positive patterns ('components/**') and negative patterns ('!test/**', '!/libs/**')
* Negative patterns starting with '!/' are treated as absolute paths from the search root
*/
patterns?: string[];
}Usage Examples:
import { findPackages } from "@pnpm/fs.find-packages";
// Basic usage - find all packages with default patterns
const allPackages = await findPackages("/path/to/monorepo");
// Custom patterns - only search in specific directories
const componentPackages = await findPackages("/path/to/monorepo", {
patterns: ["components/**", "libs/**"]
});
// Include workspace root and custom ignore patterns
const packagesWithRoot = await findPackages("/path/to/monorepo", {
includeRoot: true,
ignore: ["**/node_modules/**", "**/dist/**", "**/.tmp/**"]
});
// Exclude specific directories using negative patterns
const filteredPackages = await findPackages("/path/to/monorepo", {
patterns: ["**", "!test-fixtures/**", "!examples/**"]
});
// Negative patterns with absolute paths (note the leading slash)
const alternativeFiltered = await findPackages("/path/to/monorepo", {
patterns: ["**", "!/libs/**"] // absolute exclusion from root
});interface Project {
/** Directory path containing the package */
rootDir: ProjectRootDir;
/** Real filesystem path to the package directory */
rootDirRealPath: ProjectRootDirRealPath;
/** Optional modules directory path */
modulesDir?: string;
/** Parsed package manifest (package.json/yaml/json5) */
manifest: ProjectManifest;
/** Function to write changes back to the manifest file */
writeProjectManifest: (manifest: ProjectManifest, force?: boolean) => Promise<void>;
}
type ProjectRootDir = string & { __brand: 'ProjectRootDir' };
type ProjectRootDirRealPath = string & { __brand: 'ProjectRootDirRealPath' };
interface ProjectManifest {
// Basic package information
name?: string;
version?: string;
description?: string;
keywords?: string[];
author?: string | { name?: string; email?: string; url?: string };
maintainers?: Array<{ name?: string; email?: string; url?: string }>;
contributors?: Array<string | { name?: string; email?: string; url?: string }>;
license?: string;
// Entry points and module configuration
main?: string;
module?: string;
browser?: string | Record<string, string | false>;
type?: "module" | "commonjs";
types?: string;
typings?: string;
bin?: string | Record<string, string>;
files?: string[];
exports?: string | Record<string, any>;
// Scripts and lifecycle hooks
scripts?: Record<string, string>;
// Dependencies
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
peerDependencies?: Record<string, string>;
peerDependenciesMeta?: Record<string, { optional?: boolean }>;
optionalDependencies?: Record<string, string>;
bundleDependencies?: string[] | boolean;
bundledDependencies?: string[] | boolean;
// Configuration and constraints
engines?: Record<string, string>;
engineStrict?: boolean;
os?: string[];
cpu?: string[];
// Publishing and repository
private?: boolean;
publishConfig?: Record<string, any>;
homepage?: string;
repository?: string | { type?: string; url: string; directory?: string };
bugs?: string | { url?: string; email?: string };
funding?: string | { type?: string; url: string } | Array<string | { type?: string; url: string }>;
// Workspace and monorepo (pnpm-specific)
packageManager?: string;
workspaces?: string[] | { packages?: string[]; nohoist?: string[] };
resolutions?: Record<string, string>;
// pnpm-specific configuration
pnpm?: {
overrides?: Record<string, string>;
packageExtensions?: Record<string, any>;
peerDependencyRules?: {
ignoreMissing?: string[];
allowedVersions?: Record<string, string>;
allowAny?: string[];
};
neverBuiltDependencies?: string[];
onlyBuiltDependencies?: string[];
allowedDeprecatedVersions?: Record<string, string>;
// Workspace-specific settings
requiredScripts?: string[];
// Publishing settings
updateConfig?: {
ignoreDependencies?: string[];
};
};
// Additional fields (for extensibility)
[key: string]: any;
}The package automatically detects and parses multiple manifest file formats:
package.json - Standard JSON formatpackage.yaml - YAML formatpackage.json5 - JSON5 format with comments and trailing commasBy default, the following directories are ignored during package discovery:
**/node_modules/** - npm/yarn dependency directories**/bower_components/** - Bower dependency directories**/test/** - Test directories**/tests/** - Test directories (alternative naming)The function handles filesystem errors gracefully:
ENOENT errors) are silently ignoredtinyglobby for efficient glob pattern matchingSet data structure to automatically deduplicate discovered pathsp-filter for improved performance