<commit_before>// debug output
let __DEBUG__
function debug (...args) {
  if (__DEBUG__) {
    if (!console.group) {
      args.unshift('%credux-undo', 'font-style: italic')
    }
    console.log(...args)
  }
}
function debugStart (action, state) {
  if (__DEBUG__) {
    const args = ['action', action.type]
    if (console.group) {
      args.unshift('%credux-undo', 'font-style: italic')
      console.groupCollapsed(...args)
      console.log('received', {state, action})
    } else {
      debug(...args)
    }
  }
}
function debugEnd () {
  if (__DEBUG__) {
    return console.groupEnd && console.groupEnd()
  }
}
// /debug output

// action types
export const ActionTypes = {
  UNDO: '@@redux-undo/UNDO',
  REDO: '@@redux-undo/REDO'
}
// /action types

// action creators to change the state
export const ActionCreators = {
  undo () {
    return { type: ActionTypes.UNDO }
  },
  redo () {
    return { type: ActionTypes.REDO }
  }
}
// /action creators

// length: get length of history
function length (history) {
  const { past, future } = history
  return past.length + 1 + future.length
}
// /length

// insert: insert `state` into history, which means adding the current state
//         into `past`, setting the new `state` as `present` and erasing
//         the `future`.
function insert (history, state, limit) {
  debug('insert', {state, history, free: limit - length(history)})

  const { past, present } = history
  const historyOverflow = limit && length(history) >= limit

  if (present === undefined) {
    // init history
    return {
      past: [],
      present: state,
      future: []
    }
  }

  return {
    past: [
      ...past.slice(historyOverflow ? 1 : 0),
      present
    ],
    present: state,
    future: []
  }
}
// /insert

// undo: go back to the previous point in history
function undo (history) {
  debug('undo', {history})

  const { past, present, future } = history

  if (past.length <= 0) return history

  return {
    past: past.slice(0, past.length - 1), // remove last element from past
    present: past[past.length - 1], // set element as new present
    future: [
      present, // old present state is in the future now
      ...future
    ]
  }
}
// /undo

// redo: go to the next point in history
function redo (history) {
  debug('redo', {history})

  const { past, present, future } = history

  if (future.length <= 0) return history

  return {
    future: future.slice(1, future.length), // remove element from future
    present: future[0], // set element as new present
    past: [
      ...past,
      present // old present state is in the past now
    ]
  }
}
// /redo

// wrapState: for backwards compatibility to 0.4
function wrapState (state) {
  return {
    ...state,
    history: state
  }
}
// /wrapState

// updateState
function updateState (state, history) {
  return wrapState({
    ...state,
    ...history
  })
}
// /updateState

// createHistory
function createHistory (state) {
  return {
    past: [],
    present: state,
    future: []
  }
}
// /createHistory

// parseActions
export function parseActions (rawActions, defaultValue = []) {
  if (Array.isArray(rawActions)) {
    return rawActions
  } else if (typeof rawActions === 'string') {
    return [rawActions]
  }
  return defaultValue
}
// /parseActions

