@@ -83,54 +83,54 @@ def self.generate_help_content(site)
8383
8484 output_dir = File . join ( site . source , "_src" )
8585 FileUtils . mkdir_p ( output_dir ) unless Dir . exist? ( output_dir )
86-
86+
8787 output_file = File . join ( output_dir , "helpContentMap.tsx" )
8888
8989 help_content_tree = generate_help_content_tree ( )
9090
9191 help_content_string = to_ts_object ( help_content_tree )
9292
9393 components = analyze_used_components ( help_content_string )
94-
94+
9595 # Generate the import block
9696 import_block = generate_imports ( components )
9797
9898 ts_output = generate_ts_output ( import_block , help_content_string )
99-
99+
100100 File . write ( output_file , ts_output )
101101
102102 puts "✅ Successfully generated helpContent.tsx"
103103 end
104104
105- def self . analyze_used_components ( content )
106- components = {
107- 'View' => content . include? ( '<View' ) ,
108- 'Text' => content . include? ( '<Text' ) ,
109- 'TextLink' => content . include? ( '<TextLink' ) ,
110- 'BulletList' => content . include? ( '<BulletList' )
111- }
112- components . select { |_ , used | used } . keys
105+ def self . analyze_used_components ( content )
106+ components = {
107+ 'View' => content . include? ( '<View' ) ,
108+ 'Text' => content . include? ( '<Text' ) ,
109+ 'TextLink' => content . include? ( '<TextLink' ) ,
110+ 'BulletList' => content . include? ( '<BulletList' )
111+ }
112+ components . select { |_ , used | used } . keys
113113 end
114114
115- def self . generate_imports ( components )
116- base_imports = [
117- "import type {ReactNode} from 'react';" ,
118- "import React from 'react';" ,
119- ]
120-
121- # Always include React Native
122- base_imports << "import {#{ ( [ 'View' ] & components ) . join ( ', ' ) } } from 'react-native';"
123-
124- # Add component-specific imports
125- component_imports = [ ]
126- component_imports << "import BulletList from '@components/SidePanel/HelpComponents/HelpBulletList';" if components . include? ( 'BulletList' )
127- component_imports << "import Text from '@components/Text';" if components . include? ( 'Text' )
128- component_imports << "import TextLink from '@components/TextLink';" if components . include? ( 'TextLink' )
129-
130- # Add style imports
131- base_imports << "import type {ThemeStyles} from '@styles/index';"
132-
133- ( base_imports + component_imports ) . join ( "\n " )
115+ def self . generate_imports ( components )
116+ base_imports = [
117+ "import type {ReactNode} from 'react';" ,
118+ "import React from 'react';" ,
119+ ]
120+
121+ # Always include React Native
122+ base_imports << "import {#{ ( [ 'View' ] & components ) . join ( ', ' ) } } from 'react-native';"
123+
124+ # Add component-specific imports
125+ component_imports = [ ]
126+ component_imports << "import BulletList from '@components/SidePanel/HelpComponents/HelpBulletList';" if components . include? ( 'BulletList' )
127+ component_imports << "import Text from '@components/Text';" if components . include? ( 'Text' )
128+ component_imports << "import TextLink from '@components/TextLink';" if components . include? ( 'TextLink' )
129+
130+ # Add style imports
131+ base_imports << "import type {ThemeStyles} from '@styles/index';"
132+
133+ ( base_imports + component_imports ) . join ( "\n " )
134134 end
135135
136136 def self . generate_ts_output ( import_block , help_content_string )
@@ -158,41 +158,42 @@ def self.generate_ts_output(import_block, help_content_string)
158158 export type {ContentComponent};
159159 TS
160160 end
161-
161+
162162 def self . generate_help_content_tree ( )
163163 tree = { }
164-
164+
165165 @help_mapping . each do |route , node |
166166 parts = route . sub ( /^ref\/ / , '' ) . sub ( /\. md$/ , '' ) . split ( '/' )
167167 current = tree
168-
168+
169169 parts . each_with_index do |part , i |
170170 is_dynamic = part . start_with? ( ':' ) || part . match? ( /^\[ .*\] $/ )
171- part_key = is_dynamic ? part : part . to_sym
172-
171+ contains_dash = part . include? ( '-' )
172+ part_key = ( is_dynamic || contains_dash ) ? part : part . to_sym
173+
173174 current [ :children ] ||= { }
174175 current [ :children ] [ part_key ] ||= { }
175-
176+
176177 if i == parts . length - 1
177178 jsx_content = html_node_to_RN ( node , 1 ) . rstrip
178-
179+
179180 current [ :children ] [ part_key ] [ :content ] = <<~TS . chomp
180181 ({styles}: {styles: ThemeStyles}) => (
181182 #{ jsx_content }
182183 )
183184 TS
184185 end
185-
186+
186187 current = current [ :children ] [ part_key ]
187188 end
188189 end
189-
190+
190191 tree [ :content ] = <<~JSX
191192 () => null
192193 JSX
193194 tree
194195 end
195-
196+
196197 def self . html_node_to_RN ( node , indent_level = 0 )
197198 node_processors = {
198199 'div' => method ( :process_div ) ,
@@ -227,26 +228,26 @@ def self.process_div(node, indent_level)
227228 next if child . text? && child . text . strip . empty?
228229 html_node_to_RN ( child , indent_level + 1 )
229230 end . compact . join ( "\n " )
230-
231+
231232 "#{ ' ' * indent_level } <View>\n #{ children } \n #{ ' ' * indent_level } </View>"
232233 end
233234
234235 def self . process_heading ( node , indent_level )
235- return "#{ ' ' * indent_level } <Text style={[styles.textHeadline#{ node . name . upcase } , styles.mv4]}>#{ node . text . strip } </Text>"
236+ return "#{ ' ' * indent_level } <Text style={[styles.textHeadline#{ node . name . upcase } , styles.mv4]}>#{ CGI . escapeHTML ( node . text ) . strip } </Text>"
236237 end
237238
238239 def self . process_unordered_list ( node , indent_level )
239240 items = node . xpath ( './li' ) . map do |li |
240241 contains_ul = li . xpath ( './/ul' ) . any?
241242
242243 li_parts = li . children . map { |child | html_node_to_RN ( child , 0 ) }
243-
244+
244245 if contains_ul
245246
246247 indented_li_parts = li_parts . map do |part |
247248 part . lines . map { |line | "#{ ' ' * ( indent_level + 3 ) } #{ line . rstrip } " } . join ( "\n " )
248249 end . join ( "\n " )
249-
250+
250251 "#{ ' ' * ( indent_level + 2 ) } <>\n #{ indented_li_parts } \n #{ ' ' * ( indent_level + 2 ) } </>"
251252 else
252253 "#{ ' ' * ( indent_level + 2 ) } <Text style={styles.textNormal}>#{ li_parts . join } </Text>"
@@ -269,20 +270,20 @@ def self.process_list_item(node, indent_level)
269270
270271 def self . process_paragraph ( node , indent_level )
271272 inner = node . children . map { |c | html_node_to_RN ( c , indent_level + 1 ) } . join
272-
273+
273274 style_classes = [ 'styles.textNormal' ]
274275 style_classes << 'styles.mt4' if node . previous_element &.name == 'ul'
275276 style_classes << 'styles.mb4' if node . next_element &.name == 'p'
276-
277+
277278 "#{ ' ' * indent_level } <Text style={[#{ style_classes . join ( ', ' ) } ]}>#{ inner . strip } </Text>"
278279 end
279280
280281 def self . process_bold ( node , indent_level )
281- "<Text style={styles.textBold}>#{ node . text } </Text>"
282+ "<Text style={styles.textBold}>#{ CGI . escapeHTML ( node . text ) } </Text>"
282283 end
283284
284285 def self . process_italic ( node , indent_level )
285- "<Text style={styles.textItalic}>#{ node . text } </Text>"
286+ "<Text style={styles.textItalic}>#{ CGI . escapeHTML ( node . text ) } </Text>"
286287 end
287288
288289 def self . process_link ( node , indent_level )
@@ -292,7 +293,7 @@ def self.process_link(node, indent_level)
292293 end
293294
294295 def self . process_text ( node , indent_level )
295- node . text
296+ CGI . escapeHTML ( node . text )
296297 end
297298
298299 def self . process_default ( node , indent_level )
@@ -311,16 +312,16 @@ def self.to_ts_object(obj, indent = 0)
311312 if obj . is_a? ( Array )
312313 items = obj . map { |item | to_ts_object ( item , indent + 1 ) }
313314 return "[]" if items . empty?
314-
315- return "[\n " +
316- items . map { |item | "#{ spacing } #{ item } " } . join ( ",\n " ) +
315+
316+ return "[\n " +
317+ items . map { |item | "#{ spacing } #{ item } " } . join ( ",\n " ) +
317318 "\n #{ spacing } ]"
318319 end
319-
320+
320321 obj . each do |key , value |
321322 key_str = key . is_a? ( Symbol ) ? key . to_s : key . inspect
322323 key_line_prefix = ' ' * ( indent + 1 ) + "#{ key_str } : "
323-
324+
324325 if value . is_a? ( Hash ) || value . is_a? ( Array )
325326 nested = to_ts_object ( value , indent + 1 )
326327 lines << key_line_prefix + nested + ","
@@ -333,11 +334,11 @@ def self.to_ts_object(obj, indent = 0)
333334 lines << key_line_prefix + value . inspect + ","
334335 end
335336 end
336-
337+
337338 lines << ' ' * indent + "}"
338339 lines . join ( "\n " )
339340 end
340-
341+
341342 end
342343end
343344
0 commit comments