Class: Archsight::Import::Handlers::OpenAPISchemaParser

Inherits:
Object
  • Object
show all
Defined in:
lib/archsight/import/handlers/openapi_schema_parser.rb

Overview

Parses OpenAPI schemas and extracts DataObject information

Features:

  • Schema name normalization (strips CRUD prefixes/suffixes, singularizes)

  • Skip utility schemas (Error, Links, Metadata, etc.)

  • $ref resolution with cycle detection

  • allOf composition handling

  • Nested property extraction (up to 3 levels deep)

  • Field documentation generation (markdown table format)

Constant Summary collapse

SKIP_SCHEMAS =

Schemas that should be skipped (utility schemas)

%w[
  Error Links Offset Limit Metadata PaginationLinks ErrorMessage Pagination
  ErrorMessages Type State ErrorResponse ValidationError InternalError
  NotFoundError ForbiddenError UnauthorizedError BadRequestError
  ConflictError RateLimitError ServiceUnavailableError
].freeze
STRIP_SUFFIXES =

Suffixes to strip from schema names for normalization

%w[
  Create Read Ensure ReadList List Patch Update Put Post Response Request
  Properties Resource Item Items Collection Result Results Output Input
  Dto DTO Entity Model Data Info Details Summary Overview
].freeze
STRIP_PREFIXES =

Prefixes to strip from schema names for normalization

%w[
  Create Get Update Delete Set Add Remove List Fetch Patch
].freeze
KEEP_PLURAL =

Words that should remain plural (don’t singularize)

%w[
  Status Address Class Process Access Alias Analysis Basis
  Canvas Census Chorus Circus Corpus Crisis Diagnosis Ellipsis
  Emphasis Genesis Hypothesis Oasis Paralysis Parenthesis Synopsis
  Thesis Axis Redis Kubernetes
].freeze
MAX_PROPERTY_DEPTH =

Maximum depth for nested property extraction

3

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(openapi_doc) ⇒ OpenAPISchemaParser

Returns a new instance of OpenAPISchemaParser.

Parameters:

  • openapi_doc (Hash)

    Parsed OpenAPI document



50
51
52
53
54
55
56
# File 'lib/archsight/import/handlers/openapi_schema_parser.rb', line 50

def initialize(openapi_doc)
  @openapi_doc = openapi_doc
  @schemas = openapi_doc.dig("components", "schemas") || {}
  @parsed_objects = {}
  @visited_refs = Set.new
  @inflector = Dry::Inflector.new
end

Instance Attribute Details

#parsed_objectsObject (readonly)

Returns the value of attribute parsed_objects.



47
48
49
# File 'lib/archsight/import/handlers/openapi_schema_parser.rb', line 47

def parsed_objects
  @parsed_objects
end

#schemasObject (readonly)

Returns the value of attribute schemas.



47
48
49
# File 'lib/archsight/import/handlers/openapi_schema_parser.rb', line 47

def schemas
  @schemas
end

Class Method Details

.generate_field_docs(properties) ⇒ String

Generate markdown documentation for properties

Parameters:

  • properties (Array<Hash>)

    Property list

Returns:

  • (String)

    Markdown table



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/archsight/import/handlers/openapi_schema_parser.rb', line 102

def self.generate_field_docs(properties)
  return "" if properties.empty?

  lines = ["## Fields", "", "| Field | Type | Required | Description |", "|-------|------|----------|-------------|"]

  properties.each do |prop|
    name = "`#{prop["name"]}`"
    type = prop["type"] || "object"
    type = "#{type} (#{prop["format"]})" if prop["format"]
    required = prop["required"] ? "Yes" : "No"
    description = (prop["description"] || "").gsub(/\s+/, " ").strip

    # Truncate long descriptions
    description = "#{description[0, 80]}..." if description.length > 80

    lines << "| #{name} | #{type} | #{required} | #{description} |"
  end

  lines.join("\n")
end

Instance Method Details

#parseHash<String, Hash>

Parse all schemas and return normalized DataObjects

Returns:

  • (Hash<String, Hash>)

    Map of normalized name to data object info



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/archsight/import/handlers/openapi_schema_parser.rb', line 60

def parse
  # First pass: create entries for each unique normalized name
  @schemas.each_key do |schema_name|
    next if skip_schema?(schema_name)

    normalized_name = normalize_name(schema_name)
    next if normalized_name.empty?
    next if @parsed_objects.key?(normalized_name)

    schema = @schemas[schema_name]
    @visited_refs.clear

    properties = extract_properties(schema, depth: 0)
    next if properties.empty? && !has_schema_content?(schema)

    @parsed_objects[normalized_name] = {
      "original_names" => [schema_name],
      "properties" => properties,
      "description" => schema["description"]
    }
  end

  # Second pass: track all original names that map to each normalized name
  # rubocop:disable Style/CombinableLoops -- loops must be separate: first creates entries, second merges
  @schemas.each_key do |schema_name|
    next if skip_schema?(schema_name)

    normalized_name = normalize_name(schema_name)
    next if normalized_name.empty?
    next unless @parsed_objects.key?(normalized_name)

    original_names = @parsed_objects[normalized_name]["original_names"]
    original_names << schema_name unless original_names.include?(schema_name)
  end
  # rubocop:enable Style/CombinableLoops

  @parsed_objects
end