<commit_before>/* @flow */

import fs from 'fs'
import _ from 'lodash'

import type { Metadata } from '../metadata'
import type { ContextualizedChokidarFSEvent } from './chokidar_event'

export type PrepDeleteFolder = {type: 'PrepDeleteFolder', path: string, old: ?Metadata, ino: ?number}
export type PrepDeleteFile = {type: 'PrepDeleteFile', path: string, old: ?Metadata, ino: ?number}
export type PrepPutFolder = {type: 'PrepPutFolder', path: string, ino: number, stats: fs.Stats}
export type PrepUpdateFile = {type: 'PrepUpdateFile', path: string, ino: number, stats: fs.Stats, md5sum: string}
export type PrepAddFile = {type: 'PrepAddFile', path: string, ino: number, stats: fs.Stats, md5sum: string}
export type PrepMoveFile = {type: 'PrepMoveFile', path: string, old: Metadata, ino: number, stats: fs.Stats, md5sum: string}
export type PrepMoveFolder = {type: 'PrepMoveFolder', path: string, old: Metadata, ino: number, stats: fs.Stats}

export type PrepAction =
  | PrepDeleteFolder
  | PrepDeleteFile
  | PrepAddFile
  | PrepPutFolder
  | PrepUpdateFile
  | PrepMoveFile
  | PrepMoveFolder

// TODO: Introduce specific builders?
export const build = (type: string, path: string, opts?: {stats?: fs.Stats, md5sum?: string, old?: ?Metadata}): PrepAction => {
  const event: Object = _.assign({type, path}, opts)
  return event
}

export const maybeAddFile = (a: PrepAction): ?PrepAddFile => a.type === 'PrepAddFile' ? a : null
export const maybePutFolder = (a: PrepAction): ?PrepPutFolder => a.type === 'PrepPutFolder' ? a : null
export const maybeMoveFile = (a: PrepAction): ?PrepMoveFile => a.type === 'PrepMoveFile' ? a : null
export const maybeMoveFolder = (a: PrepAction): ?PrepMoveFolder => a.type === 'PrepMoveFolder' ? a : null
export const maybeDeleteFile = (a: PrepAction): ?PrepDeleteFile => a.type === 'PrepDeleteFile' ? a : null
export const maybeDeleteFolder = (a: PrepAction): ?PrepDeleteFolder => a.type === 'PrepDeleteFolder' ? a : null

export const find = <T>(actions: PrepAction[], maybeRightType: (PrepAction) => ?T, predicate: (T) => boolean, remove?: true): ?T => {
  for (let i = 0; i < actions.length; i++) {
    const anyAction = actions[i]
    const rightTypeAction: ?T = maybeRightType(anyAction)
    if (rightTypeAction != null && predicate(rightTypeAction)) {
      if (remove) actions.splice(i, 1)
      return rightTypeAction
    }
  }
}

// TODO: Find by maybeType & inode?
// TODO: Maybe split find and remove?
export const findAndRemove = <T>(actions: PrepAction[], maybeRightType: (PrepAction) => ?T, predicate: (T) => boolean): ?T => {
  return find(actions, maybeRightType, predicate, true)
}

export const isChildMove = (a: PrepAction, b: PrepAction) => {
  return a.type === 'PrepMoveFolder' &&
         (b.type === 'PrepMoveFolder' || b.type === 'PrepMoveFile') &&
        b.path.indexOf(a.path) === 0 &&
        a.old && b.old &&
        b.old.path.indexOf(a.old.path) === 0
}

const isDelete = (a: PrepAction): boolean => a.type === 'PrepDeleteFolder' || a.type === 'PrepDeleteFile'
const isAdd = (a: PrepAction): boolean => a.type === 'PrepPutFolder' || a.type === 'PrepAddFile'
const isMove = (a: PrepAction): boolean => a.type === 'PrepMoveFolder' || a.type === 'PrepMoveFile'

export const addPath = (a: PrepAction): ?string => isAdd(a) || isMove(a) ? a.path : null
// $FlowFixMe
export const delPath = (a: PrepAction): ?string => isDelete(a) ? a.path : isMove(a) ? a.old.path : null
export const childOf = (p1: ?string, p2: ?string): boolean => p1 != null && p2 != null && p2 !== p1 && p2.startsWith(p1)
export const lower = (p1: ?string, p2: ?string): boolean => p1 != null && p2 != null && p2 !== p1 && p1 < p2

export const isChildDelete = (a: PrepAction, b: PrepAction) => childOf(delPath(a), delPath(b))
export const isChildAdd = (a: PrepAction, b: PrepAction) => childOf(addPath(a), addPath(b))

// $FlowFixMe<commit_msg>local/prep_actions: mark predicates for flow<commit_after>/* @flow */

import fs from 'fs'
import _ from 'lodash'

import type { Metadata } from '../metadata'
import type { ContextualizedChokidarFSEvent } from './chokidar_event'

export type PrepDeleteFolder = {type: 'PrepDeleteFolder', path: string, old: ?Metadata, ino: ?number}
export type PrepDeleteFile = {type: 'PrepDeleteFile', path: string, old: ?Metadata, ino: ?number}
export type PrepPutFolder = {type: 'PrepPutFolder', path: string, ino: number, stats: fs.Stats}
export type PrepUpdateFile = {type: 'PrepUpdateFile', path: string, ino: number, stats: fs.Stats, md5sum: string}
export type PrepAddFile = {type: 'PrepAddFile', path: string, ino: number, stats: fs.Stats, md5sum: string}
export type PrepMoveFile = {type: 'PrepMoveFile', path: string, old: Metadata, ino: number, stats: fs.Stats, md5sum: string}
export type PrepMoveFolder = {type: 'PrepMoveFolder', path: string, old: Metadata, ino: number, stats: fs.Stats}

export type PrepAction =
  | PrepDeleteFolder
  | PrepDeleteFile
  | PrepAddFile
  | PrepPutFolder
  | PrepUpdateFile
  | PrepMoveFile
  | PrepMoveFolder

// TODO: Introduce specific builders?
export const build = (type: string, path: string, opts?: {stats?: fs.Stats, md5sum?: string, old?: ?Metadata}): PrepAction => {
  const event: Object = _.assign({type, path}, opts)
  return event
}

export const maybeAddFile = (a: PrepAction): ?PrepAddFile => a.type === 'PrepAddFile' ? a : null
export const maybePutFolder = (a: PrepAction): ?PrepPutFolder => a.type === 'PrepPutFolder' ? a : null
export const maybeMoveFile = (a: PrepAction): ?PrepMoveFile => a.type === 'PrepMoveFile' ? a : null
export const maybeMoveFolder = (a: PrepAction): ?PrepMoveFolder => a.type === 'PrepMoveFolder' ? a : null
export const maybeDeleteFile = (a: PrepAction): ?PrepDeleteFile => a.type === 'PrepDeleteFile' ? a : null
export const maybeDeleteFolder = (a: PrepAction): ?PrepDeleteFolder => a.type === 'PrepDeleteFolder' ? a : null

export const find = <T>(actions: PrepAction[], maybeRightType: (PrepAction) => ?T, predicate: (T) => boolean, remove?: true): ?T => {
  for (let i = 0; i < actions.length; i++) {
    const anyAction = actions[i]
    const rightTypeAction: ?T = maybeRightType(anyAction)
    if (rightTypeAction != null && predicate(rightTypeAction)) {
      if (remove) actions.splice(i, 1)
      return rightTypeAction
    }
  }
}

// TODO: Find by maybeType & inode?
// TODO: Maybe split find and remove?
export const findAndRemove = <T>(actions: PrepAction[], maybeRightType: (PrepAction) => ?T, predicate: (T) => boolean): ?T => {
  return find(actions, maybeRightType, predicate, true)
}

export const isChildMove = (a: PrepAction, b: PrepAction) => {
  return a.type === 'PrepMoveFolder' &&
         (b.type === 'PrepMoveFolder' || b.type === 'PrepMoveFile') &&
        b.path.indexOf(a.path) === 0 &&
        a.old && b.old &&
        b.old.path.indexOf(a.old.path) === 0
}

const isDelete = (a: PrepAction): boolean %checks => a.type === 'PrepDeleteFolder' || a.type === 'PrepDeleteFile'
const isAdd = (a: PrepAction): boolean %checks => a.type === 'PrepPutFolder' || a.type === 'PrepAddFile'
const isMove = (a: PrepAction): boolean %checks => a.type === 'PrepMoveFolder' || a.type === 'PrepMoveFile'

export const addPath = (a: PrepAction): ?string => isAdd(a) || isMove(a) ? a.path : null
export const delPath = (a: PrepAction): ?string => isDelete(a) ? a.path : isMove(a) ? a.old.path : null
export const childOf = (p1: ?string, p2: ?string): boolean => p1 != null && p2 != null && p2 !== p1 && p2.startsWith(p1)
export const lower = (p1: ?string, p2: ?string): boolean => p1 != null && p2 != null && p2 !== p1 && p1 < p2

export const isChildDelete = (a: PrepAction, b: PrepAction) => childOf(delPath(a), delPath(b))
export const isChildAdd = (a: PrepAction, b: PrepAction) => childOf(addPath(a), addPath(b))

// $FlowFixMe
{'fraction_non_alphanumeric': 0.16070742022299117, 'fraction_numerical': 0.006151480199923107, 'mean_word_length': 4.642805495300072, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 53, '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': '6584788', 'n_tokens_mistral': 2679, 'n_tokens_neox': 2528, 'n_words': 781}