async-matrixSourceAsyncMatrixApiPathTree

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