@@ -5,26 +5,26 @@ module SlackApi
55 class MethodsSpider < BaseSpider
66 handle 'https://api.slack.com/methods' , :process_list
77
8+ def downloader
9+ @downloader ||= SlackApi ::Docs ::Downloader . new
10+ end
11+
812 def process_list ( page , _default_data = { } )
9- methods_page = ensure! ( page , '.apiMethodPage' )
10- list = methods_page . search ( '.apiMethodPage__methodList' )
11- ref = list . search ( '[data-automount-component=ApiDocsFilterableReferenceList]' )
12- data = JSON . parse ( ref . attribute ( 'data-automount-props' ) )
13- raise ( ElementNotFound , 'Could not parse methods reference' ) unless data [ 'items' ] . any?
13+ methods = JSON . load_file ( downloader . methods_path )
1414
1515 groups = Set . new
16- data [ 'items' ] . each do |method |
17- next unless method [ 'isPublic' ]
18- next if method [ 'isDeprecated' ]
1916
20- groups += method [ 'groups' ]
17+ methods . each do |method |
18+ groups += method [ 'family' ]
2119 method_name = method [ 'name' ]
22- method_group = method [ 'groups' ] . first . split ( '.' ) . first
20+ method_group = method [ 'family' ] . first . split ( '.' ) . first
21+ downloaded_filename = downloader . method_target_path ( method_name )
2322 file_name = "methods/#{ method_group } /#{ method_name } .json"
24- method_url = resolve_url ( method [ 'link' ] , page )
23+ method_url = resolve_url ( downloader . method_url ( method_name ) , page )
2524 handle method_url ,
2625 :process_method ,
2726 filename : file_name ,
27+ downloaded_filename : downloaded_filename ,
2828 method_name : method_name ,
2929 method_group : method_group ,
3030 method_url : method_url
@@ -37,14 +37,15 @@ def process_list(page, _default_data = {})
3737 end
3838 end
3939
40- def process_method ( page , default_data = { } )
41- method_page = ensure! ( page , '.apiMethodPage' , default_data [ :method_name ] )
42- desc = method_page . search ( '.apiReference__mainDescription' ) . text . gsub ( '’' , "'" )
43- return if desc . downcase . start_with? 'deprecated:'
40+ def process_method ( method_page , default_data = { } )
41+ method_data = JSON . load_file ( default_data [ :downloaded_filename ] )
4442
45- args , arg_groups , fields = parse_args ( method_page , default_data )
46- errors = parse_errors ( method_page , default_data )
47- response = parse_response ( method_page , default_data )
43+ desc = method_data [ 'desc' ] . gsub ( '’' , "'" )
44+ return if desc . downcase . start_with? 'Deprecated:'
45+
46+ args , arg_groups , fields = parse_args ( method_page , method_data )
47+ errors = parse_errors ( method_page , method_data )
48+ response = parse_response ( method_page , method_data )
4849
4950 json_hash = {
5051 'group' => default_data [ :method_group ] ,
@@ -62,24 +63,25 @@ def process_method(page, default_data = {})
6263
6364 private
6465
65- def parse_args ( api_page , default_data = { } )
66- args_wrapper = ensure! ( api_page , '.apiReference__arguments' , default_data [ :method_name ] )
67- rows = args_wrapper . search ( '.apiMethodPage__argumentRow' )
66+ def parse_args ( _api_page , method_data = { } )
6867 args = { }
6968 fields = { }
70- rows . each do |row |
71- name = row . search ( '.apiMethodPage__argument code' ) . text
72- type = massage_type ( name ,
73- row . search ( '.apiMethodPage__argumentType' ) . text ,
74- default_data )
75- required = row . search ( '.apiMethodPage__argumentOptionality--required' ) . any?
76-
77- desc = row . search ( '.apiMethodPage__argumentDesc p' )
78- . text
79- . tap { |t | t . slice! ( "\n " ) }
80- . tap { |t | t << '.' unless t . end_with? ( '.' ) }
81- . gsub ( '’' , "'" )
82- example = row . search ( '.apiReference__exampleCode code' ) . first &.text
69+ method_data [ 'args' ] [ 'properties' ] . each_pair do |name , arg |
70+ arg [ 'anyOf' ] &.each do |coll |
71+ all = [ ]
72+ all << coll [ 'type' ]
73+ arg [ 'type' ] = all
74+ end
75+ arg . delete ( 'anyOf' )
76+
77+ type = massage_type ( name , arg , method_data )
78+ required = method_data [ 'args' ] [ 'required' ] &.include? ( name )
79+
80+ desc = arg [ 'desc' ]
81+ &.tap { |t | t . slice! ( "\n " ) }
82+ &.tap { |t | t << '.' unless t . end_with? ( '.' ) }
83+ &.gsub ( '’' , "'" )
84+ example = arg [ 'example' ] || arg [ 'default' ]
8385
8486 case name
8587 when 'token'
@@ -98,89 +100,80 @@ def parse_args(api_page, default_data = {})
98100 end
99101 end
100102
101- arg_groups = parse_arg_groups ( args_wrapper )
103+ arg_groups = parse_arg_groups ( _api_page , method_data )
102104
103- [ args , arg_groups , fields ]
105+ [ args . sort . to_h , arg_groups , fields ]
104106 end
105107
106- def parse_arg_groups ( args_wrapper )
107- # Look for groups of args that are interdependent
108- groups = args_wrapper . search ( '.apiMethodPage__argumentGroup' )
109- groups = groups . map do |group |
110- # "At least one of" or "One of"
111- requirement = group . search ( '.apiMethodPage__argument em' ) . text
112- mutually_exclusive = requirement . downcase == 'one of'
113-
114- desc = group . search ( '.apiMethodPage__argumentGroupDesc p' )
115- . text
116- . tap { |t | t . slice! ( "\n " ) }
117- . tap { |t | t << '.' unless t . end_with? ( '.' ) }
118- . gsub ( '’' , "'" )
119-
120- rows = group . search ( '.apiMethodPage__argumentRow' )
121- names = rows . map do |row |
122- row . search ( '.apiMethodPage__argument code' ) . text
123- end
124-
125- {
126- 'args' => names ,
127- 'desc' => desc ,
128- 'mutually_exclusive' => mutually_exclusive
129- }
130- end
108+ def parse_arg_groups ( _api_page , _method_data = { } )
109+ groups = { }
110+
111+ # # Look for groups of args that are interdependent
112+ # groups = args_wrapper.search('.apiMethodPage__argumentGroup')
113+ # groups = groups.map do |group|
114+ # # "At least one of" or "One of"
115+ # requirement = group.search('.apiMethodPage__argument em').text
116+ # mutually_exclusive = requirement.downcase == 'one of'
117+
118+ # desc = group.search('.apiMethodPage__argumentGroupDesc p')
119+ # .text
120+ # .tap { |t| t&.slice!("\n") }
121+ # .tap { |t| t << '.' unless t.end_with?('.') }
122+ # .gsub('’', "'")
123+
124+ # rows = group.search('.apiMethodPage__argumentRow')
125+ # names = rows.map do |row|
126+ # row.search('.apiMethodPage__argument code').text
127+ # end
128+
129+ # {
130+ # 'args' => names,
131+ # 'desc' => desc,
132+ # 'mutually_exclusive' => mutually_exclusive
133+ # }
134+ # end
131135
132136 groups unless groups . empty?
133137 end
134138
135- def massage_type ( name , detected , default_data = { } )
139+ def massage_type ( name , arg , data = { } )
140+ return 'enum' if arg . key? ( 'enum' )
141+
136142 case name
137143 when 'date' then 'date'
138144 when 'latest' , 'oldest' , 'ts' then 'timestamp'
139145 when 'file' then 'file'
140146 when 'bot' , 'user' then 'user'
141147 when 'channel'
142- case default_data [ :method_group ]
148+ case data [ :method_group ]
143149 when 'im' then 'im'
144150 when 'mpim' then 'mpim'
145151 when 'groups' then 'group'
146152 else 'channel'
147153 end
148154 else
149- case detected
155+ case detected = arg [ 'type' ]
150156 when '' , 'null' then nil
151157 else detected
152158 end
153159 end
154160 end
155161
156- def parse_response ( api_page , default_data = { } )
157- response_wrapper = ensure! ( api_page , '.apiReference__response' , default_data [ :method_name ] )
158- responses = response_wrapper . search ( '.apiReference__example' )
162+ def parse_response ( _api_page , data = { } )
159163 examples = [ ]
160- responses . each do |response |
161- response . search ( 'pre' ) . each do |pre |
162- text = pre . text . strip
163- next unless text =~ /^\{ .*}$/m
164-
165- examples . push ( text )
166- end
164+ data [ 'examples' ] &.each_pair do |_example_type , response |
165+ example = JSON . pretty_generate ( response [ 'example' ] , indent : ' ' )
166+ example . gsub! ( /\{ \n \s *\} / , '{}' )
167+ example . gsub! ( /\[ \n \s *\] / , '[]' )
168+ examples . push example
167169 end
168170 { 'examples' => examples }
169171 end
170172
171- def parse_errors ( api_page , default_data = { } )
172- errors_wrapper = ensure! ( api_page , '.apiReference__errors' , default_data [ :method_name ] )
173- rows = errors_wrapper . search ( '.apiDocsTable tr' )
173+ def parse_errors ( _api_page , data = { } )
174174 errors = { }
175- rows . each do |row |
176- next if row . search ( 'th' ) . any?
177-
178- name = row . search ( '[data-label=Error]' ) . text
179- desc = row . search ( '[data-label=Description]' ) . text
180- . tap { |t | t . slice! ( "\n " ) }
181- . tap { |t | t << '.' unless t . end_with? ( '.' ) }
182-
183- errors [ name ] = desc
175+ data [ 'errors' ] &.each_pair do |name , desc |
176+ errors [ name ] = desc [ 'desc' ]
184177 end
185178 errors
186179 end
0 commit comments