<commit_before>﻿#if METADATAFORMAT
namespace FSharp.MetadataFormat
#else
namespace FSharp.Literate
#endif

// --------------------------------------------------------------------------------------
// Helpers for parallel processing
// --------------------------------------------------------------------------------------

open System
open System.Threading.Tasks

module internal Parallel = 
  /// Parallel for loop with local state
  let pfor (input:seq<'TSource>) (localInit:unit -> 'TLocal) 
           (body:'TSource -> ParallelLoopState -> 'TLocal -> 'TLocal) =
    Parallel.ForEach
      ( input, Func<'TLocal>(localInit), 
        Func<'TSource, ParallelLoopState, 'TLocal, 'TLocal>(body), 
        Action<'TLocal>(fun _ -> ()) ) |> ignore

// --------------------------------------------------------------------------------------
// Tools for calling razor engine
// --------------------------------------------------------------------------------------

open System
open System.IO
open System.Dynamic
open System.Collections.Generic
open System.Collections.Concurrent
open RazorEngine
open RazorEngine.Text
open RazorEngine.Templating
open RazorEngine.Configuration
open RazorEngine.Compilation.ReferenceResolver

type GetMemberBinderImpl (name) =
    inherit GetMemberBinder(name, false)
    let notImpl () = raise <| new NotImplementedException()
    override x.FallbackGetMember(v, sug) = notImpl()
    
type RazorRender(layoutRoots, namespaces, templateName:string, ?modeltype:System.Type, ?references : string list) =
  let templateName =
    if templateName.EndsWith(".cshtml") then
        templateName.Substring(0, templateName.Length - 7)
    else templateName
  let templateCache = new ConcurrentDictionary<string[] * string, ITemplateSource>()
  // Create resolver & set it to the global static field 
  let templateManager = 
    { new ITemplateManager with
        member x.GetKey (name, resolveType, context) = new NameOnlyTemplateKey(name, resolveType, context) :> ITemplateKey
        member x.AddDynamic (key, source) = failwith "dynamic templates are not supported!"
        member x.Resolve templateKey = 
            let name = templateKey.Name
            let key = Array.ofSeq layoutRoots, name
            templateCache.GetOrAdd (key, fun (layoutRoots, name) -> 
                let file = RazorRender.Resolve(layoutRoots, name + ".cshtml")
                new LoadedTemplateSource(File.ReadAllText(file), file) :> ITemplateSource) }

  // Configure templating engine
  let config = new TemplateServiceConfiguration()
  do config.EncodedStringFactory <- new RawStringFactory()
  do config.TemplateManager <- templateManager
  do
    match references with
    | Some r -> 
      config.ReferenceResolver <- 
        { new IReferenceResolver with 
            member x.GetReferences (_, _) =
                r |> List.toSeq |> Seq.map (CompilerReference.From) }
    | None -> ()

  do namespaces |> Seq.iter (config.Namespaces.Add >> ignore)
  do config.BaseTemplateType <- typedefof<DocPageTemplateBase<_>>
  do config.Debug <- true 
  let razorEngine = RazorEngineService.Create(config)

  let handleCompile source f =
    try
      f ()
    with <commit_msg>Use new RazorEngine features to fix https://github.com/tpetricek/FSharp.Formatting/issues/273 . There are some downsides when F# Formatting is used as a library in a long running application, but it is an improvement for now.<commit_after>﻿#if METADATAFORMAT
namespace FSharp.MetadataFormat
#else
namespace FSharp.Literate
#endif

// --------------------------------------------------------------------------------------
// Helpers for parallel processing
// --------------------------------------------------------------------------------------

open System
open System.Threading.Tasks

module internal Parallel = 
  /// Parallel for loop with local state
  let pfor (input:seq<'TSource>) (localInit:unit -> 'TLocal) 
           (body:'TSource -> ParallelLoopState -> 'TLocal -> 'TLocal) =
    Parallel.ForEach
      ( input, Func<'TLocal>(localInit), 
        Func<'TSource, ParallelLoopState, 'TLocal, 'TLocal>(body), 
        Action<'TLocal>(fun _ -> ()) ) |> ignore

// --------------------------------------------------------------------------------------
// Tools for calling razor engine
// --------------------------------------------------------------------------------------

open System
open System.IO
open System.Dynamic
open System.Collections.Generic
open System.Collections.Concurrent
open RazorEngine
open RazorEngine.Text
open RazorEngine.Templating
open RazorEngine.Configuration
open RazorEngine.Compilation.ReferenceResolver

type GetMemberBinderImpl (name) =
    inherit GetMemberBinder(name, false)
    let notImpl () = raise <| new NotImplementedException()
    override x.FallbackGetMember(v, sug) = notImpl()
    
type RazorRender(layoutRoots, namespaces, templateName:string, ?modeltype:System.Type, ?references : string list) =
  let templateName =
    if templateName.EndsWith(".cshtml") then
        templateName.Substring(0, templateName.Length - 7)
    else templateName
  let templateCache = new ConcurrentDictionary<string, ITemplateSource>()
  // Create resolver & set it to the global static field 
  let templateManager = 
    { new ITemplateManager with
        member x.GetKey (name, resolveType, context) = new NameOnlyTemplateKey(name, resolveType, context) :> ITemplateKey
        member x.AddDynamic (key, source) = failwith "dynamic templates are not supported!"
        member x.Resolve templateKey = 
            let name = templateKey.Name
            templateCache.GetOrAdd (name, fun name -> 
                let file = RazorRender.Resolve(layoutRoots, name + ".cshtml")
                new LoadedTemplateSource(File.ReadAllText(file), file) :> ITemplateSource) }

  // Configure templating engine
  let config = new TemplateServiceConfiguration()
  do
    config.EncodedStringFactory <- new RawStringFactory()
    config.TemplateManager <- templateManager
    // NOTE: this is good in the context of running F# Formatting via F# scripts,
    // however when using F# Formatting as library this hides a memory leak.
    // We cannot really know which case this is, so applications using this library
    // should make sure they are not in the default AppDomain.
    // And F# scripts on the other hand will not explode the temp directory.
    config.DisableTempFileLocking  <- System.AppDomain.CurrentDomain.IsDefaultAppDomain()
    config.Debug <- not config.DisableTempFileLocking
    config.CachingProvider <-
      new DefaultCachingProvider(
        if config.DisableTempFileLocking then
          new System.Action<string>(fun s -> ())
        else null) :> ICachingProvider
    
    match references with
    | Some r -> 
      config.ReferenceResolver <- 
        { new IReferenceResolver with 
            member x.GetReferences (_, _) =
                r |> List.toSeq |> Seq.map (CompilerReference.From) }
    | None -> ()

    namespaces |> Seq.iter (config.Namespaces.Add >> ignore)
    config.BaseTemplateType <- typedefof<DocPageTemplateBase<_>>

  let razorEngine = RazorEngineService.Create(config)

  let handleCompile source f =
    try
      f ()
    with 
{'fraction_non_alphanumeric': 0.1784675072744908, 'fraction_numerical': 0.0009699321047526673, 'mean_word_length': 2.2809090909090908, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 52, 'https://': 1, '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': '725385', 'n_tokens_mistral': 1863, 'n_tokens_neox': 1817, 'n_words': 532}