tleunen / find-babel-config

Find the closest babel config based on a directory
MIT License
13 stars 7 forks source link

No API object for function configuration #36

Open tilgovi opened 5 years ago

tilgovi commented 5 years ago

If a configuration file exports a function, it is not called with any arguments.

It should be called with an API object: https://babeljs.io/docs/en/config-files#config-function-api

tilgovi commented 5 years ago

Since this module also does not resolve plugins and presets, a lot of the work can probably be replaced with loadPartialConfig({ configFile }) from @babel/core. It returns an object with options.

0xdevalias commented 4 years ago

I've also just hit this issue while trying to use https://github.com/tleunen/babel-plugin-module-resolver:

Error while loading rule 'module-resolver/use-alias': Cannot read property 'env' of undefined
TypeError: Error while loading rule 'module-resolver/use-alias': Cannot read property 'env' of undefined
    at module.exports.api (./babel.config.js:5:24)
    at getBabelJsConfig (./node_modules/find-babel-config/lib/index.js:21:16)
    at Function.findBabelConfigSync [as sync] (./node_modules/find-babel-config/lib/index.js:152:27)
    at Object.create (./node_modules/eslint-plugin-module-resolver/dist/rules/use-alias.js:79:49)
    at createRuleListeners (./node_modules/eslint/lib/linter.js:682:21)
    at Object.keys.forEach.ruleId (./node_modules/eslint/lib/linter.js:841:31)
    at Array.forEach (<anonymous>)
    at runRules (./node_modules/eslint/lib/linter.js:781:34)
    at Linter._verifyWithoutProcessors (./node_modules/eslint/lib/linter.js:1003:33)
    at preprocess.map.textBlock (./node_modules/eslint/lib/linter.js:1046:35)

My workaround was to mock out the aspects of api that we require (namely env), based on the docs:

// If we aren't passed an api, mock one out here..
// Ref: https://babeljs.io/docs/en/config-files#apienv
const fakedApiObject = {
  env: checkEnv => {
    const envName = process.env.NODE_ENV || 'development'

    if (typeof checkEnv === 'string') {
      return checkEnv === envName
    } else if (Array.isArray(checkEnv)) {
      return checkEnv.includes(envName)
    } else if (typeof checkEnv === 'function') {
      return checkEnv(envName)
    } else {
      return envName
    }
  }
}

