1+ # ' Write File Content in a Shinylive App to Disk
2+ # '
3+ # ' Writes file content extracted from Shinylive applications to disk, handling both
4+ # ' text and binary content appropriately. Creates any necessary parent directories
5+ # ' and ensures proper encoding of content. For binary files, automatically decodes
6+ # ' the base64-encoded content before writing.
7+ # '
8+ # ' @param content Character string containing the file content. For binary files,
9+ # ' this should be base64-encoded content. For text files, this should be the raw
10+ # ' text content.
11+ # ' @param file_path Character string specifying the path where the file should be
12+ # ' written. Parent directories will be created if they don't exist.
13+ # ' @param type Character string specifying the file type, either "text" (default)
14+ # ' or "binary". Binary files are assumed to be base64 encoded, as this is the
15+ # ' standard format for binary content in Shinylive applications.
16+ # '
17+ # ' @return Invisible NULL, called for its side effect of writing a file to disk.
18+ # '
19+ # ' @details
20+ # ' The function handles two types of content:
21+ # '
22+ # ' * Text files (`type = "text"`):
23+ # ' - Content is converted to UTF-8 encoding using `enc2utf8()`
24+ # ' - Written using `writeLines()` with `useBytes = TRUE`
25+ # '
26+ # ' * Binary files (`type = "binary"`):
27+ # ' - Content is decoded from base64 using `jsonlite::base64_dec()`
28+ # ' - Written as raw binary data using `writeBin()`
29+ # '
30+ # ' Parent directories in the file path are automatically created if they don't
31+ # ' exist using `fs::dir_create()` with `recurse = TRUE`.
32+ # '
33+ # ' @examples
34+ # ' \dontrun{
35+ # ' # Writing a text file
36+ # ' write_file_content(
37+ # ' content = "library(shiny)\n\nui <- fluidPage()",
38+ # ' file_path = "app/app.R",
39+ # ' type = "text"
40+ # ' )
41+ # '
42+ # ' # Writing a binary file (base64-encoded content)
43+ # ' write_file_content(
44+ # ' content = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==",
45+ # ' file_path = "app/www/image.png",
46+ # ' type = "binary"
47+ # ' )
48+ # ' }
49+ # '
50+ # ' @keywords internal
51+ write_file_content <- function (content , file_path , type = " text" ) {
52+ # Ensure parent directory exists
53+ parent_dir <- dirname(file_path )
54+ if (! dir.exists(parent_dir )) {
55+ fs :: dir_create(parent_dir , recurse = TRUE )
56+ }
57+
58+ # Handle content based on type
59+ if (type == " binary" ) {
60+ # Decode base64 content and write as binary
61+ decoded <- jsonlite :: base64_dec(content )
62+ writeBin(decoded , file_path , useBytes = TRUE )
63+ } else {
64+ # Write as text
65+ writeLines(enc2utf8(content ), file_path , useBytes = TRUE )
66+ }
67+
68+ invisible (NULL )
69+ }
70+
71+
172# ' Write Shinylive Applications to a Quarto Document
273# '
374# ' Converts a list of parsed Shinylive applications into a single Quarto document.
@@ -253,8 +324,7 @@ write_apps_to_quarto <- function(apps, qmd_path) {
253324# ' write_apps_to_dirs(apps, "extracted_apps")
254325# ' }
255326write_apps_to_dirs <- function (apps , base_dir ) {
256- fs :: dir_create(base_dir )
257-
327+ fs :: dir_create(base_dir , recurse = TRUE )
258328
259329 # Calculate padding width based on number of apps
260330 number_padding <- padding_width(length(apps ))
@@ -266,18 +336,19 @@ write_apps_to_dirs <- function(apps, base_dir) {
266336
267337 # Create numbered subdirectory using dynamic padding
268338 app_dir <- file.path(base_dir , sprintf(dir_format , i ))
269- fs :: dir_create(app_dir )
339+ fs :: dir_create(app_dir , recurse = TRUE )
270340
271341 # Write each file in the app
272342 for (file_name in names(app $ files )) {
273343 file_data <- app $ files [[file_name ]]
274344 file_path <- file.path(app_dir , file_name )
275345
276- # Ensure parent directory exists
277- fs :: dir_create(dirname(file_path ))
278-
279- # Write file content
280- writeLines(file_data $ content , file_path )
346+ # Write file as either a binary or text file
347+ write_file_content(
348+ content = file_data $ content ,
349+ file_path = file_path ,
350+ type = file_data $ type
351+ )
281352 }
282353
283354 # Write metadata
@@ -379,12 +450,18 @@ write_apps_to_dirs <- function(apps, base_dir) {
379450# ' @keywords internal
380451write_standalone_shinylive_app <- function (json_data , source_url , output_dir = " converted_shiny_app" ) {
381452 # Create output directory
382- fs :: dir_create(output_dir )
453+ fs :: dir_create(output_dir , recurse = TRUE )
383454
384455 # Extract files
385456 for (file in json_data ) {
386457 file_path <- file.path(output_dir , file $ name )
387- writeLines(file $ content , file_path )
458+
459+ # Write file as either a binary or text file
460+ write_file_content(
461+ content = file $ content ,
462+ file_path = file_path ,
463+ type = file $ type
464+ )
388465 }
389466
390467 # Return standalone command object
0 commit comments