-
Notifications
You must be signed in to change notification settings - Fork 289
/
Helpers.fs
760 lines (610 loc) · 32.2 KB
/
Helpers.fs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
// Copyright 2011-2015, Tomas Petricek (http://tomasp.net), Gustavo Guerra (http://functionalflow.co.uk), and other contributors
// Licensed under the Apache License, Version 2.0, see LICENSE.md in this project
//
// Helpers for writing type providers
namespace ProviderImplementation
open System
open System.Collections.Generic
open System.Reflection
open System.Text
open System.Runtime.CompilerServices
open FSharp.Core.CompilerServices
open FSharp.Quotations
open FSharp.Data.Runtime
open FSharp.Data.Runtime.IO
open FSharp.Data.Runtime.StructuralTypes
open FSharp.Data.Runtime.StructuralInference
open ProviderImplementation
open ProviderImplementation.ProvidedTypes
// ----------------------------------------------------------------------------------------------
[<AutoOpen>]
module internal PrimitiveInferedValueExtensions =
type PrimitiveInferedValue with
member x.TypeWithMeasure =
match x.UnitOfMeasure with
| None -> x.RuntimeType
| Some unit ->
if supportsUnitsOfMeasure x.RuntimeType then
ProvidedMeasureBuilder.AnnotateType(x.RuntimeType, [ unit ])
else
failwithf "Units of measure not supported by type %s" x.RuntimeType.Name
// ----------------------------------------------------------------------------------------------
[<AutoOpen>]
module internal ActivePatterns =
/// Helper active pattern that can be used when constructing InvokeCode
/// (to avoid writing pattern matching or incomplete matches):
///
/// p.InvokeCode <- fun (Singleton self) -> <@ 1 + 2 @>
///
let (|Singleton|) =
function
| [ l ] -> l
| _ -> failwith "Parameter mismatch"
/// Takes a map and succeeds if it is empty
let (|EmptyMap|_|) result (map: Map<_, _>) =
if map.IsEmpty then Some result else None
/// Takes a map and succeeds if it contains exactly one value
let (|SingletonMap|_|) (map: Map<_, _>) =
if map.Count <> 1 then
None
else
let (KeyValue (k, v)) = Seq.head map
Some(k, v)
// ----------------------------------------------------------------------------------------------
module internal ReflectionHelpers =
open FSharp.Quotations
open UncheckedQuotations
let makeDelegate (exprfunc: Expr -> Expr) argType =
let var = Var("t", argType)
let convBody = exprfunc (Expr.Var var)
Expr.NewDelegateUnchecked(typedefof<Func<_, _>>.MakeGenericType (argType, convBody.Type), [ var ], convBody)
// ----------------------------------------------------------------------------------------------
type DisposableTypeProviderForNamespaces(config, ?assemblyReplacementMap) as x =
inherit TypeProviderForNamespaces(config, ?assemblyReplacementMap = assemblyReplacementMap)
let lockObj = Object()
let disposeActions = ResizeArray()
static let mutable idCount = 0
let id = idCount
let filesToWatch = Dictionary()
do idCount <- idCount + 1
let dispose typeNameOpt =
lock lockObj (fun () ->
for i = disposeActions.Count - 1 downto 0 do
let disposeAction = disposeActions.[i]
let discard = disposeAction typeNameOpt
if discard then disposeActions.RemoveAt(i))
do
log (sprintf "Creating TypeProviderForNamespaces %O [%d]" x id)
x.Disposing.Add(fun _ ->
use _holder = logTime "DisposingEvent" (sprintf "%O [%d]" x id)
dispose None)
member _.Id = id
member _.SetFileToWatch(fullTypeName, path) =
lock filesToWatch (fun () -> filesToWatch.[fullTypeName] <- path)
member _.GetFileToWath(fullTypeName) =
lock filesToWatch (fun () ->
match filesToWatch.TryGetValue(fullTypeName) with
| true, path -> Some path
| _ -> None)
member _.AddDisposeAction action =
lock lockObj (fun () -> disposeActions.Add action)
member _.InvalidateOneType typeName =
(use _holder = logTime "InvalidateOneType" (sprintf "%s in %O [%d]" typeName x id)
dispose (Some typeName)
log (sprintf "Calling invalidate for %O [%d]" x id))
base.Invalidate()
#if LOGGING_ENABLED
override x.Finalize() = log (sprintf "Finalize %O [%d]" x id)
#endif
// ----------------------------------------------------------------------------------------------
module internal ProviderHelpers =
open System.IO
open FSharp.Data.Runtime.Caching
let unitsOfMeasureProvider =
{ new StructuralInference.IUnitsOfMeasureProvider with
member x.SI(str) = ProvidedMeasureBuilder.SI str
member x.Product(measure1, measure2) =
ProvidedMeasureBuilder.Product(measure1, measure2)
member x.Inverse(denominator) : Type =
ProvidedMeasureBuilder.Inverse(denominator) }
let asyncMap (resultType: Type) (valueAsync: Expr<Async<'T>>) (body: Expr<'T> -> Expr) =
let (?) = QuotationBuilder.(?)
let convFunc = ReflectionHelpers.makeDelegate (Expr.Cast >> body) typeof<'T>
let f = Var("f", convFunc.Type)
let body =
typeof<TextRuntime>?(nameof (TextRuntime.AsyncMap)) (typeof<'T>, resultType) (valueAsync, Expr.Var f)
Expr.Let(f, convFunc, body)
let some (typ: Type) arg =
let unionType = typedefof<option<_>>.MakeGenericType typ
let meth = unionType.GetMethod("Some")
Expr.Call(meth, [ arg ])
let private cacheDuration = TimeSpan.FromMinutes 30.0
let private invalidChars =
[ for c in "\"|<>{}[]," -> c ]
@ [ for i in 0..31 -> char i ]
|> set
let private webUrisCache = createInternetFileCache "DesignTimeURIs" cacheDuration
// part of the information needed by generateType
type TypeProviderSpec<'RuntimeValue> =
{
GeneratedType: ProvidedTypeDefinition //the generated type
//the representation type (what's returned from the constructors, may or may not be the same as Type)
RepresentationType: Type
// the constructor from a text reader to the representation
CreateFromTextReader: Expr<TextReader> -> Expr
CreateListFromTextReader: (Expr<TextReader> -> Expr) option
// the constructor from a text reader to an array of the representation
CreateFromTextReaderForSampleList: Expr<TextReader> -> Expr
/// Runtime representation of underlying data (e.g. JsonValue) * Mapper function
CreateFromValue: (Type * (Expr<'RuntimeValue> -> Expr)) option
}
type private ParseTextResult<'RuntimeValue> =
{ Spec: TypeProviderSpec<'RuntimeValue>
IsUri: bool
IsResource: bool }
let readResource (tp: DisposableTypeProviderForNamespaces, resourceName: string) =
match resourceName.Split(',') with
| [| asmName; name |] ->
let bindingCtxt = tp.TargetContext
match bindingCtxt.TryBindSimpleAssemblyNameToTarget(asmName.Trim()) with
| Choice1Of2 asm ->
use sr = new StreamReader(asm.GetManifestResourceStream(name.Trim()))
Some(sr.ReadToEnd())
| _ -> None
| _ -> None
/// <summary>
/// Reads a sample parameter for a type provider, detecting if it is a uri and fetching it if needed
/// </summary>
/// <remarks>
/// Samples from the web are cached for 30 minutes.
/// Samples from the filesystem are read using shared read, so it works when the file is locked by Excel or similar tools,
/// </remarks>
///
/// <param name="valueToBeParsedOrItsUri">the text which can be a sample or an uri for a sample</param>
/// <param name="parseFunc">receives the file/url extension (or "" if not applicable) and the text value </param>
/// <param name="formatName">the description of what is being parsed (for the error message)</param>
/// <param name="tp">the type provider</param>
/// <param name="cfg">the type provider config</param>
/// <param name="resource">when specified, we first try to treat read the sample from an embedded resource
/// (the value specified assembly and resource name e.g. "MyCompany.MyAssembly, some_resource.json")</param>
/// <param name="resolutionFolder">if the type provider allows to override the resolutionFolder pass it here</param>
/// <param name="encodingStr"></param>
/// <param name="fullTypeName"></param>
/// <param name="maxNumberOfRows"></param>
let private parseTextAtDesignTime
valueToBeParsedOrItsUri
parseFunc
formatName
(tp: DisposableTypeProviderForNamespaces)
(cfg: TypeProviderConfig)
encodingStr
resolutionFolder
resource
fullTypeName
maxNumberOfRows
=
use _holder = logTime "LoadingTextToBeParsed" valueToBeParsedOrItsUri
let tryGetResource () =
if resource = "" then None else readResource (tp, resource)
let tryGetUri str =
match Uri.TryCreate(str, UriKind.RelativeOrAbsolute) with
| false, _ -> None
| true, uri ->
if str.Trim() = ""
|| not uri.IsAbsoluteUri
&& Seq.exists invalidChars.Contains str then
None
else
Some uri
match tryGetResource () with
| Some res ->
{ Spec = parseFunc "" res
IsUri = false
IsResource = true }
| _ ->
match tryGetUri valueToBeParsedOrItsUri with
| None ->
try
{ Spec = parseFunc "" valueToBeParsedOrItsUri
IsUri = false
IsResource = false }
with e ->
failwithf
"The provided sample is neither a file, nor a well-formed %s: %s"
formatName
(e.ToString())
| Some uri ->
let resolver =
{ ResolutionType = DesignTime
DefaultResolutionFolder = cfg.ResolutionFolder
ResolutionFolder = resolutionFolder }
let readText () =
let reader, toWatch = asyncRead resolver formatName encodingStr uri
// Non need to register file watchers in fsc.exe and fsi.exe
if cfg.IsInvalidationSupported then
toWatch
|> Option.iter (fun path -> tp.SetFileToWatch(fullTypeName, path))
use reader = reader |> Async.RunSynchronously
match maxNumberOfRows with
| None -> reader.ReadToEnd()
| Some max ->
let sb = StringBuilder()
let mutable max = max
while max > 0 do
let line = reader.ReadLine()
if isNull line then
max <- 0
else
line |> sb.AppendLine |> ignore
max <- max - 1
sb.ToString()
try
let sample =
if isWeb uri then
let text =
match webUrisCache.TryRetrieve(uri.OriginalString) with
| Some text -> text
| None ->
let text = readText ()
webUrisCache.Set(uri.OriginalString, text)
text
text
else
readText ()
{ Spec = parseFunc (Path.GetExtension uri.OriginalString) sample
IsUri = true
IsResource = false }
with e ->
if not uri.IsAbsoluteUri then
// even if it's a valid uri, it could be sample text
try
{ Spec = parseFunc "" valueToBeParsedOrItsUri
IsUri = false
IsResource = false }
with _ ->
// if not, return the first exception
failwithf
"Cannot read sample %s from '%s': %s"
formatName
valueToBeParsedOrItsUri
(e.ToString())
else
failwithf
"Cannot read sample %s from '%s': %s"
formatName
valueToBeParsedOrItsUri
(e.ToString())
let private providedTypesCache = createInMemoryCache (TimeSpan.FromSeconds 30.0)
let private activeDisposeActions = HashSet<_>()
// Cache generated types for a short time, since VS invokes the TP multiple times
// Also cache temporarily during partial invalidation since the invalidation of one TP always causes invalidation of all TPs
let internal getOrCreateProvidedType
(cfg: TypeProviderConfig)
(tp: DisposableTypeProviderForNamespaces)
(fullTypeName: string)
f
=
use _holder =
logTime "GeneratingProvidedType" (sprintf "%s [%d]" fullTypeName tp.Id)
let fullKey =
(fullTypeName, cfg.RuntimeAssembly, cfg.ResolutionFolder, cfg.SystemRuntimeAssemblyVersion)
let setupDisposeAction providedType fileToWatch =
if activeDisposeActions.Add(fullTypeName, tp.Id) then
log "Setting up dispose action"
let watcher =
match fileToWatch with
| Some file ->
let name = sprintf "%s [%d]" fullTypeName tp.Id
// Hold a weak reference to the type provider instance. If the TP instance is leaked
// and not held strongly by anyone else, then don't hold it strongly here.
let tpref = WeakReference<_>(tp)
let invalidateAction () =
match tpref.TryGetTarget() with
| true, tp -> tp.InvalidateOneType(fullTypeName)
| _ -> ()
Some(watchForChanges file (name, invalidateAction))
| None -> None
// On disposal of one of the types, remove that type from the cache, and add all others to the cache
tp.AddDisposeAction(fun typeNameBeingDisposedOpt ->
// might be called more than once for each watcher, but the Dispose action is a NOP the second time
watcher
|> Option.iter (fun watcher -> watcher.Dispose())
match typeNameBeingDisposedOpt with
| Some typeNameBeingDisposed when fullTypeName = typeNameBeingDisposed ->
providedTypesCache.Remove(fullTypeName)
log (sprintf "Dropping dispose action for %s [%d]" fullTypeName tp.Id)
// for the case where a file used by two TPs, when the file changes
// there will be two invalidations: A and B
// when the dispose action is called with A, A is removed from the cache
// so we need to remove the dispose action so it will won't be added when disposed is called with B
true
| _ ->
log (sprintf "Caching %s [%d] for 5 minutes" fullTypeName tp.Id)
providedTypesCache.Set(fullTypeName, (providedType, fullKey, fileToWatch))
// for the case where a file used by two TPs, when the file changes
// there will be two invalidations: A and B
// when the dispose action is called with A, B is added to the cache
// so we need to keep the dispose action around so it will be called with B and the cache is removed
false)
match providedTypesCache.TryRetrieve(fullTypeName, true) with
| Some (providedType, fullKey2, watchedFile) when fullKey = fullKey2 ->
log "Retrieved from cache"
setupDisposeAction providedType watchedFile
providedType
| _ ->
let providedType = f ()
log "Caching for 5 minutes"
let fileToWatch = tp.GetFileToWath(fullTypeName)
providedTypesCache.Set(fullTypeName, (providedType, fullKey, fileToWatch))
setupDisposeAction providedType fileToWatch
providedType
type Source =
| Sample of string
| SampleList of string
| Schema of string
/// Creates all the constructors for a type provider: (Async)Parse, (Async)Load, (Async)GetSample(s), and default constructor
/// <param name="source">the sample/sample list/schema from which the types will be generated</param>
/// <param name="getSpec">receives the file/url extension (or "" if not applicable) and the text value of the sample or schema</param>
/// <param name="tp">the type provider</param>
/// <param name="cfg">the type provider config</param>
/// <param name="encodingStr">the encoding to be used when reading the sample or schema</param>
/// <param name="resolutionFolder -> if the type provider allows to override the resolutionFolder pass it here</param>
/// <param name="resource">when specified, we first try to treat read the sample from an embedded resource</param>
/// (the value specifies assembly and resource name e.g. "MyCompany.MyAssembly, some_resource.json")</param>
/// <param name="fullTypeName">the full name of the type provider, this will be used as the caching key</param>
/// <param name="maxNumberOfRows">the max number of rows to read from the sample or schema</param>
let generateType
formatName
source
getSpec
(tp: DisposableTypeProviderForNamespaces)
(cfg: TypeProviderConfig)
encodingStr
resolutionFolder
resource
fullTypeName
maxNumberOfRows
=
getOrCreateProvidedType cfg tp fullTypeName (fun () ->
let isRunningInFSI = cfg.IsHostedExecution
let defaultResolutionFolder = cfg.ResolutionFolder
let valueToBeParsedOrItsUri =
match source with
| Sample value -> value
| SampleList value -> value
| Schema value -> value
let parseResult =
parseTextAtDesignTime
valueToBeParsedOrItsUri
getSpec
formatName
tp
cfg
encodingStr
resolutionFolder
resource
fullTypeName
maxNumberOfRows
let spec = parseResult.Spec
let resultType = spec.RepresentationType
let resultTypeAsync = typedefof<Async<_>>.MakeGenericType (resultType)
use _holder = logTime "CommonTypeGeneration" valueToBeParsedOrItsUri
[ // Generate static Parse method
let args = [ ProvidedParameter("text", typeof<string>) ]
let m =
let parseCode (Singleton text: Expr list) =
<@ new StringReader(%%text) :> TextReader @>
|> spec.CreateFromTextReader
ProvidedMethod("Parse", args, resultType, isStatic = true, invokeCode = parseCode)
m.AddXmlDoc(sprintf "Parses the specified %s string" formatName)
yield m :> MemberInfo
match spec.CreateListFromTextReader with
| None -> ()
| Some listParser ->
let resultTypeList = resultType.MakeArrayType()
let args = [ ProvidedParameter("text", typeof<string>) ]
let parseListCode (Singleton text: Expr list) =
<@ new StringReader(%%text) :> TextReader @>
|> listParser
let m =
ProvidedMethod("ParseList", args, resultTypeList, isStatic = true, invokeCode = parseListCode)
m.AddXmlDoc(sprintf "Parses the specified %s string" formatName)
yield m :> _
// Generate static Load stream method
let args = [ ProvidedParameter("stream", typeof<Stream>) ]
let loadCode1 (Singleton stream: Expr list) =
<@ new StreamReader(%%stream: Stream) :> TextReader @>
|> spec.CreateFromTextReader
let m =
ProvidedMethod("Load", args, resultType, isStatic = true, invokeCode = loadCode1)
m.AddXmlDoc(sprintf "Loads %s from the specified stream" formatName)
yield m :> _
// Generate static Load reader method
let args = [ ProvidedParameter("reader", typeof<TextReader>) ]
let loadCode2 (Singleton reader: Expr list) =
let reader = reader |> Expr.Cast
reader |> spec.CreateFromTextReader
let m =
ProvidedMethod("Load", args, resultType, isStatic = true, invokeCode = loadCode2)
m.AddXmlDoc(sprintf "Loads %s from the specified reader" formatName)
yield m :> _
// Generate static Load uri method
let args = [ ProvidedParameter("uri", typeof<string>) ]
let loadCode3 (Singleton uri: Expr list) =
<@
Async.RunSynchronously(
asyncReadTextAtRuntime
isRunningInFSI
defaultResolutionFolder
resolutionFolder
formatName
encodingStr
%%uri
)
@>
|> spec.CreateFromTextReader
let m =
ProvidedMethod("Load", args, resultType, isStatic = true, invokeCode = loadCode3)
m.AddXmlDoc(sprintf "Loads %s from the specified uri" formatName)
yield m :> _
// Generate static AsyncLoad uri method
let args = [ ProvidedParameter("uri", typeof<string>) ]
let asyncLoadCode (Singleton uri: Expr list) =
let readerAsync =
<@
asyncReadTextAtRuntime
isRunningInFSI
defaultResolutionFolder
resolutionFolder
formatName
encodingStr
%%uri
@>
asyncMap resultType readerAsync spec.CreateFromTextReader
let m =
ProvidedMethod("AsyncLoad", args, resultTypeAsync, isStatic = true, invokeCode = asyncLoadCode)
m.AddXmlDoc(sprintf "Loads %s from the specified uri" formatName)
yield m :> _
// Generate static Load value method
match spec.CreateFromValue with
| None -> ()
| Some (valueType, valueMapper) ->
let args = [ ProvidedParameter("value", valueType) ]
let loadCode (Singleton value: Expr list) =
let value = value |> Expr.Cast
<@ %value @> |> valueMapper
let m =
ProvidedMethod("Load", args, resultType, isStatic = true, invokeCode = loadCode)
m.AddXmlDoc(sprintf "Loads %s from the specified value" formatName)
yield m :> _
if not parseResult.IsResource then
match source with
| SampleList _ ->
// the [][] case needs more work, and it's a weird scenario anyway, so we won't support it
if not resultType.IsArray then
let resultTypeArray = resultType.MakeArrayType()
let resultTypeArrayAsync = typedefof<Async<_>>.MakeGenericType (resultTypeArray)
// Generate static GetSamples method
let getSamplesCode _ =
if parseResult.IsUri then
<@
Async.RunSynchronously(
asyncReadTextAtRuntimeWithDesignTimeRules
defaultResolutionFolder
resolutionFolder
formatName
encodingStr
valueToBeParsedOrItsUri
)
@>
else
<@ new StringReader(valueToBeParsedOrItsUri) :> TextReader @>
|> spec.CreateFromTextReaderForSampleList
let m =
ProvidedMethod(
"GetSamples",
[],
resultTypeArray,
isStatic = true,
invokeCode = getSamplesCode
)
yield m :> _
if parseResult.IsUri then
// Generate static AsyncGetSamples method
let methCode _ =
let readerAsync =
<@
asyncReadTextAtRuntimeWithDesignTimeRules
defaultResolutionFolder
resolutionFolder
formatName
encodingStr
valueToBeParsedOrItsUri
@>
spec.CreateFromTextReaderForSampleList
|> asyncMap resultTypeArray readerAsync
let m =
ProvidedMethod(
"AsyncGetSamples",
[],
resultTypeArrayAsync,
isStatic = true,
invokeCode = methCode
)
yield m :> _
| Sample _ ->
let name = if resultType.IsArray then "GetSamples" else "GetSample"
let getSampleCode _ =
if parseResult.IsUri then
<@
Async.RunSynchronously(
asyncReadTextAtRuntimeWithDesignTimeRules
defaultResolutionFolder
resolutionFolder
formatName
encodingStr
valueToBeParsedOrItsUri
)
@>
else
<@ new StringReader(valueToBeParsedOrItsUri) :> TextReader @>
|> spec.CreateFromTextReader
// Generate static GetSample method
yield ProvidedMethod(name, [], resultType, isStatic = true, invokeCode = getSampleCode) :> _
if spec.GeneratedType :> Type = spec.RepresentationType then
// Generate default constructor
yield ProvidedConstructor([], invokeCode = getSampleCode) :> _
if parseResult.IsUri then
// Generate static AsyncGetSample method
let asyncGetSampleCode _ =
let readerAsync =
<@
asyncReadTextAtRuntimeWithDesignTimeRules
defaultResolutionFolder
resolutionFolder
formatName
encodingStr
valueToBeParsedOrItsUri
@>
asyncMap resultType readerAsync spec.CreateFromTextReader
let m =
ProvidedMethod(
"Async" + name,
[],
resultTypeAsync,
isStatic = true,
invokeCode = asyncGetSampleCode
)
yield m :> _
| Schema _ ->
let getSchemaCode _ =
if parseResult.IsUri then
<@
Async.RunSynchronously(
asyncReadTextAtRuntimeWithDesignTimeRules
defaultResolutionFolder
resolutionFolder
formatName
encodingStr
valueToBeParsedOrItsUri
)
@>
else
<@ new StringReader(valueToBeParsedOrItsUri) :> TextReader @>
|> spec.CreateFromTextReaderForSampleList // hack: this will actually parse the schema
// Generate static GetSchema method
yield
ProvidedMethod(
"GetSchema",
[],
typeof<System.Xml.Schema.XmlSchemaSet>,
isStatic = true,
invokeCode = getSchemaCode
)
:> _
]
|> spec.GeneratedType.AddMembers
spec.GeneratedType)
[<assembly: InternalsVisibleToAttribute("FSharp.Data.Tests, PublicKey=00240000048000001401000006020000002400005253413100080000010001000de370e30996d51c2da4ba3878423843e8553ff8cf95bd0171fe6785d20e2f73c8a54feb5bf55888115de98bdf0f8c0e26ee79e4c0f535201582628313859078ab3be84442114655340980fa0232281badaa21c1c2849c1925d0cfbc3dfa8d22b00ba9800a3d9a6c00c5daf7344e3286c3ed6c3e62d7705db32e2a35ffef84963b8ae0a3fa8a365b4020007d22127bc24783a65602e858680d88f36d4d3ff7567fcbece85143ea5945330eb74e53596d0ead1209c56eaf2c5adbb80a05d70e59ba06b50af250a3b87239dd88b60ed57263ede090ea195f093aac2216897669634235b638fdd47b78fe55c9e34389c2a7cac21250b79c49e3a6e2f78dd3de9487")>]
[<assembly: InternalsVisibleToAttribute("FSharp.Data.DesignTime.Tests, PublicKey=00240000048000001401000006020000002400005253413100080000010001000de370e30996d51c2da4ba3878423843e8553ff8cf95bd0171fe6785d20e2f73c8a54feb5bf55888115de98bdf0f8c0e26ee79e4c0f535201582628313859078ab3be84442114655340980fa0232281badaa21c1c2849c1925d0cfbc3dfa8d22b00ba9800a3d9a6c00c5daf7344e3286c3ed6c3e62d7705db32e2a35ffef84963b8ae0a3fa8a365b4020007d22127bc24783a65602e858680d88f36d4d3ff7567fcbece85143ea5945330eb74e53596d0ead1209c56eaf2c5adbb80a05d70e59ba06b50af250a3b87239dd88b60ed57263ede090ea195f093aac2216897669634235b638fdd47b78fe55c9e34389c2a7cac21250b79c49e3a6e2f78dd3de9487")>]
do ()