eslint-plugin-node icon indicating copy to clipboard operation
eslint-plugin-node copied to clipboard

--fix with file-extension-in-import can break imports of packages

Open jonahsnider opened this issue 5 years ago • 7 comments

file-extension-in-import when configured to require an extension reports the following import as invalid:

import "firebase/app";

Using --fix changes the import to

import "firebase/app.js";

Which is not a file that exists, causing a runtime ERR_MODULE_NOT_FOUND error as well as a TypeScript TS2307 compiler error.

jonahsnider avatar Feb 26 '21 01:02 jonahsnider

In general, you cannot fix imports by adding a .js suffix. Is there a standard way to resolve the imports (the same way node.js does it)? Or are there many standards out there?

Resolving imports is really difficult. In this specific instance, node_modules/firebase had a package.json file with several fields for ESM, CommonJS, etc. that pointed to files in another subdirectory.

jonahsnider avatar Feb 28 '21 22:02 jonahsnider

Can't require.resolve be used for that?

Yes, require.resolve or other internal Node.js APIs should be used for validating imports or suggesting changes. Note that different logic will be required if you are using ECMAScript modules instead of the require API.

jonahsnider avatar Mar 10 '21 16:03 jonahsnider

Note that different logic will be required if you are using ECMAScript modules instead of the require API.

Is this different logic available somewhere? The same way the node resolve logic is available through the official API.

Node.js docs mention one workaround using import.meta.url since require.resolve is unavailable in ESM.

jonahsnider avatar Mar 10 '21 16:03 jonahsnider

Here is a draft to answer part of the question:

const addLeadingDotIfNecessary = (path) => {
	if (path.startsWith('./')) return path;
	if (path.startsWith('../')) return path;
	return './' + path;
};

const partialRequireResolve = (from, to) => {
	const dir = path.dirname(from);
	const result = require.resolve(to, {paths: [dir]});
	if (/^(@[^/]+\/|)[^./]+$/.test(to)) return to;
	if (/\/node_modules\//.test(result)) {
		return result.split('/node_modules/').pop();
	}
	return path.isAbsolute(to)
		? result
		: addLeadingDotIfNecessary(path.relative(dir, result));
};

If you have a file sourceFile in which there is the import statement require(<importedId>) you can call resolve(sourceFile, importedId) to get an ESMish import identifier.