https://github.com/alcalzone/pak
Programmatic wrapper around popular Node.js package managers
https://github.com/alcalzone/pak
Last synced: about 1 year ago
JSON representation
Programmatic wrapper around popular Node.js package managers
- Host: GitHub
- URL: https://github.com/alcalzone/pak
- Owner: AlCalzone
- License: mit
- Created: 2021-04-22T11:03:34.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2024-06-21T09:22:06.000Z (almost 2 years ago)
- Last Synced: 2025-02-27T16:43:40.749Z (over 1 year ago)
- Language: TypeScript
- Size: 2.96 MB
- Stars: 4
- Watchers: 2
- Forks: 3
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# pak
Programmatic wrapper around popular Node.js package managers
Supports:
- [x] `npm`
- [x] `Yarn Classic`
- [x] `Yarn Berry`
_(not all features are available for all package managers)_
## Usage
### Auto-detect the correct package-manager to use
```ts
import { detectPackageManager } from "pak";
async function main() {
// Use the current working directory
const pak = await detectPackageManager();
// Or use a different directory. The package manager will default to that dir
const pak = await detectPackageManager({ cwd: "/path/to/dir" });
}
```
`detectPackageManager` takes an options object with the following properties:
```ts
{
/** The working directory for the package manager. Detection will start from here upwards. */
cwd?: string;
/** Whether to change the `cwd` to operate in the package's root directory instead of the current one. */
setCwdToPackageRoot?: boolean;
/** If this is `false` and no package manager with a matching lockfile was found, another pass is done without requiring one */
requireLockfile?: boolean;
}
```
### Create an instance of a specific package manager
```ts
import { packageManagers } from "pak";
const pak = new packageManagers.npm();
```
### Package manager properties
All package managers share the following properties:
| Property | Type | Description |
---------------------------------------------------------------- | -------- | --------- |
| `cwd` | `string` | The directory to run the package manager commands in. Defaults to `process.cwd()` |
| `loglevel` | `"info" \| "verbose" \| "warn" \| "error" \| "silent"` | Which loglevel to pass to the package manager. **Note:** Not every package manager supports every loglevel. |
| `stdout` | `WritableStream` | A stream to pipe the command's `stdout` into. |
| `stderr` | `WritableStream` | A stream to pipe the command's `stderr` into. |
| `stdall` | `WritableStream` | A stream to pipe the command's `stdout` and `stderr` into in the order the output comes. |
| `environment`| `"production" | "development"` | In an production environment, `pak` avoids accidentally pulling in `devDependencies` during `install` commands. |
### Install one or more packages
```ts
const result = await pak.install(packages, options);
```
- `packages` is an array of package specifiers, like `["pak", "fs-extra"]` or `["semver@1.2.3"]`
- `options`: See [common options](#common-options) for details.
If `packages` is empty or `undefined`, this will install the packages that are defined in `package.json` in the `cwd`.
### Uninstall one or more packages
```ts
const result = await pak.uninstall(packages, options);
```
- `packages` is an array of package specifiers, like `["pak", "fs-extra"]` or `["semver@1.2.3"]`
- `options`: See [common options](#common-options) for details.
### Update one or more packages
```ts
const result = await pak.update(packages, options);
```
- `packages` is an array of package names, like `["pak", "fs-extra"]`. If no packages are given, all packages in the current workspace are updated.
- `options`: See [common options](#common-options) for details.
### Recompile native packages
```ts
const result = await pak.rebuild(packages, options);
```
- `packages` is an array of package names, like `["pak", "fs-extra"]`. If no packages are given, all packages in the current workspace are rebuilt.
- `options`: See [common options](#common-options) for details.
### Pin transitive dependencies to a fixed version
```ts
const result = await pak.overrideDependencies(overrides);
```
- `overrides` is an object of packages and exact versions, like `{"pak": "1.2.3"}`
Sometimes it is necessary to update transitive dependencies, meaning dependencies of dependencies. This command changes all occurences of the given overridden dependencies in the current `node_modules` tree so that the packages have the specified versions. How it works depends on the package manager:
- `yarn` uses the built-in `"resolutions"` property for `package.json`
- `npm` patches the root `package-lock.json` and `package.json` for all dependents of the overridden packages
**Note:** This command does not support version ranges and it does not check whether the overrides are compatible with the version specified in `package.json`.
### Result object
The returned value is an object with the following properties:
```ts
interface CommandResult {
/** Whether the command execution was successful */
success: boolean;
/** The exit code of the command execution */
exitCode: number;
/** The captured stdout */
stdout: string;
/** The captured stderr */
stderr: string;
}
```
### Common options
These options are used to influence the commands' behavior. All options are optional:
| Option | Type | Description | Default | Commands |
| ---------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------- | -------- | ---------------------- |
| `dependencyType` | `"prod" \| "dev"` | Whether to install a production or dev dependency. | `"prod"` | all |
| `global` | `boolean` | Whether to install the package globally. | `false` | all |
| `exact` | `boolean` | Whether exact versions should be used instead of `"^ver.si.on"`. | `false` | `install` |
| `ignoreScripts` | `boolean` | Prevent execution of pre/post/install scripts. | `false` | `install` |
| `force` | `boolean` | Pass the `--force` flag to the package manager where applicable. The specific behavior depends on the package manager. | `false` | `install` |
| `additionalArgs` | `string[]` | Additional command line args to pass to the underlying package manager. | none | `install`, `uninstall` |
### Find the nearest parent directory with a `package.json`
```ts
await pak.findRoot();
await pak.findRoot("lockfile.json");
```
Returns a string with a path to the nearest parent directory (including `cwd`) that contains a `package.json` (and a lockfile if one was specified). Throws if none was found.
### Stream the command output
You can stream the command output (`stdout`, `stderr` or both) during the command execution, as opposed to getting the entire output at the end. To do so,
set the `stdout`, `stderr` and/or `stdall` properties of the package manager instance to a writable stream. Example:
```ts
import { PassThrough } from "stream";
import { packageManagers } from "../../src/index";
const pak = new packageManagers.npm(); // or the automatically detected one
pak.stdall = new PassThrough().on("data", (data) => {
// For example, log to console - or do something else with the data
console.log(data.toString("utf8"));
});
// execute commands
```
### Get the version of the package manager
```ts
const version = await pak.version();
```
Returns a string with the package manager's version.
### Get the paths of all workspaces in the current monorepo
```ts
const workspaces = await pak.workspaces();
```
Returns an array of strings including the paths of all workspaces in the current monorepo. This will return an empty array if the current directory is not part of a monorepo.
A folder will be considered a workspace if it contains a file `package.json` and it is referenced in the `workspaces` property of the root `package.json`.
### Pack a project or monorepo package into an installable tarball
```ts
const result = await pak.pack(options);
```
`options` are optional and control what gets packed where and has the following shape:
```ts
interface PackOptions {
/**
* In monorepos, this determines which workspace to pack. Defaults to the current working directory.
* This must be a path relative to the repo root.
*/
workspace?: string;
/** Where to save the packed tarball. Defaults to the current working directory */
targetDir?: string;
}
```
`result` is a `CommandResult` (see above) where the `stdout` contains the absolute path of the packed tarball.