public static BaseSchema GetChildSchema(BaseSchema parent, string part) { if (part == null) { throw new ArgumentNullException(nameof(part)); } if (parent == null) { return(null); } if (part == null) { return(null); } var unescapedPart = UnescapeReference(part); if (int.TryParse(unescapedPart, out int index)) { return(parent.Items); } if (parent.Properties.TryGetValue(part, out var bs)) { return(bs); } return(null); }
private static bool IsEditable(this BaseSchema schema) { if (schema?.ContentType == ContentType.Markdown) { return(true); } if (schema?.Tags == null) { return(false); } return(schema.Tags.Contains(IsEditableTag, StringComparer.OrdinalIgnoreCase)); }
public BaseSchema FindSchema(DocumentSchema rootSchema) { if (_isRoot) { return(rootSchema); } BaseSchema schema = rootSchema; foreach (var part in _parts) { schema = GetChildSchema(schema, part); } return(schema); }
public void UpdateXrefSpec(FileModel fileModel, BaseSchema schema) { if (fileModel == null) { return; } if (schema == null) { throw new ArgumentNullException(nameof(schema)); } var context = new ProcessContext(_host, fileModel); _xrefSpecUpdater.Process(fileModel.Content, schema, context); UpdateXRefSpecs((List <XRefSpec>)fileModel.Properties.XRefSpecs, context.XRefSpecs); UpdateXRefSpecs((List <XRefSpec>)fileModel.Properties.ExternalXRefSpecs, context.ExternalXRefSpecs); }
public void Traverse( YamlNode node, Dictionary <string, MarkdownFragment> fragments, BaseSchema schema) { if (node == null) { throw new ArgumentNullException(nameof(node)); } if (fragments == null) { throw new ArgumentNullException(nameof(fragments)); } if (schema == null) { throw new ArgumentNullException(nameof(schema)); } TraverseCore(node, fragments, schema, string.Empty, string.Empty); }
private static bool CheckOverwriteAbilityCore(BaseSchema schema, Dictionary <BaseSchema, bool> cache) { if (schema == null) { return(false); } if (cache.TryGetValue(schema, out var result)) { return(result); } if (schema.ContentType == ContentType.Uid) { cache[schema] = result = true; return(result); } cache[schema] = result = false; if (CheckOverwriteAbilityCore(schema.Items, cache)) { cache[schema] = result = true; return(result); } if (schema.Properties != null) { foreach (var value in schema.Properties.Values) { if (CheckOverwriteAbilityCore(value, cache)) { cache[schema] = result = true; return(result); } } } return(result); }
/// <summary> /// Return if a property is legal to appear in markdown fragments /// </summary> public static bool IsLegalInFragments(this BaseSchema schema) => IsEditable(schema);
/// <summary> /// Return if a property is required to appear in markdown fragments /// </summary> public static bool IsRequiredInFragments(this BaseSchema schema) => IsEditable(schema);
public object BuildOverwriteWithSchema(FileModel owModel, OverwriteDocumentModel overwrite, BaseSchema schema) { if (overwrite == null || owModel == null) { return(null); } if (schema == null) { throw new ArgumentNullException(nameof(schema)); } dynamic overwriteObject = ConvertToObjectHelper.ConvertToDynamic(overwrite.Metadata); overwriteObject.uid = overwrite.Uid; var overwriteModel = new FileModel(owModel.FileAndType, overwriteObject, owModel.OriginalFileAndType); var context = (((IDictionary <string, object>)(owModel.Properties)).TryGetValue("MarkdigMarkdownService", out var service)) ? new ProcessContext(_host, overwriteModel, null, (MarkdigMarkdownService)service) : new ProcessContext(_host, overwriteModel); if (_overwriteModelType == OverwriteModelType.Classic) { context.ContentAnchorParser = new ContentAnchorParser(overwrite.Conceptual); } var transformed = _overwriteProcessor.Process(overwriteObject, schema, context) as IDictionary <string, object>; if (_overwriteModelType == OverwriteModelType.Classic && !context.ContentAnchorParser.ContainsAnchor) { transformed["conceptual"] = context.ContentAnchorParser.Content; } // add SouceDetail back to transformed, in week type if (overwrite.Documentation != null) { transformed[Constants.PropertyName.Documentation] = new Dictionary <string, object> { ["remote"] = overwrite.Documentation.Remote == null ? null : new Dictionary <string, object> { ["path"] = overwrite.Documentation.Remote.RelativePath, ["branch"] = overwrite.Documentation.Remote.RemoteBranch, ["repo"] = overwrite.Documentation.Remote.RemoteRepositoryUrl, } ["path"] = overwrite.Documentation?.Path, ["startLine"] = overwrite.Documentation?.StartLine ?? 0, ["endLine"] = overwrite.Documentation?.EndLine ?? 0, }; } owModel.LinkToUids = owModel.LinkToUids.Union((context.UidLinkSources).Keys); owModel.LinkToFiles = owModel.LinkToFiles.Union((context.FileLinkSources).Keys); owModel.FileLinkSources = owModel.FileLinkSources.Merge(context.FileLinkSources); owModel.UidLinkSources = owModel.UidLinkSources.Merge(context.UidLinkSources); owModel.Uids = owModel.Uids.AddRange(context.Uids); owModel.Properties.XRefSpecs = context.XRefSpecs; owModel.Properties.ExternalXRefSpecs = context.ExternalXRefSpecs; foreach (var d in context.Dependency) { _host.ReportDependencyTo(owModel, d, DependencyTypeName.Include); } return(transformed); }
public void MergeContentWithOverwrite(ref object source, object overwrite, string uid, string path, BaseSchema schema) { _merger.Merge(ref source, overwrite, uid, path, schema); }
public void HandleProperty(string propertyKey, YamlMappingNode node, Dictionary <string, MarkdownFragment> fragments, BaseSchema schema, string oPathPrefix, string uid) { var propSchema = schema.Properties[propertyKey]; if (!propSchema.IsRequiredInFragments()) { return; } if (_isMissingUidsLogged.TryGetValue(uid, out var isLogged)) { if (!isLogged) { Logger.LogWarning($"Missing UID {uid} in markdown fragments. This may be caused by YAML update. Please ensure your markdown fragments are up to date.", code: WarningCodes.Overwrite.InvalidMarkdownFragments); _isMissingUidsLogged[uid] = true; } return; } var opath = oPathPrefix + propertyKey; if (!fragments[uid].Properties.ContainsKey(opath)) { if (string.IsNullOrEmpty(oPathPrefix) && fragments[uid].Metadata?.ContainsKey(opath) == true) { return; } // TODO: also check whether it exists in inner objects Logger.LogWarning($"Missing property '{opath}' for UID '{uid}' in markdown fragments. This may be caused by YAML update or schema update. Please ensure your markdown fragments are up to date.", code: WarningCodes.Overwrite.InvalidMarkdownFragments); } }
public void HandleUid(string uidKey, YamlMappingNode node, Dictionary <string, MarkdownFragment> fragments, BaseSchema schema, string oPathPrefix, string uid) { if (!fragments.ContainsKey(uid) && !_isMissingUidsLogged.ContainsKey(uid)) { _isMissingUidsLogged[uid] = false; } }
private object BuildOverwriteWithSchema(FileModel owModel, OverwriteDocumentModel overwrite, IHostService host, BaseSchema schema) { dynamic overwriteObject = ConvertToObjectHelper.ConvertToDynamic(overwrite.Metadata); overwriteObject.uid = overwrite.Uid; var overwriteModel = new FileModel(owModel.FileAndType, overwriteObject, owModel.OriginalFileAndType); var context = new ProcessContext(host, overwriteModel) { ContentAnchorParser = new ContentAnchorParser(overwrite.Conceptual) }; var transformed = _overwriteProcessor.Process(overwriteObject, schema, context) as IDictionary<string, object>; if (!context.ContentAnchorParser.ContainsAnchor) { transformed["conceptual"] = context.ContentAnchorParser.Content; } // add SouceDetail back to transformed, in week type transformed[Constants.PropertyName.Documentation] = new Dictionary<string, object> { ["remote"] = overwrite.Documentation.Remote == null ? null : new Dictionary<string, object> { ["path"] = overwrite.Documentation.Remote.RelativePath, ["branch"] = overwrite.Documentation.Remote.RemoteBranch, ["repo"] = overwrite.Documentation.Remote.RemoteRepositoryUrl, } ["path"] = overwrite.Documentation?.Path, ["startLine"] = overwrite.Documentation?.StartLine ?? 0, ["endLine"] = overwrite.Documentation?.EndLine ?? 0, }; owModel.LinkToUids = owModel.LinkToUids.Union((context.UidLinkSources).Keys); owModel.LinkToFiles = owModel.LinkToFiles.Union((context.FileLinkSources).Keys); owModel.FileLinkSources = owModel.FileLinkSources.Merge(context.FileLinkSources); owModel.UidLinkSources = owModel.UidLinkSources.Merge(context.UidLinkSources); owModel.Uids = owModel.Uids.AddRange(context.Uids); owModel.Properties.XRefSpecs = context.XRefSpecs; owModel.Properties.ExternalXRefSpecs = context.ExternalXRefSpecs; foreach (var d in context.Dependency) { host.ReportDependencyTo(owModel, d, DependencyTypeName.Include); } return transformed; }
private static bool CheckOverwriteAbility(BaseSchema schema) { return(CheckOverwriteAbilityCore(schema, new Dictionary <BaseSchema, bool>())); }
private void TraverseCore( YamlNode node, Dictionary <string, MarkdownFragment> fragments, BaseSchema schema, string parentOPath, string uid) { var oPathPrefix = string.IsNullOrEmpty(parentOPath) ? "" : (parentOPath + "/"); if (node is YamlMappingNode map) { var uidKey = schema.Properties.Keys.FirstOrDefault(k => schema.Properties[k].ContentType == ContentType.Uid); if (!string.IsNullOrEmpty(uidKey)) { // If a new UID is found, OPath resets. uid = map.Children[uidKey].ToString(); oPathPrefix = string.Empty; _handler.HandleUid(uidKey, (YamlMappingNode)node, fragments, schema, parentOPath, uid); } else if (string.IsNullOrEmpty(uid)) { Logger.LogError("Cannot find Uid"); return; } var keys = schema.Properties.Keys; foreach (var key in keys) { var propSchema = schema.Properties[key]; if (propSchema.Type == JSchemaType.Object || propSchema.Type == JSchemaType.Array) { if (map.Children.ContainsKey(key)) { TraverseCore(map.Children[key], fragments, propSchema, oPathPrefix + key, uid); } } else { _handler.HandleProperty(key, (YamlMappingNode)node, fragments, schema, oPathPrefix, uid); } } } else if (node is YamlSequenceNode seq) { if (string.IsNullOrEmpty(uid)) { Logger.LogError("Cannot find Uid"); return; } if (schema.Items != null && schema.Items.Properties.Any(s => s.Value.ContentType == ContentType.Markdown || s.Value.Type == JSchemaType.Object || s.Value.Type == JSchemaType.Array)) { var mergeKey = schema.Items.Properties.Keys.FirstOrDefault(k => schema.Items.Properties[k].MergeType == MergeType.Key); if (mergeKey == null) { return; } foreach (var item in seq) { if (item is YamlMappingNode mapNode) { if (mapNode.Children.ContainsKey(mergeKey)) { var opath = $"{parentOPath}[{mergeKey}=\"{mapNode.Children[mergeKey].ToString()}\"]"; TraverseCore(item, fragments, schema.Items, opath, uid); } else { Logger.LogError($"Cannot find merge key {mergeKey} in {mapNode}"); } } } } } }