Skip to content

Commit 3157392

Browse files
committed
Fix: crawn the new docusaurus site.
1 parent 632f481 commit 3157392

File tree

6 files changed

+177
-87
lines changed

6 files changed

+177
-87
lines changed

Rakefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ require 'fileutils'
99

1010
Bundler.setup :default, :development
1111

12+
load 'tasks/download.rake'
1213
load 'tasks/update.rake'

tasks/download.rake

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# frozen_string_literal: true
2+
3+
require_relative 'lib/docs/downloader'
4+
5+
namespace :api do
6+
namespace :ref do
7+
desc 'Download JSON reference.'
8+
task :download do
9+
Rake::Task['api:ref:clean_files'].invoke('docs.slack.dev')
10+
downloader = SlackApi::Docs::Downloader.new
11+
downloader.download!
12+
puts "\nFinished downloading reference."
13+
end
14+
15+
desc 'Delete all generated files except undocumented ones.'
16+
task :clean_files, :dirs do |_t, args|
17+
files = Dir["./{#{Array(args[:dirs]).join(',')}}/*"].grep_v(%r{/undocumented\b})
18+
FileUtils.rm_rf files
19+
end
20+
end
21+
end

tasks/lib/docs/downloader.rb

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
module SlackApi
2+
module Docs
3+
class Downloader
4+
def target_path
5+
@target_path ||= File.expand_path('../../../docs.slack.dev', __dir__)
6+
end
7+
8+
def events_dir
9+
File.join(target_path, 'events')
10+
end
11+
12+
def events_path
13+
File.join(events_dir, 'events.json')
14+
end
15+
16+
def methods_dir
17+
File.join(target_path, 'methods')
18+
end
19+
20+
def methods_path
21+
File.join(methods_dir, 'methods.json')
22+
end
23+
24+
def events_url
25+
'https://docs.slack.dev/reference/events.json'
26+
end
27+
28+
def methods_url
29+
'https://docs.slack.dev/reference/methods.json'
30+
end
31+
32+
def method_url(method)
33+
"https://docs.slack.dev/reference/methods/#{method}.json"
34+
end
35+
36+
def method_target_path(method_name)
37+
File.join(methods_dir, "#{method_name}.json")
38+
end
39+
40+
def download!
41+
download_methods!
42+
download_events!
43+
end
44+
45+
def download_methods!
46+
puts "#{methods_url} => #{methods_path}"
47+
FileUtils.mkdir_p(methods_dir)
48+
URI.open(methods_url) do |file|
49+
json = JSON.parse(file.read)
50+
File.write(methods_path, JSON.pretty_generate(json))
51+
json.each do |method|
52+
method_name = method['name']
53+
method_url = method_url(method_name)
54+
method_target_path = method_target_path(method_name)
55+
puts "#{method_url} => #{method_target_path}"
56+
URI.open(method_url) do |method_file|
57+
method_json = JSON.parse(method_file.read)
58+
File.write(method_target_path, JSON.pretty_generate(method_json))
59+
end
60+
end
61+
end
62+
end
63+
64+
def download_events!
65+
puts "#{events_url} => #{events_path}"
66+
URI.open(events_url) do |file|
67+
json = JSON.parse(file.read)
68+
FileUtils.mkdir_p(events_dir)
69+
File.write(events_path, JSON.pretty_generate(json))
70+
end
71+
end
72+
end
73+
end
74+
end

tasks/lib/slack_api/events_spider.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def process_list(page, _default_data = {})
1515
data['items'].each do |event|
1616
next unless event['isPublic']
1717
next if event['isDeprecated']
18-
next unless event['groups'].include?('RTM')
18+
next unless event['groups']&.include?('RTM')
1919

2020
handle resolve_url(event['link'], page),
2121
:process_event,

tasks/lib/slack_api/methods_spider.rb

Lines changed: 79 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -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

tasks/update.rake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ namespace :api do
7474

7575
desc 'Update scraped Slack events and Web API methods.'
7676
task :update do
77+
# Rake::Task['api:ref:download'].invoke
7778
Rake::Task['api:methods:update'].invoke
7879
Rake::Task['api:events:update'].invoke
7980
Rake::Task['api:delete_undocumented'].invoke

0 commit comments

Comments
 (0)