Remove protobuf stdlib module (#1976)
This commit is contained in:
1 parent
155fc5a867
commit
2d7a368b48
25 files changed
+4
-1567
No files matched your search
@@ -77,7 +77,6 @@ endif::[]
|
||||
:uri-stdlib-netModule: {uri-pkl-stdlib-docs}/net
|
||||
:uri-stdlib-net-Url: {uri-stdlib-netModule}/Url
|
||||
:uri-stdlib-xmlModule: {uri-pkl-stdlib-docs}/xml
|
||||
:uri-stdlib-protobufModule: {uri-pkl-stdlib-docs}/protobuf
|
||||
:uri-stdlib-pklbinaryModule: {uri-pkl-stdlib-docs}/pklbinary
|
||||
:uri-stdlib-yamlModule: {uri-pkl-stdlib-docs}/yaml
|
||||
:uri-stdlib-YamlParser: {uri-stdlib-yamlModule}/Parser
|
||||
|
||||
@@ -2752,7 +2752,6 @@ The standard library provides these renderers:
|
||||
* link:{uri-stdlib-baseModule}/PcfRenderer[PcfRenderer]
|
||||
* link:{uri-stdlib-baseModule}/PListRenderer[PListRenderer]
|
||||
* link:{uri-stdlib-baseModule}/PropertiesRenderer[PropertiesRenderer]
|
||||
* link:{uri-stdlib-protobufModule}/Renderer[protobuf.Renderer]
|
||||
* link:{uri-stdlib-xmlModule}/Renderer[xml.Renderer]
|
||||
* link:{uri-stdlib-baseModule}/YamlRenderer[YamlRenderer]
|
||||
|
||||
|
||||
@@ -307,7 +307,6 @@ The default output renderer for a module supports the following formats:
|
||||
* `pcf`
|
||||
* `plist`
|
||||
* `properties`
|
||||
* `textproto` (deprecated in Pkl 0.33)
|
||||
* `xml`
|
||||
* `yaml`
|
||||
|
||||
|
||||
@@ -152,7 +152,6 @@ The default output renderer for a module supports the following formats:
|
||||
* `"pcf"`
|
||||
* `"plist"`
|
||||
* `"properties"`
|
||||
* `"textproto"` (deprecated in Pkl 0.33)
|
||||
* `"xml"`
|
||||
* `"yaml"`
|
||||
====
|
||||
|
||||
@@ -52,7 +52,6 @@ data class CliEvaluatorOptions(
|
||||
* - `"pcf"` (default)
|
||||
* - `"plist"`
|
||||
* - `"properties"`
|
||||
* - `"textproto"` (deprecated in Pkl 0.33)
|
||||
* - `"xml"`
|
||||
* - `"yaml"`
|
||||
*/
|
||||
|
||||
@@ -709,8 +709,7 @@ result = someLib.x
|
||||
assertThat(output).isEqualTo("x: 1\n---\nx: 3\n")
|
||||
}
|
||||
|
||||
// prototext can't render `Dynamic`.
|
||||
@EnumSource(names = ["TEXTPROTO"], mode = EnumSource.Mode.EXCLUDE)
|
||||
@EnumSource
|
||||
@ParameterizedTest(name = "{0} console output ends with newline")
|
||||
fun `console output ends with newline`(outputFormat: OutputFormat) {
|
||||
val sourceFiles = listOf(writePklFile("test0.pkl", "foo = 0\nbar=\"Baz\""))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2024-2026 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.
|
||||
@@ -22,7 +22,6 @@ public enum OutputFormat {
|
||||
PCF("pcf"),
|
||||
PROPERTIES("properties"),
|
||||
PLIST("plist"),
|
||||
TEXTPROTO("textproto"),
|
||||
XML("xml"),
|
||||
YAML("yaml");
|
||||
|
||||
|
||||
@@ -1,663 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2024-2026 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pkl.core.stdlib.protobuf;
|
||||
|
||||
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
|
||||
import com.oracle.truffle.api.dsl.Cached;
|
||||
import com.oracle.truffle.api.dsl.Specialization;
|
||||
import com.oracle.truffle.api.nodes.IndirectCallNode;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.Optional;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.pkl.core.DurationUnit;
|
||||
import org.pkl.core.ast.member.ClassProperty;
|
||||
import org.pkl.core.ast.member.PropertyTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.BooleanTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.IntSlotTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.IntTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.ListTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.ListingOrMappingTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.ListingTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.MapTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.MappingTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.NonFinalClassTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.NullableTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.ObjectSlotTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.SetTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.StringLiteralTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.StringTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.TypeAliasTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.UnionOfStringLiteralsTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.UnionTypeNode;
|
||||
import org.pkl.core.ast.type.TypeNode.UnionTypeNodeExploded;
|
||||
import org.pkl.core.ast.type.VmTypeMismatchException;
|
||||
import org.pkl.core.runtime.Identifier;
|
||||
import org.pkl.core.runtime.VmBytes;
|
||||
import org.pkl.core.runtime.VmClass;
|
||||
import org.pkl.core.runtime.VmDataSize;
|
||||
import org.pkl.core.runtime.VmDuration;
|
||||
import org.pkl.core.runtime.VmDynamic;
|
||||
import org.pkl.core.runtime.VmExceptionBuilder;
|
||||
import org.pkl.core.runtime.VmIntSeq;
|
||||
import org.pkl.core.runtime.VmLanguage;
|
||||
import org.pkl.core.runtime.VmList;
|
||||
import org.pkl.core.runtime.VmListing;
|
||||
import org.pkl.core.runtime.VmMap;
|
||||
import org.pkl.core.runtime.VmMapping;
|
||||
import org.pkl.core.runtime.VmNull;
|
||||
import org.pkl.core.runtime.VmPair;
|
||||
import org.pkl.core.runtime.VmReference;
|
||||
import org.pkl.core.runtime.VmRegex;
|
||||
import org.pkl.core.runtime.VmSet;
|
||||
import org.pkl.core.runtime.VmType;
|
||||
import org.pkl.core.runtime.VmTyped;
|
||||
import org.pkl.core.runtime.VmUtils;
|
||||
import org.pkl.core.runtime.VmValue;
|
||||
import org.pkl.core.stdlib.AbstractStringRenderer;
|
||||
import org.pkl.core.stdlib.ExternalMethod1Node;
|
||||
import org.pkl.core.stdlib.PklConverter;
|
||||
import org.pkl.core.util.ArrayCharEscaper;
|
||||
import org.pkl.core.util.json.JsonEscaper;
|
||||
|
||||
public final class RendererNodes {
|
||||
// Defined here because only relevant to this class.
|
||||
private static final Identifier SECONDS = Identifier.get("seconds");
|
||||
private static final Identifier NANOS = Identifier.get("nanos");
|
||||
|
||||
private static final ArrayCharEscaper fieldNameEscaper =
|
||||
ArrayCharEscaper.builder().withEscape('.', "_").withEscape('#', "_").build();
|
||||
|
||||
private static final StringTypeNode STRING_TYPE =
|
||||
new StringTypeNode(VmUtils.unavailableSourceSection());
|
||||
private static final IntTypeNode INT_TYPE = new IntTypeNode(VmUtils.unavailableSourceSection());
|
||||
|
||||
private RendererNodes() {}
|
||||
|
||||
public abstract static class renderDocument extends ExternalMethod1Node {
|
||||
@Specialization
|
||||
@TruffleBoundary
|
||||
protected String eval(
|
||||
VmTyped self, Object value, @Cached("create()") IndirectCallNode callNode) {
|
||||
var builder = new StringBuilder();
|
||||
createRenderer(self, builder, callNode).renderDocument(value);
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class renderValue extends ExternalMethod1Node {
|
||||
@Specialization
|
||||
@TruffleBoundary
|
||||
protected String eval(
|
||||
VmTyped self, Object value, @Cached("create()") IndirectCallNode callNode) {
|
||||
var builder = new StringBuilder();
|
||||
createRenderer(self, builder, callNode).renderValue(value);
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class renderType extends ExternalMethod1Node {
|
||||
@SuppressWarnings("unused")
|
||||
@Specialization
|
||||
protected String eval(VmTyped self, Object value) {
|
||||
return renderType(value);
|
||||
}
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
private static String renderType(Object value) {
|
||||
var clazz =
|
||||
value instanceof VmValue vmValue
|
||||
? vmValue.getVmClass()
|
||||
: value instanceof TypeNode typeNode
|
||||
? typeNode.getType().getVmClass()
|
||||
: value.getClass();
|
||||
if (clazz == null) {
|
||||
throw new VmExceptionBuilder()
|
||||
.evalError("cannotResolveTypeForProtobuf")
|
||||
.withProgramValue("Value", value)
|
||||
.build();
|
||||
}
|
||||
var name =
|
||||
clazz instanceof VmClass vmClass
|
||||
? vmClass.getSimpleName()
|
||||
: ((Class<?>) clazz).getSimpleName();
|
||||
|
||||
return fieldNameEscaper.escape(name);
|
||||
}
|
||||
|
||||
@TruffleBoundary
|
||||
private static ProtobufRenderer createRenderer(
|
||||
VmTyped self, StringBuilder builder, IndirectCallNode callNode) {
|
||||
var indent = (String) VmUtils.readMember(self, Identifier.INDENT, callNode);
|
||||
return new ProtobufRenderer(builder, indent, PklConverter.fromRenderer(self, callNode));
|
||||
}
|
||||
|
||||
private static final class ProtobufRenderer extends AbstractStringRenderer {
|
||||
private final Deque<Identifier> propertyPath = new ArrayDeque<>();
|
||||
private final Deque<Boolean> wrapperRequirement = new ArrayDeque<>();
|
||||
private final JsonEscaper jsonEscaper = new JsonEscaper(false);
|
||||
|
||||
private @Nullable TypeNode collectionType = null;
|
||||
|
||||
public ProtobufRenderer(StringBuilder builder, String indent, PklConverter converter) {
|
||||
super("Protobuf", builder, indent, converter, true, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitDocument(Object value) {
|
||||
visit(value);
|
||||
startNewLine();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitTopLevelValue(Object value) {
|
||||
if (value instanceof VmValue && !(value instanceof VmTyped || value instanceof VmDuration)) {
|
||||
var name = value.getClass().getSimpleName();
|
||||
if (name.startsWith("Vm")) {
|
||||
name = name.substring(2);
|
||||
}
|
||||
throw new VmExceptionBuilder().evalError("invalidProtobufTopLevelValue", name).build();
|
||||
}
|
||||
assert propertyPath.isEmpty() && wrapperRequirement.isEmpty() : "Corrupted traversal stack.";
|
||||
wrapperRequirement.push(false);
|
||||
visit(value);
|
||||
var wrap = wrapperRequirement.pop();
|
||||
assert !wrap && propertyPath.isEmpty() && wrapperRequirement.isEmpty()
|
||||
: "Corrupted traversal stack.";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitRenderDirective(VmTyped value) {
|
||||
writePropertyName();
|
||||
// append verbatim
|
||||
builder.append(VmUtils.readTextProperty(value));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startDynamic(VmDynamic value) {
|
||||
throw new VmExceptionBuilder()
|
||||
.evalError("cannotRenderTypeAddConverter", "Dynamic", "Protobuf")
|
||||
.withProgramValue("Value", value)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endDynamic(VmDynamic value, boolean isEmpty) {}
|
||||
|
||||
@Override
|
||||
protected void startTyped(VmTyped value) {
|
||||
wrapperRequirement.push(false);
|
||||
if (!propertyPath.isEmpty()) {
|
||||
writePropertyName();
|
||||
startMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endTyped(VmTyped value, boolean isEmpty) {
|
||||
var popped = wrapperRequirement.pop();
|
||||
assert !popped : "Corrupted traversal stack.";
|
||||
if (!propertyPath.isEmpty()) {
|
||||
endMessage();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startListing(VmListing value) {
|
||||
startWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endListing(VmListing value, boolean isEmpty) {
|
||||
endWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startMapping(VmMapping value) {
|
||||
startMaplike();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endMapping(VmMapping value, boolean isEmpty) {
|
||||
endMaplike();
|
||||
}
|
||||
|
||||
private void startMaplike() {
|
||||
if (requiresWrapper()) {
|
||||
writePropertyName();
|
||||
propertyPath.push(Identifier.IT);
|
||||
startMessage();
|
||||
}
|
||||
wrapperRequirement.push(true);
|
||||
}
|
||||
|
||||
private void endMaplike() {
|
||||
wrapperRequirement.pop();
|
||||
if (requiresWrapper()) {
|
||||
endMessage();
|
||||
var popped = propertyPath.pop();
|
||||
assert popped == Identifier.IT : "Corrupted traversal stack.";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startList(VmList value) {
|
||||
startWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endList(VmList value) {
|
||||
endWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startSet(VmSet value) {
|
||||
startWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endSet(VmSet value) {
|
||||
endWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startMap(VmMap value) {
|
||||
startMaplike();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void endMap(VmMap value) {
|
||||
endMaplike();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitElement(long index, Object value, boolean isFirst) {
|
||||
if (requiresWrapper()) {
|
||||
propertyPath.push(Identifier.IT);
|
||||
}
|
||||
var typeName = computeName(collectionType, value);
|
||||
var addedType = false;
|
||||
if (typeName != null) {
|
||||
addedType = true;
|
||||
writePropertyName();
|
||||
startMessage();
|
||||
propertyPath.push(Identifier.get("it_" + typeName));
|
||||
}
|
||||
wrapperRequirement.push(true);
|
||||
visit(value);
|
||||
var popped = wrapperRequirement.pop();
|
||||
assert popped : "Corrupted traversal stack.";
|
||||
if (addedType) {
|
||||
propertyPath.pop();
|
||||
endMessage();
|
||||
}
|
||||
if (requiresWrapper()) {
|
||||
propertyPath.pop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitEntryKey(Object key, boolean isFirst) {
|
||||
var isDirective = isRenderDirective(key);
|
||||
var isValidKey =
|
||||
isDirective || key instanceof Long || key instanceof Boolean || key instanceof String;
|
||||
if (!isValidKey) {
|
||||
throw new VmExceptionBuilder()
|
||||
.evalError("cannotRenderProtobufMapKey")
|
||||
.withProgramValue("Key", key)
|
||||
.build();
|
||||
}
|
||||
writePropertyName();
|
||||
startMessage();
|
||||
startNewLine();
|
||||
builder.append("key: ");
|
||||
if (isDirective) {
|
||||
builder.append(VmUtils.readTextProperty(key));
|
||||
} else if (key instanceof String string) {
|
||||
builder.append('"').append(jsonEscaper.escape(string)).append('"');
|
||||
} else {
|
||||
builder.append(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitEntryValue(Object value) {
|
||||
propertyPath.push(Identifier.VALUE);
|
||||
visit(value);
|
||||
propertyPath.pop();
|
||||
endMessage();
|
||||
}
|
||||
|
||||
private @Nullable String computeName(@Nullable TypeNode it, Object value) {
|
||||
if (it instanceof UnionTypeNode unionTypeNode) {
|
||||
for (var type : unionTypeNode.getElementTypeNodes()) {
|
||||
if (type instanceof UnionTypeNode) {
|
||||
var computedName = computeName(type, value);
|
||||
if (computedName != null) {
|
||||
return computedName;
|
||||
}
|
||||
} else if (type instanceof NonFinalClassTypeNode) {
|
||||
var clazz = type.getType().getVmClass();
|
||||
if (value instanceof VmValue vmValue) {
|
||||
if (clazz == vmValue.getVmClass()) {
|
||||
return clazz.getSimpleName();
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
type.execute(VmUtils.createEmptyMaterializedFrame(), value);
|
||||
} catch (VmTypeMismatchException e) {
|
||||
continue;
|
||||
}
|
||||
return renderType(type);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitProperty(Identifier name, Object value, boolean isFirst) {
|
||||
var hasWrapper = false;
|
||||
var hasCollection = false;
|
||||
var prevCollectionType = collectionType;
|
||||
Identifier expectedName = null;
|
||||
propertyPath.push(name);
|
||||
if (enclosingValue instanceof VmTyped) {
|
||||
var clazz = value instanceof VmValue vmValue ? vmValue.getVmClass() : value.getClass();
|
||||
// Compute the name of the field in the wrapper, based on the type, but only if a wrapper
|
||||
// is required.
|
||||
var optionalType =
|
||||
Optional.of(name)
|
||||
.map(enclosingValue.getVmClass()::getProperty)
|
||||
.map(ClassProperty::getTypeNode)
|
||||
.map(PropertyTypeNode::getTypeNode)
|
||||
.map(this::resolveType);
|
||||
if (optionalType.isPresent()) {
|
||||
var type = optionalType.get();
|
||||
var computedName = computeName(type, value);
|
||||
if (computedName != null) {
|
||||
hasWrapper = true;
|
||||
writePropertyName();
|
||||
expectedName = Identifier.get("it_" + computedName);
|
||||
propertyPath.push(expectedName);
|
||||
startMessage();
|
||||
} else if (type instanceof ListingOrMappingTypeNode listingOrMappingType) {
|
||||
hasCollection = true;
|
||||
collectionType = listingOrMappingType.getValueTypeNode();
|
||||
} else if (type instanceof ListTypeNode listType) {
|
||||
hasCollection = true;
|
||||
collectionType = listType.getElementTypeNode();
|
||||
} else if (type instanceof MapTypeNode mapType) {
|
||||
hasCollection = true;
|
||||
collectionType = mapType.getValueTypeNode();
|
||||
} else if (type instanceof SetTypeNode setType) {
|
||||
hasCollection = true;
|
||||
collectionType = setType.getElementTypeNode();
|
||||
} else if (type instanceof NonFinalClassTypeNode) {
|
||||
if (type.getType().getVmClass() != clazz) {
|
||||
throw new VmExceptionBuilder()
|
||||
.evalError("cannotRenderSubtypeForProtobuf", type.getType().getVmClass(), clazz)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
visit(value);
|
||||
if (hasWrapper) {
|
||||
endMessage();
|
||||
var popped = propertyPath.pop();
|
||||
assert popped == expectedName : "Corrupted traversal stack.";
|
||||
} else if (hasCollection) {
|
||||
collectionType = prevCollectionType;
|
||||
}
|
||||
var popped = propertyPath.pop();
|
||||
assert name == popped : "Corrupted traversal stack.";
|
||||
}
|
||||
|
||||
private void startNewLine() {
|
||||
if (indent.isEmpty() || builder.isEmpty() || builder.charAt(builder.length() - 1) == '\n')
|
||||
return;
|
||||
|
||||
builder.append('\n');
|
||||
builder.append(currIndent);
|
||||
}
|
||||
|
||||
private void startWrapper() {
|
||||
if (requiresWrapper()) {
|
||||
writePropertyName();
|
||||
startMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private void endWrapper() {
|
||||
if (requiresWrapper()) {
|
||||
endMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requiresWrapper() {
|
||||
var result = wrapperRequirement.peek();
|
||||
assert result != null : "Corrupted traversal stack.";
|
||||
return result;
|
||||
}
|
||||
|
||||
private void startMessage() {
|
||||
builder.append('{');
|
||||
increaseIndent();
|
||||
}
|
||||
|
||||
private void endMessage() {
|
||||
decreaseIndent();
|
||||
if (builder.charAt(builder.length() - 1) != '{') {
|
||||
startNewLine();
|
||||
}
|
||||
builder.append('}');
|
||||
}
|
||||
|
||||
private void writePropertyName() {
|
||||
if (propertyPath.isEmpty()) return;
|
||||
startNewLine();
|
||||
var name = propertyPath.peek();
|
||||
assert name != null : "Corrupted traversal stack.";
|
||||
builder.append(name);
|
||||
builder.append(": ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitString(String value) {
|
||||
writePropertyName();
|
||||
builder.append('"').append(jsonEscaper.escape(value)).append('"');
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBoolean(Boolean value) {
|
||||
writePropertyName();
|
||||
builder.append(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInt(Long value) {
|
||||
writePropertyName();
|
||||
builder.append(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFloat(Double value) {
|
||||
writePropertyName();
|
||||
builder.append(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDuration(VmDuration value) {
|
||||
writePropertyName();
|
||||
var nanos = (long) value.convertTo(DurationUnit.NANOS).getValue() % 1000000000;
|
||||
var seconds = (long) Math.floor(value.convertTo(DurationUnit.SECONDS).getValue());
|
||||
startMessage();
|
||||
|
||||
propertyPath.push(SECONDS);
|
||||
writePropertyName();
|
||||
builder.append(seconds);
|
||||
propertyPath.pop();
|
||||
|
||||
propertyPath.push(NANOS);
|
||||
writePropertyName();
|
||||
builder.append(nanos);
|
||||
propertyPath.pop();
|
||||
|
||||
endMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitDataSize(VmDataSize value) {
|
||||
throw new VmExceptionBuilder()
|
||||
.evalError("cannotRenderTypeAddConverter", "DataSize", "Protobuf")
|
||||
.withProgramValue("Value", value)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitBytes(VmBytes value) {
|
||||
throw new VmExceptionBuilder()
|
||||
.evalError("cannotRenderTypeAddConverter", "Bytes", "Protobuf")
|
||||
.withProgramValue("Value", value)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitIntSeq(VmIntSeq value) {
|
||||
writePropertyName();
|
||||
builder.append(value.toPklString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitPair(VmPair value) {
|
||||
writePropertyName();
|
||||
builder.append(value.toPklString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitRegex(VmRegex value) {
|
||||
writePropertyName();
|
||||
builder.append(value.toPklString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNull(VmNull value) {
|
||||
writePropertyName();
|
||||
builder.append(value.toPklString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitReference(VmReference value) {
|
||||
writePropertyName();
|
||||
builder.append(value.toPklString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves types for the purpose of protobuf rendering. "Sees through" nullable types and type
|
||||
* aliases, simplifies variations of {@code Int} and {@code String} types (literate string
|
||||
* types, {@code (U)Int_X_} type aliases, etc.), and checks that map key types are legal for
|
||||
* protobuf.
|
||||
*/
|
||||
// TODO: Memoize?
|
||||
private @Nullable TypeNode resolveType(@Nullable TypeNode type) {
|
||||
if (type instanceof IntTypeNode
|
||||
|| type instanceof StringTypeNode
|
||||
|| type instanceof BooleanTypeNode) {
|
||||
return type;
|
||||
} else if (type instanceof IntSlotTypeNode) {
|
||||
return INT_TYPE;
|
||||
} else if (type instanceof UnionOfStringLiteralsTypeNode
|
||||
|| type instanceof StringLiteralTypeNode) {
|
||||
return STRING_TYPE;
|
||||
} else if (type instanceof NullableTypeNode nullableType) {
|
||||
return resolveType(nullableType.getElementTypeNode());
|
||||
} else if (type instanceof TypeAliasTypeNode typeAliasType) {
|
||||
return resolveType(
|
||||
((VmType.AliasType) typeAliasType.getType()).getVmTypeAlias().getTypeNode());
|
||||
} else if (type instanceof ListingTypeNode listingType) {
|
||||
var valueType = resolveType(listingType.getValueTypeNode());
|
||||
assert valueType != null : "Failed to resolve type node.";
|
||||
|
||||
type =
|
||||
requiresWrapper()
|
||||
? null
|
||||
: new ListingTypeNode(
|
||||
VmUtils.unavailableSourceSection(), VmLanguage.get(null), valueType);
|
||||
return type;
|
||||
} else if (type instanceof MappingTypeNode mappingType) {
|
||||
var keyType = resolveType(mappingType.getKeyTypeNode());
|
||||
if (!(keyType instanceof IntTypeNode
|
||||
|| keyType instanceof StringTypeNode
|
||||
|| keyType instanceof BooleanTypeNode)) {
|
||||
throw new VmExceptionBuilder()
|
||||
.evalError("cannotRenderProtobufMapKeyType")
|
||||
.withSourceSection(type.getSourceSection())
|
||||
.build();
|
||||
}
|
||||
var valueType = resolveType(mappingType.getValueTypeNode());
|
||||
assert valueType != null : "Incomplete or malformed Mapping type";
|
||||
mappingType =
|
||||
new MappingTypeNode(
|
||||
VmUtils.unavailableSourceSection(), VmLanguage.get(null), keyType, valueType);
|
||||
|
||||
type = requiresWrapper() ? null : mappingType;
|
||||
return type;
|
||||
} else if (type instanceof UnionTypeNode) {
|
||||
// Some non-obvious normalization going on here:
|
||||
// - A union type resolves to a union type, unless all element types are string or string
|
||||
// literal types.
|
||||
// - All element types are resolved also.
|
||||
// - All string literal types are combined into a single String case.
|
||||
var hasString = false;
|
||||
var elements = new ArrayList<@Nullable TypeNode>();
|
||||
for (var t : ((UnionTypeNode) type).getElementTypeNodes()) {
|
||||
var resolved = resolveType(t);
|
||||
if (resolved instanceof StringLiteralTypeNode || resolved instanceof StringTypeNode) {
|
||||
if (!hasString) {
|
||||
hasString = true;
|
||||
elements.add(new StringTypeNode(VmUtils.unavailableSourceSection()));
|
||||
}
|
||||
} else {
|
||||
elements.add(resolved);
|
||||
}
|
||||
}
|
||||
// Sort classes with lowest-in-hierarchy first, to correctly derive names for oneOf.
|
||||
elements.sort(
|
||||
(o1, o2) -> {
|
||||
if (o1 instanceof ObjectSlotTypeNode && o2 instanceof ObjectSlotTypeNode) {
|
||||
var t1 = o1.getType().getVmClass();
|
||||
var t2 = o2.getType().getVmClass();
|
||||
if (t1 == null || t2 == null) return 0;
|
||||
return t1.isSubclassOf(t2) ? -1 : t2.isSubclassOf(t1) ? 1 : 0;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
type =
|
||||
hasString && elements.size() == 1
|
||||
? elements.get(0)
|
||||
: new UnionTypeNodeExploded(
|
||||
VmUtils.unavailableSourceSection(), -1, elements.toArray(new TypeNode[0]));
|
||||
return type;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
@NullMarked
|
||||
package org.pkl.core.stdlib.protobuf;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
@@ -619,12 +619,6 @@ Cannot render map with non-scalar key as {0}.
|
||||
cannotRenderObjectWithNonScalarKey=\
|
||||
Cannot render object with non-scalar key as {0}.
|
||||
|
||||
cannotRenderProtobufMapKey=\
|
||||
Cannot render map with a non-scalar, floating point or byte array key.
|
||||
|
||||
cannotRenderProtobufMapKeyType=\
|
||||
Cannot render map with a non-scalar, floating point or byte array key type.
|
||||
|
||||
cannotRenderObjectWithElementsAndOtherMembers=\
|
||||
Cannot render object with both elements and properties/entries as {0}.
|
||||
|
||||
@@ -759,17 +753,6 @@ The top-level value of an XML property list must have type `Typed`, `Dynamic`, `
|
||||
invalidPropertiesTopLevelValue=\
|
||||
The top-level value of a Java properties file must have type `Typed`, `Dynamic`, `Mapping`, or `Map`, but got type `{0}`.
|
||||
|
||||
invalidProtobufTopLevelValue=\
|
||||
The top-level value of a protobuf file must have type `Typed`, but got type `{0}`.
|
||||
|
||||
cannotResolveTypeForProtobuf=\
|
||||
Failed to resolve type required for rendering protobuf.\n\
|
||||
\n\
|
||||
Consider adding a type annotation.
|
||||
|
||||
cannotRenderSubtypeForProtobuf=\
|
||||
Cannot render subtype {0} of specified type {1} in protobuf.
|
||||
|
||||
cannotExportValue=\
|
||||
A value of type `{0}` cannot be exported.
|
||||
|
||||
|
||||
@@ -1,265 +0,0 @@
|
||||
amends "../snippetTest.pkl"
|
||||
|
||||
import "pkl:protobuf"
|
||||
|
||||
local renderer = new protobuf.Renderer {}
|
||||
local function renderValue(it: Any): String =
|
||||
renderer.renderValue(it)
|
||||
|
||||
/// For testing inheritance; [Foo] is the _base_ class.
|
||||
local open class Foo {
|
||||
foo: String
|
||||
}
|
||||
|
||||
/// For testing inheritance; [Bar] is the _derived_ class.
|
||||
local class Bar extends Foo {
|
||||
foo = "Bar"
|
||||
}
|
||||
|
||||
/// For testing the rendering of types inside a `VmTyped`.
|
||||
local class Baz {
|
||||
foo: Foo
|
||||
bar: Bar
|
||||
foos: Listing<Foo>
|
||||
bars: Mapping<String, Bar>
|
||||
}
|
||||
|
||||
/// For testing how rendering deals with _annotated_ (outer) collection types.
|
||||
local class CollectionTypes {
|
||||
emptyList: List<Foo>
|
||||
list: List<Foo> = List(new Bar {}, new Foo { foo = "test foo" })
|
||||
emptyListing: Listing<Foo>
|
||||
listing: Listing<Foo> = new {
|
||||
new Bar { foo = "listing bar" }
|
||||
new Foo { foo = "listing foo" }
|
||||
}
|
||||
emptyMap: Map<Int, String>
|
||||
map: Map<Int, Foo> = Map(
|
||||
1, new Bar { foo = "first" },
|
||||
2, new Foo { foo = "second" }
|
||||
)
|
||||
emptyMapping: Mapping<Int, Bar>
|
||||
mapping: String =
|
||||
module.catch(() ->
|
||||
renderValue(new Mapping<Foo, Bar> {
|
||||
[new Foo { foo = "key foo" }] = new Bar { foo = "value bar" }
|
||||
})
|
||||
)
|
||||
emptySet: Set<Foo>
|
||||
set: Set<Foo> = Set(
|
||||
new Bar { foo = "setOne" },
|
||||
new Bar { foo = "setTwo" }
|
||||
)
|
||||
mappingWithUnannotatedValueType: Mapping<String, Listing> = new {
|
||||
["some"] {
|
||||
new Bar {}
|
||||
new Bar {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// For testing _admissable_ mapping key types.
|
||||
local class MappingKeys {
|
||||
string: Mapping<String, Bar>
|
||||
long: Mapping<Int, Bar>
|
||||
int: Mapping<Int32, Bar>
|
||||
short: Mapping<Int16, Bar>
|
||||
boolean: Mapping<Boolean, Bar>
|
||||
}
|
||||
|
||||
/// For testing that using _inadmissable_ mapping key types does indeed throw.
|
||||
local class InvalidMappingKey {
|
||||
foo: Mapping<Bar, Bar>
|
||||
}
|
||||
|
||||
local typealias StringLiteralUnion
|
||||
= *"Qux"
|
||||
| "quux"
|
||||
| "QUUX"
|
||||
|
||||
local typealias OpenEndedStringUnion
|
||||
= *"corge"
|
||||
| String // Not a union of string literals, although fully String-y.
|
||||
|
||||
local typealias HeterogeneousUnion
|
||||
= "Grault"
|
||||
| "GRAULT"
|
||||
| Int
|
||||
| Foo
|
||||
|
||||
local typealias SynonymPureEnum = StringLiteralUnion
|
||||
|
||||
local class TypeAliasBehavior {
|
||||
doubleAlias: SynonymPureEnum
|
||||
}
|
||||
|
||||
local class StringLiteralUnionBehavior {
|
||||
theProperty: StringLiteralUnion
|
||||
}
|
||||
|
||||
local class OpenEndedStringUnionBehavior {
|
||||
theProperty: OpenEndedStringUnion
|
||||
}
|
||||
|
||||
local class HeterogeneousUnionBehavior {
|
||||
theHeterogeneousUnion: Listing<HeterogeneousUnion>
|
||||
}
|
||||
|
||||
local class HeterogeneousUnionBehaviorX {
|
||||
theHeterogeneousUnion: HeterogeneousUnion
|
||||
}
|
||||
|
||||
local class InvalidUnionBehavior {
|
||||
myMapping: Mapping<HeterogeneousUnion, Int> = new {
|
||||
[5] = 5
|
||||
}
|
||||
}
|
||||
|
||||
local class DynamicBehavior {
|
||||
myDynamic: Dynamic
|
||||
}
|
||||
|
||||
local class DurationBehavior {
|
||||
myDuration: Duration = 42.ns
|
||||
}
|
||||
|
||||
local class DataSizeBehavior {
|
||||
myDataSize: DataSize
|
||||
}
|
||||
|
||||
local class SubtypingBehavior {
|
||||
myFoo: Foo
|
||||
myFooOrBar: (Foo|Bar)?
|
||||
}
|
||||
|
||||
examples {
|
||||
["Rendering primitive values"] {
|
||||
for (v in new Listing {
|
||||
true
|
||||
false
|
||||
|
||||
-42 as Int8
|
||||
-42 as Int16
|
||||
-42 as Int32
|
||||
-42 as Int
|
||||
|
||||
42 as UInt8
|
||||
42 as UInt16
|
||||
42 as UInt32
|
||||
42 as UInt
|
||||
|
||||
-13.37 as Float
|
||||
|
||||
-13.37 as Number
|
||||
13.37 as Number
|
||||
-42 as Number
|
||||
42 as Number
|
||||
|
||||
"Hello world"
|
||||
|
||||
10.min
|
||||
2.ms
|
||||
120.ns
|
||||
5.s + 120.ns
|
||||
}) {
|
||||
renderValue(v)
|
||||
}
|
||||
}
|
||||
|
||||
["Collection types"] {
|
||||
renderValue(new CollectionTypes {})
|
||||
}
|
||||
|
||||
["Typed objects rendered as protobuf.ProtoMessage"] {
|
||||
renderValue(new Foo { foo = "new" })
|
||||
renderValue(new Bar {})
|
||||
renderValue(new Bar { foo = "Baz" })
|
||||
renderValue(
|
||||
new Baz {
|
||||
foo {
|
||||
foo = "FOO"
|
||||
}
|
||||
foos {
|
||||
foo
|
||||
outer.bar
|
||||
}
|
||||
bars {
|
||||
["default"] {}
|
||||
["amended"] {
|
||||
foo = "Bars"
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
renderValue(new DurationBehavior {})
|
||||
}
|
||||
|
||||
["Unsupported types"] {
|
||||
module.catch(() -> throw(renderValue(new DynamicBehavior {})))
|
||||
module.catch(() -> throw(renderValue(new DataSizeBehavior { myDataSize = 10.kb })))
|
||||
}
|
||||
|
||||
["Types not supported at top-level"] {
|
||||
module.catch(() -> throw(renderValue(Map(3,4))))
|
||||
module.catch(() -> throw(renderValue(new Mapping {[1] = 2})))
|
||||
}
|
||||
|
||||
["Keys in maps"] {
|
||||
renderValue(new MappingKeys {
|
||||
string {
|
||||
["Hello world"] {}
|
||||
}
|
||||
long {
|
||||
[1337] {}
|
||||
}
|
||||
int {
|
||||
[42] {}
|
||||
}
|
||||
short {
|
||||
[1] {}
|
||||
}
|
||||
boolean {
|
||||
[false] {}
|
||||
}
|
||||
})
|
||||
module.catch(() -> throw(renderValue(new InvalidMappingKey {
|
||||
foo {
|
||||
[new Bar {}] {}
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
||||
["typealiases"] {
|
||||
renderValue(new TypeAliasBehavior {})
|
||||
}
|
||||
|
||||
["unions"] {
|
||||
renderValue(new StringLiteralUnionBehavior {})
|
||||
renderValue(new OpenEndedStringUnionBehavior {})
|
||||
renderValue(new HeterogeneousUnionBehaviorX {
|
||||
theHeterogeneousUnion = "Grault"
|
||||
})
|
||||
renderValue(new HeterogeneousUnionBehavior {
|
||||
theHeterogeneousUnion {
|
||||
"Grault"
|
||||
0
|
||||
new Bar {}
|
||||
}
|
||||
})
|
||||
module.catch(() -> renderValue(new InvalidUnionBehavior {}))
|
||||
}
|
||||
["subtypes"] {
|
||||
renderValue(new SubtypingBehavior {
|
||||
myFoo = new Foo { foo = "renders" }
|
||||
})
|
||||
module.catch(() ->
|
||||
renderValue(new SubtypingBehavior {
|
||||
myFoo = new Bar { foo = "shouldn't render" }
|
||||
})
|
||||
)
|
||||
renderValue(new SubtypingBehavior {
|
||||
myFoo = new Foo { foo = "renders" }
|
||||
myFooOrBar = new Bar { foo = "also renders" }
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
amends "../snippetTest.pkl"
|
||||
|
||||
import "pkl:protobuf"
|
||||
|
||||
local renderer = new protobuf.Renderer {}
|
||||
|
||||
local class NestedStructures {
|
||||
plainString: String = "plain string"
|
||||
nestedListing: Listing<Listing<String>>
|
||||
nestedListing2: Listing<Listing<Listing<Listing<String>>>>
|
||||
nestedMapping: Mapping<String, Mapping<Int, Boolean>>
|
||||
listingInMapping: Mapping<String, Listing<String>>
|
||||
mappingInListing: Listing<Mapping<Int, Boolean>>
|
||||
nestedList: List<List<String>>
|
||||
nestedMap: Map<String, Map<Int, Boolean>>
|
||||
}
|
||||
|
||||
examples {
|
||||
["some"] {
|
||||
renderer.renderDocument(new NestedStructures {
|
||||
nestedListing {
|
||||
new {
|
||||
"foo"
|
||||
"bar"
|
||||
}
|
||||
new {
|
||||
"baz"
|
||||
"qux"
|
||||
}
|
||||
}
|
||||
nestedListing2 {
|
||||
new {
|
||||
new {
|
||||
new {
|
||||
"foo"
|
||||
"bar"
|
||||
"baz"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nestedMapping {
|
||||
["quux"] {
|
||||
[42] = true
|
||||
[1337] = false
|
||||
}
|
||||
["corge"] {
|
||||
[0] = false
|
||||
}
|
||||
}
|
||||
listingInMapping {
|
||||
["grault"] {
|
||||
"grault1"
|
||||
"grault2"
|
||||
}
|
||||
["garply"] {
|
||||
"garply1"
|
||||
}
|
||||
["waldo"] {}
|
||||
}
|
||||
mappingInListing {
|
||||
new {
|
||||
[-1] = false
|
||||
[1] = true
|
||||
}
|
||||
new {
|
||||
[-2] = true
|
||||
[2] = false
|
||||
}
|
||||
}
|
||||
nestedList = List(List("pigeon", "plugh"), List(), List("xyzzy"))
|
||||
nestedMap = Map("thud", Map(), "wibble", Map(1, false, 2, true), "wobble", Map(0, false))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import "pkl:protobuf"
|
||||
|
||||
import ".../input-helper/api/annotationConverter.pkl"
|
||||
|
||||
class Comment extends Annotation
|
||||
|
||||
@protobuf.Property { name = "FOO" }
|
||||
foo: String = "a"
|
||||
|
||||
@annotationConverter.LineComment { text = "bar" }
|
||||
bar: String = "b"
|
||||
|
||||
baz: Nested
|
||||
|
||||
class Nested {
|
||||
@annotationConverter.LineComment { text = "qux" }
|
||||
qux: String = "c"
|
||||
|
||||
quux: String = "c"
|
||||
}
|
||||
|
||||
output {
|
||||
renderer = new protobuf.Renderer {
|
||||
convertPropertyTransformers {
|
||||
[annotationConverter.LineComment] { prefix = " # " }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ amends ".../snippetTest.pkl"
|
||||
|
||||
import "pkl:xml"
|
||||
import "pkl:jsonnet"
|
||||
import "pkl:protobuf"
|
||||
|
||||
examples {
|
||||
for (format, renderer in new Mapping {
|
||||
@@ -11,7 +10,6 @@ examples {
|
||||
["jsonnet"] = new jsonnet.Renderer {}
|
||||
["plist"] = new PListRenderer {}
|
||||
["properties"] = new PropertiesRenderer {}
|
||||
["textproto"] = new protobuf.Renderer {}
|
||||
["xml"] = new xml.Renderer {}
|
||||
["yaml"] = new YamlRenderer {}
|
||||
}) {
|
||||
@@ -23,9 +21,6 @@ examples {
|
||||
listing = null
|
||||
mapping = null
|
||||
}
|
||||
when (format == "textproto") {
|
||||
dynamic = null
|
||||
}
|
||||
})
|
||||
renderer.renderDocument(new RenderDirective { text = #"✅\❌ /-#;)<>"# })
|
||||
}
|
||||
|
||||
@@ -2,13 +2,6 @@ amends ".../snippetTest.pkl"
|
||||
|
||||
import "pkl:xml"
|
||||
import "pkl:jsonnet"
|
||||
import "pkl:protobuf"
|
||||
|
||||
local class TypedTestCase {
|
||||
property: String
|
||||
elements: Listing<String>
|
||||
entries: Mapping<String, String>
|
||||
}
|
||||
|
||||
examples {
|
||||
for (format, renderer in new Mapping {
|
||||
@@ -26,16 +19,6 @@ examples {
|
||||
[Listing] = (it: Listing) -> it.join(",")
|
||||
}
|
||||
} |> converters
|
||||
["textproto"] = new protobuf.Renderer {
|
||||
converters {
|
||||
[Dynamic] = (it) ->
|
||||
(it) {
|
||||
elements = it.elements.toList().toListing()
|
||||
entries = it.entries.toMap().toMapping()
|
||||
}.toTyped(TypedTestCase)
|
||||
[String] = (it) -> new RenderDirective { text = "(\(it))"}
|
||||
}
|
||||
}
|
||||
["xml"] = new xml.Renderer {} |> converters
|
||||
["yaml"] = new YamlRenderer {} |> converters
|
||||
}) {
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
examples {
|
||||
["Rendering primitive values"] {
|
||||
"true"
|
||||
"false"
|
||||
"-42"
|
||||
"-42"
|
||||
"-42"
|
||||
"-42"
|
||||
"42"
|
||||
"42"
|
||||
"42"
|
||||
"42"
|
||||
"-13.37"
|
||||
"-13.37"
|
||||
"13.37"
|
||||
"-42"
|
||||
"42"
|
||||
"\"Hello world\""
|
||||
"""
|
||||
{
|
||||
seconds: 600
|
||||
nanos: 0
|
||||
}
|
||||
"""
|
||||
"""
|
||||
{
|
||||
seconds: 0
|
||||
nanos: 2000000
|
||||
}
|
||||
"""
|
||||
"""
|
||||
{
|
||||
seconds: 0
|
||||
nanos: 120
|
||||
}
|
||||
"""
|
||||
"""
|
||||
{
|
||||
seconds: 5
|
||||
nanos: 120
|
||||
}
|
||||
"""
|
||||
}
|
||||
["Collection types"] {
|
||||
"""
|
||||
list: {
|
||||
foo: "Bar"
|
||||
}
|
||||
list: {
|
||||
foo: "test foo"
|
||||
}
|
||||
listing: {
|
||||
foo: "listing bar"
|
||||
}
|
||||
listing: {
|
||||
foo: "listing foo"
|
||||
}
|
||||
map: {
|
||||
key: 1
|
||||
value: {
|
||||
foo: "first"
|
||||
}
|
||||
}
|
||||
map: {
|
||||
key: 2
|
||||
value: {
|
||||
foo: "second"
|
||||
}
|
||||
}
|
||||
mapping: "Cannot call method `renderValue` from here because it is not `const`."
|
||||
set: {
|
||||
foo: "setOne"
|
||||
}
|
||||
set: {
|
||||
foo: "setTwo"
|
||||
}
|
||||
mappingWithUnannotatedValueType: {
|
||||
key: "some"
|
||||
value: {
|
||||
it: {
|
||||
foo: "Bar"
|
||||
}
|
||||
it: {
|
||||
foo: "Bar"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
["Typed objects rendered as protobuf.ProtoMessage"] {
|
||||
"foo: \"new\""
|
||||
"foo: \"Bar\""
|
||||
"foo: \"Baz\""
|
||||
"""
|
||||
foo: {
|
||||
foo: "FOO"
|
||||
}
|
||||
bar: {
|
||||
foo: "Bar"
|
||||
}
|
||||
foos: {
|
||||
foo: "FOO"
|
||||
}
|
||||
foos: {
|
||||
foo: "Bar"
|
||||
}
|
||||
bars: {
|
||||
key: "default"
|
||||
value: {
|
||||
foo: "Bar"
|
||||
}
|
||||
}
|
||||
bars: {
|
||||
key: "amended"
|
||||
value: {
|
||||
foo: "Bars"
|
||||
}
|
||||
}
|
||||
"""
|
||||
"""
|
||||
myDuration: {
|
||||
seconds: 0
|
||||
nanos: 42
|
||||
}
|
||||
"""
|
||||
}
|
||||
["Unsupported types"] {
|
||||
"Cannot render value of type `Dynamic` as Protobuf. Value: new Dynamic {}"
|
||||
"Cannot render value of type `DataSize` as Protobuf. Value: 10.kb"
|
||||
}
|
||||
["Types not supported at top-level"] {
|
||||
"The top-level value of a protobuf file must have type `Typed`, but got type `Map`."
|
||||
"The top-level value of a protobuf file must have type `Typed`, but got type `Mapping`."
|
||||
}
|
||||
["Keys in maps"] {
|
||||
"""
|
||||
string: {
|
||||
key: "Hello world"
|
||||
value: {
|
||||
foo: "Bar"
|
||||
}
|
||||
}
|
||||
long: {
|
||||
key: 1337
|
||||
value: {
|
||||
foo: "Bar"
|
||||
}
|
||||
}
|
||||
int: {
|
||||
key: 42
|
||||
value: {
|
||||
foo: "Bar"
|
||||
}
|
||||
}
|
||||
short: {
|
||||
key: 1
|
||||
value: {
|
||||
foo: "Bar"
|
||||
}
|
||||
}
|
||||
boolean: {
|
||||
key: false
|
||||
value: {
|
||||
foo: "Bar"
|
||||
}
|
||||
}
|
||||
"""
|
||||
"Cannot render map with a non-scalar, floating point or byte array key type."
|
||||
}
|
||||
["typealiases"] {
|
||||
"doubleAlias: \"Qux\""
|
||||
}
|
||||
["unions"] {
|
||||
"theProperty: \"Qux\""
|
||||
"theProperty: \"corge\""
|
||||
"""
|
||||
theHeterogeneousUnion: {
|
||||
it_String: "Grault"
|
||||
}
|
||||
"""
|
||||
"""
|
||||
theHeterogeneousUnion: {
|
||||
it_String: "Grault"
|
||||
}
|
||||
theHeterogeneousUnion: {
|
||||
it_Int: 0
|
||||
}
|
||||
theHeterogeneousUnion: {
|
||||
it_Foo: {
|
||||
foo: "Bar"
|
||||
}
|
||||
}
|
||||
"""
|
||||
"Cannot render map with a non-scalar, floating point or byte array key type."
|
||||
}
|
||||
["subtypes"] {
|
||||
"""
|
||||
myFoo: {
|
||||
foo: "renders"
|
||||
}
|
||||
"""
|
||||
"Cannot render subtype protobuf#Foo of specified type protobuf#Bar in protobuf."
|
||||
"""
|
||||
myFoo: {
|
||||
foo: "renders"
|
||||
}
|
||||
myFooOrBar: {
|
||||
it_Bar: {
|
||||
foo: "also renders"
|
||||
}
|
||||
}
|
||||
"""
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
examples {
|
||||
["some"] {
|
||||
"""
|
||||
plainString: "plain string"
|
||||
nestedListing: {
|
||||
it: "foo"
|
||||
it: "bar"
|
||||
}
|
||||
nestedListing: {
|
||||
it: "baz"
|
||||
it: "qux"
|
||||
}
|
||||
nestedListing2: {
|
||||
it: {
|
||||
it: {
|
||||
it: "foo"
|
||||
it: "bar"
|
||||
it: "baz"
|
||||
}
|
||||
}
|
||||
}
|
||||
nestedMapping: {
|
||||
key: "quux"
|
||||
value: {
|
||||
it: {
|
||||
key: 42
|
||||
value: true
|
||||
}
|
||||
it: {
|
||||
key: 1337
|
||||
value: false
|
||||
}
|
||||
}
|
||||
}
|
||||
nestedMapping: {
|
||||
key: "corge"
|
||||
value: {
|
||||
it: {
|
||||
key: 0
|
||||
value: false
|
||||
}
|
||||
}
|
||||
}
|
||||
listingInMapping: {
|
||||
key: "grault"
|
||||
value: {
|
||||
it: "grault1"
|
||||
it: "grault2"
|
||||
}
|
||||
}
|
||||
listingInMapping: {
|
||||
key: "garply"
|
||||
value: {
|
||||
it: "garply1"
|
||||
}
|
||||
}
|
||||
listingInMapping: {
|
||||
key: "waldo"
|
||||
value: {}
|
||||
}
|
||||
mappingInListing: {
|
||||
it: {
|
||||
key: -1
|
||||
value: false
|
||||
}
|
||||
it: {
|
||||
key: 1
|
||||
value: true
|
||||
}
|
||||
}
|
||||
mappingInListing: {
|
||||
it: {
|
||||
key: -2
|
||||
value: true
|
||||
}
|
||||
it: {
|
||||
key: 2
|
||||
value: false
|
||||
}
|
||||
}
|
||||
nestedList: {
|
||||
it: "pigeon"
|
||||
it: "plugh"
|
||||
}
|
||||
nestedList: {}
|
||||
nestedList: {
|
||||
it: "xyzzy"
|
||||
}
|
||||
nestedMap: {
|
||||
key: "thud"
|
||||
value: {}
|
||||
}
|
||||
nestedMap: {
|
||||
key: "wibble"
|
||||
value: {
|
||||
it: {
|
||||
key: 1
|
||||
value: false
|
||||
}
|
||||
it: {
|
||||
key: 2
|
||||
value: true
|
||||
}
|
||||
}
|
||||
}
|
||||
nestedMap: {
|
||||
key: "wobble"
|
||||
value: {
|
||||
it: {
|
||||
key: 0
|
||||
value: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
FOO: "a"
|
||||
bar: "b" # bar
|
||||
baz: {
|
||||
qux: "c" # qux
|
||||
quux: "c"
|
||||
}
|
||||
@@ -176,37 +176,6 @@ examples {
|
||||
"""
|
||||
"✅\\❌ /-#;)<>"
|
||||
}
|
||||
["textproto"] {
|
||||
"""
|
||||
1"2
|
||||
3\t4'
|
||||
"""
|
||||
"+* /\\-;)❌#✅<>"
|
||||
"""
|
||||
directiveProperty: ✅/&\\;)*❌
|
||||
normalProperty: 42
|
||||
listing: "foo"
|
||||
listing: 💰
|
||||
listing: "baz"
|
||||
mapping: {
|
||||
key: "key"
|
||||
value: "value"
|
||||
}
|
||||
mapping: {
|
||||
key: 🔑
|
||||
value: 42
|
||||
}
|
||||
mapping: {
|
||||
key: "other"
|
||||
value: 💰
|
||||
}
|
||||
|
||||
"""
|
||||
"""
|
||||
✅\\❌ /-#;)<>
|
||||
|
||||
"""
|
||||
}
|
||||
["xml"] {
|
||||
"""
|
||||
1"2
|
||||
|
||||
@@ -79,22 +79,6 @@ examples {
|
||||
|
||||
"""
|
||||
}
|
||||
["textproto"] {
|
||||
"""
|
||||
property: (value)
|
||||
elements: (element1)
|
||||
elements: (element2)
|
||||
entries: {
|
||||
key: (key1)
|
||||
value: (value1)
|
||||
}
|
||||
entries: {
|
||||
key: (key2)
|
||||
value: (value2)
|
||||
}
|
||||
|
||||
"""
|
||||
}
|
||||
["xml"] {
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
-1
@@ -20,7 +20,6 @@ pkl:net
|
||||
pkl:pklbinary
|
||||
pkl:platform
|
||||
pkl:Project
|
||||
pkl:protobuf
|
||||
pkl:ref
|
||||
pkl:reflect
|
||||
pkl:release
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2024-2026 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.
|
||||
@@ -30,7 +30,6 @@ class ReflectModuleTest {
|
||||
"pkl:json",
|
||||
"pkl:jsonnet",
|
||||
"pkl:math",
|
||||
"pkl:protobuf",
|
||||
"pkl:reflect",
|
||||
"pkl:settings",
|
||||
"pkl:shell",
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
start_timestamp_ms: 0
|
||||
end_timestamp_ms: 100
|
||||
people: {
|
||||
key: "Pigeon"
|
||||
value: {
|
||||
name: "Pigeon"
|
||||
profile: {
|
||||
isExtinct: false
|
||||
}
|
||||
fictional: true
|
||||
height: 1.77
|
||||
hobbies: "cooing"
|
||||
role: Lead
|
||||
}
|
||||
}
|
||||
people: {
|
||||
key: "Parrot"
|
||||
value: {
|
||||
name: "Parrot"
|
||||
fictional: true
|
||||
height: 1.76
|
||||
hobbies: "singing"
|
||||
role: Lead
|
||||
}
|
||||
}
|
||||
owner: "Pigeon"
|
||||
+1
-4
@@ -26,7 +26,6 @@ import "pkl:math"
|
||||
import "pkl:net"
|
||||
import "pkl:pklbinary"
|
||||
// noinspection Deprecated
|
||||
import "pkl:protobuf"
|
||||
import "pkl:xml"
|
||||
import "pkl:yaml"
|
||||
|
||||
@@ -116,8 +115,6 @@ abstract external class Module {
|
||||
new PListRenderer {}
|
||||
else if (format == "properties")
|
||||
new PropertiesRenderer {}
|
||||
else if (format == "textproto")
|
||||
new protobuf.Renderer {}
|
||||
else if (format == "xml")
|
||||
new xml.Renderer {}
|
||||
else if (format == "yaml")
|
||||
@@ -126,7 +123,7 @@ abstract external class Module {
|
||||
new pklbinary.Renderer {}
|
||||
else
|
||||
throw(
|
||||
"Unknown output format: `\(format)`. Supported formats are `json`, `jsonnet`, `pcf`, `plist`, `properties`, `textproto`, `xml`, `yaml`, `pkl-binary`."
|
||||
"Unknown output format: `\(format)`. Supported formats are `json`, `jsonnet`, `pcf`, `plist`, `properties`, `xml`, `yaml`, `pkl-binary`."
|
||||
)
|
||||
text =
|
||||
if (renderer is ValueRenderer)
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Copyright © 2024-2026 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.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// A renderer for [Protocol Buffers](https://developers.google.com/protocol-buffers).
|
||||
///
|
||||
/// WARNING:
|
||||
/// This module is deprecated, and scheduled for removal without replacement.
|
||||
/// For rendering into a protobuf wire format, consider rendering to
|
||||
/// [ProtoJSON](https://protobuf.dev/programming-guides/json/) using [json.Renderer].
|
||||
@ModuleInfo { minPklVersion = "0.34.0" }
|
||||
@Deprecated { since = "0.33.0"; message = "Scheduled for removal without replacement" }
|
||||
module pkl.protobuf
|
||||
|
||||
import "pkl:json"
|
||||
import "pkl:reflect"
|
||||
|
||||
/// A renderer for [Protocol Buffers](https://developers.google.com/protocol-buffers).
|
||||
/// Note: This class is _experimental_ and not ready for production use.
|
||||
///
|
||||
/// As of this release, only Protocol Buffers' text format is supported.
|
||||
///
|
||||
/// The [Property] annotation can be used to change how a property name renders into Protobuf.
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// import "pkl:protobuf"
|
||||
///
|
||||
/// @protobuf.Property { name = "wing_span" }
|
||||
/// wingSpan: Int
|
||||
/// ```
|
||||
class Renderer extends ValueRenderer {
|
||||
/// The characters to use for indenting output.
|
||||
///
|
||||
/// Defaults to two spaces.
|
||||
indent: String = " "
|
||||
|
||||
external function renderDocument(value: Any): String
|
||||
|
||||
external function renderValue(value: Any): String
|
||||
|
||||
/// Returns the canonical name for [type].
|
||||
external function renderType(type: reflect.Type): String
|
||||
}
|
||||
|
||||
/// Annotate properties of classes and modules with this class to override how a [Renderer]
|
||||
/// interprets a property's name.
|
||||
@Since { version = "0.31.0" }
|
||||
class Property extends ConvertProperty {
|
||||
/// The new name to use for the annotated property when rendered by [Renderer].
|
||||
name: String
|
||||
|
||||
render = (prop, renderer) -> if (renderer is Renderer) Pair(name, prop.value) else prop
|
||||
}
|
||||
Reference in new issue
Block a user