66require "fileutils"
77
88root = File . expand_path ( ".." , __dir__ )
9- docs_gen = File . join ( root , "docs" , "lib" , "log-generation" )
10- enums_path = File . join ( docs_gen , "sorbet-enums.json" )
11- structs_path = File . join ( docs_gen , "sorbet-log-structs.json" )
12- keys_path = File . join ( docs_gen , "log-fields.json" )
9+ docs_generated = File . join ( root , "docs" , "generated" , "logstruct" )
10+ structs_path = File . join ( docs_generated , "sorbet-log-structs.json" )
11+ enums_path = File . join ( docs_generated , "sorbet-enums.json" )
1312
14- unless File . exist? ( enums_path ) && File . exist? ( structs_path ) && File . exist? ( keys_path )
15- abort "Missing generated files in #{ docs_gen } . Run `task generate ` first."
13+ unless File . exist? ( structs_path ) && File . exist? ( enums_path )
14+ abort "Missing generated files in #{ docs_generated } . Run `scripts/generate_structs.rb ` first."
1615end
1716
18- enums = JSON . parse ( File . read ( enums_path ) )
1917structs = JSON . parse ( File . read ( structs_path ) )
20- keys = JSON . parse ( File . read ( keys_path ) )
18+ enums = JSON . parse ( File . read ( enums_path ) )
19+
20+ def camel_to_snake ( value )
21+ value
22+ . gsub ( /([A-Z\d ]+)([A-Z][a-z])/ , '\\1_\\2' )
23+ . gsub ( /([a-z\d ])([A-Z])/ , '\\1_\\2' )
24+ . downcase
25+ end
2126
22- # Build lookup maps for enum serialized values
23- event_values = { }
24- ( enums [ "LogStruct::Event" ] || [ ] ) . each { |e | event_values [ e [ "name" ] ] = e [ "value" ] }
25- source_values = { }
26- ( enums [ "LogStruct::Source" ] || [ ] ) . each { |e | source_values [ e [ "name" ] ] = e [ "value" ] }
27+ log_field_enum = enums . fetch ( "LogStruct::LogField" ) do
28+ abort "LogStruct::LogField enum missing from #{ enums_path } ."
29+ end
30+
31+ keys = log_field_enum . fetch ( "values" , [ ] ) . each_with_object ( { } ) do |enum_value , memo |
32+ name = enum_value . fetch ( "name" )
33+ serialized = enum_value . fetch ( "serialized" )
34+ memo [ camel_to_snake ( name ) ] = serialized
35+ end
2736
28- catalog = { "keys" => keys , "structs" => { } }
37+ keys = keys . sort . to_h
38+
39+ groups = Hash . new { |h , k | h [ k ] = { sources : [ ] , events : [ ] } }
40+
41+ def collect_serialized ( field )
42+ return [ ] unless field . is_a? ( Hash )
43+
44+ values = [ ]
45+ values << field [ "default_enum_serialized" ]
46+ values << field [ "enum_value_serialized" ]
47+ enum_values = field [ "enum_values_serialized" ]
48+ values . concat ( enum_values ) if enum_values . is_a? ( Array )
49+
50+ values . compact . map ( &:to_s ) . uniq
51+ end
2952
3053structs . each do |fq_name , info |
31- name = info [ "name" ] || fq_name . split ( "::" ) . last
32- fields = info [ "fields" ] || { }
33- s = { "name" => name }
34-
35- # Fixed source if enum_single
36- if fields [ "source" ] && fields [ "source" ] [ "type" ] == "enum_single" && fields [ "source" ] [ "enum_value" ]
37- src_name = fields [ "source" ] [ "enum_value" ]
38- s [ "fixed_source" ] = source_values [ src_name ] || src_name . downcase
39- else
40- s [ "fixed_source" ] = nil
41- end
54+ next unless fq_name . start_with? ( "LogStruct::Log::" )
4255
43- # Allowed events (serialized)
44- allowed = [ ]
45- if fields [ "event" ]
46- ef = fields [ "event" ]
47- case ef [ "type" ]
48- when "enum_single"
49- if ef [ "enum_value" ]
50- nm = ef [ "enum_value" ]
51- allowed << ( event_values [ nm ] || nm . downcase )
52- end
53- when "enum_union"
54- ( ef [ "enum_values" ] || [ ] ) . each do |nm |
55- allowed << ( event_values [ nm ] || nm . downcase )
56- end
57- end
58- end
59- s [ "allowed_events" ] = allowed . uniq
56+ fields = info [ "fields" ]
57+ next unless fields . is_a? ( Hash )
58+
59+ event_field = fields [ "event" ]
60+ event_values = collect_serialized ( event_field )
61+ next if event_values . empty?
62+
63+ log_type = fq_name . split ( "::" ) [ 2 ]
64+ next unless log_type
65+
66+ group = groups [ log_type ]
67+ group [ :events ] = ( group [ :events ] | event_values )
68+
69+ source_field = fields [ "source" ]
70+ source_values = collect_serialized ( source_field )
71+ group [ :sources ] = ( group [ :sources ] | source_values ) if source_values . any?
72+ end
73+
74+ catalog_structs = groups . each_with_object ( { } ) do |( log_type , data ) , memo |
75+ events = data [ :events ] . uniq . sort
76+ next if events . empty?
77+
78+ sources = data [ :sources ] . uniq
79+ fixed_source = ( sources . size == 1 ) ? sources . first : nil
6080
61- catalog [ "structs" ] [ name ] = s
81+ memo [ log_type ] = {
82+ "name" => log_type ,
83+ "fixed_source" => fixed_source ,
84+ "allowed_events" => events
85+ }
6286end
6387
88+ catalog_structs = catalog_structs . sort . to_h
89+
90+ catalog = { "keys" => keys , "structs" => catalog_structs }
91+
6492provider_dir = File . join ( root , "terraform-provider-logstruct" )
6593data_dir = File . join ( provider_dir , "pkg" , "data" )
6694FileUtils . mkdir_p ( data_dir )
6795
68- # Always write JSON (useful for inspection)
6996catalog_path = File . join ( data_dir , "catalog.json" )
7097File . write ( catalog_path , JSON . pretty_generate ( catalog ) )
7198
72- # Also generate a Go source file with embedded types and data for zero runtime parsing
7399gen_path = File . join ( data_dir , "catalog_gen.go" )
74100
75101def go_string ( str )
76- # Escape backslashes and quotes for Go string literals
77102 str . to_s . gsub ( "\\ " , "\\ \\ " ) . gsub ( '"' , '\\"' )
78103end
79104
@@ -83,19 +108,24 @@ def go_string(str)
83108go << "type StructCatalog struct {\n \t Name string\n \t FixedSource *string\n \t AllowedEvents []string\n }\n \n "
84109go << "type Catalog struct {\n \t Keys map[string]string\n \t Structs map[string]StructCatalog\n }\n \n "
85110go << "var CatalogData = Catalog{\n \t Keys: map[string]string{\n "
86- keys . each do |k , v |
87- go << "\t \t \" #{ go_string ( k ) } \" : \" #{ go_string ( v ) } \" ,\n "
111+ keys . each do |key , value |
112+ go << "\t \t \" #{ go_string ( key ) } \" : \" #{ go_string ( value ) } \" ,\n "
88113end
89114go << "\t },\n \t Structs: map[string]StructCatalog{\n "
90- catalog [ "structs" ] . each do |name , s |
91- go << "\t \t \" #{ go_string ( name ) } \" : {Name: \" #{ go_string ( s [ "name" ] ) } \" ,"
92- go << if s [ "fixed_source" ]
93- " FixedSource: ptr(\" #{ go_string ( s [ "fixed_source" ] ) } \" ),"
115+ catalog_structs . each do |name , data |
116+ go << "\t \t \" #{ go_string ( name ) } \" : {Name: \" #{ go_string ( data [ "name" ] ) } \" ,"
117+ fixed_source = data [ "fixed_source" ]
118+ fragment = if fixed_source
119+ " FixedSource: ptr(\" #{ go_string ( fixed_source ) } \" ),"
94120 else
95121 " FixedSource: nil,"
96122 end
123+ go << fragment
97124 go << " AllowedEvents: []string{"
98- go << s [ "allowed_events" ] . map { |ev | "\" #{ go_string ( ev ) } \" " } . join ( ", " )
125+ events = data [ "allowed_events" ]
126+ if events . any?
127+ go << events . map { |event | "\" #{ go_string ( event ) } \" " } . join ( ", " )
128+ end
99129 go << "}},\n "
100130end
101131go << "\t },\n }\n "
0 commit comments