babel / babel

🐠 Babel is a compiler for writing next generation JavaScript.
https://babel.dev
MIT License
43.23k stars 5.64k forks source link

Template string failing with Cannot read property 'range' of null #10904

Closed yitomok closed 4 years ago

yitomok commented 4 years ago

It throws error when dynamic import, template literal inline and rule template-curly-spacing as follow:

Tested on:

babel-eslint@10.0.3 (with @babel/parser@7.7.7) eslint@6.7.2

Sample code:

import(`${'package.json'}`)

.eslintrc.json

{
  "parser": "babel-eslint",
  "rules": {
    "template-curly-spacing": ["error", "never"]
  }
}

The problem is coming from @babel/parser@7.7.7, which added ImportExpression.

Originally posted by @yitomok in https://github.com/babel/babel-eslint/issues/799#issuecomment-567598343


Edits by @JLHwung

If you come across this issue from search engine, see below for the solution:

  1. uninstall babel-eslint
  2. install @babel/eslint-parser
  3. replace babel-eslint by @babel/eslint-parser in your ESLint config
  4. if you use eslint-plugin-babel, do 4.a - 4.c, otherwise skip it 4.a uninstall eslint-plugin-babel 4.b install @babel/eslint-plugin 4.c replace "babel" or "eslint-plugin-babel" to "@babel"
  5. The working ESLint config should look like https://github.com/babel/babel/issues/10904#issuecomment-691827355
babel-bot commented 4 years ago

Hey @yitomok! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack community that typically always has someone willing to help. You can sign-up here for an invite."

kaicataldo commented 4 years ago

I think this should be fixed by https://github.com/babel/babel/pull/10828, but will have to verify.

kaicataldo commented 4 years ago

Added to https://github.com/babel/babel/issues/10752 so I don't forget to verify this when I start going through rules.

jlchereau commented 4 years ago

The following does not trigger the 'range' of null error:

const { location } = window;
const root = `${location.protocol}//${location.host}/`;

but the following does:

const { location } = window;
const schemes = {
    root: `${location.protocol}//${location.host}/`
};
kaicataldo commented 4 years ago

What version are you using?

jlchereau commented 4 years ago

Hey @kaicataldo,

    "@babel/cli": "^7.8.4",
    "@babel/core": "^7.9.0",
    "@babel/plugin-transform-runtime": "^7.9.0",
    "@babel/preset-env": "^7.9.0",
    "@babel/register": "^7.9.0",
    "babel-eslint": "^10.1.0",
    "babel-loader": "^8.1.0",
    "babel-plugin-istanbul": "^6.0.0",
    "babel-plugin-module-resolver": "^4.0.0",
    "eslint": "^6.8.0",
    "eslint-config-airbnb-base": "^14.1.0",
    "eslint-config-prettier": "^6.10.1",
    "eslint-import-resolver-babel-module": "^5.1.2",
    "eslint-plugin-import": "^2.20.2",
    "eslint-plugin-node": "^11.1.0",
    "eslint-plugin-prettier": "^3.1.2",
rjgotten commented 4 years ago

@kaicataldo For what it's worth - I'm also having this problem with the template-curly-spacing throwing on a dynamic import.

Relevant packages:

"@babel/core": "^7.9.0",
"@babel/plugin-transform-runtime": "^7.9.0",
"@babel/preset-env": "^7.9.0",
"babel-eslint": "^11.0.0-beta.2",
"eslint": "^6.8.0",
"eslint-plugin-import": "^2.20.2",

(NOTE: Problem actually occurs with babel-eslint versions 10.0.3; 10.1.0 as well as the 11.0.0-beta2 under its @next. Checked all of them.)

Unlisted dependencies confirmed fully de-duped:

@babel/types - 7.9.0
@babel/parser - 7.9.4
@babel/traverse - 7.9.0
tmcdos commented 4 years ago

I am experiencing this problem when I lint code like this (string templates without any interpolation inside):

this.box = `<div>
text line
</div>`;
kaicataldo commented 4 years ago

This should be fixed in the latest v11 prerelease (and will be included in the next major release, which will be under a new package name).

brettz9 commented 4 years ago

