Skip to content

import-x/extensions rule doesn't work with Node.js subpath imports #437

@sairus2k

Description

@sairus2k

The import-x/extensions rule fails to check file extensions for Node.js subpath imports.

Current Behavior

When using subpath imports defined in package.json:

{
  "imports": {
    "#utils/*": "./src/utils/*.js"
  }
}

The import-x/extensions rule doesn't validate extensions:

import { helper } from '#utils/helper';     // ✓ No error (but should check extension)
import { helper } from '#utils/helper.js';  // Rule doesn't verify this either

Expected Behavior

The rule should check file extensions for subpath imports the same way it does for regular imports:

// With "import-x/extensions": ["error", "always"]
import { helper } from '#utils/helper';     // ❌ Should error: missing extension
import { helper } from '#utils/helper.js';  // ✓ Should pass

Root Cause

The parsePath function treats # as a URL hash fragment, causing the pathname to be extracted incorrectly:

export const parsePath = (path: string): ParsedPath => {
  const hashIndex = path.indexOf('#')
  const queryIndex = path.indexOf('?')
  const hasHash = hashIndex !== -1
  const hash = hasHash ? path.slice(hashIndex) : ''
  const pathname = hasHash ? path.slice(0, hashIndex) : path
  // For '#utils/helper', this results in pathname: '' and hash: '#utils/helper'
}

This causes the import-x/extensions rule (and potentially other rules) to skip validation since it doesn't see a valid pathname.

Suggested Fix

The parsePath function should not treat URLs started with the symbol # as hash fragments.

export const parsePath = (path: string): ParsedPath => {
  const hashIndex = path.indexOf('#')
  const hasHash = hashIndex > 0
  // ... rest of the existing logic
}

Environment

  • Node.js version: v24.11.0
  • eslint-plugin-import-x version: v4.16.1 (latest at the moment)

Additional Context

Resolution appears to work correctly, but path parsing for rule validation is broken.

Other rules that depend on parsePath might also be affected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions