es-tooling / module-replacements-codemods

MIT License
188 stars 26 forks source link

fix(is-npm): support more ways of importing + non-standard import names #62

Closed MeLlamoPablo closed 4 months ago

MeLlamoPablo commented 4 months ago

Currently, the is-npm codemod assumes that developers name the imported members isNpm, isYarn and isYarnOrNpm. However, there are two ways in which developers could alter the imports that can't be handled by the codemod:

// ESM
import { isNpm as banana, isYarn as pear, isNpmOrYarn as strawberry } from 'is-npm';
import * as banana from 'is-npm';

// CJS
const { isNpm: banana, isYarn: pear, isNpmOrYarn: strawberry } = require('is-npm');
const banana = require('is-npm');

Moreover, by relying on hardcoded names, we also could potentially make unsafe modifications to developer code (they could have an isNpm variable themselves which is different from the imported one and has a different meaning)

This PR makes the codemod detect the imported names dynamically so that it supports the styles above. It also adds test cases to handle the new styles.

The PR introduces the getImportIdentifierMap helper which creates a map like this:

// import { isNpm as banana, isYarn as pear, isNpmOrYarn as strawberry } from 'is-npm';
const map = {
  isNpm: "banana",
  isYarn: "pear",
  isNpmOrYarn: "strawberry"
}

// import * as banana from 'is-npm';
const map = {
  [Symbol(NAMEPSACE_IMPORT)]: "banana"
}

This helper should be useful for cases where a module exports multiple names and const { identifier } = removeImport() is not sufficient.

There is some duplication in the codemod code, as the "individual name import" and "namespace import" cases need to be handled separately. However, since I suspect that this issue will also apply to other codemods, I believe the duplication is fine for now — we can figure out better abstractions as we continue improving the mods.

Thanks for reading!

thepassle commented 4 months ago

Nice, thanks!