History

cleanup the code

Chaitanya Rahalkar committed 1 year ago

Commit b2188361 parent b7393f41 file · +180 −185Browse files

Unified · Split

lib/docs/filters/threejs/clean_html.rb+180−185
@@ -1,243 +1,238 @@
11 module Docs
22 class Threejs
33 class CleanHtmlFilter < Filter
4+ PATTERNS = {
5+ method_this: /\[method:this\s+([^\]]+)\]\s*\((.*?)\)/,
6+ method_return: /\[method:([^\s\]]+)\s+([^\]]+)\]\s*\((.*?)\)/,
7+ method_no_params: /\[method:([^\s\]]+)\s+([^\]]+)\](?!\()/,
8+ property: /\[property:([^\]]+?)\s+([^\]]+?)\]/,
9+ example_link: /\[example:([^\s\]]+)\s+([^\]]+)\]/,
10+ external_link_text: /\[link:([^\s\]]+)\s+([^\]]+)\]/,
11+ external_link: /\[link:([^\]]+)\]/,
12+ page_link_text: /\[page:([^\]]+?)\s+([^\]]+?)\]/,
13+ page_link: /\[page:([^\]]+?)\]/,
14+ inline_code: /`([^`]+)`/,
15+ name_placeholder: /\[name\]/,
16+ constructor_param: /\[param:([^\]]+?)\s+([^\]]+?)\]/
17+ }.freeze
18+
419 def call
5− # Remove unnecessary elements
20+ remove_unnecessary_elements
21+ wrap_code_blocks
22+ process_sections
23+ format_links
24+ add_section_structure
25+ format_notes
26+ add_heading_attributes
27+ doc
28+ end
29+
30+ private
31+
32+ def remove_unnecessary_elements
633 css('head, script, style').remove
7−
8− # Wrap code blocks with pre tags and add syntax highlighting
34+ end
35+
36+ def wrap_code_blocks
937 css('code').each do |node|
10− unless node.parent.name == 'pre'
11− pre = node.wrap('<pre>')
12− pre['data-language'] = 'javascript'
13− pre['class'] = 'language-javascript'
14− end
38+ next if node.parent.name == 'pre'
39+ pre = node.wrap('<pre>')
40+ pre['data-language'] = pre['class'] = 'language-javascript'
1541 end
16−
42+ end
43+
44+ def process_sections
1745 # Handle source links
1846 css('h2').each do |node|
19− if node.content.strip == 'Source'
20− content = node.next_element&.inner_html
21− if content
22− # Clean up any existing formatting
23− content = content.gsub(/<[^>]+>/, '')
24− # Extract the path from the content
25− if content =~ /src\/(.*?)\.js/
26− path = "/#{$1}.js"
27− formatted_link = %Q(<a class="reference external" href="https://github.com/mrdoob/three.js/blob/master/src#{path}">src#{path}</a>)
28− node.next_element.inner_html = formatted_link if node.next_element
29− end
30− end
31− end
47+ next unless node.content.strip == 'Source'
48+ handle_source_link(node)
3249 end
3350
34− # Handle method signatures
51+ # Handle method signatures and properties
3552 css('h3').each do |node|
3653 content = node.inner_html
37−
38− # Handle [method:this methodName]( param1, param2, ... ) format
39− content = content.gsub(/\[method:this\s+([^\]]+)\]\s*\((.*?)\)/) do |match|
40− method_name, params_str = $1, $2
41−
42− # Format parameters
43− params = params_str.split(',').map do |param|
44− param = param.strip
45− if param.include?(' ')
46− type, name = param.split(' ', 2).map(&:strip)
47− "<span class='sig-param'><span class='sig-type'>#{type}</span> <span class='sig-name'>#{name}</span></span>"
48− else
49− "<span class='sig-param'>#{param}</span>"
50− end
51− end.join("<span class='sig-paren'>, </span>")
52−
53− "<dt class='sig sig-object js' id='#{method_name}'>" \
54− "<span class='property'><span class='pre'>this</span></span>." \
55− "<span class='sig-name descname'>#{method_name}</span>" \
56− "<span class='sig-paren'>(</span>" \
57− "#{params}" \
58− "<span class='sig-paren'>)</span></dt>"
59− end
60−
61− # Handle [method:returnType methodName]( param1, param2, ... ) format
62− content = content.gsub(/\[method:([^\s\]]+)\s+([^\]]+)\]\s*\((.*?)\)/) do |match|
63− return_type, method_name, params_str = $1, $2, $3
64− next if method_name.start_with?('this') # Skip if already handled above
65−
66− # Format parameters
67− params = params_str.split(',').map do |param|
68− param = param.strip
69− if param.include?(' ')
70− type, name = param.split(' ', 2).map(&:strip)
71− "<span class='sig-param'><span class='sig-type'>#{type}</span> <span class='sig-name'>#{name}</span></span>"
72− else
73− "<span class='sig-param'>#{param}</span>"
74− end
75− end.join("<span class='sig-paren'>, </span>")
76−
77− "<dt class='sig sig-object js' id='#{method_name}'>" \
78− "<span class='sig-name descname'>#{method_name}</span>" \
79− "<span class='sig-paren'>(</span>" \
80− "#{params}" \
81− "<span class='sig-paren'>)</span>" \
82− "<span class='sig-returns'><span class='sig-colon'>:</span> " \
83− "<span class='sig-type'>#{return_type}</span></span></dt>"
84− end
85−
86− # Handle [method:returnType methodName] format (no parameters)
87− content = content.gsub(/\[method:([^\s\]]+)\s+([^\]]+)\](?!\()/) do |match|
88− return_type, method_name = $1, $2
89− "<dt class='sig sig-object js' id='#{method_name}'>" \
90− "<span class='sig-name descname'>#{method_name}</span>" \
91− "<span class='sig-paren'>(</span>" \
92− "<span class='sig-paren'>)</span>" \
93− "<span class='sig-returns'><span class='sig-colon'>:</span> " \
94− "<span class='sig-type'>#{return_type}</span></span></dt>"
95− end
96−
54+ content = handle_method_signatures(content)
55+ content = handle_properties(content)
9756 node.inner_html = content
9857 end
9958
100− # Handle [name] placeholders in headers and constructor
59+ # Handle name placeholders and constructor params
10160 css('h1, h3').each do |node|
10261 content = node.inner_html
103−
104− # Replace [name] with class name
105− content = content.gsub(/\[name\]/) do
106− name = slug.split('/').last.gsub('.html', '')
107− "<span class='descname'>#{name}</span>"
108− end
109−
110− # Format constructor parameters
111− content = content.gsub(/\[param:([^\]]+?)\s+([^\]]+?)\]/) do |match|
112− type, name = $1, $2
113− "<span class='sig-param'><span class='sig-type'>#{type}</span> <code class='sig-name'>#{name}</code></span>"
114− end
115−
62+ content = handle_name_placeholders(content)
63+ content = format_constructor_params(content)
11664 node.inner_html = content
11765 end
66+ end
11867
119− # Clean up property formatting
120− css('h3').each do |node|
121− node.inner_html = node.inner_html.gsub(/\[property:([^\]]+?)\s+([^\]]+?)\]/) do |match|
122− type, name = $1, $2
123− "<dt class='sig sig-object js'>" \
124− "<span class='sig-name descname'>#{name}</span>" \
125− "<span class='sig-colon'>:</span> " \
126− "<span class='sig-type'>#{type}</span></dt>"
68+ def handle_source_link(node)
69+ content = node.next_element&.inner_html
70+ return unless content
71+ content = content.gsub(/<[^>]+>/, '')
72+ if content =~ /src\/(.*?)\.js/
73+ path = "/#{$1}.js"
74+ formatted_link = %Q(<a class="reference external" href="https://github.com/mrdoob/three.js/blob/master/src#{path}">src#{path}</a>)
75+ node.next_element.inner_html = formatted_link if node.next_element
76+ end
77+ end
78+
79+ def handle_method_signatures(content)
80+ content
81+ .gsub(PATTERNS[:method_this]) { format_method_signature('this', $1, $2) }
82+ .gsub(PATTERNS[:method_return]) do |match|
83+ next if $2.start_with?('this')
84+ format_method_signature($1, $2, $3, true)
12785 end
86+ .gsub(PATTERNS[:method_no_params]) { format_method_signature($1, $2, nil, true) }
87+ end
88+
89+ def format_method_signature(type_or_this, name, params_str, with_return = false)
90+ params = if params_str
91+ params_str.split(',').map { |param| format_parameter(param.strip) }.join("<span class='sig-paren'>, </span>")
12892 end
12993
130− # Clean up external links
94+ html = "<dt class='sig sig-object js' id='#{name}'>"
95+ if type_or_this == 'this'
96+ html << "<span class='property'><span class='pre'>this</span></span>."
97+ end
98+ html << "<span class='sig-name descname'>#{name}</span>" \
99+ "<span class='sig-paren'>(</span>" \
100+ "#{params}" \
101+ "<span class='sig-paren'>)</span>"
102+ if with_return
103+ html << "<span class='sig-returns'><span class='sig-colon'>:</span> " \
104+ "<span class='sig-type'>#{type_or_this}</span></span>"
105+ end
106+ html << "</dt>"
107+ end
108+
109+ def format_parameter(param)
110+ if param.include?(' ')
111+ type, name = param.split(' ', 2).map(&:strip)
112+ "<span class='sig-param'><span class='sig-type'>#{type}</span> <span class='sig-name'>#{name}</span></span>"
113+ else
114+ "<span class='sig-param'>#{param}</span>"
115+ end
116+ end
117+
118+ def handle_properties(content)
119+ content.gsub(PATTERNS[:property]) do |match|
120+ type, name = $1, $2
121+ "<dt class='sig sig-object js'>" \
122+ "<span class='sig-name descname'>#{name}</span>" \
123+ "<span class='sig-colon'>:</span> " \
124+ "<span class='sig-type'>#{type}</span></dt>"
125+ end
126+ end
127+
128+ def handle_name_placeholders(content)
129+ content.gsub(PATTERNS[:name_placeholder]) do
130+ name = slug.split('/').last.gsub('.html', '')
131+ "<span class='descname'>#{name}</span>"
132+ end
133+ end
134+
135+ def format_constructor_params(content)
136+ content.gsub(PATTERNS[:constructor_param]) do |match|
137+ type, name = $1, $2
138+ "<span class='sig-param'><span class='sig-type'>#{type}</span> <code class='sig-name'>#{name}</code></span>"
139+ end
140+ end
141+
142+ def format_links
131143 css('*').each do |node|
132144 next if node.text?
133145
134− # Handle example links [example:tag Title]
135− node.inner_html = node.inner_html.gsub(/\[example:([^\s\]]+)\s+([^\]]+)\]/) do |match|
136− tag, title = $1, $2
137− "<a class='reference external' href='https://threejs.org/examples/##{tag}'>#{title}</a>"
138− end
139−
140− # Handle external links with [link:url text] format
141− node.inner_html = node.inner_html.gsub(/\[link:([^\s\]]+)\s+([^\]]+)\]/) do |match|
142− url, text = $1, $2
143− "<a class='reference external' href='#{url}'>#{text}</a>"
144− end
146+ content = node.inner_html
147+ .gsub(PATTERNS[:example_link]) { create_external_link("https://threejs.org/examples/##{$1}", $2) }
148+ .gsub(PATTERNS[:external_link_text]) { create_external_link($1, $2) }
149+ .gsub(PATTERNS[:external_link]) { create_external_link($1, $1) }
150+ .gsub(PATTERNS[:page_link_text]) { create_internal_link($1, $2) }
151+ .gsub(PATTERNS[:page_link]) { create_internal_link($1, $1) }
152+
153+ node.inner_html = content
154+ end
145155
146− # Handle external links with [link:url] format
147− node.inner_html = node.inner_html.gsub(/\[link:([^\]]+)\]/) do |match|
148− url = $1
149− "<a class='reference external' href='#{url}'>#{url}</a>"
150− end
156+ normalize_href_attributes
157+ end
151158
152− # Handle internal page links with text
153− node.inner_html = node.inner_html.gsub(/\[page:([^\]]+?)\s+([^\]]+?)\]/) do
154− path, text = $1, $2
155− "<a class='reference internal' href='#{path.downcase}'><code class='xref js js-#{path.downcase}'>#{text}</code></a>"
156− end
159+ def create_external_link(url, text)
160+ %Q(<a class='reference external' href='#{url}'>#{text}</a>)
161+ end
157162
158− # Handle internal page links without text
159− node.inner_html = node.inner_html.gsub(/\[page:([^\]]+?)\]/) do |match|
160− path = $1
161− "<a class='reference internal' href='#{path.downcase}'><code class='xref js js-#{path.downcase}'>#{path}</code></a>"
162− end
163− end
163+ def create_internal_link(path, text)
164+ %Q(<a class='reference internal' href='#{path.downcase}'><code class='xref js js-#{path.downcase}'>#{text}</code></a>)
165+ end
164166
165− # Fix all href attributes to be lowercase and remove .html
167+ def normalize_href_attributes
166168 css('a[href]').each do |link|
167169 next if link['href'].start_with?('http')
168170 link['href'] = link['href'].remove('../').downcase.sub(/\.html$/, '')
169171 link['class'] = 'reference internal'
170172 end
173+ end
171174
172− # Add section classes
175+ def add_section_structure
173176 css('h2').each do |node|
174177 node['class'] = 'section-title'
175178 section = node.next_element
176− if section
177− wrapper = doc.document.create_element('div')
178− wrapper['class'] = 'section'
179− node.after(wrapper)
180− wrapper.add_child(node)
181− current = section
182− while current && current.name != 'h2'
183− next_el = current.next
184− wrapper.add_child(current)
185− current = next_el
186− end
179+ next unless section
180+
181+ wrapper = doc.document.create_element('div')
182+ wrapper['class'] = 'section'
183+ node.after(wrapper)
184+ wrapper.add_child(node)
185+
186+ current = section
187+ while current && current.name != 'h2'
188+ next_el = current.next
189+ wrapper.add_child(current)
190+ current = next_el
187191 end
188192 end
189193
190− # Format description paragraphs
191− css('p.desc').each do |node|
192− node['class'] = 'section-desc'
193− end
194+ css('p.desc').each { |node| node['class'] = 'section-desc' }
195+ end
194196
195− # Handle inline code/backticks in text
196− css('p, li, dt, dd').each do |node|
197− next if node.at_css('pre') # Skip if contains a code block
197+ def format_notes
198+ css('p').each do |node|
199+ next unless node.content.start_with?('Note:')
198200
199− # Replace backticks with proper code formatting
200− node.inner_html = node.inner_html.gsub(/`([^`]+)`/) do |match|
201− code = $1
202− "<code class='docutils literal notranslate'><span class='pre'>#{code}</span></code>"
203− end
201+ wrapper = doc.document.create_element('div')
202+ wrapper['class'] = 'admonition note'
203+
204+ title = doc.document.create_element('p')
205+ title['class'] = 'first admonition-title'
206+ title.content = 'Note'
207+
208+ content = doc.document.create_element('p')
209+ content['class'] = 'last'
210+ content.inner_html = node.inner_html.sub('Note:', '').strip
211+
212+ wrapper.add_child(title)
213+ wrapper.add_child(content)
214+ node.replace(wrapper)
204215 end
216+ end
205217
206− # Handle inline code in property descriptions
207− css('.property-type').each do |node|
208− node.inner_html = node.inner_html.gsub(/`([^`]+)`/) do |match|
209− code = $1
210− "<code class='docutils literal notranslate'><span class='pre'>#{code}</span></code>"
211− end
212− end
213−
214− # Add proper heading IDs and classes
218+ def add_heading_attributes
215219 css('h1, h2, h3, h4').each do |node|
216220 node['id'] ||= node.content.strip.downcase.gsub(/[^\w]+/, '-')
217221 existing_class = node['class'].to_s
218222 node['class'] = "#{existing_class} section-header"
219223 end
220224
221− # Add note styling
222− css('p').each do |node|
223− if node.content.start_with?('Note:')
224− wrapper = doc.document.create_element('div')
225− wrapper['class'] = 'admonition note'
226−
227− title = doc.document.create_element('p')
228− title['class'] = 'first admonition-title'
229− title.content = 'Note'
230−
231− content = doc.document.create_element('p')
232− content['class'] = 'last'
233− content.inner_html = node.inner_html.sub('Note:', '').strip
234−
235− wrapper.add_child(title)
236− wrapper.add_child(content)
237− node.replace(wrapper)
225+ format_inline_code
226+ end
227+
228+ def format_inline_code
229+ selectors = ['p', 'li', 'dt', 'dd', '.property-type'].join(', ')
230+ css(selectors).each do |node|
231+ next if node.at_css('pre')
232+ node.inner_html = node.inner_html.gsub(PATTERNS[:inline_code]) do |match|
233+ "<code class='docutils literal notranslate'><span class='pre'>#{$1}</span></code>"
238234 end
239235 end
240− doc
241236 end
242237 end
243238 end