Class: Generator::JsonSchemaExtractor

Inherits:
Object
  • Object
show all
Defined in:
lib/generator/parsers/json_schema_extractor.rb

Overview

Extracts nested type definitions from JSON Schema files Converts inline nested objects into flat definitions that can be processed by Type generator

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(schema, notification_name) ⇒ JsonSchemaExtractor

Returns a new instance of JsonSchemaExtractor.



12
13
14
15
16
# File 'lib/generator/parsers/json_schema_extractor.rb', line 12

def initialize(schema, notification_name)
  @schema = schema
  @notification_name = notification_name
  @extracted_types = {}
end

Instance Attribute Details

#notification_nameObject (readonly)

Returns the value of attribute notification_name.



10
11
12
# File 'lib/generator/parsers/json_schema_extractor.rb', line 10

def notification_name
  @notification_name
end

#schemaObject (readonly)

Returns the value of attribute schema.



10
11
12
# File 'lib/generator/parsers/json_schema_extractor.rb', line 10

def schema
  @schema
end

Instance Method Details

#extract_typesObject

Extract all nested types from the notification schema or feed schema Returns a hash of type_name => definition (OpenAPI-style)



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/generator/parsers/json_schema_extractor.rb', line 20

def extract_types
  # Start with any existing definitions from the schema
  # These are pre-defined types (especially common in B2B notifications)
  schema["definitions"]&.each do |type_name, type_def|
    # Skip special definitions that aren't actual types (case-insensitive)
    next if ["notificationResponse", "payload"].any? { |skip| skip.casecmp?(type_name) }
    # Skip money-like types - they'll use the shared Money type
    next if money_like_object?(type_def)
    # Skip definitions that are just $ref aliases (no actual object structure)
    # Example: {"$ref": "#/definitions/moneyType", "description": "..."}
    next if type_def["$ref"] && !type_def["type"] && !type_def["properties"]
    # Skip definitions that are just primitive types (string, integer, etc.)
    # Example: {"type": "string", "description": "..."}
    next if ["string", "integer", "number", "boolean"].include?(type_def["type"]) && !type_def["properties"]

    # Convert to PascalCase for consistency
    pascal_name = type_name.camelize
    @extracted_types[pascal_name] = type_def
  end

  # Try to extract from notification schema first (for notification types)
  payload_schema = schema.dig("properties", "payload") || schema.dig("properties", "Payload")

  if payload_schema
    # Find notification-specific object (e.g., "anyOfferChangedNotification" or "AnyOfferChangedNotification")
    notification_schema = find_notification_schema(payload_schema)

    if notification_schema
      # Start recursive extraction from the notification root (will override pre-existing if needed)
      extract_nested_objects(notification_schema, "", notification_name)
    end
  else
    # No payload property - this might be a feed schema with root-level properties
    # Extract types from root properties that are objects
    extract_root_level_types
  end

  # Always run replace_with_refs! to process any extracted types (including definitions-only schemas like B2B)
  replace_with_refs!

  @extracted_types
end