<commit_before>'use strict'

const _ = require('lodash')

const Type = {
  NULL: 0,
  BOOLEAN: 1,
  NUMBER: 2,
  STRING: 3,
  ARRAY: 4,
  OBJECT: 5,
  UNKNOWN: 6
}

const decoderDefaults = {
  optional: false
}

// VOLATILE: path attribute should not be public
function jsonDecode (dataInput, decoderInput, path = '<data>') {
  const dataType = dataToType(dataInput)

  // VOLATILE: what if user has object with type as a key - { type: stuff }
  const isDecoderAsObject = _.isObject(decoderInput) && 'type' in decoderInput
  const decoderInputValue = isDecoderAsObject ? decoderInput.type : decoderInput
  const decoder = Object.assign(
    {},
    decoderDefaults,
    {
      value: decoderInputValue,
      type: decoderToType(decoderInputValue)
    }
  )

  if (dataType !== decoder.type) {
    return {
      error: {
        message: `Expected data type "${typeToString(decoder.type)}", got data type "${typeToString(dataType)}"`,
        path: path,
        code: 100
      },
      data: null
    }
  }

  switch (decoder.type) {
    case Type.NULL:
    case Type.BOOLEAN:
    case Type.NUMBER:
    case Type.STRING:
      break
    case Type.ARRAY:
      if (decoder.value.length === 0) {
        return {
          error: {
            message: `Decoder is specified as Array but type of its values is not specified`,
            path: path,
            code: 200
          },
          data: null
        }
      } else if (decoder.value.length >= 2) {
        // TODO: maybe this should not be error but implicit tuple decoding
        return {
          error: {
            message: `More than one type of Array values is specified`,
            path: path,
            code: 300
          },
          data: null
        }
      }

      const decoderArrayValue = decoder.value[0]
      const typeArrayDecoder = decoderToType(decoderArrayValue)
      switch (typeArrayDecoder) {
        case Type.NULL:
        case Type.BOOLEAN:
        case Type.NUMBER:
        case Type.STRING:
          for (let i = 0; i < dataInput.length; i++) {
            const arrayValue = dataInput[i]
            const res = jsonDecode(arrayValue, decoderArrayValue, path)
            if (res.error) {
              return res
            }
          }

          break
        case Type.ARRAY:
        case Type.OBJECT:
          for (const arrayValue of dataInput) {
            const res = jsonDecode(arrayValue, decoderArrayValue, path)
            if (res.error) {
              return res
            }
          }
          break
      }
      break
    case Type.OBJECT:
      if (Object.keys(decoder.value).length === 0) {
        return {
          error: {
            message: `Decoder is specified as Object there are no keys specified in the decoder.`,
            path: path,
            code: 400
          },
          data: null
        }
      }

      for (const decoderObjectKey in decoder.value) {
        if (!decoder.value.hasOwnProperty(decoderObjectKey)) break

        if (!(decoderObjectKey in dataInput)) {
          path += `.${decoderObjectKey}`
          return {
            error: {
              message: `Key "${decoderObjectKey}" is missing in the data ${dataInput}.`,
              path: path,
              code: 500
            },
            data: null
          }
        }

        const decoderObjectValue = decoder.value[decoderObjectKey]
        const objectValue = dataInput[decoderObjectKey]
        const res = jsonDecode(objectValue, decoderObjectValue, path)
        if (res.error) {
          return res
        }
      }
      break
    default:<commit_msg>cleanup names<commit_after>'use strict'

const _ = require('lodash')

const Type = {
  NULL: 0,
  BOOLEAN: 1,
  NUMBER: 2,
  STRING: 3,
  ARRAY: 4,
  OBJECT: 5,
  UNKNOWN: 6
}

const decoderDefaults = {
  optional: false
}

// VOLATILE: path attribute should not be public
function jsonDecode (dataInput, decoderInput, path = '<data>') {
  const dataInputType = dataToType(dataInput)

  // VOLATILE: what if user has object with type as a key - { type: stuff }
  const isDecoderAsObject = _.isObject(decoderInput) && 'type' in decoderInput
  const decoderInputValue = isDecoderAsObject ? decoderInput.type : decoderInput
  const decoder = Object.assign(
    {},
    decoderDefaults,
    {
      value: decoderInputValue,
      type: decoderToType(decoderInputValue)
    }
  )

  if (dataInputType !== decoder.type) {
    return {
      error: {
        message: `Expected data type "${typeToString(decoder.type)}", got data type "${typeToString(dataInputType)}"`,
        path: path,
        code: 100
      },
      data: null
    }
  }

  switch (decoder.type) {
    case Type.NULL:
    case Type.BOOLEAN:
    case Type.NUMBER:
    case Type.STRING:
      break
    case Type.ARRAY:
      if (decoder.value.length === 0) {
        return {
          error: {
            message: `Decoder is specified as Array but type of its values is not specified`,
            path: path,
            code: 200
          },
          data: null
        }
      } else if (decoder.value.length >= 2) {
        // TODO: maybe this should not be error but implicit tuple decoding
        return {
          error: {
            message: `More than one type of Array values is specified`,
            path: path,
            code: 300
          },
          data: null
        }
      }

      const arrayDecoder = decoder.value[0]
      const arrayDecoderType = decoderToType(arrayDecoder)
      switch (arrayDecoderType) {
        case Type.NULL:
        case Type.BOOLEAN:
        case Type.NUMBER:
        case Type.STRING:
          for (let i = 0; i < dataInput.length; i++) {
            const arrayValue = dataInput[i]
            const res = jsonDecode(arrayValue, arrayDecoder, path)
            if (res.error) {
              return res
            }
          }

          break
        case Type.ARRAY:
        case Type.OBJECT:
          for (const arrayValue of dataInput) {
            const res = jsonDecode(arrayValue, arrayDecoder, path)
            if (res.error) {
              return res
            }
          }
          break
      }
      break
    case Type.OBJECT:
      if (Object.keys(decoder.value).length === 0) {
        return {
          error: {
            message: `Decoder is specified as Object there are no keys specified in the decoder.`,
            path: path,
            code: 400
          },
          data: null
        }
      }

      for (const objectDecoderKey in decoder.value) {
        if (!decoder.value.hasOwnProperty(objectDecoderKey)) break

        if (!(objectDecoderKey in dataInput)) {
          path += `.${objectDecoderKey}`
          return {
            error: {
              message: `Key "${objectDecoderKey}" is missing in the data ${dataInput}.`,
              path: path,
              code: 500
            },
            data: null
          }
        }

        const objectDecoder = decoder.value[objectDecoderKey]
        const objectValue = dataInput[objectDecoderKey]
        const res = jsonDecode(objectValue, objectDecoder, path)
        if (res.error) {
          return res
        }
      }
      break
    default:
{'fraction_non_alphanumeric': 0.09395413481584433, 'fraction_numerical': 0.007505211952744961, 'mean_word_length': 1.7319665907365225, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 7, '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': '840228', 'n_tokens_mistral': 2094, 'n_tokens_neox': 1954, 'n_words': 588}