Skip to content

Commit

Permalink
feat: checkVersionRange() / getInstalledData()
Browse files Browse the repository at this point in the history
  • Loading branch information
voxpelli committed Mar 11, 2024
1 parent 0d214fb commit 9c5ec35
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 43 deletions.
168 changes: 144 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,43 +30,163 @@ if (result.errors.length) {
}
```

### In CommonJS using available [`import()`](https://nodejs.org/api/esm.html#import-expressions) expression
### In CommonJS using dynamic [`import()`](https://nodejs.org/api/esm.html#import-expressions) expression

```javascript
const { installedCheck } = await import('installed-check-core');
```

## Syntax
## API

```javascript
const { errors, warnings } = await installedCheck({
path: 'path/to/module',
engineCheck: true,
engineIgnores: ['foo'],
engineNoDev: true,
versionCheck: true,
});
### checkVersionRange()

The rich version range check that `installed-check` itself uses.

#### Syntax

```ts
checkVersionRange(mainPackage, key, installedDependencies, [options]) => VersionRangeResult
```

### Parameters
#### Arguments

* `mainPackage`: Type `NormalizedPackageJson` – the content of the `package.json` file to check
* `key`: Type `string` – the key of the version range to check, eg `engines.node`
* `installedDependencies`: Type `InstalledDependencies` – the installed dependencies to use when checking
* `options`: Type `VersionRangeOptions` – optional options

1. `options` – optional object containing additional options for the module
#### Types

### Returns
```ts
import type { NormalizedPackageJson } from 'read-pkg'

A Promise resolving to:
type InstalledDependencies = Map<string, NormalizedPackageJson>

type VersionRangeItem = {
valid: boolean|undefined,
suggested?: string|undefined,
note: string|undefined,
}
type VersionRangeResult = VersionRangeItem & {
packageNotes: Array<
VersionRangeItem & { name: string }
>
}
```
#### Options
* `expectedInDependencies = false` – when set a warning will be issued when the key is empty or not found in a dependency
* `noDev = false` – if set then dev dependencies won't be included in the check
* `ignore = string[]` – if set then the specified module names won't be included in the check.
* `strict = false` – converts most warnings into failures.
#### Example
```javascript
{
warnings: ['Abc'],
errors: ['Xyz']
};
import { checkVersionRange, getInstalledData } from 'installed-check-core';

const { installedDependencies, mainPackage } = await getInstalledData(path);

const result = await checkVersionRange(
mainPackage,
'engines.node',
installedDependencies,
{
expectedInDependencies: true,
noDev: true,
ignore: ['example'],
strict: true,
}
);

for (const item of result.packageNotes) {
if (item.note) {
console.log(`${item.valid === false ? 'Error' : 'Warning'} in ${item.name}: ${item.note}`);
}
}

if (result.note) {
console.log(`${result.valid === false ? 'Error' : 'Warning'}: ${result.note}`);
}

if (result.valid === true) {
console.log('All good!');
} else if (result.suggested) {
console.log('Combined engines.node needs to be narrower:', result.suggested);
} else {
console.log('Incompatible combined engines.node requirements.');
}
```

## Options
### 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(path = '.') => Promise<InstalledData>
```

#### Arguments

* `path` – specifies the path to the package to be checked, with its `package.json` expected to be there and its installed `node_modules` as well.

* `path` – defaults to `.`. Specifies the path to where the target to be checked can be found, with its `package.json` being there and its `node_modules` as well.
* `engineCheck` – if set `installed-check` will check that the installed modules comply with the [engines requirements](https://docs.npmjs.com/files/package.json#engines) of the `package.json` and suggest an alternative requirement if the installed modules don't comply.
* `engineIgnores` – if set then the specified module names won't be included in the engine check. `engineIgnores` should an array of module names while the CLI flags should be set once for each module name.
* `engineNoDev` – if set then dev dependencies won't be included in the engine check.
* `versionCheck` – if set `installed-check` will check that the installed modules comply with the version requirements set for them the `package.json`.
#### Types

```ts
import type { NormalizedPackageJson } from 'read-pkg'

type InstalledDependencies = Map<string, NormalizedPackageJson>

type InstalledData = {
mainPackage: NormalizedPackageJson,
installedDependencies: InstalledDependencies,
}
```
#### Example
See example of [`checkVersionRange()`](#checkversionrange)
### installedCheck()
The full on `installed-check` experience, returning error and warning strings only.
#### Syntax
```ts
installedCheck(options) => Promise<InstalledCheckResult>
```
#### Types
```ts
type InstalledCheckResult = { errors: string[], warnings: string[] }
```
#### Options
* `path = '.'` – specifies the path to the package to be checked, with its `package.json` expected to be there and its installed `node_modules` as well.
* `engineCheck = false` – if set `installed-check` will check that the installed modules comply with the [engines requirements](https://docs.npmjs.com/files/package.json#engines) of the `package.json` and suggest an alternative requirement if the installed modules don't comply.
* `engineIgnores = string[]` – if set then the specified module names won't be included in the engine check. `engineIgnores` should an array of module names while the CLI flags should be set once for each module name.
* `engineNoDev = false` – if set then dev dependencies won't be included in the engine check.
* `strict = false` – converts most warnings into failures.
* `versionCheck = false` – if set `installed-check` will check that the installed modules comply with the version requirements set for them the `package.json`.
#### Example
```javascript
import { installedCheck } from 'installed-check-core';

