/// <summary> /// Creates an <see cref="OpenApiUrlTreeNode"/> from a collection of <see cref="OpenApiDocument"/>. /// </summary> /// <param name="sources">Dictionary of labels and their corresponding <see cref="OpenApiDocument"/> objects.</param> /// <returns>The created <see cref="OpenApiUrlTreeNode"/>.</returns> public static OpenApiUrlTreeNode CreateOpenApiUrlTreeNode(Dictionary <string, OpenApiDocument> sources) { var rootNode = OpenApiUrlTreeNode.Create(); foreach (var source in sources) { rootNode.Attach(source.Value, source.Key); } return(rootNode); }
/// <summary> /// Assembles the constituent properties of an <see cref="OpenApiUrlTreeNode"/> node. /// </summary> /// <param name="segments">IEnumerable subdirectories of a relative path.</param> /// <param name="pathItem">Path Item object that describes the operations available on an OpenAPI path.</param> /// <param name="label">A name tag for labelling the <see cref="OpenApiUrlTreeNode"/> node.</param> /// <param name="currentPath">The relative path of a node.</param> /// <returns>An <see cref="OpenApiUrlTreeNode"/> node with all constituent properties assembled.</returns> private OpenApiUrlTreeNode Attach(IEnumerable <string> segments, OpenApiPathItem pathItem, string label, string currentPath) { var segment = segments.FirstOrDefault(); if (string.IsNullOrEmpty(segment)) { if (PathItems.ContainsKey(label)) { throw new ArgumentException("A duplicate label already exists for this node.", nameof(label)); } Path = currentPath; PathItems.Add(label, pathItem); return(this); } // If the child segment has already been defined, then insert into it if (Children.ContainsKey(segment)) { var newPath = currentPath + PathSeparator + segment; return(Children[segment].Attach(segments: segments.Skip(1), pathItem: pathItem, label: label, currentPath: newPath)); } else { var newPath = currentPath + PathSeparator + segment; var node = new OpenApiUrlTreeNode(segment) { Path = newPath }; Children[segment] = node; return(node.Attach(segments: segments.Skip(1), pathItem: pathItem, label: label, currentPath: newPath)); } }
private static IDictionary <OperationType, OpenApiOperation> GetOpenApiOperations(OpenApiUrlTreeNode rootNode, string relativeUrl, string label) { if (relativeUrl.Equals("/", StringComparison.Ordinal) && rootNode.HasOperations(label)) { return(rootNode.PathItems[label].Operations); } var urlSegments = relativeUrl.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); IDictionary <OperationType, OpenApiOperation> operations = null; var targetChild = rootNode; /* This will help keep track of whether we've skipped a segment * in the target url due to a possible parameter naming mismatch * with the corresponding OpenApiUrlTreeNode target child segment. */ var parameterNameOffset = 0; for (var i = 0; i < urlSegments?.Length; i++) { var tempTargetChild = targetChild?.Children? .FirstOrDefault(x => x.Key.Equals(urlSegments[i], StringComparison.OrdinalIgnoreCase)).Value; // Segment name mismatch if (tempTargetChild == null) { if (i == 0) { /* If no match and we are at the 1st segment of the relative url, * exit; no need to continue matching subsequent segments. */ break; } /* Attempt to get the parameter segment from the children of the current node: * We are assuming a failed match because of different parameter namings * between the relative url segment and the corresponding OpenApiUrlTreeNode segment name * ex.: matching '/users/12345/messages' with '/users/{user-id}/messages' */ tempTargetChild = targetChild?.Children? .FirstOrDefault(x => x.Value.IsParameter).Value; /* If no parameter segment exists in the children of the * current node or we've already skipped a parameter * segment in the relative url from the last pass, * then exit; there's no match. */ if (tempTargetChild == null || parameterNameOffset > 0) { break; } /* To help us know we've skipped a * corresponding segment in the relative url. */ parameterNameOffset++; } else { parameterNameOffset = 0; } // Move to the next segment targetChild = tempTargetChild; // We want the operations of the last segment of the path. if (i == urlSegments.Length - 1 && targetChild.HasOperations(label)) { operations = targetChild.PathItems[label].Operations; } } return(operations); }