4646file = "deps"), meta = NULL,
4747script = {script_name},
4848stylesheet = {css_name}, head = NULL, attachment = NULL, package = "{rpkgname}",
49- all_files = FALSE), class = "html_dependency")""" # noqa:E501
49+ all_files = FALSE{async_or_dynamic} ), class = "html_dependency")""" # noqa:E501
5050
5151frame_body_template = """`{project_shortname}` = structure(list(name = "{project_shortname}",
5252version = "{project_ver}", src = list(href = NULL,
5353file = "deps"), meta = NULL,
5454script = {script_name},
5555stylesheet = {css_name}, head = NULL, attachment = NULL, package = "{rpkgname}",
56- all_files = FALSE), class = "html_dependency")""" # noqa:E501
56+ all_files = FALSE{async_or_dynamic} ), class = "html_dependency")""" # noqa:E501
5757
5858frame_close_template = """)
5959return(deps_metadata)
8181"""
8282
8383description_template = """Package: {package_name}
84- Title: {package_description }
84+ Title: {package_title }
8585Version: {package_version}
86- Authors @R: as.person(c({package_author}))
8786Description: {package_description}
8887Depends: R (>= 3.0.2){package_depends}
8988Imports: {package_imports}
9291URL: {package_url}
9392BugReports: {package_issues}
9493Encoding: UTF-8
95- LazyData: true
94+ LazyData: true{vignette_builder}
95+ KeepSource: true
9696Author: {package_author_no_email}
9797Maintainer: {maintainer}
9898"""
@@ -276,18 +276,23 @@ def generate_js_metadata(pkg_data, project_shortname):
276276 # pylint: disable=consider-using-enumerate
277277 if len (alldist ) > 1 :
278278 for dep in range (len (alldist )):
279- rpp = alldist [dep ]["relative_package_path" ]
279+ curr_dep = alldist [dep ]
280+ rpp = curr_dep ["relative_package_path" ]
281+
282+ async_or_dynamic = get_async_type (curr_dep )
283+
280284 if "dash_" in rpp :
281285 dep_name = rpp .split ("." )[0 ]
282286 else :
283287 dep_name = "{}" .format (project_shortname )
284- project_ver = str ( dep )
288+
285289 if "css" in rpp :
286290 css_name = "'{}'" .format (rpp )
287291 script_name = 'NULL'
288292 else :
289293 script_name = "'{}'" .format (rpp )
290294 css_name = 'NULL'
295+
291296 function_frame += [
292297 frame_element_template .format (
293298 dep_name = dep_name ,
@@ -296,23 +301,30 @@ def generate_js_metadata(pkg_data, project_shortname):
296301 project_shortname = project_shortname ,
297302 script_name = script_name ,
298303 css_name = css_name ,
304+ async_or_dynamic = async_or_dynamic ,
299305 )
300306 ]
301307 function_frame_body = ",\n " .join (function_frame )
302308 elif len (alldist ) == 1 :
303- rpp = alldist [0 ]["relative_package_path" ]
309+ dep = alldist [0 ]
310+ rpp = dep ["relative_package_path" ]
311+
312+ async_or_dynamic = get_async_type (dep )
313+
304314 if "css" in rpp :
305315 css_name = "'{}'" .format (rpp )
306316 script_name = "NULL"
307317 else :
308318 script_name = "'{}'" .format (rpp )
309319 css_name = "NULL"
320+
310321 function_frame_body = frame_body_template .format (
311322 project_shortname = project_shortname ,
312323 project_ver = project_ver ,
313324 rpkgname = rpkgname ,
314325 script_name = script_name ,
315326 css_name = css_name ,
327+ async_or_dynamic = async_or_dynamic ,
316328 )
317329
318330 function_string = "" .join (
@@ -322,6 +334,24 @@ def generate_js_metadata(pkg_data, project_shortname):
322334 return function_string
323335
324336
337+ # determine whether dependency uses async or dynamic flag
338+ # then return the properly formatted string if so, i.e.
339+ # " async = TRUE,". a dependency can have async or
340+ # dynamic elements, neither of these, but never both.
341+ def get_async_type (dep ):
342+ async_or_dynamic = ""
343+ for key in dep .keys ():
344+ if (key in ['async' , 'dynamic' ]):
345+ keyval = dep [key ]
346+ if not isinstance (keyval , bool ):
347+ keyval = "'{}'" .format (keyval .lower ())
348+ else :
349+ keyval = str (keyval ).upper ()
350+ async_or_dynamic = \
351+ ", {} = {}" .format (key , keyval )
352+ return async_or_dynamic
353+
354+
325355# This method wraps code within arbitrary LaTeX-like tags, which are used
326356# by R's internal help parser for constructing man pages
327357def wrap (tag , code ):
@@ -369,6 +399,15 @@ def write_help_file(name, props, description, prefix, rpkg_data):
369399 for p in prop_keys
370400 )
371401
402+ # auto-replace any unescaped backslashes for compatibility with R docs
403+ description = re .sub (r"(?<!\\)%" , "\\ %" , description )
404+ item_text = re .sub (r"(?<!\\)%" , "\\ %" , item_text )
405+
406+ # scrub examples which begin with **Example Usage**, as these should be
407+ # provided as R code within dash-info.yaml
408+ if "**Example Usage**" in description :
409+ description = description .split ("**Example Usage**" )[0 ].rstrip ()
410+
372411 if any (key .endswith ("-*" ) for key in prop_keys ):
373412 default_argtext += ', ...'
374413 item_text += wildcard_help_template .format (get_wildcards_r (prop_keys ))
@@ -400,6 +439,7 @@ def write_help_file(name, props, description, prefix, rpkg_data):
400439 fa .write (result + '\n ' )
401440
402441
442+ # pylint: disable=too-many-arguments
403443def write_class_file (name ,
404444 props ,
405445 description ,
@@ -509,7 +549,21 @@ def generate_rpkg(
509549
510550 package_name = snake_case_to_camel_case (project_shortname )
511551 lib_name = pkg_data .get ("name" )
512- package_description = pkg_data .get ("description" , "" )
552+
553+ if rpkg_data is not None :
554+ if rpkg_data .get ("pkg_help_title" ):
555+ package_title = rpkg_data .get ("pkg_help_title" ,
556+ pkg_data .get ("description" ,
557+ "" ))
558+ if rpkg_data .get ("pkg_help_description" ):
559+ package_description = rpkg_data .get ("pkg_help_description" ,
560+ pkg_data .get ("description" ,
561+ "" ))
562+ else :
563+ # fall back to using description in package.json, if present
564+ package_title = pkg_data .get ("description" , "" )
565+ package_description = pkg_data .get ("description" , "" )
566+
513567 package_version = pkg_data .get ("version" , "0.0.1" )
514568
515569 # remove leading and trailing commas
@@ -547,6 +601,16 @@ def generate_rpkg(
547601
548602 maintainer = pkg_data .get ("maintainer" , pkg_data .get ("author" ))
549603
604+ if "<" not in package_author or "<" not in maintainer :
605+ print (
606+ "Error, aborting R package generation: "
607+ "R packages require a properly formatted author or "
608+ "maintainer field or installation will fail. Please include "
609+ "an email address enclosed within < > brackets in package.json. " ,
610+ file = sys .stderr ,
611+ )
612+ sys .exit (1 )
613+
550614 if not (os .path .isfile ("LICENSE" ) or os .path .isfile ("LICENSE.txt" )):
551615 package_license = pkg_data .get ("license" , "" )
552616 else :
@@ -565,6 +629,14 @@ def generate_rpkg(
565629 for rpackage in rpackage_list :
566630 packages_string += "\n import({})\n " .format (rpackage )
567631
632+ if os .path .exists ("vignettes" ):
633+ vignette_builder = "VignetteBuilder: knitr\n "
634+ if "knitr" not in package_suggests and \
635+ "rmarkdown" not in package_suggests :
636+ package_suggests += ", knitr, rmarkdown" .lstrip (", " )
637+ else :
638+ vignette_builder = ""
639+
568640 pkghelp_stub_path = os .path .join ("man" , package_name + "-package.Rd" )
569641
570642 # generate the internal (not exported to the user) functions which
@@ -582,6 +654,7 @@ def generate_rpkg(
582654
583655 description_string = description_template .format (
584656 package_name = package_name ,
657+ package_title = package_title ,
585658 package_description = package_description ,
586659 package_version = package_version ,
587660 package_author = package_author ,
@@ -591,6 +664,7 @@ def generate_rpkg(
591664 package_license = package_license ,
592665 package_url = package_url ,
593666 package_issues = package_issues ,
667+ vignette_builder = vignette_builder ,
594668 package_author_no_email = package_author_no_email ,
595669 maintainer = maintainer ,
596670 )
0 commit comments