internal static Metadata Make(MetadataLevel level, AccessRights rights) { var domain = rights?.Keys ?? RESTarConfig.Resources; var entityResources = domain .OfType <IEntityResource>() .Where(r => r.IsGlobal) .OrderBy(r => r.Name) .ToList(); var terminalResources = domain .OfType <ITerminalResource>() .ToList(); if (level == MetadataLevel.OnlyResources) { return new Metadata { CurrentAccessScope = new Dictionary <IResource, Method[]>(rights ?? AccessRights.Root), EntityResources = entityResources.ToArray(), TerminalResources = terminalResources.ToArray() } } ; var checkedTypes = new HashSet <Type>(); void parseType(Type type) { switch (type) { case var _ when type.IsEnum: checkedTypes.Add(type); break; case var _ when type.IsNullable(out var baseType): parseType(baseType); break; case var _ when type.ImplementsGenericInterface(typeof(IEnumerable <>), out var param) && param.Any(): if (param[0].ImplementsGenericInterface(typeof(IEnumerable <>))) { break; } parseType(param[0]); break; case var _ when type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair <,>): case var _ when IsPrimitive(type): case var _ when type == typeof(object): break; case var _ when checkedTypes.Add(type): type.GetFields(BindingFlags.Public | BindingFlags.Instance) .Where(p => !p.RESTarIgnored()) .Select(p => p.FieldType) .ForEach(parseType); type.GetDeclaredProperties().Values .Where(p => !p.Hidden) .Select(p => p.Type) .ForEach(parseType); break; } } var entityTypes = entityResources.Select(r => r.Type).ToList(); var terminalTypes = terminalResources.Select(r => r.Type).ToList(); entityTypes.ForEach(parseType); checkedTypes.ExceptWith(entityTypes); terminalTypes.ForEach(parseType); checkedTypes.ExceptWith(terminalTypes); return(new Metadata { CurrentAccessScope = new Dictionary <IResource, Method[]>(rights ?? AccessRights.Root), EntityResources = entityResources.ToArray(), TerminalResources = terminalResources.ToArray(), EntityResourceTypes = new ReadOnlyDictionary <Type, Member[]>(entityTypes.ToDictionary(t => t, type => type.GetDeclaredProperties().Values.Cast <Member>().ToArray())), PeripheralTypes = new ReadOnlyDictionary <Type, Member[]>(checkedTypes.ToDictionary(t => t, type => { var props = type.GetDeclaredProperties().Values; var fields = type.GetFields(BindingFlags.Public | BindingFlags.Instance) .Where(p => !p.RESTarIgnored()) .Select(f => new Field(f)); return props.Union <Member>(fields).ToArray(); })) }); }
/// <summary> /// Generates metadata according to a given metadata level /// </summary> public static Metadata Get(MetadataLevel level) => Make(level, null);