module Jazzy module SymbolGraph # Constraint is a tidied-up JSON object, used by both Symbol and # Relationship, and key to reconstructing extensions. class Constraint attr_accessor :kind attr_accessor :lhs attr_accessor :rhs private def initialize(kind, lhs, rhs) self.kind = kind # "==" or ":" self.lhs = lhs self.rhs = rhs end public KIND_MAP = { 'conformance' => ':', 'superclass' => ':', 'sameType' => '==', }.freeze # Init from a JSON hash def self.new_hash(hash) kind = KIND_MAP[hash[:kind]] raise "Unknown constraint kind '#{kind}'" unless kind lhs = hash[:lhs].sub(/^Self\./, '') rhs = hash[:rhs].sub(/^Self\./, '') new(kind, lhs, rhs) end # Init from a Swift declaration fragment eg. 'A : B' def self.new_declaration(decl) decl =~ /^(.*?)\s*([:<=]+)\s*(.*)$/ new(Regexp.last_match[2], Regexp.last_match[1], Regexp.last_match[3]) end def to_swift "#{lhs} #{kind} #{rhs}" end # The first component of types in the constraint def type_names Set.new([lhs, rhs].map { |n| n.sub(/\..*$/, '') }) end def self.new_list(hash_list) hash_list.map { |h| Constraint.new_hash(h) }.sort.uniq end # Swift protocols and reqs have an implementation/hidden conformance # to their own protocol: we don't want to think about this in docs. def self.new_list_for_symbol(hash_list, path_components) hash_list.map do |hash| if hash[:lhs] == 'Self' && hash[:kind] == 'conformance' && path_components.include?(hash[:rhs]) next nil end Constraint.new_hash(hash) end.compact end # Workaround Swift 5.3 bug with missing constraint rels def self.new_list_from_declaration(decl) decl.split(/\s*,\s*/).map { |cons| Constraint.new_declaration(cons) } end # Sort order - by Swift text include Comparable def <=>(other) to_swift <=> other.to_swift end alias eql? == def hash to_swift.hash end end end end class Array def to_where_clause empty? ? '' : ' where ' + map(&:to_swift).join(', ') end end