Skip to content

Commit

Permalink
Support native ESM in Node.js.
Browse files Browse the repository at this point in the history
  • Loading branch information
jaydenseric committed Jun 14, 2020
1 parent 65c5e81 commit 8fde22a
Show file tree
Hide file tree
Showing 20 changed files with 166 additions and 44 deletions.
2 changes: 2 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@

- Updated supported Node.js versions to `^10.17.0 || ^12.0.0 || >= 13.7.0`.
- Updated dependencies, some of which require newer Node.js versions than were previously supported.
- Added a [package `exports` field](https://nodejs.org/api/esm.html#esm_package_entry_points) with [conditional exports](https://nodejs.org/api/esm.html#esm_conditional_exports) to support native ESM in Node.js and keep internal code private, [whilst avoiding the dual package hazard](https://nodejs.org/api/esm.html#esm_approach_1_use_an_es_module_wrapper). Published files have been reorganized, so previously undocumented deep imports will need to be rewritten according to the newly documented paths.

### Patch

- Updated Prettier config and scripts.
- Added ESM related keywords to the package `keywords` field.
- Updated ESLint config to match the new Node.js version support.
- Moved reading `process.argv` into the `coverageNode` function scope.
- Improved a JSDoc return type.
Expand Down
12 changes: 6 additions & 6 deletions cli/coverage-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
const { spawn } = require('child_process');
const { disposableDirectory } = require('disposable-directory');
const kleur = require('kleur');
const analyseCoverage = require('../lib/analyseCoverage');
const childProcessPromise = require('../lib/childProcessPromise');
const coverageSupported = require('../lib/coverageSupported');
const minNodeVersion = require('../lib/coverageSupportedMinNodeVersion');
const errorConsole = require('../lib/errorConsole');
const reportCoverage = require('../lib/reportCoverage');
const childProcessPromise = require('../private/childProcessPromise');
const errorConsole = require('../private/errorConsole');
const analyseCoverage = require('../public/analyseCoverage');
const coverageSupported = require('../public/coverageSupported');
const minNodeVersion = require('../public/coverageSupportedMinNodeVersion');
const reportCoverage = require('../public/reportCoverage');

/**
* Powers the `coverage-node` CLI. Runs Node.js with the given arguments and
Expand Down
14 changes: 0 additions & 14 deletions lib/coverageSupportedMinNodeVersion.js

This file was deleted.

18 changes: 15 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,25 @@
"check",
"report",
"code",
"coverage"
"coverage",
"esm",
"mjs"
],
"files": [
"cli",
"lib"
"private",
"public"
],
"main": "lib",
"main": "public",
"exports": {
".": {
"import": "./public/index.mjs",
"require": "./public/index.js"
},
"./public/": "./public/",
"./package": "./package.json",
"./package.json": "./package.json"
},
"bin": {
"coverage-node": "cli/coverage-node.js"
},
Expand Down
File renamed without changes.
4 changes: 2 additions & 2 deletions lib/errorConsole.js → private/errorConsole.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
const { Console } = require('console');

/*
* The `console` API, but all output is to `stderr`. This allows
* `console.group` to be used with `console.error`.
* The `console` API, but all output is to `stderr`. This allows `console.group`
* to be used with `console.error`.
*/
module.exports = new Console({
stdout: process.stderr,
Expand Down
File renamed without changes.
File renamed without changes.
16 changes: 14 additions & 2 deletions lib/analyseCoverage.js → public/analyseCoverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const fs = require('fs');
const { join } = require('path');
const { fileURLToPath } = require('url');
const { mergeProcessCovs } = require('@bcoe/v8-coverage');
const sourceRange = require('./sourceRange');
const sourceRange = require('../private/sourceRange');

/**
* Analyzes [Node.js generated V8 JavaScript code coverage data](https://nodejs.org/api/cli.html#cli_node_v8_coverage_dir)
Expand All @@ -13,10 +13,22 @@ const sourceRange = require('./sourceRange');
* @name analyseCoverage
* @param {string} coverageDirPath Code coverage data directory path.
* @returns {Promise<CoverageAnalysis>} Resolves the coverage analysis.
* @example <caption>How to import.</caption>
* @example <caption>Ways to `import`.</caption>
* ```js
* import { analyseCoverage } from 'coverage-node';
* ```
*
* ```js
* import analyseCoverage from 'coverage-node/public/analyseCoverage.js';
* ```
* @example <caption>Ways to `require`.</caption>
* ```js
* const { analyseCoverage } = require('coverage-node');
* ```
*
* ```js
* const analyseCoverage = require('coverage-node/public/analyseCoverage');
* ```
*/
module.exports = async function analyseCoverage(coverageDirPath) {
const coverageDirFileNames = await fs.promises.readdir(coverageDirPath);
Expand Down
16 changes: 14 additions & 2 deletions lib/coverageSupported.js → public/coverageSupported.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
'use strict';

const semver = require('../private/semver');
const {
major: minMajor,
minor: minMinor,
patch: minPatch,
} = require('./coverageSupportedMinNodeVersion');
const semver = require('./semver');

const { major, minor, patch } = semver(process.versions.node);

Expand All @@ -15,10 +15,22 @@ const { major, minor, patch } = semver(process.versions.node);
* @kind constant
* @name coverageSupported
* @type {boolean}
* @example <caption>How to import.</caption>
* @example <caption>Ways to `import`.</caption>
* ```js
* import { coverageSupported } from 'coverage-node';
* ```
*
* ```js
* import coverageSupported from 'coverage-node/public/coverageSupported.js';
* ```
* @example <caption>Ways to `require`.</caption>
* ```js
* const { coverageSupported } = require('coverage-node');
* ```
*
* ```js
* const coverageSupported = require('coverage-node/public/coverageSupported');
* ```
*/
module.exports =
// coverage ignore next line
Expand Down
26 changes: 26 additions & 0 deletions public/coverageSupportedMinNodeVersion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
'use strict';

/**
* Minimum Node.js version supported for code coverage. Although Node.js v10+
* supports coverage, only v13.3+ produces coverage data reliable enough to use.
* @kind constant
* @name coverageSupportedMinNodeVersion
* @type {SemanticVersion}
* @example <caption>Ways to `import`.</caption>
* ```js
* import { coverageSupportedMinNodeVersion } from 'coverage-node';
* ```
*
* ```js
* import coverageSupportedMinNodeVersion from 'coverage-node/public/coverageSupportedMinNodeVersion.js';
* ```
* @example <caption>Ways to `require`.</caption>
* ```js
* const { coverageSupportedMinNodeVersion } = require('coverage-node');
* ```
*
* ```js
* const coverageSupportedMinNodeVersion = require('coverage-node/public/coverageSupportedMinNodeVersion');
* ```
*/
module.exports = { major: 13, minor: 3, patch: 0 };
File renamed without changes.
4 changes: 4 additions & 0 deletions public/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export { default as coverageSupported } from './coverageSupported.js';
export { default as coverageSupportedMinNodeVersion } from './coverageSupportedMinNodeVersion.js';
export { default as analyseCoverage } from './analyseCoverage.js';
export { default as reportCoverage } from './reportCoverage.js';
16 changes: 14 additions & 2 deletions lib/reportCoverage.js → public/reportCoverage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,29 @@

const { relative } = require('path');
const kleur = require('kleur');
const errorConsole = require('./errorConsole');
const errorConsole = require('../private/errorConsole');

/**
* Reports a code coverage analysis to the console.
* @kind function
* @name reportCoverage
* @param {CoverageAnalysis} coverageAnalysis Coverage analysis from [`analyseCoverage`]{@link analyseCoverage}.
* @example <caption>How to import.</caption>
* @example <caption>Ways to `import`.</caption>
* ```js
* import { reportCoverage } from 'coverage-node';
* ```
*
* ```js
* import reportCoverage from 'coverage-node/public/reportCoverage.js';
* ```
* @example <caption>Ways to `require`.</caption>
* ```js
* const { reportCoverage } = require('coverage-node');
* ```
*
* ```js
* const reportCoverage = require('coverage-node/public/reportCoverage');
* ```
*/
module.exports = function reportCoverage({
filesCount,
Expand Down
64 changes: 60 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,25 @@ Analyzes [Node.js generated V8 JavaScript code coverage data](https://nodejs.org

#### Examples

_How to import._
_Ways to `import`._

> ```js
> import { analyseCoverage } from 'coverage-node';
> ```
>
> ```js
> import analyseCoverage from 'coverage-node/public/analyseCoverage.js';
> ```
_Ways to `require`._
> ```js
> const { analyseCoverage } = require('coverage-node');
> ```
>
> ```js
> const analyseCoverage = require('coverage-node/public/analyseCoverage');
> ```
---
Expand All @@ -107,11 +121,25 @@ Reports a code coverage analysis to the console.
#### Examples
_How to import._
_Ways to `import`._
> ```js
> import { reportCoverage } from 'coverage-node';
> ```
>
> ```js
> import reportCoverage from 'coverage-node/public/reportCoverage.js';
> ```
_Ways to `require`._
> ```js
> const { reportCoverage } = require('coverage-node');
> ```
>
> ```js
> const reportCoverage = require('coverage-node/public/reportCoverage');
> ```
---
Expand All @@ -123,11 +151,25 @@ Is the process Node.js version greater at least [the minimum required to support
#### Examples
_How to import._
_Ways to `import`._
> ```js
> import { coverageSupported } from 'coverage-node';
> ```
>
> ```js
> import coverageSupported from 'coverage-node/public/coverageSupported.js';
> ```
_Ways to `require`._
> ```js
> const { coverageSupported } = require('coverage-node');
> ```
>
> ```js
> const coverageSupported = require('coverage-node/public/coverageSupported');
> ```
---
Expand All @@ -139,11 +181,25 @@ Minimum Node.js version supported for code coverage. Although Node.js v10+ suppo
#### Examples
_How to import._
_Ways to `import`._
> ```js
> import { coverageSupportedMinNodeVersion } from 'coverage-node';
> ```
>
> ```js
> import coverageSupportedMinNodeVersion from 'coverage-node/public/coverageSupportedMinNodeVersion.js';
> ```
_Ways to `require`._
> ```js
> const { coverageSupportedMinNodeVersion } = require('coverage-node');
> ```
>
> ```js
> const coverageSupportedMinNodeVersion = require('coverage-node/public/coverageSupportedMinNodeVersion');
> ```
---
Expand Down
4 changes: 2 additions & 2 deletions test/cli/coverage-node.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ const { strictEqual } = require('assert');
const fs = require('fs');
const { join, relative } = require('path');
const { disposableDirectory } = require('disposable-directory');
const coverageSupported = require('../../lib/coverageSupported');
const minNodeVersion = require('../../lib/coverageSupportedMinNodeVersion');
const coverageSupported = require('../../public/coverageSupported');
const minNodeVersion = require('../../public/coverageSupportedMinNodeVersion');
const execFilePromise = require('../execFilePromise');
const stripStackTraces = require('../stripStackTraces');

Expand Down
6 changes: 3 additions & 3 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ const { TestDirector } = require('test-director');
const tests = new TestDirector();

require('./cli/coverage-node.test')(tests);
require('./lib/analyseCoverage.test')(tests);
require('./lib/semver.test')(tests);
require('./lib/sourceRange.test')(tests);
require('./private/semver.test')(tests);
require('./private/sourceRange.test')(tests);
require('./public/analyseCoverage.test')(tests);

tests.run();
2 changes: 1 addition & 1 deletion test/lib/semver.test.js → test/private/semver.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const { deepStrictEqual } = require('assert');
const semver = require('../../lib/semver');
const semver = require('../../private/semver');

module.exports = (tests) => {
tests.add('`semver` with a simple version.', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict';

const { deepStrictEqual } = require('assert');
const sourceRange = require('../../lib/sourceRange');
const sourceRange = require('../../private/sourceRange');

module.exports = (tests) => {
tests.add('`sourceRange` with a single char line.', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ const { spawn } = require('child_process');
const fs = require('fs');
const { join } = require('path');
const { disposableDirectory } = require('disposable-directory');
const analyseCoverage = require('../../lib/analyseCoverage');
const childProcessPromise = require('../../lib/childProcessPromise');
const childProcessPromise = require('../../private/childProcessPromise');
const analyseCoverage = require('../../public/analyseCoverage');

module.exports = (tests) => {
tests.add(
Expand Down

0 comments on commit 8fde22a

Please sign in to comment.