module.exports = (api = fakedApiObject) => {
// ..snip..

That ends up getting further, but then is dying on this (but that is likely more related to eslint-plugin-module-resolver than this package):

TypeError: Cannot read property 'loc' of undefined
    at CallExpression (./node_modules/eslint-plugin-module-resolver/dist/rules/use-alias.js:108:36)
    at listeners.(anonymous function).forEach.listener (./node_modules/eslint/lib/util/safe-emitter.js:47:58)
    at Array.forEach (<anonymous>)
    at Object.emit (./node_modules/eslint/lib/util/safe-emitter.js:47:38)
    at NodeEventGenerator.applySelector (./node_modules/eslint/lib/util/node-event-generator.js:251:26)
    at NodeEventGenerator.applySelectors (./node_modules/eslint/lib/util/node-event-generator.js:280:22)
    at NodeEventGenerator.enterNode (./node_modules/eslint/lib/util/node-event-generator.js:294:14)
    at CodePathAnalyzer.enterNode (./node_modules/eslint/lib/code-path-analysis/code-path-analyzer.js:608:23)
    at Traverser.enter [as _enter] (./node_modules/eslint/lib/linter.js:865:28)
    at Traverser._traverse (./node_modules/eslint/lib/util/traverser.js:132:14)
    at Traverser._traverse (./node_modules/eslint/lib/util/traverser.js:147:30)
    at Traverser._traverse (./node_modules/eslint/lib/util/traverser.js:144:34)
    at Traverser._traverse (./node_modules/eslint/lib/util/traverser.js:144:34)
    at Traverser.traverse (./node_modules/eslint/lib/util/traverser.js:115:14)
    at runRules (./node_modules/eslint/lib/linter.js:862:15)
    at Linter._verifyWithoutProcessors (./node_modules/eslint/lib/linter.js:1003:33)

Super cutting down the file it's failing on, it basically looks like this:

import { makeFile } from '../../../helpers/file-helpers'

const file = makeFile()

The file-helpers exists correctly at that path, the error seems to occur regardless of whether it contains any content/exports though.

It seems it may be related to it not being able to find my module-transform config in my babel config, as I was doing it through jest's babel config override section. If I comment everything aside from the relative path import i get the following eslint error:

warning  Unable to find config for babel-plugin-module-resolver  module-resolver/use-alias

Which goes away once i add the config back in :

[
  'module-resolver',
  {
    root: ['./spec/javascripts'],
    alias: {
      'test-helpers': './helpeaaarstestfoo',
    },
  },
],

I'm not 100%.. but I think this could possibly also be solved by using loadPartialConfig from @babel/core, as I know jest makes use of similar to add it's own config changes. I expect what this rule is seeing isn't representative of the final babel config as jest/etc would see it.

Edit: Opened https://github.com/HeroProtagonist/eslint-plugin-module-resolver/issues/44 RE: the 2nd part of my issue here with further details.

HeroProtagonist commented 4 years ago

@0xdevalias @tilgovi

I added support for config files with these lines. No value is passed into the config when it is called, so it makes sense that this happens.

Do you guys know if babel exports this api object so we could pass it in? Or is there a better way to handle the config when it is a function?

tilgovi commented 4 years ago

Do you guys know if babel exports this api object so we could pass it in? Or is there a better way to handle the config when it is a function?

@babel/core may do everything you need:

> require('@babel/core').loadPartialConfig({ rootMode: 'upward-optional' })
PartialConfig {
  options: {
    rootMode: 'upward-optional',
    babelrc: false,
    configFile: false,
    passPerPreset: false,
    envName: 'development',
    cwd: '...',
    root: '...',
    filename: undefined,
    plugins: [ [ConfigItem], [ConfigItem], [ConfigItem] ],
    presets: [ [ConfigItem] ]
  },
  babelignore: undefined,
  babelrc: undefined,
  config: '.../babel.config.js'
}
tilgovi commented 4 years ago

Unfortunately, I suspect there are probably exotic uses of find-babel-config and babel-plugin-module-resolver and eslint-import-resolver-babel-module and places where options that may be important to pass might conflict with their meaning for this function.

I made an effort to catalogue some of the issues here: https://github.com/tleunen/eslint-import-resolver-babel-module/issues/89#issuecomment-541482240

My recommendation, at this point, would be to try out a branch of eslint-resolver-babel-module and babel-plugin-module-resolver that just use the core loadPartialConfig function and nothing else. Possibly a near total rewrite. If it works, it would greatly simplify the whole situation and you could bump a major version number.

tilgovi commented 4 years ago

My recommendation, at this point, would be to try out a branch of eslint-resolver-babel-module and babel-plugin-module-resolver that just use the core loadPartialConfig function and nothing else. Possibly a near total rewrite. If it works, it would greatly simplify the whole situation and you could bump a major version number.

I think that would look like option 4 in my comment. The babel-plugin-module-resolver would not use this package (find-babel-config) at all. It should either use the current working directory, or an explicit root, or get it from the babel configuration somehow. I don't know if Babel passes the root directory through to plugins or not, but Babel definitely knows it. If it doesn't pass it, use loadPartialConfig to find it. Then eslint-import-resolver-babel-module should not take any configuration that isn't a Babel configuration option used for finding the config, and all other options should be taken from the configuration for babel-plugin-module-resolver.

tilgovi commented 4 years ago

Just in case it doesn't go without saying: none of this is meant as an attack. Thank you for your work on these projects. They've been immensely helpful to me. If I can help by prototyping any of the above, please let me know what makes sense to you.

tleunen commented 4 years ago

@tilgovi - No worries, I don't take it personally. I've been away from these projects for a long time because I'm not an active user/consumer of these anymore. So it's hard for me to find the time and the motivation to keep improving them.

I'd like to update this library to use loadPartialConfig since Babel provides this function now. In term of babel-plugin-module-resolver using this package or not, we can debate this in its own repo as well. If loadPartialConfig makes it super easy, I don't see a real valid use case of keeping find-babel-config honestly.

tilgovi commented 4 years ago

Cool. I'll let you know what I find.