<commit_before>﻿// --------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation 2005-2012.
// This sample code is provided "as is" without warranty of any kind. 
// We disclaim all warranties, either express or implied, including the 
// warranties of merchantability and fitness for a particular purpose. 
//
// A simple F# portable parser for JSON data
// --------------------------------------------------------------------------------------

namespace FSharp.Data

open System
open System.IO
open System.Text
open System.Globalization
open FSharp.Data
open FSharp.Data.Runtime
open FSharp.Data.Runtime.HttpUtils
open FSharp.Data.Runtime.IO

/// Specifies the formatting behaviour of JSON values
[<RequireQualifiedAccess>]
[<Flags>]
type JsonSaveOptions = 
  /// Format (indent) the JsonValue
  | None              = 0b0000
  /// Print the JsonValue in one line in a compact way
  | DisableFormatting = 0b0001
  /// Prevent null Record attributes from appearing
  | RemoveNulls       = 0b0010
  /// Prevent JavaScript encoding
  | NoEncoding        = 0b0100

/// Represents a JSON value. Large numbers that do not fit in the 
/// Decimal type are represented using the Float case, while
/// smaller numbers are represented as decimals to avoid precision loss.
[<RequireQualifiedAccess>]
type JsonValue =
  | String of string
  | Number of decimal
  | Float of float 
  | Record of properties:(string * JsonValue)[]
  | Array of elements:JsonValue[]
  | Boolean of bool
  | Null

  override x.ToString() = x.ToString(JsonSaveOptions.None)

  member x.ToString saveOptions = 
    let saveOption flag = saveOptions &&& flag <> enum 0
    let noSaveOption = saveOption >> not
    let rec serialize (sb:StringBuilder) indentation json =
      let newLine plus =
        if noSaveOption JsonSaveOptions.DisableFormatting then
          sb.AppendLine() |> ignore
          System.String(' ', indentation + plus) |> sb.Append |> ignore
      match json with
      | Null -> sb.Append "null"
      | Boolean b -> sb.Append(if b then "true" else "false")
      | Number number -> sb.Append(number.ToString(CultureInfo.InvariantCulture))
      | Float number -> sb.Append(number.ToString(CultureInfo.InvariantCulture))
      | String s ->
        if saveOption JsonSaveOptions.NoEncoding then
            sb.Append("\"").Append(s).Append("\"")
        else
            sb.Append("\"").Append(JavaScriptStringEncode s).Append("\"")
      | Record properties -> 
          let isNotFirst = ref false
          sb.Append "{"  |> ignore
          for k, v in properties do
            if v = JsonValue.Null && noSaveOption JsonSaveOptions.RemoveNulls then
                if !isNotFirst then sb.Append "," |> ignore else isNotFirst := true
                newLine 2
                if saveOption JsonSaveOptions.DisableFormatting then
                  sb.AppendFormat("\"{0}\":", k) |> ignore
                else
                  sb.AppendFormat("\"{0}\": ", k) |> ignore
                serialize sb (indentation + 2) v |> ignore
          newLine 0
          sb.Append "}"
      | Array elements -> 
          let isNotFirst = ref false
          sb.Append "[" |> ignore
          for element in elements do
            if !isNotFirst then sb.Append "," |> ignore else isNotFirst := true
            newLine 2
            serialize sb (indentation + 2) element |> ignore
          if elements.Length > 0 then 
            newLine 0
          sb.Append "]"

    (serialize (new StringBuilder()) 0 x).ToString()

/// [omit]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module JsonValue =

  /// Active Pattern to view a `JsonValue.Record of (string * JsonValue)[]` as a `JsonValue.Object of Map<string, JsonValue>` for<commit_msg>fix a silly logic error I introduced that was causing json to serialize incorrectly<commit_after>﻿// --------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation 2005-2012.
