@@ -4,88 +4,115 @@ defmodule Mix.Tasks.Lvn.Swiftui.Gen.Docs do
44 use Mix.Task
55 require Logger
66
7- # Using a temporary folder outside of the project avoids ElixirLS file watching issues
8- defp temp_doc_folder , do: Path . join ( System . tmp_dir! ( ) , "temp_swiftui_docs" )
9- defp generate_swift_lvn_docs_command , do: ~c" xcodebuild docbuild -scheme LiveViewNative -destination generic/platform=iOS -derivedDataPath #{ temp_doc_folder ( ) } -skipMacroValidation -skipPackagePluginValidation"
7+ defp generate_swift_lvn_docs_command ( doc_path ) , do: ~c" xcrun xcodebuild docbuild -scheme LiveViewNative -destination generic/platform=iOS -derivedDataPath #{ doc_path } -skipMacroValidation -skipPackagePluginValidation"
108 @ swiftui_interface_path "Platforms/XROS.platform/Developer/SDKs/XROS.sdk/System/Library/Frameworks/SwiftUI.framework/Modules/SwiftUI.swiftmodule/arm64-apple-xros.swiftinterface"
119 defp generate_modifier_documentation_extensions ( xcode_path ) , do: ~c( xcrun swift run ModifierGenerator documentation-extensions --interface "#{ Path . join ( xcode_path , @ swiftui_interface_path ) } " --output Sources/LiveViewNative/LiveViewNative.docc/DocumentationExtensions)
1210 @ generate_documentation_extensions ~c( xcrun swift package plugin --allow-writing-to-package-directory generate-documentation-extensions)
1311 defp modifier_list ( xcode_path ) , do: ~s( xcrun swift run ModifierGenerator list --interface "#{ Path . join ( xcode_path , @ swiftui_interface_path ) } " --modifier-search-path Sources/LiveViewNative/Stylesheets/Modifiers)
1412 @ xcode_select_print_path ~c( xcode-select --print-path)
1513 @ allow_writing_to_package_dir_command ~c" xcrun swift package plugin --allow-writing-to-package-directory generate-documentation-extensions"
1614 @ doc_folder "generated_docs"
17- @ cheatsheet_path "#{ @ doc_folder } /view-index.cheatmd "
15+ @ cheatsheet_path "#{ @ doc_folder } /view-index.md "
1816 @ modifier_cheatsheet_path "#{ @ doc_folder } /modifier-index.md"
1917
2018 @ shortdoc "Generates ex doc files for all SwiftUI views"
21- def run ( _ ) do
19+ def run ( args ) do
20+ { kwargs , [ ] , [ ] } = OptionParser . parse ( args , strict: [ doc_path: :string , no_generate_docc: :boolean ] )
21+
22+ # Using a temporary folder outside of the project avoids ElixirLS file watching issues
23+ doc_path = Keyword . get ( kwargs , :doc_path , Path . join ( System . tmp_dir! ( ) , "temp_swiftui_docs" ) )
24+ |> Path . absname ( )
25+
2226 Logger . info ( "Locating Xcode installation" )
2327 xcode_path = :os . cmd ( @ xcode_select_print_path ) |> to_string ( ) |> String . trim ( )
2428
25- Logger . info ( "Enabling writing to package..." )
26- :os . cmd ( @ allow_writing_to_package_dir_command )
29+ if not Keyword . get ( kwargs , :no_generate_docc , false ) do
30+ Logger . info ( "Enabling writing to package..." )
31+ :os . cmd ( @ allow_writing_to_package_dir_command )
32+
33+ Logger . info ( "Generating documentation extensions" )
34+ :os . cmd ( @ generate_documentation_extensions )
2735
28- Logger . info ( "Generating documentation extensions" )
29- :os . cmd ( @ generate_documentation_extensions )
30- Logger . info ( "Generating modifier documentation extensions" )
31- :os . cmd ( generate_modifier_documentation_extensions ( xcode_path ) )
36+ Logger . info ( "Generating modifier documentation extensions" )
37+ :os . cmd ( generate_modifier_documentation_extensions ( xcode_path ) )
3238
33- Logger . info ( "Generating SwiftUI documentation files..." )
34- :os . cmd ( generate_swift_lvn_docs_command ( ) )
39+ Logger . info ( "Generating SwiftUI documentation files..." )
40+ :os . cmd ( generate_swift_lvn_docs_command ( doc_path ) )
41+ end
3542
3643 Logger . info ( "Generating LiveView Native documentation files..." )
3744 # Ensure generated_docs folder exists
3845 File . mkdir ( "generated_docs" )
3946
40- # clear cheatsheet
41- File . write! ( @ cheatsheet_path , "# View Index\n " )
42-
4347 # generate documentation and cheatsheat
44- for { category , views } <- categorized_views ( ) do
45- # build cheatsheet sections
46- File . write! ( @ cheatsheet_path , "## #{ category } \n {: .col-2}\n " , [ :append ] )
47-
48- for view <- views do
49- with { :ok , data } <-
50- File . read (
51- "#{ temp_doc_folder ( ) } /Build/Products/Debug-iphoneos/LiveViewNative.doccarchive/data/documentation/liveviewnative/#{ view } .json"
52- ) do
53- docs = Jason . decode! ( data )
54- path = "#{ @ doc_folder } /#{ category } /#{ view } .md"
55- File . mkdir_p! ( Path . dirname ( path ) )
56- File . write! ( path , markdown ( docs , docs ) )
57-
58- # build cheatsheet entries
59- File . write! ( @ cheatsheet_path , cheatsheet ( docs , docs ) <> "\n " , [ :append ] )
60- end
61- end
62- end
48+ views = Path . wildcard ( "Sources/LiveViewNative/Views/**/*.swift" )
49+ |> Enum . map ( fn view -> Path . basename ( view , ".swift" ) end )
50+ |> Enum . sort ( )
51+ |> Enum . map ( fn view ->
52+ {
53+ "`<#{ view } >`" ,
54+ "#{ doc_path } /Build/Products/Debug-iphoneos/LiveViewNative.doccarchive/data/documentation/liveviewnative/#{ view } .json"
55+ }
56+ end )
57+ write_cheatsheet (
58+ "View Index" ,
59+ doc_path ,
60+ views ,
61+ @ cheatsheet_path
62+ )
6363
6464 Logger . info ( "Generating LiveView Native modifier documentation files..." )
65+ modifiers = System . shell ( modifier_list ( xcode_path ) )
66+ |> elem ( 0 )
67+ |> String . split ( "\n " )
68+ |> Enum . map ( fn modifier ->
69+ {
70+ modifier ,
71+ "#{ doc_path } /Build/Products/Debug-iphoneos/LiveViewNative.doccarchive/data/documentation/liveviewnative/_#{ modifier } Modifier.json"
72+ }
73+ end )
74+ write_cheatsheet (
75+ "Modifier Index" ,
76+ doc_path ,
77+ modifiers ,
78+ @ modifier_cheatsheet_path ,
79+ true
80+ )
6581
66- modifiers = System . shell ( modifier_list ( xcode_path ) ) |> elem ( 0 ) |> String . split ( "\n " )
82+ if Keyword . get ( kwargs , :doc_path ) == nil do
83+ Logger . info ( "Cleaning up temporary files..." )
84+ File . rm_rf ( doc_path )
85+ end
86+ end
6787
88+ defp write_cheatsheet ( title , doc_path , paths , output_path , use_tabs \\ false ) do
6889 # clear cheatsheet
69- File . write! ( @ modifier_cheatsheet_path , "# Modifier Index\n " )
70-
71- all_modifier_references = MapSet . new ( )
72- for modifier <- modifiers do
73- with { :ok , data } <-
74- File . read (
75- "#{ temp_doc_folder ( ) } /Build/Products/Debug-iphoneos/LiveViewNative.doccarchive/data/documentation/liveviewnative/_#{ modifier } Modifier.json"
76- ) do
90+ File . write! ( output_path , "# #{ title } \n " )
91+
92+ references = MapSet . new ( )
93+ for { name , path } <- paths do
94+ with { :ok , data } <- File . read ( path ) do
7795 docs = Jason . decode! ( data )
78- File . write! ( @ modifier_cheatsheet_path , "## #{ modifier } \n " , [ :append ] )
79- File . write! ( @ modifier_cheatsheet_path , "<!-- tabs-open -->\n " , [ :append ] )
80- File . write! ( @ modifier_cheatsheet_path , modifier_cheatsheet ( docs , docs ) <> "\n " , [ :append ] )
81- File . write! ( @ modifier_cheatsheet_path , "<!-- tabs-close -->\n " , [ :append ] )
82- reduce_references ( docs , all_modifier_references )
96+ File . write! ( output_path , "## #{ name } \n " , [ :append ] )
97+ if use_tabs do
98+ File . write! ( output_path , "<!-- tabs-open -->\n " , [ :append ] )
99+ end
100+ ctx = if use_tabs do
101+ docs
102+ else
103+ docs |> Map . put ( "inlineHeadings" , true )
104+ end
105+ File . write! ( output_path , modifier_cheatsheet ( docs , ctx ) <> "\n " , [ :append ] )
106+ if use_tabs do
107+ File . write! ( output_path , "<!-- tabs-close -->\n " , [ :append ] )
108+ end
109+ reduce_references ( docs , references )
83110 end
84111 end
85112
86- all_modifier_references = modifiers
87- |> Enum . reduce ( MapSet . new ( ) , fn modifier , acc ->
88- with { :ok , data } <- File . read ( " #{ temp_doc_folder ( ) } /Build/Products/Debug-iphoneos/LiveViewNative.doccarchive/data/documentation/liveviewnative/_ #{ modifier } Modifier.json" )
113+ references = paths
114+ |> Enum . reduce ( MapSet . new ( ) , fn { _ , path } , acc ->
115+ with { :ok , data } <- File . read ( path )
89116 do
90117 docs = Jason . decode! ( data )
91118 reduce_references ( docs , acc )
@@ -95,9 +122,9 @@ defmodule Mix.Tasks.Lvn.Swiftui.Gen.Docs do
95122 end )
96123
97124 # collect references made in references
98- all_modifier_references = Enum . reduce ( all_modifier_references , all_modifier_references , fn reference , acc ->
125+ references = Enum . reduce ( references , references , fn reference , acc ->
99126 path = String . trim_leading ( reference , "doc://LiveViewNative/documentation/LiveViewNative/" )
100- with { :ok , data } <- File . read ( "#{ temp_doc_folder ( ) } /Build/Products/Debug-iphoneos/LiveViewNative.doccarchive/data/documentation/liveviewnative/#{ path } .json" )
127+ with { :ok , data } <- File . read ( "#{ doc_path } /Build/Products/Debug-iphoneos/LiveViewNative.doccarchive/data/documentation/liveviewnative/#{ path } .json" )
101128 do
102129 docs = Jason . decode! ( data )
103130 reduce_references ( docs , acc )
@@ -107,13 +134,10 @@ defmodule Mix.Tasks.Lvn.Swiftui.Gen.Docs do
107134 end )
108135
109136 # write references to end of modifier index
110- File . write! ( @ modifier_cheatsheet_path , "## Types\n " , [ :append ] )
111- for reference <- Enum . sort ( all_modifier_references ) do
112- File . write! ( @ modifier_cheatsheet_path , attribute_details ( String . trim_leading ( reference , "doc://LiveViewNative/documentation/LiveViewNative/" ) ) <> "\n " , [ :append ] )
137+ File . write! ( output_path , "## Types\n " , [ :append ] )
138+ for reference <- Enum . sort ( references ) do
139+ File . write! ( output_path , attribute_details ( String . trim_leading ( reference , "doc://LiveViewNative/documentation/LiveViewNative/" ) , doc_path ) <> "\n " , [ :append ] )
113140 end
114-
115- Logger . info ( "Cleaning up temporary files..." )
116- File . rm_rf ( temp_doc_folder ( ) )
117141 end
118142
119143 ### Cheatsheet
@@ -184,7 +208,7 @@ defmodule Mix.Tasks.Lvn.Swiftui.Gen.Docs do
184208 <!-- attribute list -->
185209 # References
186210
187- #{ Enum . map ( attributes , & attribute_details ( Path . basename ( url ) , & 1 ) ) }
211+ #{ Enum . map ( attributes , & attribute_details ( Path . basename ( url ) , & 1 , ctx . doc_path ) ) }
188212
189213 <!-- end attribute list -->
190214 """
@@ -249,7 +273,7 @@ defmodule Mix.Tasks.Lvn.Swiftui.Gen.Docs do
249273 % { "references" => references , "includeAllReferences" => true }
250274 ) do
251275 % { "title" => title } = Map . get ( references , identifier )
252- hash = "#{ title |> String . replace ( "<" , "" ) |> String . replace ( ">" , "" ) } /1"
276+ hash = "#{ identifier } /1"
253277 "[`#{ title } `](##{ hash } )"
254278 end
255279
@@ -258,7 +282,7 @@ defmodule Mix.Tasks.Lvn.Swiftui.Gen.Docs do
258282 % { "references" => references , "identifier" => % { "url" => base_url } }
259283 ) do
260284 % { "title" => title , "url" => url } = Map . get ( references , identifier )
261- hash = "#{ title |> String . replace ( "<" , "" ) |> String . replace ( ">" , "" ) } /1"
285+ hash = "#{ url } /1"
262286
263287 resolved_url =
264288 case url do
@@ -278,23 +302,24 @@ defmodule Mix.Tasks.Lvn.Swiftui.Gen.Docs do
278302
279303 def markdown ( _data , _ctx ) , do: ""
280304
281- defp attribute_details ( view , identifier ) do
282- attribute_details ( "#{ view } /#{ Path . basename ( identifier ) } " )
305+ defp attribute_details ( view , identifier , doc_path ) do
306+ attribute_details ( "#{ view } /#{ Path . basename ( identifier ) } " , doc_path )
283307 end
284308
285- defp attribute_details ( path ) do
286- "#{ temp_doc_folder ( ) } /Build/Products/Debug-iphoneos/LiveViewNative.doccarchive/data/documentation/liveviewnative/#{ path } .json"
309+ defp attribute_details ( path , doc_path ) do
310+ "#{ doc_path } /Build/Products/Debug-iphoneos/LiveViewNative.doccarchive/data/documentation/liveviewnative/#{ path } .json"
287311 |> File . read ( )
288312 |> case do
289313 { :ok , data } ->
290314 docs = Jason . decode! ( data )
291315
292316 title = Map . get ( docs , "metadata" , % { } ) |> Map . get ( "title" , "" )
317+ url = Map . get ( docs , "identifier" , % { } ) |> Map . get ( "url" , "" )
293318 abstract = Map . get ( docs , "abstract" , [ ] )
294319 content = Map . get ( docs , "primaryContentSections" , [ ] )
295320
296321 docs = Map . put ( docs , "inlineHeadings" , true ) |> Map . put ( "includeAllReferences" , true )
297- hash = "#{ title } /1"
322+ hash = "#{ url } /1"
298323
299324 """
300325 <section id="#{ hash } " class="detail">
@@ -349,13 +374,4 @@ defmodule Mix.Tasks.Lvn.Swiftui.Gen.Docs do
349374 ) , do: items |> Enum . reduce ( acc , fn % { "content" => content } , acc -> reduce_references ( content , acc ) end )
350375
351376 defp reduce_references ( _markdown , acc ) , do: acc
352-
353- @ spec categorized_views ( ) :: % { String . t ( ) => [ String . t ( ) ] }
354- defp categorized_views do
355- Path . wildcard ( "Sources/LiveViewNative/Views/**/*.swift" )
356- |> Enum . group_by (
357- & Path . basename ( Path . dirname ( & 1 ) ) ,
358- & Path . basename ( & 1 , ".swift" )
359- )
360- end
361377end
0 commit comments