// redux-undo higher order reducer
export default function undoable (reducer, rawConfig = {}) {
  __DEBUG__ = rawConfig.debug

  const config = {
    initialState: rawConfig.initialState,
    initTypes: parseActions(rawConfig.initTypes, ['@@redux/INIT', '@@INIT']),
    limit: rawConfig.limit,
    filter: rawConfig.filter || () => true,
    undoType: rawConfig.undoType || ActionTypes.UNDO,
    redoType: rawConfig.redoType || ActionTypes.REDO
  }
  config.history = rawConfig.initialHistory || createHistory(config.initialState)

  if (config.initTypes.length === 0) {
    console.warn('redux-undo: supply at least one action type in initTypes to ensure initial state')
  }

  return (state, action) => {
    debugStart(action, state)
    let res
    switch (action.type) {
      case config.undoType:
        res = undo(state)
        debug('after undo', res)
        debugEnd()
        return res ? updateState(state, res) : state

      case config.redoType:
        res = redo(state)
        debug('after redo', res)
        debugEnd()
        return res ? updateState(state, res) : state

      default:
        res = reducer(state && state.present, action)

        if (config.initTypes.some((actionType) => actionType === action.type)) {
          debug('reset history due to init action')
          debugEnd()
          return wrapState({
            ...state,
            ...createHistory(res)
          })
        }

        if (config.filter && typeof config.filter === 'function') {
          if (!config.filter(action, res, state && state.present)) {
            debug('filter prevented action, not storing it')
            debugEnd()
            return wrapState({
              ...state,
              present: res<commit_msg>Implemented jump to future or past with index. closes #13<commit_after>// debug output
let __DEBUG__
function debug (...args) {
  if (__DEBUG__) {
    if (!console.group) {
      args.unshift('%credux-undo', 'font-style: italic')
    }
    console.log(...args)
  }
}
function debugStart (action, state) {
  if (__DEBUG__) {
    const args = ['action', action.type]
    if (console.group) {
      args.unshift('%credux-undo', 'font-style: italic')
      console.groupCollapsed(...args)
      console.log('received', {state, action})
    } else {
      debug(...args)
    }
  }
}
function debugEnd () {
  if (__DEBUG__) {
    return console.groupEnd && console.groupEnd()
  }
}
// /debug output

// action types
export const ActionTypes = {
  UNDO: '@@redux-undo/UNDO',
  REDO: '@@redux-undo/REDO',
  JUMP_TO_FUTURE: '@@redux-undo/JUMP_TO_FUTURE',
  JUMP_TO_PAST: '@@redux-undo/JUMP_TO_PAST'
}
// /action types

// action creators to change the state
export const ActionCreators = {
  undo () {
    return { type: ActionTypes.UNDO }
  },
  redo () {
    return { type: ActionTypes.REDO }
  },
  jumpToFuture (index) {
    return { type: ActionTypes.JUMP_TO_FUTURE, index: index }
  },
  jumpToPast (index) {
    return { type: ActionTypes.JUMP_TO_PAST, index }
  }
}
// /action creators

// length: get length of history
function length (history) {
  const { past, future } = history
  return past.length + 1 + future.length
}
// /length

// insert: insert `state` into history, which means adding the current state
//         into `past`, setting the new `state` as `present` and erasing
//         the `future`.
function insert (history, state, limit) {
  debug('insert', {state, history, free: limit - length(history)})

  const { past, present } = history
  const historyOverflow = limit && length(history) >= limit

  if (present === undefined) {
    // init history
    return {
      past: [],
      present: state,
      future: []
    }
  }

  return {
    past: [
      ...past.slice(historyOverflow ? 1 : 0),
      present
    ],
    present: state,
    future: []
  }
}
// /insert

// undo: go back to the previous point in history
function undo (history) {
  debug('undo', {history})

  const { past, present, future } = history

  if (past.length <= 0) return history

  return {
    past: past.slice(0, past.length - 1), // remove last element from past
    present: past[past.length - 1], // set element as new present
    future: [
      present, // old present state is in the future now
      ...future
    ]
  }
}
// /undo

// redo: go to the next point in history
function redo (history) {
  debug('redo', {history})

  const { past, present, future } = history

  if (future.length <= 0) return history

  return {
    future: future.slice(1, future.length), // remove element from future
    present: future[0], // set element as new present
    past: [
      ...past,
      present // old present state is in the past now
    ]
  }
}
// /redo

// jumpToFuture: jump to requested index in future history
function jumpToFuture (history, index) {
  if (index === 0) return redo(history)

  const { past, present, future } = history

  return {
    future: future.slice(index + 1),
    present: future[index],
    past: past.concat([present])
              .concat(future.slice(0, index))
  }
}
// /jumpToFuture

// jumpToPast: jump to requested index in past history
function jumpToPast (history, index) {
  if (index === history.past.length - 1) return undo(history)

  const { past, present, future } = history

  return {
    future: past.slice(index + 1)
                .concat([present])
                .concat(future),
    present: past[index],
    past: past.slice(0, index)
  }
}
// /jumpToPast

// wrapState: for backwards compatibility to 0.4
function wrapState (state) {
  return {
    ...state,
    history: state
  }
}
// /wrapState

// updateState
function updateState (state, history) {
  return wrapState({
    ...state,
    ...history
  })
}
// /updateState

// createHistory
function createHistory (state) {
  return {
    past: [],
    present: state,
    future: []
  }
}
// /createHistory

// parseActions
export function parseActions (rawActions, defaultValue = []) {
  if (Array.isArray(rawActions)) {
    return rawActions
  } else if (typeof rawActions === 'string') {
    return [rawActions]
  }
  return defaultValue
}
// /parseActions

// redux-undo higher order reducer
export default function undoable (reducer, rawConfig = {}) {
  __DEBUG__ = rawConfig.debug

  const config = {
    initialState: rawConfig.initialState,
    initTypes: parseActions(rawConfig.initTypes, ['@@redux/INIT', '@@INIT']),
    limit: rawConfig.limit,
    filter: rawConfig.filter || () => true,
    undoType: rawConfig.undoType || ActionTypes.UNDO,
    redoType: rawConfig.redoType || ActionTypes.REDO,
    jumpToPastType: rawConfig.jumpToPastType || ActionTypes.JUMP_TO_PAST,
    jumpToFutureType: rawConfig.jumpToFutureType || ActionTypes.JUMP_TO_FUTURE
  }
  config.history = rawConfig.initialHistory || createHistory(config.initialState)

  if (config.initTypes.length === 0) {
    console.warn('redux-undo: supply at least one action type in initTypes to ensure initial state')
  }

  return (state, action) => {
    debugStart(action, state)
    let res
    switch (action.type) {
      case config.undoType:
        res = undo(state)
        debug('after undo', res)
        debugEnd()
        return res ? updateState(state, res) : state

      case config.redoType:
        res = redo(state)
        debug('after redo', res)
        debugEnd()
        return res ? updateState(state, res) : state

      case config.jumpToPastType:
        res = jumpToPast(state, action.index)
        debug('after jumpToPast', res)
        debugEnd()
        return res ? updateState(state, res) : state

      case config.jumpToFutureType:
        res = jumpToFuture(state, action.index)
        debug('after jumpToFuture', res)
        debugEnd()
        return res ? updateState(state, res) : state

      default:
        res = reducer(state && state.present, action)

        if (config.initTypes.some((actionType) => actionType === action.type)) {
          debug('reset history due to init action')
          debugEnd()
          return wrapState({
            ...state,
            ...createHistory(res)
          })
        }

        if (config.filter && typeof config.filter === 'function') {
          if (!config.filter(action, res, state && state.present)) {
            debug('filter prevented action, not storing it')
            debugEnd()
            return wrapState({
              ...state,
              present: res
{'fraction_non_alphanumeric': 0.13241072954040664, 'fraction_numerical': 0.0029044934221766614, 'mean_word_length': 2.5454270139309507, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 11, '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': '5779217', 'n_tokens_mistral': 3642, 'n_tokens_neox': 3516, 'n_words': 1009}