const { errors, warnings } = await installedCheck({
path: 'path/to/module',
engineCheck: true,
engineIgnores: ['foo'],
engineNoDev: true,
versionCheck: true,
});
```
9 changes: 8 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
/** @typedef {import('./lib/installed-check.js').InstalledCheckResult} InstalledCheckResult */
/** @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/get-installed-data.js').NormalizedPackageJson} NormalizedPackageJson */
/** @typedef {import('./lib/get-installed-data.js').InstalledDependencies} InstalledDependencies */
/** @typedef {import('./lib/installed-check.js').InstalledCheckOptions} InstalledCheckOptions */
/** @typedef {import('./lib/installed-check.js').InstalledCheckResult} InstalledCheckResult */

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

/**
* @param {import('read-pkg').NormalizedPackageJson} mainPackage
* @param {Map<string, import('list-installed').NormalizedPackageJson>} installedDependencies
* @param {import('./get-installed-data.js').NormalizedPackageJson} mainPackage
* @param {import('./get-installed-data.js').InstalledDependencies} installedDependencies
* @param {Omit<import('./check-version-range.js').VersionRangeOptions, 'expectedInDependencies'>} options
* @returns {{ errors: string[], warnings: string[] }}
*/
Expand Down
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('read-pkg').NormalizedPackageJson} mainPackage
* @param {Map<string, import('list-installed').NormalizedPackageJson>} installedDependencies
* @param {import('./get-installed-data.js').NormalizedPackageJson} mainPackage
* @param {import('./get-installed-data.js').InstalledDependencies} installedDependencies
* @returns {{ errors: string[], warnings: string[] }}
*/
export function checkPackageVersions (mainPackage, installedDependencies) {
Expand Down
19 changes: 10 additions & 9 deletions lib/check-version-range.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ import { getStringValueByPath } from './utils.js';

/**
* @typedef VersionRangeOptions
* @property {boolean} [expectedInDependencies]
* @property {boolean} [noDev]
* @property {string[]} [ignore]
* @property {boolean} [strict]
* @property {boolean} [expectedInDependencies=false] When set a warning will be issued when the key is empty or not found in a dependency
* @property {boolean} [noDev=false] If set then dev dependencies won't be included in the check
* @property {string[]} [ignore] If set then the specified module names won't be included in the
* @property {boolean} [strict=false] Converts most warnings into failures
*/

/** @typedef {VersionRangeItem & { packageNotes: Array<VersionRangeItem & { name: string }> }} VersionRangeResult */

/**
* @param {import('read-pkg').NormalizedPackageJson} mainPackage
* @param {import('./get-installed-data.js').NormalizedPackageJson} mainPackage
* @param {string} key
* @param {Map<string, import('list-installed').NormalizedPackageJson>} installedDependencies
* @param {import('./get-installed-data.js').InstalledDependencies} installedDependencies
* @param {VersionRangeOptions} [options]
* @returns {VersionRangeResult}
*/
Expand Down Expand Up @@ -66,7 +66,7 @@ export function checkVersionRange (mainPackage, key, installedDependencies, opti
return {
valid: intersection === referenceRange
? true
: (!rawReferenceRange && !strict ? undefined : false),
: ((rawReferenceRange || strict) ? false : undefined),
suggested: intersection || undefined,
packageNotes,
note: rawReferenceRange === false
Expand All @@ -78,7 +78,7 @@ export function checkVersionRange (mainPackage, key, installedDependencies, opti
/**
* @param {string} referenceRange
* @param {string} key
* @param {import('list-installed').NormalizedPackageJson|undefined} dependencyPackage
* @param {import('./get-installed-data.js').NormalizedPackageJson|undefined} dependencyPackage
* @param {boolean} isOptional
* @param {Omit<VersionRangeOptions, 'noDev'>} [options]
* @returns {VersionRangeItem | undefined}
Expand All @@ -91,7 +91,8 @@ function checkDependencyRange (referenceRange, key, dependencyPackage, isOptiona

if (!dependencyPackage) {
return {
valid: isOptional || !strict ? undefined : false,
// Always a warning when optional, otherwise warning only when not strict
valid: isOptional ? undefined : (strict ? false : undefined),
note: 'Dependency is not installed. Can\'t check its requirements',
};
}
Expand Down
9 changes: 6 additions & 3 deletions lib/get-installed-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@ import { listInstalled } from 'list-installed';
import { ErrorWithCause } from 'pony-cause';
import { readPackage } from 'read-pkg';

/** @typedef {import('read-pkg').NormalizedPackageJson} NormalizedPackageJson */
/** @typedef {Map<string, NormalizedPackageJson>} InstalledDependencies */

/**
* @typedef InstalledData
* @property {Map<string, import('list-installed').NormalizedPackageJson>} installedDependencies
* @property {import('read-pkg').NormalizedPackageJson} mainPackage
* @property {InstalledDependencies} installedDependencies
* @property {NormalizedPackageJson} mainPackage
*/

/**
* @throws {Error}
* @param {string} [path]
* @param {string} [path] Specifies the path to the package to be checked, with its `package.json` expected to be there and its installed `node_modules` as well
* @returns {Promise<InstalledData>}
*/
export async function getInstalledData (path = '.') {
Expand Down
4 changes: 2 additions & 2 deletions lib/perform-installed-checks.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { checkPackageVersions } from './check-package-versions.js';

/**
* @throws {Error}
* @param {import('read-pkg').NormalizedPackageJson} mainPackage
* @param {Map<string, import('list-installed').NormalizedPackageJson>} installedDependencies
* @param {import('./get-installed-data.js').NormalizedPackageJson} mainPackage
* @param {import('./get-installed-data.js').InstalledDependencies} installedDependencies
* @param {Omit<import('./installed-check.js').InstalledCheckOptions, 'path'>} options
* @returns {Promise<import('./installed-check.js').InstalledCheckResult>}
*/
Expand Down

0 comments on commit 9c5ec35

Please sign in to comment.