<commit_before>package io.sphere

import cats.data.Validated.{Invalid, Valid}
import cats.data.{NonEmptyList, ValidatedNel}
import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.databind.JsonMappingException

import io.sphere.util.Logging
import org.json4s.{DefaultFormats, JsonInput, StringInput}
import org.json4s.JsonAST._
import org.json4s.ParserUtil.ParseException
import org.json4s.jackson.{compactJson, parseJson}

/** Provides functions for reading & writing JSON, via type classes JSON/JSONR/JSONW. */
package object json extends Logging {

  implicit val liftJsonFormats = DefaultFormats

  type JValidation[A] = ValidatedNel[JSONError, A]

  def parseJSON(json: JsonInput): JValidation[JValue] =
    try Valid(parseJson(json)) catch {
      case e: ParseException => jsonParseError(e.getMessage)
      case e: JsonMappingException => jsonParseError(e.getOriginalMessage)
      case e: JsonParseException => jsonParseError(e.getOriginalMessage)
    }

  def parseJSON(json: String): JValidation[JValue] =
    parseJSON(StringInput(json))

  def jsonParseError[A](msg: String): Invalid[NonEmptyList[JSONError]] =
    Invalid(NonEmptyList.of(JSONParseError(msg)))

  def fromJSON[A: FromJSON](json: JsonInput): JValidation[A] =
    parseJSON(json).andThen(fromJValue[A])

  def fromJSON[A: FromJSON](json: String): JValidation[A] =
    parseJSON(json).andThen(fromJValue[A])

  private val jNothingStr = "{}"

  def toJSON[A: ToJSON](a: A): String = toJValue(a) match {
    case JNothing => jNothingStr
    case jval => compactJson(jval)
  }

  /** Parses a JSON string into a type A.
   *  Throws a [[JSONException]] on failure.
   *
   * @param json The JSON string to parse.
   * @return An instance of type A. */
  def getFromJSON[A: FromJSON](json: JsonInput): A =
    getFromJValue[A](parseJson(json))

  def getFromJSON[A: FromJSON](json: String): A =
    getFromJSON(StringInput(json))

  def fromJValue[A](jval: JValue)(implicit json: FromJSON[A]): JValidation[A] =
    json.read(jval)

  def toJValue[A](a: A)(implicit json: ToJSON[A]): JValue =
    json.write(a)

  def getFromJValue[A: FromJSON](jval: JValue): A =
    fromJValue[A](jval) match {
      case Valid(a) => a
      case Invalid(errs) => throw new JSONException(errs.toList.mkString(", "))
    }

  /** Extracts a JSON value of type A from a named field of a JSON object.
    *
    * @param name The name of the field.
    * @param jObject The JObject from which to extract the field.
    * @return A success with a value of type A or a non-empty list of errors. */
  def field[A](
    name: String,
    default: Option[A] = None
  )(jObject: JObject)(implicit jsonr: FromJSON[A]): JValidation[A] = {
    val fields = jObject.obj
    fields
      .find(f => f._1 == name && f._2 != JNull && f._2 != JNothing)
      .map(f => jsonr.read(f._2).leftMap(
        errs => errs map {
          case JSONParseError(msg) => JSONFieldError(List(name), msg)
          case JSONFieldError(path, msg) => JSONFieldError(name :: path, msg)
        }))
      .orElse(default.map(Valid(_)))
      .orElse(jsonr.read(JNothing).fold(_ => None, x => Some(Valid(x)))) // orElse(jsonr.default)
      .getOrElse(Invalid(NonEmptyList(JSONFieldError(List(name), "Missing required value"), Nil)))
  }
}
<commit_msg>use NonEmptyList.one where possible<commit_after>package io.sphere

import cats.data.Validated.{Invalid, Valid}
import cats.data.{NonEmptyList, ValidatedNel}
import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.databind.JsonMappingException

import io.sphere.util.Logging
import org.json4s.{DefaultFormats, JsonInput, StringInput}
import org.json4s.JsonAST._
import org.json4s.ParserUtil.ParseException
import org.json4s.jackson.{compactJson, parseJson}

/** Provides functions for reading & writing JSON, via type classes JSON/JSONR/JSONW. */
package object json extends Logging {

  implicit val liftJsonFormats = DefaultFormats

  type JValidation[A] = ValidatedNel[JSONError, A]

  def parseJSON(json: JsonInput): JValidation[JValue] =
    try Valid(parseJson(json)) catch {
      case e: ParseException => jsonParseError(e.getMessage)
      case e: JsonMappingException => jsonParseError(e.getOriginalMessage)
      case e: JsonParseException => jsonParseError(e.getOriginalMessage)
    }

  def parseJSON(json: String): JValidation[JValue] =
    parseJSON(StringInput(json))

  def jsonParseError[A](msg: String): Invalid[NonEmptyList[JSONError]] =
    Invalid(NonEmptyList.one(JSONParseError(msg)))

  def fromJSON[A: FromJSON](json: JsonInput): JValidation[A] =
    parseJSON(json).andThen(fromJValue[A])

  def fromJSON[A: FromJSON](json: String): JValidation[A] =
    parseJSON(json).andThen(fromJValue[A])

  private val jNothingStr = "{}"

  def toJSON[A: ToJSON](a: A): String = toJValue(a) match {
    case JNothing => jNothingStr
    case jval => compactJson(jval)
  }

  /** Parses a JSON string into a type A.
   *  Throws a [[JSONException]] on failure.
   *
   * @param json The JSON string to parse.
   * @return An instance of type A. */
  def getFromJSON[A: FromJSON](json: JsonInput): A =
    getFromJValue[A](parseJson(json))

  def getFromJSON[A: FromJSON](json: String): A =
    getFromJSON(StringInput(json))

  def fromJValue[A](jval: JValue)(implicit json: FromJSON[A]): JValidation[A] =
    json.read(jval)

  def toJValue[A](a: A)(implicit json: ToJSON[A]): JValue =
    json.write(a)

  def getFromJValue[A: FromJSON](jval: JValue): A =
    fromJValue[A](jval) match {
      case Valid(a) => a
      case Invalid(errs) => throw new JSONException(errs.toList.mkString(", "))
    }

  /** Extracts a JSON value of type A from a named field of a JSON object.
    *
    * @param name The name of the field.
    * @param jObject The JObject from which to extract the field.
    * @return A success with a value of type A or a non-empty list of errors. */
  def field[A](
    name: String,
    default: Option[A] = None
  )(jObject: JObject)(implicit jsonr: FromJSON[A]): JValidation[A] = {
    val fields = jObject.obj
    fields
      .find(f => f._1 == name && f._2 != JNull && f._2 != JNothing)
      .map(f => jsonr.read(f._2).leftMap(
        errs => errs map {
          case JSONParseError(msg) => JSONFieldError(name :: Nil, msg)
          case JSONFieldError(path, msg) => JSONFieldError(name :: path, msg)
        }))
      .orElse(default.map(Valid(_)))
      .orElse(jsonr.read(JNothing).fold(_ => None, x => Some(Valid(x)))) // orElse(jsonr.default)
      .getOrElse(Invalid(NonEmptyList.one(JSONFieldError(name :: Nil, "Missing required value"))))
  }
}

{'fraction_non_alphanumeric': 0.129981884057971, 'fraction_numerical': 0.0024154589371980675, 'mean_word_length': 3.955123410620793, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, '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': '2972846', 'n_tokens_mistral': 2224, 'n_tokens_neox': 2150, 'n_words': 540}