Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: undefined is not iterable #9210

Closed
CaelanStewart opened this issue Dec 19, 2018 · 2 comments · Fixed by #10396
Closed

TypeError: undefined is not iterable #9210

CaelanStewart opened this issue Dec 19, 2018 · 2 comments · Fixed by #10396
Labels
area: errors outdated A closed issue/PR that is archived due to age. Recommended to make a new issue

Comments

@CaelanStewart
Copy link

CaelanStewart commented Dec 19, 2018

Bug Report

I'm not familiar with Webpack's specifies, or Babel's internals, as I'm being lazy and using laravel-mix. However, the error I'm receiving seems like a bug in the compiler to me. But you, the experts, can be the judge of that.

Current Behaviour
A clear and concise description of the behaviour.

Using for ... of in a certain context doesn't work, but it works elsewhere as expected.

The error I receive is:

TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))

Input Code

This is a method from the containing class. It's a very simple CSS parser (no block support) for a specific use case I have. The whole module can be seen under "Additional Context", below.

toObject() {
    let statements = this.css.split(';'),
        object = { };

    console.log(statements);

    for (let statement of statements) {
        let [property, value] = this.parseStatement(statement);

        object[property] = value;
    }

    return object;
}

Output Code
You didn't ask for it, but I think it may be useful.

{
    key: "toObject",
    value: function toObject() {
      var statements = this.css.split(';'),
          object = {};
      console.log(statements);
      var _iteratorNormalCompletion = true;
      var _didIteratorError = false;
      var _iteratorError = undefined;

      try {
        for (var _iterator = statements[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
          var statement = _step.value;

          var _this$parseStatement = this.parseStatement(statement),
              _this$parseStatement2 = _slicedToArray(_this$parseStatement, 2),
              property = _this$parseStatement2[0],
              value = _this$parseStatement2[1];

          object[property] = value;
        }
      } catch (err) {
        _didIteratorError = true;
        _iteratorError = err;
      } finally {
        try {
          if (!_iteratorNormalCompletion && _iterator.return != null) {
            _iterator.return();
          }
        } finally {
          if (_didIteratorError) {
            throw _iteratorError;
          }
        }
      }

      return object;
    }
  }

Expected behavior/code
I expected it to iterate over the plain JS array, like it does elsewhere I use for ... of.

Babel Configuration (.babelrc, package.json, cli command)

Unknown. I've not yet forced myself to learn more about what's beneath laravel-mix.

But whatever laravel-mix uses by default, basically.

But, as follows, these are the package versions.

├─ laravel-mix@4.0.12
│  ├─ @babel/core@^7.2.0

Environment

  • Babel version(s): 7.2.0
  • Yarn version: yarn@1.12.3
  • OS: macOS 10.14.2 (18C54)
  • How you are using Babel: via laravel-mix

Additional context
Add any other context about the problem here. If applicable, add screenshots to help explain.

Here is the whole module:

class CSSParser {
    constructor(css) {
        this.css = css;
    }

    getProperty(property, defaultValue) {
        return this.toObject()[property] || defaultValue;
    }

    toObject() {
        let statements = this.css.split(';'),
            object = { };

        console.log(statements);

        for (let statement of statements) {
            let [property, value] = this.parseStatement(statement);

            object[property] = value;
        }

        return object;
    }

    parseStatement(statement) {
        let trim = statement.trim(),
            split = trim.split(':');

        // If empty statement, move on. Not exactly invalid. Also prevents error when no code at all is specified.
        if ( ! trim) {
            return;
        }

        if (split.length < 2) {
            throw new SyntaxError(`Invalid CSS syntax at statement: ${statement}`);
        }

        let [property, ...value] = split;

        value = value.join(':');

        if ( ! CSSParser.isValidPropertyName(property)) {
            throw new SyntaxError(`Invalid property name at statement: ${statement}`);
        }
        
        return [property, value];
    }

    static isValidPropertyName(property) {
        return /^[a-z\-]+$/.test(property);
    }

    static isValid(css) {
        try {
            this.parse(css);
        } catch (error) {
            return false;
        }
    }

    static parse(css) {
        return (new this(css)).toObject();
    }
}

export default CSSParser;
@babel-bot
Copy link
Collaborator

Hey @CaelanStewart! 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.

@CaelanStewart
Copy link
Author

I've been a bit of a div, and prematurely assumed the cause was the for ... of loop. But the inaccurate line numbers in the source maps didn't help.

Basically, it was happening because of the return; statement in the parseStatement method in the specified code. Therefore the array unpacking syntax used in the loop in the toObject method was operating on an undefined value.

Perhaps the error in that circumstance could be a little clearer, plus the reported line number points to the for ... of loop, not the line where the unpacking occurred.

Only issue with all this abstraction is the increased debugging difficulty, due to unreliable error messages and line numbers.

Another thing that confused me was the fact that the last two calls on the stack trace are apparently from bus.js:177, which isn't even a module used by the offending code, and also points to a line containing only a closing brace. Guess that's the inaccurate source mappings again.

I definitely made sure it wasn't a cached source map. That damn issue with Chrome caching source maps and not refreshing them on Ctrl+Shift+Enter at random times still seems to exist.

@lock lock bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label Dec 6, 2019
@lock lock bot locked as resolved and limited conversation to collaborators Dec 6, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area: errors outdated A closed issue/PR that is archived due to age. Recommended to make a new issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants