npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

package-exports

v1.0.0

Published

Get the exports of a package

Downloads

76

Readme

package-exports

Build Coverage Downloads Size

Get the exports of a package.

Contents

What is this?

This package find out what is exposed from a package. It also emits many possible warnings about potential problems.

When should I use this?

You can use this to programatically figure out what can be used from a package. You can also use this to lint packages.

Install

This package is ESM only. In Node.js (version 18+), install with npm:

npm install package-exports

Use

import {packageExports} from 'package-exports'
import {reporter} from 'vfile-reporter'

const thisPackage = await packageExports(new URL('.', import.meta.url))

console.dir(thisPackage, {depth: undefined})

const tar = await packageExports(new URL('node_modules/tar/', import.meta.url))
console.error(reporter(tar.file))

Yields:

{
  exports: [
    {
      conditions: undefined,
      exists: true,
      jsonPath: [ 'exports' ],
      specifier: '.',
      url: 'file:///Users/…/package-exports/index.js'
    }
  ],
  file: VFile { … },
  name: 'package-exports'
}
node_modules/tar/package.json
1:1-70:2 warning Unexpected inferred main export `./index.js`, it’s recommended to use an export map such as `"exports": "./index.js"` main-inferred package-exports
1:1-70:2 warning Unexpected missing `type` field, expected `type: 'commonjs'` or `'module'`                                            type-missing  package-exports

⚠ 2 warnings

API

This package exports the identifier packageExports. It exports the TypeScript types Export and Result. There is no default export.

packageExports(folder)

Get the exports of a package.

Parameters
  • folder (URL, required) — file URL to folder of a package
Returns

Result (Promise<Result>).

Export

Export (TypeScript type).

Fields
  • conditions (Array<string>) — conditions
  • exists (boolean) — whether this file exists
  • jsonPath (Array<number | string>) — path in package.json
  • specifier (string) — specifier that exposes this
  • url (URL) — resolved URL to file

Result

Result of finding exports (TypeScript type).

Fields
  • exports (Array<Exports>) — exports
  • file (VFile) – file
  • name (string or undefined) – package name

Errors

This package lints for many problems in npm packages and adds each message to the vfile. Messages will have a source field set to package-exports and a ruleId to one of the following values.

exports-alternatives

package.json:

