Skip to content

Commit 0ad9a0c

Browse files
committed
Try but fail to use $call(simplify = FALSE)
1 parent d49373f commit 0ad9a0c

File tree

3 files changed

+39
-49
lines changed

3 files changed

+39
-49
lines changed

DESCRIPTION

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ License: MIT + file LICENSE
1414
Imports:
1515
cli,
1616
rlang (>= 1.1.0),
17-
V8
17+
V8 (>= 6.0.5)
1818
Suggests:
1919
testthat (>= 3.0.0)
2020
Config/testthat/edition: 3
2121
Encoding: UTF-8
2222
Roxygen: list(markdown = TRUE)
2323
RoxygenNote: 7.3.2
24+
Remotes:
25+
jeroen/V8

R/parse.R

Lines changed: 17 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,15 @@ text_parse <- function(text, ..., parse_options = NULL) {
7878
check_string(text)
7979
parse_options <- parse_options %||% parse_options()
8080
check_no_text_parse_errors("parse", text, parse_options = parse_options)
81-
out <- js_call(jsonc, "ffi_text_parse", text, parse_options)
82-
out
81+
82+
# In particular, JSON arrays can have mixed types like `[1, "a"]` and we
83+
# don't want those to be forcibly simplified to `c("1", "a")` on the way in.
84+
#
85+
# We don't need this for every function, but when we parse a JSON file
86+
# we want predictable output, and for us that means no simplification
87+
simplify <- FALSE
88+
89+
jsonc$call("ffi_text_parse", text, parse_options, simplify = simplify)
8390
}
8491

8592
#' @rdname parse
@@ -98,8 +105,13 @@ text_parse_at_path <- function(text, path, ..., parse_options = NULL) {
98105
path <- check_and_normalize_path(path)
99106
parse_options <- parse_options %||% parse_options()
100107
check_no_text_parse_errors("parse", text, parse_options = parse_options)
101-
out <- js_call(jsonc, "ffi_text_parse_at_path", text, path, parse_options)
102-
out
108+
jsonc$call(
109+
"ffi_text_parse_at_path",
110+
text,
111+
path,
112+
parse_options,
113+
simplify = FALSE
114+
)
103115
}
104116

105117
#' @rdname parse
@@ -141,7 +153,7 @@ text_parse_errors <- function(text, ..., parse_options = NULL) {
141153
check_dots_empty0(...)
142154
check_string(text, .internal = TRUE)
143155
parse_options <- parse_options %||% parse_options()
144-
js_call(jsonc, "ffi_text_parse_errors", text, parse_options)
156+
jsonc$call("ffi_text_parse_errors", text, parse_options, simplify = FALSE)
145157
}
146158

147159
check_no_text_parse_errors <- function(
@@ -253,46 +265,3 @@ error_code_to_error_message <- function(code) {
253265

254266
lookup[[code]]
255267
}
256-
257-
# Call a JavaScript function
258-
#
259-
# This is `jsonc$call()` but with two changes:
260-
# - A `NULL` returns visibly
261-
# - The conversion from JSON does NO simplification
262-
#
263-
# In particular, JSON arrays can have mixed types like `[1, "a"]` and we
264-
# don't want those to be forcibly simplified to `c("1", "a")` on the way in.
265-
#
266-
# We don't need this for every function, but when we parse a JSON file
267-
# we want predictable output, and for us that means no simplification
268-
js_call <- function(context, fun, ...) {
269-
args <- list(...)
270-
271-
if (!is.null(names(args))) {
272-
stop("Named arguments are not supported in JavaScript.")
273-
}
274-
275-
args <- vapply(
276-
args,
277-
function(x) jsonlite::toJSON(x, auto_unbox = TRUE),
278-
character(1)
279-
)
280-
281-
args <- paste(args, collapse = ",")
282-
src <- paste0("(", fun, ")(", args, ");")
283-
284-
out <- context$eval(src, serialize = TRUE, await = FALSE)
285-
286-
if (is.null(out)) {
287-
# A JavaScript `undefined` becomes `NULL` and `fromJSON()` doesn't want that
288-
NULL
289-
} else {
290-
# Otherwise, assume JSON but DON'T SIMPLIFY for stability and predictability
291-
jsonlite::fromJSON(
292-
out,
293-
simplifyVector = FALSE,
294-
simplifyDataFrame = FALSE,
295-
simplifyMatrix = FALSE
296-
)
297-
}
298-
}

tests/testthat/test-parse.R

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,25 @@ test_that("empty file parsing works", {
33
expect_identical(text_parse_at_path("", "a"), NULL)
44
})
55

6+
test_that("Output is always returned visibly", {
7+
expect_identical(withVisible(text_parse("{}"))$visible, TRUE)
8+
expect_identical(
9+
withVisible(text_parse_at_path('{ "a": 1 }', "a"))$visible,
10+
TRUE
11+
)
12+
13+
# These must return visible `NULL`
14+
expect_identical(withVisible(text_parse(""))$visible, TRUE)
15+
expect_identical(withVisible(text_parse_at_path("", "a"))$visible, TRUE)
16+
17+
# These must return visible `NULL`
18+
expect_identical(withVisible(text_parse("null"))$visible, TRUE)
19+
expect_identical(
20+
withVisible(text_parse_at_path('{ "a": null }', "a"))$visible,
21+
TRUE
22+
)
23+
})
24+
625
test_that("works outside of a base object `{`", {
726
expect_identical(text_parse("1"), 1L)
827
expect_identical(text_parse("1.5"), 1.5)

0 commit comments

Comments
 (0)