public void SectionMerge_6() { var conf1 = "r{ a{} c{}}".AsLaconicConfig(handling: ConvertErrorHandling.Throw); var conf2 = "r{ b{ z = 134 } c{name='id1' y=456} c{name='id2' z=789 } c{ gg=123}}".AsLaconicConfig(handling: ConvertErrorHandling.Throw); var rules = new NodeOverrideRules { AppendSectionsWithoutMatchAttr = true }; conf1.OverrideBy(conf2, rules); Aver.AreEqual(6, conf1.ChildCount); //<-- 6 because names are different, but 6th gets added due to rules Aver.IsTrue(conf1.Navigate("/a").Exists); Aver.IsTrue(conf1.Navigate("/b").Exists); Aver.IsTrue(conf1.Navigate("/c").Exists); Aver.IsTrue(conf1.Navigate("/c[name=id1]").Exists); Aver.IsTrue(conf1.Navigate("/c[name=id2]").Exists); Aver.IsTrue(conf1.Navigate("/c[gg=123]").Exists); Aver.IsTrue(conf1.Navigate("/b/$z").Exists); Aver.AreEqual(134, conf1.Navigate("/b/$z").ValueAsInt()); Aver.IsTrue(conf1.Navigate("/c[gg=123]/$gg").Exists); Aver.IsTrue(conf1.Navigate("/c[name=id1]/$y").Exists); Aver.IsTrue(conf1.Navigate("/c[name=id2]/$z").Exists); Aver.AreEqual(123, conf1.Navigate("/c[gg=123]/$gg").ValueAsInt()); Aver.AreEqual(456, conf1.Navigate("/c[name=id1]/$y").ValueAsInt()); Aver.AreEqual(789, conf1.Navigate("/c[name=id2]/$z").ValueAsInt()); }
public void SectionMerge_3() { var conf1 = "r{ a{} c{}}".AsLaconicConfig(handling: ConvertErrorHandling.Throw); var conf2 = "r{ b{ z = 134 } c{ y=456} c{z=789 }}".AsLaconicConfig(handling: ConvertErrorHandling.Throw); var rules = new NodeOverrideRules { AppendSectionsWithoutMatchAttr = true }; conf1.OverrideBy(conf2, rules); Aver.AreEqual(5, conf1.ChildCount);//<---- 5 because all "C" get appended Aver.IsTrue(conf1.Navigate("/a").Exists); Aver.IsTrue(conf1.Navigate("/b").Exists); Aver.IsTrue(conf1.Navigate("/c").Exists); Aver.IsTrue(conf1.Navigate("/b/$z").Exists); Aver.AreEqual(134, conf1.Navigate("/b/$z").ValueAsInt()); Aver.IsTrue(conf1.Navigate("/c[y=456]").Exists); Aver.IsTrue(conf1.Navigate("/c[z=789]").Exists); Aver.AreEqual(456, conf1.Navigate("/c[y=456]/$y").ValueAsInt()); Aver.AreEqual(789, conf1.Navigate("/c[z=789]/$z").ValueAsInt()); }
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { if (instance is ReleaseAttribute release) { var node = dataRoot.AddChildNode("release"); node.AddAttributeNode("type", release.Type); node.AddAttributeNode("utc", release.ReleaseTimestampUtc); node.AddAttributeNode("title", release.Title); if (release.Tags.IsNotNullOrWhiteSpace()) { node.AddAttributeNode("tags", release.Tags); } if (release.Description.IsNotNullOrWhiteSpace()) { node.AddAttributeNode("descr", release.Description); } if (context.DetailLevel > MetadataDetailLevel.Public) { if (release.Metadata.IsNotNullOrWhiteSpace()) { node.AddAttributeNode("meta", release.Metadata); } } } return(dataRoot); }
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { var tperm = member.NonNull(nameof(member)) as Type; if (tperm == null || !typeof(Permission).IsAssignableFrom(tperm)) { return(null); } var node = dataRoot.AddChildNode("permission"); MetadataUtils.AddMetadataTokenIdAttribute(node, tperm); if (instance is Permission perm) { node.AddAttributeNode("name", perm.Name); node.AddAttributeNode("path", perm.Path); node.AddAttributeNode("description", perm.Description); node.AddAttributeNode("level", perm.Level); } else { node.AddAttributeNode("name", tperm.Name.Replace("Permission", string.Empty)); node.AddAttributeNode("ns", tperm.Namespace); } return(dataRoot); }
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { if (member is Type tController && instance is ApiDocGenerator.ControllerContext apictx) { var apiAttr = tController.GetCustomAttribute <ApiControllerDocAttribute>(); if (apiAttr != null) { return(describe(tController, instance, apictx, dataRoot, overrideRules)); } } return(null); }
private ConfigSectionNode describe(Type tController, object instance, ApiDocGenerator.ControllerContext apictx, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules) { var cdata = dataRoot.AddChildNode("scope"); var cattr = apictx.ApiDocAttr; var docContent = tController.GetText(cattr.DocFile ?? "{0}.md".Args(tController.Name)); var ctlTitle = MarkdownUtils.GetTitle(docContent); var ctlDescription = MarkdownUtils.GetTitleDescription(docContent); (var drequest, var dresponse) = writeCommon(ctlTitle, ctlDescription, tController, apictx.Generator, cattr, cdata); cdata.AddAttributeNode("uri-base", cattr.BaseUri); cdata.AddAttributeNode("auth", cattr.Authentication); cdata.AddAttributeNode("doc-content", docContent); var allMethodContexts = apictx.Generator.GetApiMethods(tController, apictx.ApiDocAttr); foreach (var mctx in allMethodContexts) { var edata = cdata.AddChildNode("endpoint"); (var mrequest, var mresponse) = writeCommon(null, null, mctx.Method, apictx.Generator, mctx.ApiEndpointDocAttr, edata); var epuri = mctx.ApiEndpointDocAttr.Uri.AsString().Trim(); if (epuri.IsNullOrWhiteSpace()) { // infer from action attribute var action = mctx.Method.GetCustomAttributes <ActionBaseAttribute>().FirstOrDefault(); if (action != null) { epuri = action.Name; } if (epuri.IsNullOrWhiteSpace()) { epuri = mctx.Method.Name; } } if (!epuri.StartsWith("/")) { var bu = cattr.BaseUri.Trim(); if (!bu.EndsWith("/")) { bu += "/"; } epuri = bu + epuri; } edata.AddAttributeNode("uri", epuri); writeCollection(mctx.ApiEndpointDocAttr.Methods, "method", mrequest, ':'); //docAnchor var docAnchor = mctx.ApiEndpointDocAttr.DocAnchor.Default("### " + epuri); edata.AddAttributeNode("doc-content", MarkdownUtils.GetSectionContent(docContent, docAnchor)); //Get all method attributes except ApiDoc var epattrs = mctx.Method .GetCustomAttributes(true) .Where(a => !(a is ApiDocAttribute) && !(a is ActionBaseAttribute)); writeInstanceCollection(epattrs.Where(a => !(a is IInstanceCustomMetadataProvider) || (a is IInstanceCustomMetadataProvider cip && cip.ShouldProvideInstanceMetadata(apictx.Generator, edata))).ToArray(), TYPE_REF, edata, apictx.Generator); writeTypeCollection(epattrs.Select(a => a.GetType()) .Where(t => !apictx.Generator.IsWellKnownType(t)) .Distinct() .ToArray(), TYPE_REF, edata, apictx.Generator);//distinct attr types //todo Get app parameters look for Docs and register them and also permissions var epargs = mctx.Method.GetParameters() .Where(pi => !pi.IsOut && !pi.ParameterType.IsByRef && !apictx.Generator.IsWellKnownType(pi.ParameterType)) .Select(pi => pi.ParameterType).ToArray(); writeTypeCollection(epargs, TYPE_REF, edata, apictx.Generator); } return(cdata); }
private ConfigSectionNode describe(Type tController, object instance, ApiDocGenerator.ControllerContext apictx, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules) { var cdata = dataRoot.AddChildNode("scope"); var cattr = apictx.ApiDocAttr; var docContent = tController.GetText(cattr.DocFile ?? "{0}.md".Args(tController.Name)); var ctlTitle = MarkdownUtils.GetTitle(docContent); var ctlDescription = MarkdownUtils.GetTitleDescription(docContent); (var drequest, var dresponse) = writeCommon(ctlTitle, ctlDescription, tController, apictx.Generator, cattr, cdata); cdata.AddAttributeNode("uri-base", cattr.BaseUri); cdata.AddAttributeNode("auth", cattr.Authentication); cdata.AddAttributeNode("doc-content-tpl", docContent); var allMethodContexts = apictx.Generator.GetApiMethods(tController, apictx.ApiDocAttr); foreach (var mctx in allMethodContexts) { var edata = cdata.AddChildNode("endpoint"); (var mrequest, var mresponse) = writeCommon(null, null, mctx.Method, apictx.Generator, mctx.ApiEndpointDocAttr, edata); var epuri = mctx.ApiEndpointDocAttr.Uri.AsString().Trim(); if (epuri.IsNullOrWhiteSpace()) { // infer from action attribute var action = mctx.Method.GetCustomAttributes <ActionBaseAttribute>().FirstOrDefault(); if (action != null) { epuri = action.Name; } if (epuri.IsNullOrWhiteSpace()) { epuri = mctx.Method.Name; } } if (!epuri.StartsWith("/")) { var bu = cattr.BaseUri.Trim(); if (!bu.EndsWith("/")) { bu += "/"; } epuri = bu + epuri; } edata.AddAttributeNode("uri", epuri); writeCollection(mctx.ApiEndpointDocAttr.Methods, "method", mrequest, ':'); //Get all method attributes except ApiDoc var epattrs = mctx.Method .GetCustomAttributes(true) .Where(a => !(a is ApiDocAttribute) && !(a is ActionBaseAttribute) && !apictx.Generator.IgnoreTypePatterns.Any(ignore => a.GetType().FullName.MatchPattern(ignore)) ); writeInstanceCollection(epattrs.Where(a => !(a is IInstanceCustomMetadataProvider) || (a is IInstanceCustomMetadataProvider cip && cip.ShouldProvideInstanceMetadata(apictx.Generator, edata))).ToArray(), TYPE_REF, edata, apictx.Generator); writeTypeCollection(epattrs.Select(a => a.GetType()) .Where(t => !apictx.Generator.IsWellKnownType(t)) .Distinct() .ToArray(), TYPE_REF, edata, apictx.Generator);//distinct attr types //get method parameters var epargs = mctx.Method.GetParameters() .Where(pi => !pi.IsOut && !pi.ParameterType.IsByRef && !apictx.Generator.IsWellKnownType(pi.ParameterType) && !apictx.Generator.IgnoreTypePatterns.Any(ignore => pi.ParameterType.FullName.MatchPattern(ignore)) ) .Select(pi => pi.ParameterType).ToArray(); writeTypeCollection(epargs, TYPE_REF, edata, apictx.Generator); //docAnchor var docAnchor = mctx.ApiEndpointDocAttr.DocAnchor.Default("### " + epuri); var epDocContent = MarkdownUtils.GetSectionContent(docContent, docAnchor); edata.AddAttributeNode("doc-content-tpl", epDocContent); //finally regenerate doc content expanding all variables epDocContent = MarkdownUtils.EvaluateVariables(epDocContent, (v) => { if (v.IsNullOrWhiteSpace()) { return(v); } //Escape: ``{{a}}`` -> `{a}` if (v.StartsWith("{") && v.EndsWith("}")) { return(v.Substring(1, v.Length - 2)); } if (v.StartsWith("@")) { return($"`{{{v}}}`"); //do not expand TYPE spec here } //else navigate config path return(edata.Navigate(v).Value); }); edata.AddAttributeNode("doc-content", epDocContent); }//all endpoints //finally regenerate doc content expanding all variables for the controller docContent = MarkdownUtils.EvaluateVariables(docContent, (v) => { if (v.IsNullOrWhiteSpace()) { return(v); } //Escape: ``{{a}}`` -> `{a}` if (v.StartsWith("{") && v.EndsWith("}")) { return(v.Substring(1, v.Length - 2)); } if (v.StartsWith("@")) { return($"`{{{v}}}`"); //do not expand TYPE spec here } //else navigate config path return(cdata.Navigate(v).Value); }); cdata.AddAttributeNode("doc-content", docContent); return(cdata); }
public override ConfigSectionNode ProvideInstanceMetadata(IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { dataRoot.AddAttributeNode("max-content-length", MaxContentLength); return(dataRoot); }
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { var data = "score=110 description='Cars built in Japan' origin{_override=stop country=jap} z=1".AsLaconicConfig(); dataRoot.MergeAttributes(data); dataRoot.MergeSections(data); return(dataRoot); }
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { var data = "description='Honda motors'".AsLaconicConfig(); dataRoot.MergeAttributes(data); dataRoot.MergeSections(data); return(dataRoot); }
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { var data = "score=40 description='Luxury item, but unreliable' origin{country=XYZYZ/*this will never take effect*/}".AsLaconicConfig(); dataRoot.MergeAttributes(data); dataRoot.MergeSections(data); return(dataRoot); }
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { var data = "score=90 description='Very usable and decent quality' a=-900".AsLaconicConfig(); dataRoot.MergeAttributes(data); dataRoot.MergeSections(data); return(dataRoot); }
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { var data = "a=123 b=789 score=100 description='Generic car' origin{_override=all country=world} z=0".AsLaconicConfig(); dataRoot.MergeAttributes(data); dataRoot.MergeSections(data); return(dataRoot); }
/// <summary> /// Called by various metadata consumers to get additional metadata about the decorated type /// </summary> /// <param name="member">A member (e.g. a type or a method) which is being described</param> /// <param name="instance"> /// Optional instance of Type when member represents a type, this way the metadata may depend on instance, /// e.g. when generating permissions the instance contains the required access level /// </param> /// <param name="context">IMetadataGenerator context in which the metadata acquisition takes place</param> /// <param name="dataRoot">Root data node under which THIS entity is supposed to create its sub-node to provide its metadata into</param> /// <param name="overrideRules">Config node override rules to use for structured merging, or null to use the defaults</param> /// <returns>A new data node that this provider has written into, such as a new node which is a child of dataRoot</returns> public abstract ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null);
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { var tdoc = member.NonNull(nameof(member)) as Type; if (tdoc == null || !typeof(Doc).IsAssignableFrom(tdoc)) { return(null); } var typed = tdoc.IsSubclassOf(typeof(TypedDoc)); var ndoc = dataRoot.AddChildNode("data-doc"); Schema schema; if (instance is Doc doc) { schema = doc.Schema; } else if (typed) { schema = Schema.GetForTypedDoc(tdoc); } else { schema = null; } MetadataUtils.AddMetadataTokenIdAttribute(ndoc, tdoc); ndoc.AddAttributeNode("kind", typed ? "typed" : "dynamic"); CustomMetadataAttribute.Apply(typeof(Schema), schema, context, ndoc, overrideRules); return(ndoc); }
public override ConfigSectionNode ProvideMetadata(MemberInfo member, object instance, IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) { var schema = instance as Schema;//is a sealed class by design if (schema == null) { return(null); } var ndoc = dataRoot.AddChildNode("schema"); if (context.DetailLevel > MetadataDetailLevel.Public) { ndoc.AddAttributeNode("name", schema.Name); } else { ndoc.AddAttributeNode("name", schema.TypedDocType?.Name ?? schema.Name); } ndoc.AddAttributeNode("read-only", schema.ReadOnly); TypedDoc doc = null; if (schema.TypedDocType != null) { ndoc.AddAttributeNode("typed-doc-type", context.AddTypeToDescribe(schema.TypedDocType)); if (!schema.TypedDocType.IsAbstract) { try { //this may fail because there may be constructor incompatibility, then we just can get instance-specific metadata doc = Activator.CreateInstance(schema.TypedDocType, true) as TypedDoc; context.App.InjectInto(doc); } catch { } } } foreach (var def in schema) { var nfld = ndoc.AddChildNode("field"); try { var targetName = context.GetSchemaDataTargetName(schema, doc); field(targetName, def, context, nfld, doc); } catch (Exception error) { var err = new CustomMetadataException(StringConsts.METADATA_GENERATION_SCHEMA_FIELD_ERROR.Args(schema.Name, def.Name, error.ToMessageWithType()), error); nfld.AddAttributeNode("--ERROR--", StringConsts.METADATA_GENERATION_SCHEMA_FIELD_ERROR.Args(schema.Name, def.Name, "<logged>")); context.ReportError(Log.MessageType.CriticalAlert, err); } } return(ndoc); }
public virtual ConfigSectionNode ProvideInstanceMetadata(IMetadataGenerator context, ConfigSectionNode dataRoot, NodeOverrideRules overrideRules = null) => dataRoot;