Skip to content

Commit

Permalink
feat: support checking workspaces
Browse files Browse the repository at this point in the history
Fixes: #115

And removes `getInstalledData()`, which now lives in `list-installed` instead
  • Loading branch information
voxpelli committed Mar 18, 2024
1 parent 9c45b17 commit dce06cf
Show file tree
Hide file tree
Showing 22 changed files with 222 additions and 192 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
*.d.ts
*.d.ts.map
!/lib/**/*-types.d.ts
!/index.d.ts

# Library specific ones
100 changes: 53 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ checkVersionRange(pkg, key, installed, [options]) => VersionRangeResult

#### Arguments

* `pkg`: Type `PackageJsonLike` – the content of the `package.json` file to check, see [`getInstalledData()`](#getinstalleddata)
* `pkg`: Type [`PackageJsonLike`](#packagejsonlike) – the content of the `package.json` file to check
* `key`: Type `string` – the key of the version range to check, eg `engines.node`
* `installed`: Type `InstalledDependencies` – the installed dependencies to use when checking, see [`getInstalledData()`](#getinstalleddata)
* `installed`: Type [`InstalledDependencies`](#installeddependencies) – the `package.json` files of the installed dependencies
* `options`: Type `VersionRangeOptions` – optional options

#### Types
Expand Down Expand Up @@ -80,9 +80,16 @@ type VersionRangeResult = VersionRangeItem & {
#### Example
```javascript
import { checkVersionRange, getInstalledData } from 'installed-check-core';
import { checkVersionRange } from 'installed-check-core';
import { listInstalled } from 'list-installed';
import { readPackage } from 'read-pkg';

const { installed, pkg } = await getInstalledData(cwd);
const cwd = '.';

const [pkg, installed] = await Promise.all([
readPackage({ cwd }),
listInstalled(cwd),
]);

const result = await checkVersionRange(
pkg,
Expand Down Expand Up @@ -134,63 +141,38 @@ checkVersionRangeCollection(pkg, key, installed, [options]) => VersionRangesResu

See main description of [`checkVersionRangeCollection()`](#checkversionrangecollection) and full docs for [`checkVersionRange()`](#checkversionrange).

### getInstalledData()

Companion method to eg. `checkVersionRange()` that which makes it easy to get the correct data required. Not meant for any other use.

Is a simple wrapper around [`read-pkg`](https://github.com/sindresorhus/read-pkg) and [`list-installed`](https://github.com/voxpelli/list-installed) – those or similar modules can be used directly just as well.

#### Syntax

```ts
getInstalledData(cwd = '.') => Promise<InstalledData>
```

#### Arguments

* `cwd` – specifies the path of the package to be checked, with its `package.json` expected to exist in that path and its installed `node_modules` as well.

#### Types

```ts
// Subset of import('type-fest').PackageJson / import('read-pkg').NormalizedPackageJson
export type PackageJsonLike = {
name?: string | undefined;
version?: string | undefined;
engines?: Record<string, string | undefined>;
dependencies?: Record<string, string | undefined>;
devDependencies?: Record<string, string | undefined>;
optionalDependencies?: Record<string, string | undefined>;
peerDependencies?: Record<string, string | undefined>;
};

// A map is allowed since that's what import('list-installed).listInstalled returns
export type InstalledDependencies = Map<string, PackageJsonLike> | Record<string, PackageJsonLike>;
```

#### Example

See example of [`checkVersionRange()`](#checkversionrange)

### installedCheck()

The full on `installed-check` experience, returning error and warning strings only.

#### Syntax

```ts
installedCheck(checks, options) => Promise<InstalledCheckResult>
installedCheck(checks, [lookupOptions], [options]) => Promise<InstalledCheckResult>
```

#### Arguments

* `checks`: Type `InstalledChecks[]` – the checks to run, an array of one or more of: `'engine'`, `'peer'`, `'version'`
* `options`: Type `InstalledCheckOptions`
* `lookupOptions`: Type `LookupOptions` – optional – defaults to `cwd='.'` and `includeWorkspaceRoot: true`
* `options`: Type `InstalledCheckOptions` – optional

#### Types

```ts
type LookupOptions = {
includeWorkspaceRoot?: boolean;
cwd?: string;
skipWorkspaces?: boolean;
workspace?: string[];
};
type InstalledChecks = 'engine' | 'peer' | 'version'
type InstalledCheckOptions = {
ignore?: string[] | undefined;
noDev?: boolean | undefined;
prefix?: string | undefined;
strict?: boolean | undefined;
};
type InstalledCheckResult = { errors: string[], warnings: string[] }
```
Expand Down Expand Up @@ -221,7 +203,7 @@ const { errors, warnings } = await installedCheck(['engine', 'version'], {
### performInstalledCheck()
Same as [`installedCheck()`](#installedcheck) but without looking up any data on its own but instead expects the data from [`getInstalledData()`](#getinstalleddata) or similar to be given to it.
Similar to [`installedCheck()`](#installedcheck) but expects to be given package data instead of looking it up itself..
#### Syntax
Expand All @@ -232,10 +214,34 @@ performInstalledCheck(checks, pkg, installed, options) => Promise<InstalledCheck
#### Arguments
* `checks`: Type `InstalledChecks[]` – same as for [`installedCheck()`](#installedcheck)
* `pkg`: Type `PackageJsonLike` – the content of the `package.json` file to check, see [`getInstalledData()`](#getinstalleddata)
* `installed`: Type `InstalledDependencies` – the installed dependencies to use when checking, see [`getInstalledData()`](#getinstalleddata)
* `pkg`: Type [`PackageJsonLike`](#packagejsonlike) – the content of the `package.json` file to check
* `installed`: Type [`InstalledDependencies`](#installeddependencies) – the `package.json` files of the installed dependencies
* `options`: Type `InstalledCheckOptions` – same as for [`installedCheck()`](#installedcheck), but without the `cwd` option
## Types
### PackageJsonLike
```ts
// Subset of import('type-fest').PackageJson / import('read-pkg').NormalizedPackageJson
export type PackageJsonLike = {
name?: string | undefined;
version?: string | undefined;
engines?: Record<string, string | undefined>;
dependencies?: Record<string, string | undefined>;
devDependencies?: Record<string, string | undefined>;
optionalDependencies?: Record<string, string | undefined>;
peerDependencies?: Record<string, string | undefined>;
};
```
### InstalledDependencies
```ts
// A map is allowed since that's what import('list-installed).listInstalled returns
export type InstalledDependencies = Map<string, PackageJsonLike> | Record<string, PackageJsonLike>;
```
## Used by
* Used by the [`installed-check`](https://github.com/voxpelli/node-installed-check) CLI tool
Expand Down
1 change: 1 addition & 0 deletions declaration.tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

{
"extends": "./tsconfig",
"files": [],
"exclude": [
"test/**/*"
],
Expand Down
9 changes: 9 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type * from './lib/lookup-types.d.ts';

export type { VersionRangeItem, VersionRangeOptions, VersionRangeResult, VersionRangesOptions } from './lib/check-version-range.js';
export type { LookupOptions } from './lib/installed-check.js';
export type { InstalledChecks, InstalledCheckOptions, InstalledCheckResult } from './lib/perform-installed-check.js';

export { checkVersionRange, checkVersionRangeCollection } from './lib/check-version-range.js';
export { installedCheck } from './lib/installed-check.js';
export { performInstalledCheck } from './lib/perform-installed-check.js';
13 changes: 0 additions & 13 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,3 @@
/** @typedef {import('./lib/check-version-range.js').VersionRangeItem} VersionRangeItem */
/** @typedef {import('./lib/check-version-range.js').VersionRangeOptions} VersionRangeOptions */
/** @typedef {import('./lib/check-version-range.js').VersionRangeResult} VersionRangeResult */
/** @typedef {import('./lib/check-version-range.js').VersionRangeOptions} VersionRangesOptions */

/** @typedef {import('./lib/get-installed-data.js').PackageJsonLike} PackageJsonLike */
/** @typedef {import('./lib/get-installed-data.js').InstalledDependencies} InstalledDependencies */

/** @typedef {import('./lib/perform-installed-check.js').InstalledChecks} InstalledChecks */
/** @typedef {import('./lib/perform-installed-check.js').InstalledCheckOptions} InstalledCheckOptions */
/** @typedef {import('./lib/perform-installed-check.js').InstalledCheckResult} InstalledCheckResult */

export { checkVersionRange, checkVersionRangeCollection } from './lib/check-version-range.js';
export { getInstalledData } from './lib/get-installed-data.js';
export { installedCheck } from './lib/installed-check.js';
export { performInstalledCheck } from './lib/perform-installed-check.js';
4 changes: 2 additions & 2 deletions lib/check-package-versions.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import semver from 'semver';

/**
* @param {import('./get-installed-data.js').PackageJsonLike} pkg
* @param {import('./get-installed-data.js').InstalledDependencies} installedDependencies
* @param {import('./lookup-types.d.ts').PackageJsonLike} pkg
* @param {import('./lookup-types.d.ts').InstalledDependencies} installedDependencies
* @returns {{ errors: string[], warnings: string[] }}
*/
export function checkPackageVersions (pkg, installedDependencies) {
Expand Down
10 changes: 5 additions & 5 deletions lib/check-version-range.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import { getObjectValueByPath, getStringValueByPath } from './utils.js';
/** @typedef {VersionRangeItem & { packageNotes: Array<VersionRangeItem & { name: string }> }} VersionRangeResult */

/**
* @param {import('./get-installed-data.js').PackageJsonLike} pkg
* @param {import('./lookup-types.d.ts').PackageJsonLike} pkg
* @param {string} key
* @param {import('./get-installed-data.js').InstalledDependencies} installed
* @param {import('./lookup-types.d.ts').InstalledDependencies} installed
* @param {VersionRangeOptions} [options]
* @returns {VersionRangeResult}
*/
Expand Down Expand Up @@ -93,9 +93,9 @@ export function checkVersionRange (pkg, key, installed, options) {
/** @typedef {VersionRangeOptions & { defaultKeys?: string[] }} VersionRangesOptions */

/**
* @param {import('./get-installed-data.js').PackageJsonLike} pkg
* @param {import('./lookup-types.d.ts').PackageJsonLike} pkg
* @param {string} topKey
* @param {import('./get-installed-data.js').InstalledDependencies} installed
* @param {import('./lookup-types.d.ts').InstalledDependencies} installed
* @param {VersionRangesOptions} [options]
* @returns {{ [key: string]: VersionRangeResult }}
*/
Expand Down Expand Up @@ -123,7 +123,7 @@ export function checkVersionRangeCollection (pkg, topKey, installed, options) {
/**
* @param {string} referenceRange
* @param {string} key
* @param {import('./get-installed-data.js').PackageJsonLike|undefined} dependencyPackage
* @param {import('./lookup-types.d.ts').PackageJsonLike|undefined} dependencyPackage
* @param {boolean} [isOptional]
* @param {Omit<VersionRangeOptions, 'noDev'>} [options]
* @returns {(VersionRangeItem & { valid: false | undefined }) | undefined}
Expand Down
4 changes: 2 additions & 2 deletions lib/check-versions.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { checkVersionRangeCollection } from './check-version-range.js';

/**
* @param {import('./get-installed-data.js').PackageJsonLike} pkg
* @param {import('./lookup-types.d.ts').PackageJsonLike} pkg
* @param {string} key
* @param {import('./get-installed-data.js').InstalledDependencies} installed
* @param {import('./lookup-types.d.ts').InstalledDependencies} installed
* @param {import('./check-version-range.js').VersionRangesOptions} options
* @returns {{ errors: string[], warnings: string[] }}
*/
Expand Down
46 changes: 0 additions & 46 deletions lib/get-installed-data.js

This file was deleted.

47 changes: 41 additions & 6 deletions lib/installed-check.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,50 @@
import { getInstalledData } from './get-installed-data.js';
import { workspaceLookup } from 'list-installed';

import { performInstalledCheck } from './perform-installed-check.js';

/** @typedef {Omit<import('list-installed').WorkspaceLookupOptions, 'path'> & { cwd?: string }} LookupOptions */

const ROOT = Symbol('workspace root');

/**
* @param {import('./perform-installed-check.js').InstalledChecks[]} checks
* @param {import('./perform-installed-check.js').InstalledCheckOptions & { cwd?: string }} [options]
* @param {LookupOptions} [lookupOptions]
* @param {import('./perform-installed-check.js').InstalledCheckOptions} [options]
* @returns {Promise<import('./perform-installed-check.js').InstalledCheckResult>}
*/
export async function installedCheck (checks, options) {
const { cwd = '.', ...checkOptions } = options || {};
export async function installedCheck (checks, lookupOptions, options) {
const { cwd = '.', ...lookupOptionsRest } = lookupOptions || {};

/** @type {Map<string|ROOT, string[]>} */
const errors = new Map();
/** @type {Map<string|ROOT, string[]>} */
const warnings = new Map();

for await (const item of workspaceLookup({ ...lookupOptionsRest, path: cwd })) {
const result = await performInstalledCheck(checks, item.pkg, item.installed, options);

const { installed, pkg } = await getInstalledData(cwd);
const key = 'workspace' in item ? item.workspace : ROOT;

return performInstalledCheck(checks, pkg, installed, checkOptions);
errors.set(key, result.errors);
warnings.set(key, result.warnings);
}

return {
errors: prefixNotes(errors, lookupOptions),
warnings: prefixNotes(warnings, lookupOptions),
};
}

/**
* @param {Map<string|ROOT, string[]>} notes
* @param {LookupOptions} [lookupOptions]
* @returns {string[]}
*/
function prefixNotes (notes, lookupOptions) {
if (lookupOptions?.includeWorkspaceRoot !== false && notes.size === 1) {
return [...notes.values()].flat();
}
return [...notes].flatMap(([key, items]) =>
items.map(item => `${key === ROOT ? 'root' : key}: ${item}`)
);
}
11 changes: 11 additions & 0 deletions lib/lookup-types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export type PackageJsonLike = {
name?: string | undefined;
version?: string | undefined;
engines?: Record<string, string | undefined>;
dependencies?: Record<string, string | undefined>;
devDependencies?: Record<string, string | undefined>;
optionalDependencies?: Record<string, string | undefined>;
peerDependencies?: Record<string, string | undefined>;
};

export type InstalledDependencies = Map<string, PackageJsonLike> | Record<string, PackageJsonLike>;
Loading

0 comments on commit dce06cf

Please sign in to comment.