<commit_before>import React, { useEffect, useRef } from 'react'
import { connect as reduxConnect } from 'react-redux'

import { convertInputToLogic, convertPartialDynamicInput } from '../logic/index'
import { hasConnectWithKey } from '../logic/connect'
import { attachReducer } from '../store/reducer'

import { getCache } from '../cache'

import { mountPaths, unmountPaths } from './mount'

export function kea (input) {
  const globalPlugins = getCache().plugins
  const plugins = input.plugins && input.plugins.length > 0 ? [...globalPlugins, ...input.plugins] : [...globalPlugins]

  plugins.forEach(p => p.beforeKea && p.beforeKea(input))

  const mountDirectly = !input.key && !hasConnectWithKey(input.connect)
  const lazy = (input.options && input.options.lazy) || !mountDirectly || false

  const wrapper = (Klass) => {
    // make this.actions work if it's a React.Component we're operating with
    injectActionsIntoClass(Klass)

    const Connect = reduxConnect(
      mapStateToPropsCreator(input, plugins),
      mapDispatchToPropsCreator(input, plugins)
    )(Klass)

    // inject proptypes into the class if it's a React.Component
    // not using useRef here since we do it only once per component
    let injectPropTypes = !isStateless(Klass)

    return function Kea (props) {
      const logic = convertInputToLogic({ input, props, plugins })

      // inject proptypes to React.Component
      if (injectPropTypes && logic.propTypes) {
        injectPropTypes = false
        Klass.propTypes = Object.assign(Klass.propTypes || {}, logic.propTypes)
      }

      // mount paths only on first render
      const firstRender = useRef(true)
      if (firstRender.current) {
        firstRender.current = false

        // give access to the logic to the return value
        if (!mountDirectly) {
          Object.assign(wrapper, logic)
        }

        mountPaths(logic, plugins)
      }

      // unmount paths when component gets removed
      useEffect(() => () => unmountPaths(logic, plugins, lazy), [])

      // TODO: unmount & remount if path changed

      plugins.forEach(p => p.beforeRender && p.beforeRender(logic, props))

      return <Connect {...props} />
    }
  }

  // TODO: legacy names. remove/change them?
  wrapper._isKeaFunction = true
  wrapper._isKeaSingleton = mountDirectly

  if (input.key) {
    wrapper.withKey = keyOrCreator => {
      if (typeof keyOrCreator === 'function') {
        const withKey = props => {
          const logic = convertInputToLogic({ input, key: keyOrCreator(props), props, plugins })
          return Object.assign({}, wrapper, logic)
        }
        withKey._isKeaWithKey = true
        return withKey
      } else {
        const logic = convertInputToLogic({ input, key: keyOrCreator, plugins })
        return Object.assign({}, wrapper, logic)
      }
    }
  }

  if (mountDirectly) {
    const logic = convertInputToLogic({ input, plugins })

    // if we're in eager mode (!lazy), attach the reducer directly
    if (!lazy && logic.reducer && !logic.mounted) {
      attachReducer(logic.path, logic.reducer)
      logic.mounted = true
    }

    Object.assign(wrapper, logic)
  } else {
    Object.assign(wrapper, convertPartialDynamicInput({ input, plugins }))
  }

  return wrapper
}

export function connect (input) {
  return kea({ connect: input })
}
<commit_msg>redefine what it means to be lazy<commit_after>import React, { useEffect, useRef } from 'react'
import { connect as reduxConnect } from 'react-redux'

import { convertInputToLogic, convertPartialDynamicInput } from '../logic/index'
import { hasConnectWithKey } from '../logic/connect'
import { attachReducer } from '../store/reducer'

import { getCache } from '../cache'

import { mountPaths, unmountPaths } from './mount'

export function kea (input) {
  const globalPlugins = getCache().plugins
  const plugins = input.plugins && input.plugins.length > 0 ? [...globalPlugins, ...input.plugins] : [...globalPlugins]

  plugins.forEach(p => p.beforeKea && p.beforeKea(input))

  const lazy = (input.options && input.options.lazy) || !!input.key || hasConnectWithKey(input.connect) || false

  const wrapper = (Klass) => {
    // make this.actions work if it's a React.Component we're operating with
    injectActionsIntoClass(Klass)

    const Connect = reduxConnect(
      mapStateToPropsCreator(input, plugins),
      mapDispatchToPropsCreator(input, plugins)
    )(Klass)

    // inject proptypes into the class if it's a React.Component
    // not using useRef here since we do it only once per component
    let injectPropTypes = !isStateless(Klass)

    return function Kea (props) {
      const logic = convertInputToLogic({ input, props, plugins })

      // inject proptypes to React.Component
      if (injectPropTypes && logic.propTypes) {
        injectPropTypes = false
        Klass.propTypes = Object.assign(Klass.propTypes || {}, logic.propTypes)
      }

      // mount paths only on first render
      const firstRender = useRef(true)
      if (firstRender.current) {
        firstRender.current = false

        // give access to the logic to the return value
        if (lazy) {
          Object.assign(wrapper, logic)
        }

        mountPaths(logic, plugins)
      }

      // unmount paths when component gets removed
      useEffect(() => () => unmountPaths(logic, plugins, lazy), [])

      // TODO: unmount & remount if path changed

      plugins.forEach(p => p.beforeRender && p.beforeRender(logic, props))

      return <Connect {...props} />
    }
  }

  // TODO: legacy names. remove/change them?
  wrapper._isKeaFunction = true
  wrapper._isKeaSingleton = !lazy

  if (input.key) {
    wrapper.withKey = keyOrCreator => {
      if (typeof keyOrCreator === 'function') {
        const withKey = props => {
          const logic = convertInputToLogic({ input, key: keyOrCreator(props), props, plugins })
          return Object.assign({}, wrapper, logic)
        }
        withKey._isKeaWithKey = true
        return withKey
      } else {
        const logic = convertInputToLogic({ input, key: keyOrCreator, plugins })
        return Object.assign({}, wrapper, logic)
      }
    }
  }

  if (!lazy) {
    const logic = convertInputToLogic({ input, plugins })

    // if we're in eager mode (!lazy), attach the reducer directly
    if (!lazy && logic.reducer && !logic.mounted) {
      attachReducer(logic.path, logic.reducer)
      logic.mounted = true
    }

    Object.assign(wrapper, logic)
  } else {
    Object.assign(wrapper, convertPartialDynamicInput({ input, plugins }))
  }

  return wrapper
}

export function connect (input) {
  return kea({ connect: input })
}

{'fraction_non_alphanumeric': 0.1168441577921104, 'fraction_numerical': 0.0002999850007499625, 'mean_word_length': 2.897136177673875, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 21, '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': '6110431', 'n_tokens_mistral': 1970, 'n_tokens_neox': 1904, 'n_words': 545}