Add support for rendering Bytes values with YamlRenderer (#1276)

This commit is contained in:
Jen Basch
2025-10-30 15:53:43 -07:00
committed by GitHub
parent 10eccb100c
commit eab71229e7
11 changed files with 80 additions and 7 deletions

View File

@@ -76,7 +76,6 @@ endif::[]
:uri-stdlib-protobufModule: {uri-pkl-stdlib-docs}/protobuf
:uri-stdlib-pklbinaryModule: {uri-pkl-stdlib-docs}/pklbinary
:uri-stdlib-evaluatorSettingsModule: {uri-pkl-stdlib-docs}/EvaluatorSettings
:uri-stdlib-pklbinaryModule: {uri-pkl-stdlib-docs}/pklbinary
:uri-stdlib-evaluatorSettingsHttpClass: {uri-stdlib-evaluatorSettingsModule}/Http
:uri-stdlib-Boolean: {uri-stdlib-baseModule}/Boolean
:uri-stdlib-xor: {uri-stdlib-baseModule}/Boolean#xor()
@@ -135,6 +134,7 @@ endif::[]
:uri-stdlib-BaseValueRenderer: {uri-stdlib-baseModule}/BaseValueRenderer
:uri-stdlib-ValueRenderer: {uri-stdlib-baseModule}/ValueRenderer
:uri-stdlib-BytesRenderer: {uri-stdlib-baseModule}/BytesRenderer
:uri-stdlib-YamlRenderer: {uri-stdlib-baseModule}/YamlRenderer
:uri-stdlib-PcfRenderer-converters: {uri-stdlib-baseModule}/PcfRenderer#converters
:uri-stdlib-Function: {uri-stdlib-baseModule}/Function
:uri-stdlib-Function0: {uri-stdlib-baseModule}/Function0

View File

@@ -265,6 +265,21 @@ pkl eval --trace-mode pretty myModule.pkl
Thanks to https://github.com/ssalevan[@ssalevan] for their contribution to this feature!
=== Better support for `Bytes` when rendering YAML
Previously, attempting to render a `Bytes` value using {uri-stdlib-YamlRenderer}[`YamlRenderer`] required the use of a link:{uri-stdlib-PcfRenderer-converters}[converter].
Now, Pkl can natively render YAML containing https://yaml.org/type/binary.html[binary scalars] (https://github.com/apple/pkl/pull/1276[#1276]).
[source,pkl%tested]
----
foo {
bar = Bytes(1, 2, 3)
}
rendered = new YamlRenderer {}.renderValue(foo) // <1>
----
<1> Result: `bar: !!binary AQID`
[[pkldoc-perf-improvements]]
=== `pkldoc` performance improvements
@@ -364,7 +379,7 @@ See <<pkldoc-migration>> for more details.
== Miscellaneous [small]#🐸#
* Dependency updates (https://github.com/apple/pkl/pull/1184[#1184], https://github.com/apple/pkl/pull/1225[#1225], https://github.com/apple/pkl/pull/1226[#1226], https://github.com/apple/pkl/pull/1228[#1228]).
* Enforce Pkl formatting of stdlib (https://github.com/apple/pkl/pull/1236[#1236], https://github.com/apple/pkl/pull/1253[#1253], https://github.com/apple/pkl/pull/1258[#1258]).
* Enforce Pkl formatting of stdlib (https://github.com/apple/pkl/pull/1236[#1236], https://github.com/apple/pkl/pull/1253[#1253], https://github.com/apple/pkl/pull/1258[#1258], https://github.com/apple/pkl/pull/1278[#1278]).
* Add internal IntelliJ plugin that's meant to assist with development of the Pkl codebase itself (https://github.com/apple/pkl/pull/1248[#1248]).
* Update CircleCI macOS instance type and Xcode version (https://github.com/apple/pkl/pull/1243[#1243], https://github.com/apple/pkl/pull/1244[#1244]).
* Disable multi-jdk testing when running on Windows ARM (https://github.com/apple/pkl/pull/1223[#1223]).

View File

@@ -153,8 +153,7 @@ final class YamlRenderer implements ValueRenderer {
@Override
public void visitBytes(byte[] value) {
throw new RendererException(
String.format("Values of type `Bytes` cannot be rendered as YAML. Value: %s", value));
emitter.emit(YamlUtils.bytesScalar(value));
}
@Override

View File

@@ -180,7 +180,8 @@ public final class YamlRendererNodes {
@Override
public void visitBytes(VmBytes value) {
cannotRenderTypeAddConverter(value);
if (!builder.isEmpty()) builder.append(' ');
emitter.emit(value.getBytes(), currIndent, false);
}
@Override

View File

@@ -15,6 +15,8 @@
*/
package org.pkl.core.util.yaml;
import java.util.Base64;
// Useful links:
// https://yaml-online-parser.appspot.com
// https://github.com/FasterXML/jackson-dataformats-text/pull/201
@@ -210,6 +212,11 @@ public abstract class YamlEmitter {
builder.append(value);
}
public final void emit(byte[] value, StringBuilder currIndent, boolean isKey) {
builder.append("!!binary ");
emit(Base64.getEncoder().encodeToString(value), currIndent, isKey);
}
public final void emitNull() {
builder.append("null");
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,6 +33,9 @@ public final class YamlUtils {
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private static final Optional<String> STRING_TAG = Optional.of(Tag.STR.toString());
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private static final Optional<String> BINARY_TAG = Optional.of(Tag.BINARY.toString());
private static final ImplicitTuple TUPLE = new ImplicitTuple(true, true);
private YamlUtils() {}
@@ -56,6 +59,13 @@ public final class YamlUtils {
return new ScalarEvent(Optional.empty(), STRING_TAG, tuple, value, scalarStyle);
}
/** Constructs a {@link ScalarEvent} for emitting the given value as YAML binary. */
public static ScalarEvent bytesScalar(byte[] value) {
var encoded = Base64.getEncoder().encodeToString(value);
return new ScalarEvent(
Optional.empty(), BINARY_TAG, new ImplicitTuple(false, false), encoded, ScalarStyle.PLAIN);
}
/** Constructs a {@link ScalarEvent} for emitting the given value in plain style. */
public static ScalarEvent plainScalar(String value, Tag tag) {
return new ScalarEvent(

View File

@@ -18,6 +18,9 @@ res13 = new Dynamic { name = "pigeon"; age = 30 }
res14 = new Person { name = "pigeon" }
res15 = null
res16 = Pair(1, 2)
res17 = Bytes()
res18 = Bytes(1, 2, 3)
res19 = IntSeq(0, 127).toList().toBytes()
output {
renderer = new YamlRenderer {

View File

@@ -18,6 +18,7 @@ res13 = new Dynamic { name = "pigeon"; age = 30 }
res14 = new Person { name = "pigeon"; age = 30 }
res15 = null
res16 = Pair(1, 2)
res17 = Bytes(1, 2, 3)
output {
renderer = new YamlRenderer {
@@ -38,6 +39,7 @@ output {
[Null] = (it) -> "converted"
[Pair] = (it) -> "converted"
[IntSeq] = (it) -> "converted"
[Bytes] = (it) -> "converted"
}
}
}

View File

@@ -37,3 +37,6 @@ res15: String
res16:
- 2
- 3
res17: !!binary ''
res18: !!binary AQID
res19: !!binary AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8=

View File

@@ -13,3 +13,4 @@ res13: converted
res14: converted
res15: converted
res16: converted
res17: converted

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -146,4 +146,36 @@ class YamlRendererTest {
.trimIndent()
)
}
@Test
fun `render byte array values as binary`() {
val evaluator = Evaluator.preconfigured()
val module =
evaluator.evaluate(
ModuleSource.text(
"""
res1 = Bytes()
res2 = Bytes(1, 2, 3)
res3 = IntSeq(0, 127).toList().toBytes()
"""
.trimIndent()
)
)
val writer = StringWriter()
val renderer = ValueRenderers.yaml(writer, 2, true, false)
renderer.renderDocument(module)
val output = writer.toString()
assertThat(output.trim())
.isEqualTo(
"""
res1: !!binary ''
res2: !!binary 'AQID'
res3: !!binary 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn8='
"""
.trimIndent()
)
}
}