Babel-eslint: Indent - Maximum call stack size exceeded

Created on 28 Mar 2018  ·  10Comments  ·  Source: babel/babel-eslint

Stumbled across an odd issue:

[email protected]
[email protected]

var a = `${() => {
  `${''}`
}}`;
var b = `${''}`;
vagrant@vagrant:~/tmp$ eslint --rule {"indent":[2]} --parser babel-eslint test.js
Maximum call stack size exceeded
RangeError: Maximum call stack size exceeded
    at RegExp.test (<anonymous>)
    at OffsetStorage.getDesiredIndent (/vagrant/node_modules/eslint/lib/rules/indent.js:445:32)
    at OffsetStorage.getDesiredIndent (/vagrant/node_modules/eslint/lib/rules/indent.js:451:45)
    at OffsetStorage.getDesiredIndent (/vagrant/node_modules/eslint/lib/rules/indent.js:451:45)
    at OffsetStorage.getDesiredIndent (/vagrant/node_modules/eslint/lib/rules/indent.js:451:45)
    at OffsetStorage.getDesiredIndent (/vagrant/node_modules/eslint/lib/rules/indent.js:451:45)
    at OffsetStorage.getDesiredIndent (/vagrant/node_modules/eslint/lib/rules/indent.js:451:45)
    at OffsetStorage.getDesiredIndent (/vagrant/node_modules/eslint/lib/rules/indent.js:451:45)
    at OffsetStorage.getDesiredIndent (/vagrant/node_modules/eslint/lib/rules/indent.js:451:45)
    at OffsetStorage.getDesiredIndent (/vagrant/node_modules/eslint/lib/rules/indent.js:451:45)

This originally happened in my application's mid-size state store file, and I reduced it down to this with the issue staying constant. I wasn't able to replicate the issue without the backticks so I'm assuming this is specific to babel-eslint and not base eslint, but I don't know for certain - happy to move this.

It's pretty easy to work around once you know what's causing the problem, as even a minor change will cause the issue to stop occurring. I ended up changing the arrow function to use parentheses instead of curly braces and it went away.

bug

Most helpful comment

Just published 8.2.4, which should fix this issue!

All 10 comments

I have recently run into this error as well, have yet to determine the offending code. Will update this thread if I determine what is causing it.

Got the same error and posted a duplicate issue but it contains a snippet to reproduce the error: https://github.com/babel/babel-eslint/issues/609#issue-313450649

package.json

"babel-eslint": "8.2.3",
"eslint": "4.19.1",

Eslint Rule:

"indent": [2, 2],

Result:

Maximum call stack size exceeded
RangeError: Maximum call stack size exceeded
    at RegExp.test (<anonymous>)

Does this happen with the default parser (Espree) too? If so, this bug should be filed with ESLint core, since that's where the code for the indent rule is.