Regarding the "latest v11 prerelease", I guess you mean the next such release, @kaicataldo, as npm is showing the latest release for babel-eslint as 11.0.0-beta.2 from 5 months ago (and https://www.npmjs.com/package/@babel/eslint-parser shows nothing yet)?

githoniel commented 4 years ago

when will this release? use 8.x babel-eslint will result in other bugs...

LexSwed commented 4 years ago

The issue persists. Any workaround? Fixing the version to @babel/parser@7.7.5 or 7.10.5 doesn't help

Strahinja commented 4 years ago

The issue persists. Any workaround? Fixing the version to @babel/parser@7.7.5 or 7.10.5 doesn't help

As mentioned here, I could get this to work using the "resolutions" fix that @pi0 suggested.

LexSwed commented 4 years ago

Fixed with https://github.com/atlassian/yarn-deduplicate apparently in my case one package messes up dependency tree.

EarthyOrange commented 4 years ago

"babel-eslint": "10.1.0" OR "@babel/eslint-parser": "^7.11.0", "eslint": "7.6.0",

The babel-eslint parser can be used by eslint to allow it to parse JS code using babel plugins which are in proposal stage.

I ran in to this particular issue with babel-eslint when it tried to parse the following code with optional chaining:

  this.x?.y(`template ${z}`);

The eslint doesn't throw the error if the optional chaining is removed from ☝️.

A log at https://github.com/babel/babel-eslint/blob/10.x/lib/babylon-to-espree/toAST.js#L101 or https://github.com/babel/babel/blob/master/eslint/babel-eslint-parser/src/convert/convertAST.js#L64 to log the node object shows that the following node is missing when optional chaining is present.

Node {
  type: 'TemplateLiteral',
  start: 9583,
  end: 9650,
  loc:
   SourceLocation {
     start: Position { line: 254, column: 10 },
     end: Position { line: 254, column: 77 } },
  range: [ 9583, 9650 ],
  expressions:
   [ Node {
       type: 'MemberExpression',
       start: 9626,
       end: 9647,
       loc: [SourceLocation],
       range: [Array],
       object: [Node],
       property: [Node],
       computed: false,
       optional: false,
       _babelType: 'MemberExpression' } ],
  quasis:
   [ Node {
       type: 'TemplateElement',
       start: 9584,
       end: 9624,
       loc: [SourceLocation],
       range: [Array],
       value: [Object],
       tail: false,
       _babelType: 'TemplateElement' },
     Node {
       type: 'TemplateElement',
       start: 9648,
       end: 9649,
       loc: [SourceLocation],
       range: [Array],
       value: [Object],
       tail: true,
       _babelType: 'TemplateElement' } ],
  _babelType: 'TemplateLiteral' }

I believe that these nodes are generated by the "@babel/parser" library. Is it possible that the issue is in the parser lib?

kaicataldo commented 4 years ago

@EarthyOrange Thanks for digging into this! I'll look into this with this new information (though if you want to continue investigating, feel free). This could be a bug in @babel/parser's logic (most likely in the estree plugin) or it could be a bug in @babel/eslint-parser, which serves as the compatibility layer between ESLint and Babel (and does perform some mutations of the AST).

cdoublev commented 4 years ago

Hello @kaicataldo,

I also looked at this issue, since the workaround (resolutions) given above is valid only when using yarn (and I'm using npm, of course).

Files used to debug this issue:

// ./index.js
import(`./${'foo'}.js`)
// ./foo.js
export default ''
// .eslintrc.js
module.exports = {
    env: { es2020: true },
    parser: '@babel/eslint-parser',
    parserOptions: {
        ecmaFeatures: { impliedStrict: true },
        sourceType: 'module',
    },
    rules: {
        // 'indent': 'warn',
        'template-curly-spacing': 'warn',
    },
}
// babel.config.js
module.exports = {}

First, running eslint -- debug index.js outputs this message: eslint:traverser Unknown node type "ImportExpression": Estimated visitor keys ["type","start","end","loc","range","source"]. I believe that ImportExpression is missing from the exported lib/visitor-keys.js in @babel/eslint-parser.

But even after including it, the first token that is supposed to be returned from the template literal (here) remains null.

I couldn't go any further (for now) than observing that the ForwardTokenCursor uses a wrong indexEnd (here) to check the space before } (closing of the template literal). Its value is derived from an index map created here.

cdoublev commented 4 years ago

It seems that defining ImportExpression in @babel/types definitions fixes this issue. But I'm totally ignorent of how to properly define it. I used the following, which is obviously incomplete:

defineType("ImportExpression", {
  visitor: ["source"],
  fields: {},
  aliases: [],
});
JLHwung commented 4 years ago

@cdoublev ImportExpression is defined in eslint-visitor-keys@1.3.0, which should be depended by eslint>=7.5.0. What is your eslint version?

cdoublev commented 4 years ago

7.6.0 but what I'm saying is that it's not in the visitor keys exported by @babel/eslint-parser. Adding it + defining ImportExpression in @babel/types like suggested in my previous comment, fixes this issue.

JLHwung commented 4 years ago

Fixed in @babel/eslint-parser@7.11.3.

geopamplona commented 4 years ago

How should fix, upgrading packages?? or Should wait some new release? I upgrade to @babel/eslint-parser@7.11.3 but I still have these problem. Thanks !

lebaz20 commented 4 years ago

Fixed with https://github.com/atlassian/yarn-deduplicate apparently in my case one package messes up dependency tree.

Thanks @LexSwed, It seems that was the problem in my case as well. I needed to run yarn-deduplicate yarn.lock after installing @babel/eslint-parser@7.11.3 to get it to work.

soletan commented 4 years ago

Came here from https://github.com/eslint/eslint/issues/13394. Could someone give me brief instructions on how to handle this fix, please?

I'm aware of FOSS requiring some interest and time to spent to work with. I know it's about shared efforts. However, right now I'd like to use ESLint to check my own FOSS code. I have a basic understanding on what babel is and when to use it, but I don't know all the relations between all that babel-packages mentioned in this thread and how they are integrated with ESLint. Currently I'm quite little interested in studying those internals to get babel-eslint working as a parser in ESLint again. So, is there any easy way to fix that linked issue when trying to add babel-eslint to ESLint?

cdoublev commented 4 years ago

Try switching to @babel/eslint-parser.

With the next iteration of babel-eslint, we have decided to publish the package under a new name: @babel/eslint-parser.

https://babeljs.io/blog/2020/07/13/the-state-of-babel-eslint

soletan commented 4 years ago

I found this minimum configuration helpful (with unrelated or too specific pieces removed):

package.json

{
    "name": "your-project",
    "devDependencies": {
        "@babel/core": "^7.11.6",
        "@babel/eslint-parser": "^7.11.5",
        "@babel/eslint-plugin": "^7.11.5",
        "@babel/preset-env": "^7.11.5",
        "eslint": "^7.9.0"
    }
}

.babelrc (required)

{
    "presets": [
        [
            "@babel/env",
            {
                "targets": {
                    "edge": "17",
                    "firefox": "60",
                    "chrome": "67",
                    "safari": "11.1"
                },
                "useBuiltIns": "usage",
                "corejs": "3.6.4"
            }
        ]
    ]
}

.eslintrc

{
    "plugins": [
        "@babel"
    ],
    "extends": [
        "your-preferred-ruleset-here"
    ],
    "parser": "@babel/eslint-parser",
}
rjgotten commented 3 years ago

FYI; This is still broken.

package versions eslint@7.13.0 @babel/eslint-parser@7.12.1

Have to selectively disable ESLint rules to skirt the problem, like so:

"template-curly-spacing" : "off"

or ESLint still blows up with:

TypeError: Cannot read property 'value' of null
Occurred while linting [redacted]
    at checkSpacingBefore ([redacted]\node_modules\eslint\lib\rules\template-curly-spacing.js:52:24)
    at TemplateElement ([redacted]\node_modules\eslint\lib\rules\template-curly-spacing.js:136:17)
    at [redacted]\node_modules\eslint\lib\linter\safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit ([redacted]\node_modules\eslint\lib\linter\safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector ([redacted]\node_modules\eslint\lib\linter\node-event-generator.js:254:26)
    at NodeEventGenerator.applySelectors ([redacted]\node_modules\eslint\lib\linter\node-event-generator.js:283:22)
    at NodeEventGenerator.enterNode ([redacted]\node_modules\eslint\lib\linter\node-event-generator.js:297:14)
    at CodePathAnalyzer.enterNode ([redacted]\node_modules\eslint\lib\linter\code-path-analysis\code-path-analyzer.js:711:23)
    at [redacted]\node_modules\eslint\lib\linter\linter.js:952:32

Here, inside template-curly-spacing the sourceCode.getFirstToken call ends up returning null:

return {
  TemplateElement(node) {
    const token = sourceCode.getFirstToken(node);

    checkSpacingBefore(token);
    checkSpacingAfter(token);
  }
};

[EDIT]

Looks like this is STILL the problem with a wrong version of @babel/types being used. After a thorough wipe and reinstall of all things @babel (as npm dedup was deduping to the WRONG version) it does work.

I though the whole idea of having the eslint parser go into the mono repo was to maintain it together with Babel and prevent exactly that shitty issue?

jiandandkl commented 3 years ago

use @babel/eslint-parser, because image