static InlineCode WriteNodeProperties( CodeGenerationContext codeGenContext, List <NodeProperty> nodeProperties) { nodeProperties = nodeProperties.OrderBy(p => p.Name).ToList(); var alwaysWrittenProperties = nodeProperties.Where(p => p.Conditional == null).ToList(); var conditionalProperties = nodeProperties.Where(p => p.Conditional != null).ToList(); IEnumerable <AnyExpression> renderNode() { var sortedProperties = alwaysWrittenProperties.Concat(conditionalProperties).ToArray(); // tricky code ahead. If there are always written props, we optimise by simply always writing the separator // except for the first. // If not, we generate the tracking var. if (alwaysWrittenProperties.Any()) { for (var index = 0; index < sortedProperties.Length; index++) { yield return(sortedProperties[index].ToCode(index == 0 ? null : new InlineCode(codeGenContext.JsonWriter.WriteValueSeparator()))); } } else { var propAlreadyWritten = New.Var <bool>("propAlreadyWritten"); yield return(propAlreadyWritten); yield return(propAlreadyWritten.Assign(false)); var separator = new InlineCode( If.ThenElse( propAlreadyWritten.EqualTo(true), Expression.Block(codeGenContext.JsonWriter.WriteValueSeparator()), propAlreadyWritten.Assign(true)) ); foreach (var nodeProp in sortedProperties) { yield return(nodeProp.ToCode(separator)); } } } return(new InlineCode(renderNode())); }
static IEnumerable <AnyExpression> RendererBlock(CompilerContext compilerContext) { var resourceIn = New.Parameter <object>("resource"); var options = New.Parameter <SerializationContext>("options"); var stream = New.Parameter <Stream>("stream"); yield return(resourceIn); yield return(options); yield return(stream); var retVal = New.Var <Task>("retVal"); var resource = Expression.Variable(compilerContext.Resource.ResourceType, "typedResource"); yield return(resource); yield return(Expression.Assign(resource, Expression.Convert(resourceIn, compilerContext.Resource.ResourceType))); var jsonWriter = New.Var <JsonWriter>("jsonWriter"); var buffer = New.Var <ArraySegment <byte> >("buffer"); yield return(jsonWriter); yield return(buffer); yield return(Expression.Assign(jsonWriter, Expression.New(typeof(JsonWriter)))); var jsonFormatterResolver = New.Var <HydraJsonFormatterResolver>("resolver"); var assignResolver = jsonFormatterResolver.Assign(New.Instance <HydraJsonFormatterResolver>()); yield return(jsonFormatterResolver); yield return(assignResolver); var codeGenContext = new CodeGenerationContext(jsonWriter, resource, options, jsonFormatterResolver); yield return(CodeGenerator.ResourceDocument(compilerContext, codeGenContext)); yield return(Expression.Assign(buffer, jsonWriter.GetBuffer())); yield return(Expression.Assign(retVal, stream.WriteAsync(buffer))); yield return(retVal); }
static NodeProperty WriteNodeLink( CodeGenerationContext codeGenContext, string linkRelationship, Uri linkUri, TypedExpression <string> resourceUri, ResourceLinkModel link) { var jsonWriter = codeGenContext.JsonWriter; IEnumerable <AnyExpression> getNodeLink() { yield return(jsonWriter.WritePropertyName(linkRelationship)); yield return(jsonWriter.WriteBeginObject()); yield return(jsonWriter.WriteRaw(Nodes.IdProperty)); var uriCombinationMethodInfo = link.CombinationType == ResourceLinkCombination.SubResource ? Reflection.HydraTextExtensions.UriSubResourceCombine : Reflection.HydraTextExtensions.UriStandardCombine; var uriCombine = new MethodCall <string>(Expression.Call( uriCombinationMethodInfo, resourceUri, Expression.Constant(linkUri, typeof(Uri)))); yield return(jsonWriter.WriteString(uriCombine)); if (link.Type != null) { yield return(jsonWriter.WriteValueSeparator()); yield return(jsonWriter.WritePropertyName("@type")); yield return(jsonWriter.WriteString(link.Type)); } yield return(jsonWriter.WriteEndObject()); } return(new NodeProperty(linkRelationship) { Code = new InlineCode(getNodeLink()) }); }
public static CodeBlock ResourceDocument( CompilerContext compilerContext, CodeGenerationContext codeGenContext) { var contextUri = StringMethods.Concat(codeGenContext.BaseUri, New.Const(CompilerContext.ContextUri)); var rootNode = WriteNode( compilerContext, codeGenContext, new[] { WriteContext(codeGenContext.JsonWriter, contextUri) }); return(new CodeBlock( codeGenContext.JsonWriter.WriteBeginObject(), rootNode, codeGenContext.JsonWriter.WriteEndObject() )); }
static IEnumerable <NodeProperty> GetNodeProperties(CompilerContext compilerContext, CodeGenerationContext codeGenContext, TypedExpression <string> resourceUri) { var propNames = compilerContext.Resource .Hydra().ResourceProperties .Select(p => p.Name) .ToArray(); var generatedIdNode = propNames.All(name => name != "@id") && compilerContext.Resource.Uris.Any() ? new[] { WriteId(codeGenContext.JsonWriter, resourceUri) } : Enumerable.Empty <NodeProperty>(); var generatedTypeNode = propNames.Any(name => name == "@type") ? Enumerable.Empty <NodeProperty>() : new[] { compilerContext.Resource.Hydra().JsonLdTypeFunc != null ? WriteType(codeGenContext.JsonWriter, codeGenContext.TypeGenerator.Invoke(codeGenContext.ResourceInstance)) : WriteType(codeGenContext.JsonWriter, compilerContext.Resource.Hydra().JsonLdType) }; var linkNodes = compilerContext.Resource.Links .Select(link => WriteNodeLink(codeGenContext, link.Relationship, link.Uri, resourceUri, link)); var valueNodes = compilerContext.Resource.Hydra() .ResourceProperties .Where(resProperty => resProperty.IsValueNode) .Select(resProperty => CreateNodePropertyValue(codeGenContext, resProperty, codeGenContext.ResourceInstance)) .ToList(); var propNodes = compilerContext.Resource.Hydra() .ResourceProperties .Where(resProperty => !resProperty.IsValueNode) .Select(resProperty => CreateNodeProperty(compilerContext, codeGenContext, resProperty)) .ToList(); return(generatedIdNode.Concat(generatedTypeNode).Concat(propNodes).Concat(valueNodes).Concat(linkNodes).ToList()); }
static CodeBlock WriteNode( CompilerContext compilerContext, CodeGenerationContext codeGenContext, NodeProperty[] existingNodeProperties = null) { var resourceUri = codeGenContext.UriGenerator.Invoke(codeGenContext.ResourceInstance); var nodeProperties = new List <NodeProperty>(existingNodeProperties ?? Enumerable.Empty <NodeProperty>()); nodeProperties.AddRange( GetNodeProperties(compilerContext, codeGenContext, resourceUri)); IEnumerable <AnyExpression> render() { if (compilerContext.Resource.Hydra().Collection.IsCollection&& !compilerContext.Resource.Hydra().Collection.IsHydraCollectionType) { var collectionItemType = compilerContext.Resource.Hydra().Collection.ItemType; var hydraCollectionType = HydraTypes.Collection.MakeGenericType(collectionItemType); var collectionCtor = hydraCollectionType.GetConstructor(new[] { typeof(IEnumerable <>).MakeGenericType(collectionItemType), typeof(string) }); if (collectionCtor == null) { throw new InvalidOperationException( $"Could not generate new HydraCollection<{collectionItemType.Name}>(IEnumerable<{collectionItemType.Name}>, string>()"); } var collectionWrapper = Expression.Variable(hydraCollectionType, "hydraCollectionType"); yield return(collectionWrapper); var instantiateCollection = Expression.Assign( collectionWrapper, Expression.New(collectionCtor, codeGenContext.ResourceInstance, Expression.Constant(compilerContext.Resource.Hydra().Collection.ManagesRdfTypeName))); yield return(instantiateCollection); var hydraCollectionModel = compilerContext.MetaModel.GetResourceModel(hydraCollectionType); var hydraCollectionProperties = GetNodeProperties( compilerContext.Push(hydraCollectionModel), codeGenContext.Push(collectionWrapper), resourceUri).ToList(); var nodeTypeNode = nodeProperties.FirstOrDefault(x => x.Name == "@type"); if (nodeTypeNode != null && compilerContext.Resource.Hydra().Collection.IsFrameworkCollection) { nodeProperties.Clear(); nodeProperties.AddRange(hydraCollectionProperties); } else { hydraCollectionProperties.RemoveAll(n => n.Name == "@type"); nodeProperties.AddRange(hydraCollectionProperties); } } if (nodeProperties.Any()) { yield return(WriteNodeProperties(codeGenContext, nodeProperties)); } } return(new CodeBlock(render())); }
static NodeProperty CreateNodePropertyAsList( CompilerContext compilerContext, CodeGenerationContext codeGenContext, ResourceProperty property, List <(Type itemType, List <ResourceModel> models)> itemResourceRegistrations, ParameterExpression propertyValue,
static NodeProperty CreateNodeProperty( CompilerContext compilerContext, CodeGenerationContext codeGenContext, ResourceProperty property) { Expression resource = codeGenContext.ResourceInstance; if (codeGenContext.ResourceInstance != resource) { throw new InvalidOperationException("yo backtrack"); } var pi = property.Member; // var propertyValue; Debug.Assert(pi.DeclaringType != null, "pi.DeclaringType != null"); var propertyValue = Expression.Variable(pi.PropertyType, $"val{pi.DeclaringType.Name}{pi.Name}"); // propertyValue = resource.Property; var propertyValueAssignment = Expression.Assign(propertyValue, Expression.MakeMemberAccess(resource, pi)); var preamble = new InlineCode(new Expression[] { propertyValue, propertyValueAssignment }); if (compilerContext.MetaModel.TryGetResourceModel(pi.PropertyType, out var propertyResourceModel)) { var jsonPropertyName = property.Name; return(new NodeProperty(jsonPropertyName) { Preamble = preamble, Code = new InlineCode(new[] { codeGenContext.JsonWriter.WritePropertyName(jsonPropertyName), codeGenContext.JsonWriter.WriteBeginObject(), WriteNode( compilerContext.Push(propertyResourceModel), codeGenContext.Push(propertyValue)), codeGenContext.JsonWriter.WriteEndObject() }), Conditional = Expression.NotEqual(propertyValue, Expression.Default(pi.PropertyType)) }); } var itemTypes = (from i in pi.PropertyType.GetInterfaces() .Concat(pi.PropertyType.IsInterface ? new[] { pi.PropertyType } : Array.Empty <Type>()) where i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable <>) let itemType = i.GetGenericArguments()[0] where itemType != typeof(object) select itemType).ToList(); // not an iri node itself, but is it a list of nodes? var itemResourceRegistrations = ( from itemType in itemTypes let resourceModels = compilerContext.MetaModel.ResourceRegistrations.Where(r => r.ResourceType != null && itemType.IsAssignableFrom(r.ResourceType)).ToList() where resourceModels.Any() orderby resourceModels.Count() descending select ( itemType, (from possible in resourceModels orderby possible.ResourceType.GetInheritanceDistance(itemType) select possible).ToList() )).ToList <(Type itemType, List <ResourceModel> models)>(); if (itemResourceRegistrations.Any()) { return(CreateNodePropertyAsList(compilerContext, codeGenContext, property, itemResourceRegistrations, propertyValue, preamble)); } // not a list of iri or blank nodes var propValue = CreateNodePropertyValue(codeGenContext, property, resource); propValue.Preamble = preamble; propValue.Conditional = Expression.NotEqual(propertyValue, Expression.Default(pi.PropertyType)); return(propValue); // it's a list of nodes }