{
  "exports": {
    ".": "./index.js",
    "./other": [
      "./other.js"
    ]
  },
  "files": [
    "index.js",
    "other.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:16-6:6: Unexpected alternatives list at `exports['./other']`, several tools don’t support this and pick the first item

Fix:

@@ -1,7 +1,7 @@
 {
   "exports": {
     ".": "./index.js",
-    "./other": ["./other.js"]
+    "./other": "./other.js"
   },
   "files": ["index.js", "other.js"],
   "name": "x",

exports-alternatives-empty

package.json:

{
  "exports": {
    ".": "./index.js",
    "./other": []
  },
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:16-4:18: Unexpected empty array at `exports['./other']` doing nothing, expected a single item

Fix:

@@ -1,7 +1,6 @@
 {
   "exports": {
-    ".": "./index.js",
-    "./other": []
+    ".": "./index.js"
   },
   "files": ["index.js"],
   "name": "x",

exports-conditions-default-misplaced

package.json:

{
  "exports": {
    "default": "./index.js",
    "production": "./other.js"
  },
  "files": [
    "index.js",
    "other.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:19-4:31: Unexpected non-last `default` conditions at `exports` ignoring everything after it, move the `default` condition to the end

Fix:

@@ -1,7 +1,7 @@
 {
   "exports": {
-    "default": "./index.js",
-    "production": "./other.js"
+    "production": "./other.js",
+    "default": "./index.js"
   },
   "files": ["index.js", "other.js"],
   "name": "x",

exports-conditions-default-missing

package.json:

{
  "exports": {
    "production": "./index.js"
  },
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

2:14-4:4: Unexpected conditions without a `default` entry at `exports` making specifier `.` unusable by default, expected `'default'` condition as the last field

Fix:

@@ -1,6 +1,7 @@
 {
   "exports": {
-    "production": "./index.js"
+    "production": "./index.js",
+    "default": "./other.js"
   },
   "files": [
     "index.js"

exports-conditions-mutually-exclusive

package.json:

{
  "exports": {
    "import": {
      "require": "./other.js",
      "default": "./index.js"
    },
    "default": "./index.js"
  },
  "files": [
    "index.js",
    "other.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:18-4:30: Unexpected condition `require` mutually exclusive with `import` at `exports.import` which never matches, use only one of these conditions

Fix:

@@ -1,10 +1,7 @@
 {
   "exports": {
-    "import": {
-      "require": "./other.js",
-      "default": "./index.js"
-    },
-    "default": "./index.js"
+    "require": "./other.js",
+    "import": "./index.js"
   },
   "files": [
     "index.js",

exports-conditions-verbose

package.json:

{
  "exports": {
    "default": "./index.js"
  },
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

2:14-4:4: Unexpected verbose conditions object with sole key `default` at `exports`, replace the object with the value at `default`

Fix:

@@ -1,7 +1,5 @@
 {
-  "exports": {
-    "default": "./index.js"
-  },
+  "exports": "./index.js",
   "files": [
     "index.js"
   ],

exports-main-missing

package.json:

{
  "exports": {
    "./x": "./index.js"
  },
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

1:1-10:2: Unexpected missing main specifier `.`, expected an export to the main module

Fix:

@@ -1,5 +1,6 @@
 {
   "exports": {
+    ".": "./index.js",
     "./x": "./index.js"
   },
   "files": [

exports-negated-missing

package.json:

{
  "exports": {
    ".": "./index.js",
    "./*": null
  },
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:12-4:16: Unexpected negation specifier `./*` at `exports['./*']` with nothing to negate

Fix:

@@ -1,6 +1,7 @@
 {
   "exports": {
     ".": "./index.js",
+    "./x": "./index.js",
     "./*": null
   },
   "files": [

exports-object-empty

package.json:

{
  "exports": {
    ".": "./index.js",
    "./other": {}
  },
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:16-4:18: Unexpected empty object at `exports['./other']` doing nothing, expected fields

Fix:

@@ -1,7 +1,6 @@
 {
   "exports": {
-    ".": "./index.js",
-    "./other": {}
+    ".": "./index.js"
   },
   "files": [
     "index.js"

exports-object-mixed

package.json:

{
  "exports": {
    ".": "./index.js",
    "default": "./other.js"
  },
  "files": [
    "index.js",
    "other.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

1:1-12:2: Unexpected missing main specifier `.`, expected an export to the main module
2:14-5:4: Unexpected mixed specifiers (starting with `.`) and conditions (without `.`) at `exports`, expected either specifiers or conditions

Fix:

@@ -1,6 +1,6 @@
 {
   "exports": {
-    ".": "./index.js",
+    "other": "./index.js",
     "default": "./other.js"
   },
   "files": [

exports-path-not-found

package.json:

{
  "exports": {
    ".": "./index.js",
    "./x": "./missing.js"
  },
  "files": [
    "index.js",
    "missing.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:12-4:26: Unexpected missing file `./missing.js` for specifier `./x` at `exports['./x']`

Fix: make sure files exist.

exports-path-unprefixed

package.json:

{
  "exports": "index.js",
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

1:1-8:2: Unexpected missing main specifier `.`, expected an export to the main module
2:14-2:24: Unexpected unprefixed value `'index.js'` at `exports` which is not importable, did you mean `'./index.js'`

Fix:

@@ -1,5 +1,5 @@
 {
-  "exports": "index.js",
+  "exports": "./index.js",
   "files": [
     "index.js"
   ],

exports-path-wildcard-not-found

package.json:

{
  "exports": {
    ".": "./index.js",
    "./*": "./lib/*"
  },
  "files": [
    "lib/",
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:12-4:21: Unexpected dynamic file glob `./lib/*` at `exports['./*']` pointing to nothing, expected files

Fix: make sure files exist.

exports-specifier-extension

package.json:

{
  "exports": {
    ".": "./index.js",
    "./other.js": "./other.js"
  },
  "files": [
    "index.js",
    "other.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

2:14-5:4: Unexpected extension `.js` in specifier `./other.js` at `exports`, extensions have no meaning in specifiers, expected `./other`

Fix:

@@ -1,7 +1,7 @@
 {
   "exports": {
     ".": "./index.js",
-    "./other.js": "./other.js"
+    "./other": "./other.js"
   },
   "files": [
     "index.js",

exports-specifier-nested

package.json:

{
  "exports": {
    ".": "./index.js",
    "./other": {
      "./more": "./other.js"
    }
  },
  "files": [
    "index.js",
    "other.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:16-6:6: Unexpected nested specifier `./more` at `exports['./other']`, expected conditions

Fix:

@@ -1,9 +1,7 @@
 {
   "exports": {
     ".": "./index.js",
-    "./other": {
-      "./more": "./other.js"
-    }
+    "./other/more": "./other.js"
   },
   "files": [
     "index.js",

exports-specifier-wildcard-invalid

package.json:

{
  "exports": {
    ".": "./index.js",
    "./x/*/y/*": "./other.js"
  },
  "files": [
    "index.js",
    "other.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:18-4:30: Unexpected extra wildcard in dynamic specifier `./x/*/y/*` at `exports['./x/*/y/*']`, one wildcard is allowed

Fix:

@@ -1,7 +1,7 @@
 {
   "exports": {
     ".": "./index.js",
-    "./x/*/y/*": "./other.js"
+    "./x/*/y": "./other.js"
   },
   "files": [
     "index.js",

exports-specifier-wildcard-useless

package.json:

{
  "exports": {
    ".": "./index.js",
    "./*": "./other.js"
  },
  "files": [
    "index.js",
    "other.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:12-4:24: Unexpected dynamic specifier `./*` pointing to static file `./other.js` at `exports['./*']`, use dynamic specifiers with dynamic file globs

Fix:

@@ -1,7 +1,7 @@
 {
   "exports": {
     ".": "./index.js",
-    "./*": "./other.js"
+    "./other": "./other.js"
   },
   "files": [
     "index.js",

exports-specifiers-verbose

package.json:

{
  "exports": {
    ".": "./index.js"
  },
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

2:14-4:4: Unexpected verbose specifier object with sole key `.` at `exports`, replace the object with the value at `.`

Fix:

@@ -1,7 +1,5 @@
 {
-  "exports": {
-    ".": "./index.js"
-  },
+  "exports": "./index.js",
   "files": [
     "index.js"
   ],

exports-types-verbose

package.json:

{
  "exports": {
    "types": "./index.d.ts",
    "default": "./index.js"
  },
  "files": [
    "index.d.ts",
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

3:14-3:28: Unexpected verbose `types` condition at `exports` matching what TypeScript would load for `default` without it, remove it

Fix:

@@ -1,8 +1,5 @@
 {
-  "exports": {
-    "types": "./index.d.ts",
-    "default": "./index.js"
-  },
+  "exports": "./index.js",
   "files": [
     "index.d.ts",
     "index.js"

exports-value-invalid

package.json:

{
  "exports": {
    ".": "./index.js",
    "./other": 1
  },
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:16-4:17: Unexpected invalid value `1` at `exports['./other']` which is not importable, expected conditions object, `string` (path to file), or `null` (negated)

Fix:

+++ b/example/package.json
@@ -1,7 +1,7 @@
 {
   "exports": {
     ".": "./index.js",
-    "./other": 1
+    "./other": "./other.js"
   },
   "files": [
     "index.js"

files-missing

package.json:

{
  "exports": "./index.js",
  "name": "x",
  "type": "module",
}

Yields:

1:1-5:2: Unexpected missing `files` field, expected array of allowed files to include

Fix:

@@ -1,5 +1,8 @@
 {
   "exports": "./index.js",
+  "files": [
+    "index.js"
+  ],
   "name": "x",
   "type": "module"
 }

main

package.json:

{
  "files": [
    "index.js",
    "other.js"
  ],
  "main": "index.js",
  "name": "x",
  "type": "module"
}

Yields:

6:11-6:21: Unexpected legacy `main` field that does not encapsulate the package, it’s recommended to use an export map such as `"exports": "./index.js"`

Fix:

@@ -1,9 +1,9 @@
 {
+  "exports": "./index.js",
   "files": [
     "index.js",
     "other.js"
   ],
-  "main": "index.js",
   "name": "x",
   "type": "module"
 }

main-extra

package.json:

{
  "exports": "./index.js",
  "files": [
    "index.js"
  ],
  "main": "index.js",
  "name": "x",
  "type": "module"
}

Yields:

6:11-6:21: Unexpected unused legacy `main` field with modern `exports`, remove it

Fix:

@@ -3,7 +3,6 @@
   "files": [
     "index.js"
   ],
-  "main": "index.js",
   "name": "x",
   "type": "module"
 }

main-inferred

package.json:

{
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "commonjs"
}

Yields:

1:1-7:2: Unexpected inferred main export `./index.js`, it’s recommended to use an export map such as `"exports": "./index.js"`

Fix:

@@ -1,4 +1,5 @@
 {
+  "exports": "./index.js",
   "files": [
     "index.js"
   ],

main-invalid

package.json:

{
  "files": [
    "index.js"
  ],
  "main": 1,
  "name": "x",
  "type": "commonjs"
}

Yields:

1:1-8:2: Unexpected inferred main export `./index.js`, it’s recommended to use an export map such as `"exports": "./index.js"`
5:11-5:12: Unexpected non-string `main` field `1`

Fix:

@@ -1,8 +1,8 @@
 {
+  "exports": "./index.js",
   "files": [
     "index.js"
   ],
-  "main": 1,
   "name": "x",
   "type": "commonjs"
 }

main-missing

package.json:

{
  "files": [
    "default.js"
  ],
  "name": "x",
  "type": "commonjs"
}

Yields:

1:1-7:2: Unexpected missing main module, it’s recommended to use an export map such as `"exports": "./index.js"`

Fix:

@@ -1,4 +1,5 @@
 {
+  "exports": "./default.js",
   "files": [
     "default.js"
   ],

main-not-found

package.json:

{
  "files": [
    "index.js"
  ],
  "main": "./missing.js",
  "name": "x",
  "type": "commonjs"
}

Yields:

1:1-8:2: Unexpected inferred main export `./index.js`, it’s recommended to use an export map such as `"exports": "./index.js"`
5:11-5:25: Unexpected missing file for `main` field `./missing.js`

Fix:

@@ -1,8 +1,8 @@
 {
+  "exports": "./index.js",
   "files": [
     "index.js"
   ],
-  "main": "./missing.js",
   "name": "x",
   "type": "commonjs"
 }

main-resolve-commonjs

package.json:

{
  "files": [
    "index.js"
  ],
  "main": "index",
  "name": "x",
  "type": "commonjs"
}

Yields:

5:11-5:18: Unexpected `main` field `index` that resolves to `./index.js` in CJS, this works but is slow and doesn’t work with `type: 'module', use the resolved value explicitly

Fix:

@@ -1,8 +1,8 @@
 {
+  "exports": "./index.js",
   "files": [
     "index.js"
   ],
-  "main": "index",
   "name": "x",
   "type": "commonjs"
 }

main-resolve-module

package.json:

{
  "files": [
    "index.js"
  ],
  "main": "index",
  "name": "x",
  "type": "module"
}

Yields:

1:1-9:2: Unexpected inferred main export `./index.js`, it’s recommended to use an export map such as `"exports": "./index.js"`
6:11-6:18: Unexpected `main` field `index` that does not resolve with `type: 'module'`, use an export map such as `"exports": "./index.js"`

Fix:

@@ -1,8 +1,8 @@
 {
+  "exports": "./index.js",
   "files": [
     "index.js"
   ],
-  "main": "index",
   "name": "x",
   "type": "module"
 }

name-missing

package.json:

{
  "exports": "./index.js",
  "files": [
    "index.js"
  ],
  "type": "module"
}

Yields:

1:1-7:2: Unexpected missing `name` field, expected a package name

Fix:

@@ -3,5 +3,6 @@
   "files": [
     "index.js"
   ],
+  "name": "x",
   "type": "module"
 }

npm-ignored

package.json:

{
  "exports": {
    ".": "./index.js",
    "./other": "./other.js"
  },
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "module"
}

Yields:

4:16-4:28: Unexpected file `./other.js` at `exports['./other']` which is excluded from the npm package, add it to `files` in `package.json`

Fix:

@@ -4,7 +4,8 @@
     "./other": "./other.js"
   },
   "files": [
-    "index.js"
+    "index.js",
+    "other.js"
   ],
   "name": "x",
   "type": "module"

type-invalid

package.json:

{
  "exports": "./index.js",
  "files": [
    "index.js"
  ],
  "name": "x",
  "type": "umd",
}

Yields:

7:11-7:16: Unexpected invalid `type` value `umd`, expected `commonjs` or `module`

Fix:

@@ -4,5 +4,5 @@
     "index.js"
   ],
   "name": "x",
-  "type": "umd"
+  "type": "module"
 }

type-missing

package.json:

{
  "exports": "./index.js",
  "files": [
    "index.js"
  ],
  "name": "x"
}

Yields:

1:1-7:2: Unexpected missing `type` field, expected `type: 'commonjs'` or `'module'`

Fix:

@@ -3,5 +3,6 @@
   "files": [
     "index.js"
   ],
-  "name": "x"
+  "name": "x",
+  "type": "commonjs"
 }

Compatibility

This projects is compatible with maintained versions of Node.js.

When we cut a new major release, we drop support for unmaintained versions of Node. This means we try to keep the current release line, package-exports@1, compatible with Node.js 18.

Security

This package is safe.

Contribute

Yes please! See How to Contribute to Open Source.

License

MIT © Titus Wormer