class PathTree
A trie of valid Matrix API paths, built from OpenAPI 3.1.0 YAML schemas.
Each leaf node stores the set of HTTP methods valid at that path.
Template segments like roomId become wildcard nodes that match any value.
Example: tree = PathTree.load tree.match(["_matrix", "client", "v3", "rooms", "!abc:ex.com", "ban"], "POST")
=> valid: true, operation_id: "ban", methods: ["post"]
Definitions
def self.load(schema_dir: SCHEMA_DIR)
Load all OpenAPI schemas from data/ and build the tree.
Implementation
def self.load(schema_dir: SCHEMA_DIR)
tree = new
Pathname.glob(schema_dir / "*.yaml").each do |path|
tree.load_schema(path)
end
tree
end
def load_schema(path)
Parse a single OpenAPI YAML file and insert its paths into the tree.
Implementation
def load_schema(path)
doc = YAML.safe_load(File.read(path), permitted_classes: [Symbol], aliases: true)
return unless doc.is_a?(Hash)
base_path = extract_base_path(doc)
paths = doc["paths"]
return unless paths.is_a?(Hash)
paths.each do |path_template, methods_hash|
next unless methods_hash.is_a?(Hash)
# Build full path: basePath + path_template
full_path = "#{base_path}#{path_template.strip}"
segments = full_path.split("/").reject(&:empty?)
methods_hash.each do |method, operation|
next unless %w[get post put delete patch head].include?(method)
operation_id = operation.is_a?(Hash) ? operation["operationId"] : nil
insert(segments, method, operation_id)
end
end
end
def insert(segments, method, operation_id = nil)
Insert a path (as array of segments) with an HTTP method into the trie.
Implementation
def insert(segments, method, operation_id = nil)
node = @root
segments.each do |segment|
if segment.start_with?("{") && segment.end_with?("}")
# Wildcard segment — matches any value
node.wildcard ||= Node.new
node = node.wildcard
else
node.children[segment] ||= Node.new
node = node.children[segment]
end
end
node.methods << method.downcase unless node.methods.include?(method.downcase)
node.operation_ids[method.downcase] = operation_id if operation_id
end
def match(segments, method = nil)
Match a concrete path (array of segments) against the trie. Returns a result hash.
Implementation
def match(segments, method = nil)
node = @root
segments.each do |segment|
if node.children.key?(segment)
node = node.children[segment]
elsif node.wildcard
node = node.wildcard
else
return {valid: false, methods: [], operation_id: nil}
end
end
if method
method_down = method.downcase
valid = node.methods.include?(method_down)
{valid: valid, methods: node.methods, operation_id: node.operation_ids[method_down]}
else
{valid: node.methods.any?, methods: node.methods, operation_id: nil}
end
end