Socket
Socket
Sign inDemoInstall

@jsenv/importmap-eslint-resolver

Package Overview
Dependencies
Maintainers
2
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jsenv/importmap-eslint-resolver

importmap resolution for eslint.


Version published
Weekly downloads
78
decreased by-75.7%
Maintainers
2
Weekly downloads
 
Created
Source

importmap-eslint-resolver

Import maps resolution for ESLint.

github package npm package github ci codecov coverage

Table of contents

Presentation

Import maps are used to remap import to somewhere else. For instance the following importmap allows to remap "foo" to "./foo.js".

{
  "imports": {
    "foo": "./foo.js"
  }
}

By providing this importmap to the browser or Node.js, js imports resolution becomes aware of the importmap file remappings. You can write the following js file and it would search for file at "./foo.js".

import { value } from "foo"

console.log(value)

If you use import/no-unresolved rule from eslint-plugin-import these imports are reported as not resolved as shown in images below.

screenshot import not resolved in vscode
screenshot eslint error in vscode

This is why @jsenv/importmap-eslint-resolver exists: to make import/no-unresolved compatible with importmap file.

— see ESLint website
— see eslint-plugin-import on github
— see importmap spec on github

Installation

Follow the steps below to enable importmap resolution for ESLint.

Install eslint-plugin-import

If you already use this ESLint plugin you can skip this step.

npm install --save-dev eslint-plugin-import
Install importmap-eslint-resolver
npm install --save-dev @jsenv/importmap-eslint-resolver
Configure ESLint

Your ESLint config must:

  • enable eslint-plugin-import in plugins
  • configure eslint-plugin-import to use @jsenv/importmap-eslint-resolver as resolver
  • configure projectDirectoryUrl and importMapFileRelativeUrl

Your minimal .eslintrc.cjs file looks like this:

module.exports = {
  plugins: ["import"],
  settings: {
    "import/resolver": {
      [require.resolve("@jsenv/importmap-eslint-resolver")]: {
        projectDirectoryUrl: __dirname,
        importMapFileRelativeUrl: "./project.importmap",
      },
    },
  },
}

About resolution

By default the resolution is:

  • case sensitive
  • browser like
    • consider node core modules (fs, url) as not found
    • do not implement node module resolution
    • do not understand path without extension (does not try to auto add extension)

This resolution default behaviour is documented in this section and can be configured to your convenience.

Case sensitivity

This resolver is case sensitive by default: An import is found only if the import path and actual file on the filesystem have same case.

import { getUser } from "./getUser.js"

The import above is found only if there is a file getUser.js. It won't be found if file is named getuser.js, even if the filesystem is case insensitive.

This ensure two things:

  • Project is compatible with Windows or other operating system where filesystem is case sensitive.
  • import paths are consistent with what is actually on the filesystem

Case sensitivity can be disabled using caseSensitive parameter

Node module resolution

This resolver consider files are written for browsers by default: Node core modules will be considered as not found.

import { readFile } from "fs"

The import above would be reported by ESLint as not found.

If the file is written for Node.js, you can consider node core modules as found and enable node module resolution using node parameter

Extensionless import

Extensionless import means an import where the specifier omits the file extension.

import { value } from "./file"

But these type of specifier are problematic: you don't know where to look at for the corresponding file.

  • Is it ./file ?
  • Is it ./file.js ?
  • Is it ./file.ts ?

The best solution to avoid configuring your brain and your browser is to keep the extension on the specifier.

- import { value } from './file'
+ import { value } from './file.js'

But if for some reason this is problematic you can allow extensionless specifiers using defaultExtension parameter

Bare specifier

A specifier is what is written after the from keyword in an import statement.

import value from "specifier"

If there is no mapping of "specifier" to "./specifier.js" the imported file will not be found. This is because import map consider "specifier" as a special kind of specifier called bare specifier. And every bare specifier must have a mapping or it cannot be resolved. To fix this either add a mapping or put explicitely "./specifier.js".

Please note that "specifier.js" is also a bare specifier. You should write "./specifier.js" instead.

Configuration

importMapFileRelativeUrl parameter

importMapFileRelativeUrl parameter is a string leading to an importmap file. This parameter is optional and undefined by default.

module.exports = {
  plugins: ["import"],
  settings: {
    "import/resolver": {
      [require.resolve("@jsenv/importmap-eslint-resolver")]: {
        projectDirectoryUrl: __dirname,
        importMapFileRelativeUrl: "./project.importmap",
      },
    },
  },
}
caseSensitive parameter

caseSensitive parameter is a boolean indicating if the file path will be case sensitive. This parameter is optional and enabled by default. See Case sensitivity.

module.exports = {
  plugins: ["import"],
  settings: {
    "import/resolver": {
      [require.resolve("@jsenv/importmap-eslint-resolver")]: {
        projectDirectoryUrl: __dirname,
        importMapFileRelativeUrl: "./project.importmap",
        caseSensitive: false,
      },
    },
  },
}
defaultExtension parameter

defaultExtension parameter is a boolean indicating if a default extension will be automatically added to import without file extension. This parameter is optional and disabled by default. See Extensionless import

When enabled the following import

import { value } from "./file"

Will search for a file with an extension. The extension is "inherited" from the file where the import is written:

If written in whatever.js, searches at file.js.
If written in whatever.ts, searches at file.ts.

node parameter

node parameter is a boolean indicating if the file are written for Node.js. This parameter is optional and disabled by default. See Node core modules

When enabled node core modules (path, fs, url, etc) will be considered as found.

module.exports = {
  plugins: ["import"],
  settings: {
    "import/resolver": {
      [require.resolve("@jsenv/importmap-eslint-resolver")]: {
        projectDirectoryUrl: __dirname,
        importMapFileRelativeUrl: "./project.importmap",
        node: true,
      },
    },
  },
}

Advanced configuration example

In a project mixing files written for the browser AND for Node.js you should tell ESLint which are which. This is possible thanks to overrides. overrides is documented on ESLint in Configuration Based on Glob Patterns.

.eslintrc.cjs

const importResolverPath = require.resolve("@jsenv/importmap-eslint-resolver")

module.exports = {
  plugins: ["import"],
  env: {
    es6: true,
    // ESLint will consider all files as written for a browser by default
    browser: true,
    node: false,
  },
  settings: {
    "import/resolver": {
      [importResolverPath]: {
        projectDirectoryUrl: __dirname,
        importMapFileRelativeUrl: "./project.importmap",
      },
    },
  },
  overrides: [
    {
      // ESLint will consider all files inside script/ and ending with .cjs as written for Node.js
      files: ["script/**/*.js", "**/*.cjs"],
      env: {
        es6: true,
        browser: false,
        node: true,
      },
      settings: {
        "import/resolver": {
          [importResolverPath]: {
            node: true,
          },
        },
      },
    },
  ],
}

FAQs

Package last updated on 30 Apr 2021

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc