<commit_before>import React, {PureComponent} from 'react'

import {connect} from 'react-redux'
import _ from 'lodash'

import TimeMachine from 'src/ifql/components/TimeMachine'
import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts'
import {Suggestion, FlatBody} from 'src/types/ifql'
import {InputArg, Handlers, DeleteFuncNodeArgs, Func} from 'src/types/ifql'

import {bodyNodes} from 'src/ifql/helpers'
import {getSuggestions, getAST} from 'src/ifql/apis'
import * as argTypes from 'src/ifql/constants/argumentTypes'
import {ErrorHandling} from 'src/shared/decorators/errors'

interface Links {
  self: string
  suggestions: string
  ast: string
}

interface Props {
  links: Links
}

interface Body extends FlatBody {
  id: string
}

interface State {
  body: Body[]
  ast: object
  script: string
  suggestions: Suggestion[]
}

export const IFQLContext = React.createContext()

@ErrorHandling
export class IFQLPage extends PureComponent<Props, State> {
  constructor(props) {
    super(props)
    this.state = {
      body: [],
      ast: null,
      suggestions: [],
      script:
        'foo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nbar = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n',
    }
  }

  public async componentDidMount() {
    const {links} = this.props

    try {
      const suggestions = await getSuggestions(links.suggestions)
      this.setState({suggestions})
    } catch (error) {
      console.error('Could not get function suggestions: ', error)
    }

    this.getASTResponse(this.state.script)
  }

  public render() {
    const {suggestions, script} = this.state

    return (
      <IFQLContext.Provider value={this.handlers}>
        <KeyboardShortcuts onControlEnter={this.handleSubmitScript}>
          <div className="page hosts-list-page">
            <div className="page-header">
              <div className="page-header__container">
                <div className="page-header__left">
                  <h1 className="page-header__title">Time Machine</h1>
                </div>
              </div>
            </div>
            <div className="page-contents">
              <div className="container-fluid">
                <TimeMachine
                  script={script}
                  body={this.state.body}
                  suggestions={suggestions}
                  onSubmitScript={this.handleSubmitScript}
                  onChangeScript={this.handleChangeScript}
                />
              </div>
            </div>
          </div>
        </KeyboardShortcuts>
      </IFQLContext.Provider>
    )
  }

  private get handlers(): Handlers {
    return {
      onAddNode: this.handleAddNode,
      onChangeArg: this.handleChangeArg,
      onSubmitScript: this.handleSubmitScript,
      onChangeScript: this.handleChangeScript,
      onDeleteFuncNode: this.handleDeleteFuncNode,
      onGenerateScript: this.handleGenerateScript,
    }
  }

  private handleSubmitScript = () => {
    this.getASTResponse(this.state.script)
  }

  private handleGenerateScript = (): void => {
    this.getASTResponse(this.bodyToScript)
  }

  private handleChangeArg = ({
    key,
    value,
    generate,
    funcID,
    declarationID = '',
    bodyID,
  }: InputArg): void => {
    const body = this.state.body.map(b => {
      if (b.id !== bodyID) {
        return b
      }

      if (declarationID) {
        const declarations = b.declarations.map(d => {
          if (d.id !== declarationID) {
            return d
          }

          const functions = this.editFuncArgs({
            funcs: d.funcs,
            funcID,
            key,
            value,
          })

          return {...d, funcs: functions}
        })

        return {...b, declarations}
      }

      const funcs = this.editFuncArgs({
        funcs: b.funcs,
        funcID,
        key,
        value,
      })

      return {...b, funcs}
    })

    this.setState({body}, () => {
      if (generate) {
        this.handleGenerateScript()
      }
    })
  }

  private editFuncArgs = ({funcs, funcID, key, value}): Func[] => {
    return funcs.map(f => {
      if (f.id !== funcID) {
        return f
      }

      const args = f.args.map(a => {
        if (a.key === key) {
          return {...a, value}
        }

        return a
      })

      return {...f, args}
    })
  }

  private get bodyToScript(): string {
    return this.state.body.reduce((acc, b) => {
      if (b.declarations.length) {
        const declaration = _.get(b, 'declarations.0', false)
        if (!declaration) {
          return acc
        }

        return `${acc}${declaration.name} = ${this.funcsToScript(
          declaration.funcs
        )}\n\n`
      }

      return `${acc}${this.funcsToScript(b.funcs)}\n\n`
    }, '')
  }

  private funcsToScript(funcs): string {
    return funcs
      .map(func => `${func.name}(${this.argsToScript(func.args)})`)
      .join('\n\t|> ')
  }

  private argsToScript(args): string {
    const withValues = args.filter(arg => arg.value || arg.value === false)
<commit_msg>Fix not handling literal variable declarations<commit_after>import React, {PureComponent} from 'react'

import {connect} from 'react-redux'
import _ from 'lodash'

import TimeMachine from 'src/ifql/components/TimeMachine'
import KeyboardShortcuts from 'src/shared/components/KeyboardShortcuts'
import {Suggestion, FlatBody} from 'src/types/ifql'
import {InputArg, Handlers, DeleteFuncNodeArgs, Func} from 'src/types/ifql'

import {bodyNodes} from 'src/ifql/helpers'
import {getSuggestions, getAST} from 'src/ifql/apis'
import * as argTypes from 'src/ifql/constants/argumentTypes'
import {ErrorHandling} from 'src/shared/decorators/errors'

interface Links {
  self: string
  suggestions: string
  ast: string
}

interface Props {
  links: Links
}

interface Body extends FlatBody {
  id: string
}

interface State {
  body: Body[]
  ast: object
  script: string
  suggestions: Suggestion[]
}

export const IFQLContext = React.createContext()

@ErrorHandling
export class IFQLPage extends PureComponent<Props, State> {
  constructor(props) {
    super(props)
    this.state = {
      body: [],
      ast: null,
      suggestions: [],
      script:
        'foo = "baz"\n\nfoo = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\nbar = from(db: "telegraf")\n\t|> filter() \n\t|> range(start: -15m)\n\n',
    }
  }

  public async componentDidMount() {
    const {links} = this.props

    try {
      const suggestions = await getSuggestions(links.suggestions)
      this.setState({suggestions})
    } catch (error) {
      console.error('Could not get function suggestions: ', error)
    }

    this.getASTResponse(this.state.script)
  }

  public render() {
    const {suggestions, script} = this.state

    return (
      <IFQLContext.Provider value={this.handlers}>
        <KeyboardShortcuts onControlEnter={this.handleSubmitScript}>
          <div className="page hosts-list-page">
            <div className="page-header">
              <div className="page-header__container">
                <div className="page-header__left">
                  <h1 className="page-header__title">Time Machine</h1>
                </div>
              </div>
            </div>
            <div className="page-contents">
              <div className="container-fluid">
                <TimeMachine
                  script={script}
                  body={this.state.body}
                  suggestions={suggestions}
                  onSubmitScript={this.handleSubmitScript}
                  onChangeScript={this.handleChangeScript}
                />
              </div>
            </div>
          </div>
        </KeyboardShortcuts>
      </IFQLContext.Provider>
    )
  }

  private get handlers(): Handlers {
    return {
      onAddNode: this.handleAddNode,
      onChangeArg: this.handleChangeArg,
      onSubmitScript: this.handleSubmitScript,
      onChangeScript: this.handleChangeScript,
      onDeleteFuncNode: this.handleDeleteFuncNode,
      onGenerateScript: this.handleGenerateScript,
    }
  }

  private handleSubmitScript = () => {
    this.getASTResponse(this.state.script)
  }

  private handleGenerateScript = (): void => {
    this.getASTResponse(this.bodyToScript)
  }

  private handleChangeArg = ({
    key,
    value,
    generate,
    funcID,
    declarationID = '',
    bodyID,
  }: InputArg): void => {
    const body = this.state.body.map(b => {
      if (b.id !== bodyID) {
        return b
      }

      if (declarationID) {
        const declarations = b.declarations.map(d => {
          if (d.id !== declarationID) {
            return d
          }

          const functions = this.editFuncArgs({
            funcs: d.funcs,
            funcID,
            key,
            value,
          })

          return {...d, funcs: functions}
        })

        return {...b, declarations}
      }

      const funcs = this.editFuncArgs({
        funcs: b.funcs,
        funcID,
        key,
        value,
      })

      return {...b, funcs}
    })

    this.setState({body}, () => {
      if (generate) {
        this.handleGenerateScript()
      }
    })
  }

  private editFuncArgs = ({funcs, funcID, key, value}): Func[] => {
    return funcs.map(f => {
      if (f.id !== funcID) {
        return f
      }

      const args = f.args.map(a => {
        if (a.key === key) {
          return {...a, value}
        }

        return a
      })

      return {...f, args}
    })
  }

  private get bodyToScript(): string {
    return this.state.body.reduce((acc, b) => {
      if (b.declarations.length) {
        const declaration = _.get(b, 'declarations.0', false)
        if (!declaration) {
          return acc
        }

        if (!declaration.funcs) {
          return `${acc}${b.source}\n\n`
        }

        return `${acc}${declaration.name} = ${this.funcsToScript(
          declaration.funcs
        )}\n\n`
      }

      return `${acc}${this.funcsToScript(b.funcs)}\n\n`
    }, '')
  }

  private funcsToScript(funcs): string {
    return funcs
      .map(func => `${func.name}(${this.argsToScript(func.args)})`)
      .join('\n\t|> ')
  }

  private argsToScript(args): string {
    const withValues = args.filter(arg => arg.value || arg.value === false)

{'fraction_non_alphanumeric': 0.13213038416763678, 'fraction_numerical': 0.0013581684128831976, 'mean_word_length': 2.1458651205370765, 'pattern_counts': {'":': 0, '<': 43, '<?xml version=': 0, '>': 77, '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': '1669902', 'n_tokens_mistral': 3228, 'n_tokens_neox': 3131, 'n_words': 658}