@kaicataldo it looks like its an issue related to how we convert Babylon template tokens, I published a PR for a fix if you want to review (https://github.com/babel/babel-eslint/pull/610)!

Just published 8.2.4, which should fix this issue!

Still can reproduce this bug. @existentialism

@zhangtemplar please give a reduced test case and I’ll look into it

@existentialism Sure, check this one:

/* eslint-disable */
import {
  createUser, deleteUser, deleteUserUser,
  queryMore, queryReportee, queryReporter,
  queryUser,
  queryUserByProject, queryUserFrom, queryUserTo,
  queryUserUser,
  updateUser,
} from '../services/api';
import { getCurrentUser } from '../utils/authority';
import { setGroup } from '../utils/group';

/**
 * Builds the query to perform aggregation query for user.
 *
 * @param payload an object for the query
 * @return {{}}
 */
function buildQueryForAggeregation(payload) {
  const query = {
    $projection: {
      'user.id': 1,
      'user.name': 1,
      'user.keyword': 1,
      'user.abstract': 1,
      'user.time': 1,
      'user.logo': 1,
      id: 1,
      fromId: 1,
      toId: 1,
      name: 1,
      time: 1,
      type: 1,
    },
  };
  if (payload !== null) {
    query.$where = payload;
  } else {
    query.$where = {};
  }
  return query;
}

function merge(response) {
  const list = {};
  response._items.forEach((relationship) => {
    relationship.user.forEach((user) => { list[user.id] = user; });
  });
  return {
    ...response,
    _items: Object.values(list),
  };
}

export default {
  namespace: 'user',

  state: {
    list: null,
    currentUser: null,
    item: null,
    // meta data associated with this query, e.g., total number of results available to query.
    meta: null,
    // links for navigation purpose.
    links: null,
    // the groups and its members
    group: null,
  },

  /** 数据字典 */
  FIELDS : {
    ch :{
      id: { name: 'ID', hint: '用户唯一标识' },
      name: { name: '用户名', hint: '用户名不能为空' },
      abstract: { name: '简介', hint: '个人简介,不超过20字' },
      detail: { name: '详细介绍', hint: '详细介绍,不超过200字' },
      type: { name: '用户类型', hint: '用户类型' },
      keyword: { name: '关键词', hint: '多个词语请用逗号分隔' },
      email: { name: '邮箱', hint: '' },
      phone: { name: '手机', hint: '' },
      password: { name: '密码', hint: '密码' },
      website: { name: '网站', hint: '网站URL' },
      address: { name: '住址', hint: '常用住址' },
      capital: { name: '总投资额', hint: '总投资额' },
      netCapital: { name: '单项投资额', hint: '单项投资额' },
      title: { name: '头衔', hint: '头衔' },
      company: { name: '公司', hint: '公司' },
      education: { name: '学历', hint: '学历' },
      credit: { name: '信用', hint: '保留' },
    },
    en :{
      id: { name: 'ID', hint: 'User uniquely identifier.' },
      name: { name: 'Name', hint: 'Username cannot be empty.' },
      abstract: { name: 'Abstract', hint: 'Your personal profile, not more than 20 words' },
      detail: { name: 'Detail', hint: 'Your detailed introduction, not more than 200 words.' },
      type: { name: 'Type', hint: 'User type.' },
      keyword: { name: 'Keyword', hint: 'Please use a comma to separate.' },
      email: { name: 'Email', hint: '' },
      phone: { name: 'Phone', hint: '' },
      password: { name: 'Password', hint: 'Password' },
      website: { name: 'Website', hint: 'Website URL' },
      address: { name: 'Address', hint: 'Common Address' },
      capital: { name: 'Capital', hint: 'Total Investment' },
      netCapital: { name: 'Net Capital', hint: 'Single Investment' },
      title: { name: 'Title', hint: 'Title' },
      company: { name: 'Company', hint: 'Company' },
      education: { name: 'Education', hint: 'Education' },
      credit: { name: 'Reserved', hint: 'Reserved' },
    },
  },

  /**
   * User types on a bit map.
   */
  USER_TYPES: {
    expert: 1,
    investor: 2,
    service: 4,
    government: 8,
    entrepenuer: 16,
    angel: 32,
    competitor: 64,
    judges: 128,
    // Those two types are not supposed to change by an user.
    admin: 1073741824,
    group: 2147483648,
  },

  /**
   * @return object 标准的user数据结构
   * */
  getTemplate: () => {
    return {
      id: '',
      name: '',
      abstract: '',
      detail: '',
      creationTime: 0,
      type: 0,
      keyword: [],
      email: '',
      phone: '',
      password: '',
      website: '',
      address: '',
      capital: 0.0,
      netCapital: 0.0,
      title: '',
      company: '',
      education: '',
      credit: 0.0,
    }
  },

  effects: {
    *update({ payload, callback }, { call, put }) {
      let response = null;
      if (payload.href) {
        console.log('update user for %o', payload);
        response = yield call(updateUser, payload);
      } else {
        console.log('create user for %o', payload);
        response = yield call(createUser, payload.body);
      }
      if (callback) {
        callback(response);
      } else {
        yield put({
          type: 'queryItem',
          payload: response,
        });
      }
    },
    *fetchCurrent({ payload, callback }, { put }) {
      if (callback) {
        callback(getCurrentUser());
      } else {
        yield put({
          type: 'saveCurrentUser',
          payload: getCurrentUser(),
        });
      }
    },
    *verifyId({ payload, callback }, { call, put }) {
      console.log('search user with: %o', payload);
      const response = yield call(queryUser, `where=${
        encodeURIComponent(JSON.stringify({ id: payload }))}&projection=${
        encodeURIComponent(JSON.stringify({ id: 1, name: 1 }))}`);
      if (callback) {
        callback(response);
      } else {
        yield put({
          type: 'queryList',
          payload: response,
        });
      }
    },
    *fetchByName({ payload, callback }, { call, put }) {
      console.log('search user with: %o', payload);
      const response = yield call(queryUser, `where=${
        encodeURIComponent(JSON.stringify({ name: { $regex: `(?i)^${payload}` } }))}&projection=${
        encodeURIComponent(JSON.stringify({ id: 1, name: 1 }))}`);
      if (callback) {
        callback(response);
      } else {
        yield put({
          type: 'queryList',
          payload: response,
        });
      }
    },
    *fetchById({ payload, callback }, { call, put }) {
      const id = typeof payload === 'string' ? payload : payload.id;
      console.log('request user with %s', id);
      const response = yield call(queryUser, `where=${
        encodeURIComponent(JSON.stringify({ id }))}`);
      if (callback) {
        callback(response);
      } else {
        yield put({
          type: 'queryItem',
          payload: response,
        });
      }
    },
    *fetchMore({ payload, callback }, { call, put }) {
      const response = yield call(queryMore, payload);
      const result = payload.includes('project/from') ||
        payload.includes('user/from') ||
        payload.includes('user/to')
        ? merge(response)
        : response;
      if (callback) {
        callback(result);
      } else {
        yield put({
          type: 'queryList',
          payload: result,
        });
      }
    },
    *fetchByType({ payload, callback }, { call, put }) {
      console.log('search user with: %o', payload);
      const query = payload === null ? null : { type: { $bitsAnySet: payload } };
      yield put({
        type: 'search',
        payload: query,
        callback,
      })
    },
    *fetchByProject({ payload, callback }, { call, put }) {
      console.log('search user by project with: %o', payload);
      const query = buildQueryForAggeregation(payload);
      const response = yield call(
        queryUserByProject,
        `aggregate=${encodeURIComponent(JSON.stringify(query))}`);
      const result = merge(response);
      if (callback) {
        callback(result);
      } else {
        yield put({
          type: 'queryList',
          payload: result,
        });
      }
    },
    *fetchAsFrom({ payload, callback }, { call, put }) {
      console.log('search user as fromId with: %o', payload);
      const query = buildQueryForAggeregation(payload);
      const response = yield call(
        queryUserFrom,
        `aggregate=${encodeURIComponent(JSON.stringify(query))}`);
      const result = merge(response);
      if (callback) {
        callback(result);
      } else {
        yield put({
          type: 'queryList',
          payload: result,
        });
      }
    },
    *fetchAsTo({ payload, callback }, { call, put }) {
      console.log('search user as toId with: %o', payload);
      const query = buildQueryForAggeregation(payload);
      const response = yield call(
        queryUserTo,
        `aggregate=${encodeURIComponent(JSON.stringify(query))}`);
      const result = merge(response);
      if (callback) {
        callback(result);
      } else {
        yield put({
          type: 'queryList',
          payload: result,
        });
      }
    },
    *search({ payload, callback }, { call, put }) {
      console.log('search project with: %o', payload);
      const query = payload === null
        ? ''
        : `where=${encodeURIComponent(JSON.stringify(payload))}&`;
      const response = yield call(queryUser, `${query}projection=${
        encodeURIComponent(JSON.stringify({
          id: 1,
          name: 1,
          keyword: 1,
          abstract: 1,
          time: 1,
          logo: 1,
        }))}`);
      if (callback) {
        callback(response);
      } else {
        yield put({
          type: 'queryList',
          payload: response,
        });
      }
    },
    *deleteGroup({ payload, callback }, { call, put }) {
      console.log('delete group and user-user relationship with: %o', payload);
      // Find all the relationship related to this group.
      const response = yield call(
        queryUserUser,
        `where=${encodeURIComponent(JSON.stringify({
          $or: [
            { fromId: payload.id },
            { toId: payload.id }
          ],
          type: 4
        }))}`);
      // Remove the group
      console.log('delete group %o', payload._id);
      yield call(deleteUser, { href: payload._id, etag: null } );
      // Remove all the related relationship
      for (let item of response._items) {
        console.log('delete user user relationship %o', item._id);
        yield call(deleteUserUser, { href: item._id, etag: null });
      }
      if (callback) {
        callback(response);
      } else {
        yield put({
          type: 'queryItem',
          payload: response,
        });
      }
    },
    *fetchColleague({ payload, callback }, { call, put }) {
      const reporteeQuery = {
        fromId: payload,
        type: 4,
      };
      const projection = {
        'manager.id': 1,
        'manager.user.id': 1,
        'manager.user.name': 1,
        'manager.user.abstract': 1,
        'member.id': 1,
        'member.user.id': 1,
        'member.user.name': 1,
        'member.user.abstract': 1,
      };
      const reportee = yield call(queryReportee, `aggregate=${
        encodeURIComponent(JSON.stringify({
          $where: reporteeQuery, $projection: projection }))}`);
      const reporterQuery = {
        toId: payload,
        type: 4,
      };
      const reporter = yield call(queryReporter, `aggregate=${
        encodeURIComponent(JSON.stringify({
          $where: reporterQuery, $projection: projection }))}`);
      // merge the groups.
      const groups = {};
      const reduce = (data, from, to) => {
        data._items[0][from].forEach(item => {
          const { id, user } = item;
          if (!Object.prototype.hasOwnProperty.call(groups, id)) {
            groups[id] = { managers: [], members: [] };
          }
          groups[id][to].push(...user);
        });
      };
      reduce(reportee, 'manager', 'managers');
      reduce(reportee, 'member', 'members');
      reduce(reporter, 'manager', 'managers');
      reduce(reporter, 'member', 'members');
      setGroup(groups);
      /* eslint-enable no-param-reassign,prefer-destructuring */
      if (callback) {
        callback(groups);
      } else {
        yield put({
          type: 'queryGroup',
          payload: groups,
        });
      }
    },
  },

  reducers: {
    /**
     * Saves the results to list.
     *
     * @return state/list
     */
    queryList(state, action) {
      console.log('%d users are fetched', action.payload._items.length);
      return {
        ...state,
        list: action.payload._items,
        meta: Object.prototype.hasOwnProperty.call(action.payload, '_meta')
          ? action.payload._meta
          : null,
        links: Object.prototype.hasOwnProperty.call(action.payload, '_links')
          ? action.payload._links
          : null,
      };
    },
    /**
     * Saves the result to item.
     *
     * @return state/item
     */
    queryItem(state, action) {
      return {
        ...state,
        item: Object.prototype.hasOwnProperty.call(action.payload, '_items') &&
        action.payload._items.length > 0
          ? action.payload._items[0]
          : action.payload,
      };
    },
    save(state, action) {
      return {
        ...state,
        list: action.payload,
      };
    },
    saveCurrentUser(state, action) {
      return {
        ...state,
        currentUser: action.payload,
      };
    },
    changeNotifyCount(state, action) {
      return {
        ...state,
        currentUser: {
          ...state.currentUser,
          notifyCount: action.payload,
        },
      };
    },
    queryGroup(state, action) {
      return {
        ...state,
        group: action.payload,
      };
    },
  },
};

this code work:

return props.error ? 'border-bottom: 1px solid ' + color.red : 'border-bottom: 1px solid rgba(0, 0, 0, 0.12)'

this code falls with Maximum call stack size exceeded:

return props.error ? `border-bottom: 1px solid ${color.red}`: `border-bottom: 1px solid rgba(0, 0, 0, 0.12)`;

different single quotes

Was this page helpful?
0 / 5 - 0 ratings