<commit_before>import state from './state';
import {
  __DEV__,
  timer,
  isString,
  isReactComponent,
  isReactPureComponent,
  isReactStatelessComponent,
  isReactComponentInstance,
  override,
  getComponentName,
} from './utils';

const connectWrapper = (Component, cursorPaths = ['']) => {
  if (Component.__noflux) {
    throw new SyntaxError(`You should not use @connect for component ${getComponentName(Component)} more than once, use @connect(path1, path2, ...) instead.`);
  }
  Component.__noflux = {};

  const cursors = cursorPaths.map(cursorPath => {
    if (!isString(cursorPath) && !Array.isArray(cursorPath)) {
      throw new TypeError('@connect(path1, path2, ...) every path must be String or Array.');
    }
    return state.cursor(cursorPath);
  });

  override(Component, 'componentDidMount', originComponentDidMount => function componentDidMount() {
    this.__noflux = {};
    const cursorChange = () => {
      if (__DEV__) {
        this.__noflux.timers = {
          startUpdate: timer.now(),
        };
      }
      this.forceUpdate(() => {
        if (__DEV__) {
          this.__noflux.timers.endUpdate = timer.now();
          const cost = this.__noflux.timers.endUpdate - this.__noflux.timers.startUpdate;
          // eslint-disable-next-line no-console
          console.log(`[noflux] ${getComponentName(Component)} rendering time ${cost.toFixed(3)} ms`);
        }
      });
    };

    this.__noflux.cursorChangeHandlers = cursors.map(cursor => cursor.on('change', cursorChange));
    if (originComponentDidMount) {
      originComponentDidMount.call(this);
    }
  });

  override(Component, 'componentWillUnmount', originComponentWillUnmount => function componentWillUnmount() {
    this.__noflux.cursorChangeHandlers.forEach(handler => handler());
    if (originComponentWillUnmount) {
      originComponentWillUnmount.call(this);
    }
  });

  return Component;
};

const verifyReactImpureComponent = (target, prop, descriptor) => {
  if (isReactComponentInstance(target) && prop && descriptor) {
    throw new SyntaxError('@connect should not be used for component method.');
  }
  if (isReactStatelessComponent(target)) {
    throw new TypeError('@connect should not be used for stateless component.');
  }
  if (isReactPureComponent(target)) {
    throw new TypeError('@connect should not be used for pure component.');
  }
  if (isReactComponent(target)) {
    return true;
  }
  return false;
};

const connectWithCursor = cursorPaths => (target, prop, descriptor) => {
  if (!target) {
    throw new TypeError('connect(path1, path2, ...)() is invalid, the param component must be given.');<commit_msg>skip change emitted after unmounting component<commit_after>import state from './state';
import {
  __DEV__,
  timer,
  isString,
  isReactComponent,
  isReactPureComponent,
  isReactStatelessComponent,
  isReactComponentInstance,
  override,
  getComponentName,
} from './utils';

const connectWrapper = (Component, cursorPaths = ['']) => {
  if (Component.__noflux) {
    throw new SyntaxError(`You should not use @connect for component ${getComponentName(Component)} more than once.`);
  }
  Component.__noflux = {};

  const cursors = cursorPaths.map(cursorPath => {
    if (!isString(cursorPath)) {
      throw new TypeError('@connect([path1, path2, ...]) every path must be String.');
    }
    return state.cursor(cursorPath);
  });

  override(Component, 'componentDidMount', originComponentDidMount => function componentDidMount() {
    this.__noflux = {};

    const cursorChange = () => {
      // skip change emitted after unmounting component
      // TODO: test this guard
      if (!this.__noflux.mounted) return;

      if (__DEV__) {
        this.__noflux.timers = {
          startUpdate: timer.now(),
        };
      }
      this.forceUpdate(() => {
        if (__DEV__) {
          this.__noflux.timers.endUpdate = timer.now();
          const cost = this.__noflux.timers.endUpdate - this.__noflux.timers.startUpdate;
          // eslint-disable-next-line no-console
          console.log(`[noflux] ${getComponentName(Component)} rendering time ${cost.toFixed(3)} ms`);
        }
      });
    };

    // register cursor change handlers
    this.__noflux.cursorChangeHandlers = cursors.map(cursor => cursor.on('change', cursorChange));

    // call origin componentDidMount
    if (originComponentDidMount) {
      originComponentDidMount.call(this);
    }

    // set component mounted flag
    this.__noflux.mounted = true;
  });

  override(Component, 'componentWillUnmount', originComponentWillUnmount => function componentWillUnmount() {
    // unregister cursor change handlers
    this.__noflux.cursorChangeHandlers.forEach(handler => handler());

    // call origin componentWillUnmount
    if (originComponentWillUnmount) {
      originComponentWillUnmount.call(this);
    }

    // reset component mounted flag
    this.__noflux.mounted = false;
  });

  return Component;
};

const verifyReactImpureComponent = (target, prop, descriptor) => {
  if (isReactComponentInstance(target) && prop && descriptor) {
    throw new SyntaxError('@connect should not be used for component method.');
  }
  if (isReactStatelessComponent(target)) {
    throw new TypeError('@connect should not be used for stateless component.');
  }
  if (isReactPureComponent(target)) {
    throw new TypeError('@connect should not be used for pure component.');
  }
  if (isReactComponent(target)) {
    return true;
  }
  return false;
};

const connectWithCursor = cursorPaths => (target, prop, descriptor) => {
  if (!target) {
    throw new TypeError('connect(...)() is invalid, the param component must be given.');
{'fraction_non_alphanumeric': 0.12689460697920338, 'fraction_numerical': 0.0017624250969333803, 'mean_word_length': 3.511128775834658, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1946973', 'n_tokens_mistral': 1655, 'n_tokens_neox': 1636, 'n_words': 389}