// This sample code is provided "as is" without warranty of any kind. 
// We disclaim all warranties, either express or implied, including the 
// warranties of merchantability and fitness for a particular purpose. 
//
// A simple F# portable parser for JSON data
// --------------------------------------------------------------------------------------

namespace FSharp.Data

open System
open System.IO
open System.Text
open System.Globalization
open FSharp.Data
open FSharp.Data.Runtime
open FSharp.Data.Runtime.HttpUtils
open FSharp.Data.Runtime.IO

/// Specifies the formatting behaviour of JSON values
[<RequireQualifiedAccess>]
[<Flags>]
type JsonSaveOptions = 
  /// Format (indent) the JsonValue
  | None              = 0b0000
  /// Print the JsonValue in one line in a compact way
  | DisableFormatting = 0b0001
  /// Prevent null Record attributes from appearing
  | RemoveNulls       = 0b0010
  /// Prevent JavaScript encoding
  | NoEncoding        = 0b0100

/// Represents a JSON value. Large numbers that do not fit in the 
/// Decimal type are represented using the Float case, while
/// smaller numbers are represented as decimals to avoid precision loss.
[<RequireQualifiedAccess>]
type JsonValue =
  | String of string
  | Number of decimal
  | Float of float 
  | Record of properties:(string * JsonValue)[]
  | Array of elements:JsonValue[]
  | Boolean of bool
  | Null

  override x.ToString() = x.ToString(JsonSaveOptions.None)

  member x.ToString saveOptions = 
    let saveOption flag = saveOptions &&& flag <> enum 0
    let noSaveOption = saveOption >> not
    let rec serialize (sb:StringBuilder) indentation json =
      let newLine plus =
        if noSaveOption JsonSaveOptions.DisableFormatting then
          sb.AppendLine() |> ignore
          System.String(' ', indentation + plus) |> sb.Append |> ignore
      match json with
      | Null -> sb.Append "null"
      | Boolean b -> sb.Append(if b then "true" else "false")
      | Number number -> sb.Append(number.ToString(CultureInfo.InvariantCulture))
      | Float number -> sb.Append(number.ToString(CultureInfo.InvariantCulture))
      | String s ->
        if saveOption JsonSaveOptions.NoEncoding then
            sb.Append("\"").Append(s).Append("\"")
        else
            sb.Append("\"").Append(JavaScriptStringEncode s).Append("\"")
      | Record properties -> 
          let isNotFirst = ref false
          sb.Append "{"  |> ignore
          for k, v in properties do
            if v <> JsonValue.Null || noSaveOption JsonSaveOptions.RemoveNulls then
                if !isNotFirst then sb.Append "," |> ignore else isNotFirst := true
                newLine 2
                if saveOption JsonSaveOptions.DisableFormatting then
                  sb.AppendFormat("\"{0}\":", k) |> ignore
                else
                  sb.AppendFormat("\"{0}\": ", k) |> ignore
            serialize sb (indentation + 2) v |> ignore
          newLine 0
          sb.Append "}"
      | Array elements -> 
          let isNotFirst = ref false
          sb.Append "[" |> ignore
          for element in elements do
            if !isNotFirst then sb.Append "," |> ignore else isNotFirst := true
            newLine 2
            serialize sb (indentation + 2) element |> ignore
          if elements.Length > 0 then 
            newLine 0
          sb.Append "]"

    (serialize (new StringBuilder()) 0 x).ToString()

/// [omit]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module JsonValue =

  /// Active Pattern to view a `JsonValue.Record of (string * JsonValue)[]` as a `JsonValue.Object of Map<string, JsonValue>` for
{'fraction_non_alphanumeric': 0.13858942719833744, 'fraction_numerical': 0.010131185868294583, 'mean_word_length': 2.158326497128794, 'pattern_counts': {'":': 4, '<': 16, '<?xml version=': 0, '>': 58, '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': '7111242', 'n_tokens_mistral': 2062, 'n_tokens_neox': 1926, 'n_words': 686}