From 0c9553db8ca7c2da12bea0d2eb026e24f7bae9a4 Mon Sep 17 00:00:00 2001 From: Yi Jin Date: Thu, 20 Jan 2022 19:50:31 -0800 Subject: [PATCH 1/3] Implement quote_keys flag for std functions manifestYamlDoc/manifestYamlStream to match official jsonnet doc --- sjsonnet/src/sjsonnet/Std.scala | 20 +++++++++++++++---- sjsonnet/src/sjsonnet/YamlRenderer.scala | 12 ++++++++++- .../test/src/sjsonnet/YamlRendererTests.scala | 6 +++++- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/sjsonnet/src/sjsonnet/Std.scala b/sjsonnet/src/sjsonnet/Std.scala index 79bf7b09..32697407 100644 --- a/sjsonnet/src/sjsonnet/Std.scala +++ b/sjsonnet/src/sjsonnet/Std.scala @@ -1121,33 +1121,45 @@ class Std { builtin(ManifestTomlEx), builtinWithDefaults("manifestYamlDoc", "v" -> null, - "indent_array_in_object" -> Val.False(dummyPos)){ (args, pos, ev) => + "indent_array_in_object" -> Val.False(dummyPos), + "quote_keys" -> Val.True(dummyPos)){ (args, pos, ev) => val v = args(0) val indentArrayInObject = args(1) match { case Val.False(_) => false case Val.True(_) => true case _ => Error.fail("indent_array_in_object has to be a boolean, got" + v.getClass) } + val quoteKeys = args(2) match { + case Val.False(_) => false + case Val.True(_) => true + case _ => Error.fail("quote_keys has to be a boolean, got " + v.getClass) + } Materializer.apply0( v, - new YamlRenderer(indentArrayInObject = indentArrayInObject) + new YamlRenderer(indentArrayInObject = indentArrayInObject, quoteKeys = quoteKeys) )(ev).toString }, builtinWithDefaults("manifestYamlStream", "v" -> null, - "indent_array_in_object" -> Val.False(dummyPos)){ (args, pos, ev) => + "indent_array_in_object" -> Val.False(dummyPos), + "quote_keys" -> Val.True(dummyPos)){ (args, pos, ev) => val v = args(0) val indentArrayInObject = args(1) match { case Val.False(_) => false case Val.True(_) => true case _ => Error.fail("indent_array_in_object has to be a boolean, got" + v.getClass) } + val quoteKeys = args(2) match { + case Val.False(_) => false + case Val.True(_) => true + case _ => Error.fail("quote_keys has to be a boolean, got " + v.getClass) + } v match { case arr: Val.Arr => arr.asLazyArray .map { item => Materializer.apply0( item.force, - new YamlRenderer(indentArrayInObject = indentArrayInObject) + new YamlRenderer(indentArrayInObject = indentArrayInObject, quoteKeys = quoteKeys) )(ev).toString() } .mkString("---\n", "\n---\n", "\n...\n") diff --git a/sjsonnet/src/sjsonnet/YamlRenderer.scala b/sjsonnet/src/sjsonnet/YamlRenderer.scala index b542fad2..84c0700b 100644 --- a/sjsonnet/src/sjsonnet/YamlRenderer.scala +++ b/sjsonnet/src/sjsonnet/YamlRenderer.scala @@ -8,7 +8,7 @@ import upickle.core.{ArrVisitor, ObjVisitor} class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayInObject: Boolean = false, - indent: Int = 2) extends BaseCharRenderer(_out, indent){ + quoteKeys: Boolean = true, indent: Int = 2) extends BaseCharRenderer(_out, indent){ var newlineBuffered = false var dashBuffered = false var afterKey = false @@ -30,6 +30,15 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI } } + private[this] def removeQuoteKey(): Unit = { + // refer to quote_keys parameter in https://jsonnet.org/ref/stdlib.html, only unquote keys + if (!quoteKeys && !afterKey) { + val key = elemBuilder.makeString() + elemBuilder.reset() + elemBuilder.appendAll(key.toCharArray, 1, key.length - 2); + } + } + override def visitString(s: CharSequence, index: Int): StringWriter = { flushBuffer() val len = s.length() @@ -49,6 +58,7 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI depth -= 1 } else { upickle.core.RenderUtils.escapeChar(unicodeCharBuilder, elemBuilder, s, true) + removeQuoteKey() } flushCharBuilder() _out diff --git a/sjsonnet/test/src/sjsonnet/YamlRendererTests.scala b/sjsonnet/test/src/sjsonnet/YamlRendererTests.scala index 72958fa1..ad6aab07 100644 --- a/sjsonnet/test/src/sjsonnet/YamlRendererTests.scala +++ b/sjsonnet/test/src/sjsonnet/YamlRendererTests.scala @@ -30,7 +30,11 @@ object YamlRendererTests extends TestSuite{ """- "a": | - 1""".stripMargin } - + test("noQuote") { + ujson.transform(ujson.Obj("k0" -> "v0", "k1" -> "(\\d+)"), new YamlRenderer(quoteKeys = false)).toString ==> + """k0: "v0" + |k1: "(\\d+)"""".stripMargin + } } } \ No newline at end of file From 77417869d3eee108d1b08d5f7669b9a489c513cb Mon Sep 17 00:00:00 2001 From: Stephen Amar Date: Tue, 10 Dec 2024 13:40:11 -0800 Subject: [PATCH 2/3] Add bare keys check and support for c_document_end in yaml stream --- sjsonnet/src/sjsonnet/BaseCharRenderer.scala | 49 +- sjsonnet/src/sjsonnet/Std.scala | 12 +- sjsonnet/src/sjsonnet/YamlRenderer.scala | 81 ++- .../test/resources/test_suite/stdlib.jsonnet | 624 +++++++++--------- .../test_suite/stdlib_native.jsonnet | 354 +++++----- 5 files changed, 580 insertions(+), 540 deletions(-) diff --git a/sjsonnet/src/sjsonnet/BaseCharRenderer.scala b/sjsonnet/src/sjsonnet/BaseCharRenderer.scala index 1108feb2..78822945 100644 --- a/sjsonnet/src/sjsonnet/BaseCharRenderer.scala +++ b/sjsonnet/src/sjsonnet/BaseCharRenderer.scala @@ -4,16 +4,16 @@ package sjsonnet // with some private definitions made accessible to subclasses import ujson._ + import scala.annotation.switch -import upickle.core.{ArrVisitor, ObjVisitor} +import upickle.core.{ArrVisitor, ObjVisitor, Visitor} class BaseCharRenderer[T <: upickle.core.CharOps.Output] (out: T, indent: Int = -1, escapeUnicode: Boolean = false, newline: Array[Char] = Array('\n')) extends JsVisitor[T, T]{ protected[this] val elemBuilder = new upickle.core.CharBuilder - protected[this] val unicodeCharBuilder = new upickle.core.CharBuilder() - def flushCharBuilder() = { + def flushCharBuilder(): Unit = { elemBuilder.writeOutToIfLongerThan(out, if (depth == 0) 0 else 1000) } @@ -22,25 +22,29 @@ class BaseCharRenderer[T <: upickle.core.CharOps.Output] protected[this] var commaBuffered = false - def flushBuffer() = { + def flushBuffer(): Unit = { if (commaBuffered) { commaBuffered = false elemBuilder.append(',') renderIndent() } } - def visitArray(length: Int, index: Int) = new ArrVisitor[T, T] { + + def visitArray(length: Int, index: Int): ArrVisitor[T, T] = new ArrVisitor[T, T] { flushBuffer() elemBuilder.append('[') depth += 1 renderIndent() - def subVisitor = BaseCharRenderer.this + + def subVisitor: Visitor[T, T] = BaseCharRenderer.this + def visitValue(v: T, index: Int): Unit = { flushBuffer() commaBuffered = true } - def visitEnd(index: Int) = { + + def visitEnd(index: Int): T = { commaBuffered = false depth -= 1 renderIndent() @@ -50,21 +54,26 @@ class BaseCharRenderer[T <: upickle.core.CharOps.Output] } } - def visitObject(length: Int, index: Int) = new ObjVisitor[T, T] { + def visitObject(length: Int, index: Int): ObjVisitor[T, T] = new ObjVisitor[T, T] { flushBuffer() elemBuilder.append('{') depth += 1 renderIndent() - def subVisitor = BaseCharRenderer.this - def visitKey(index: Int) = BaseCharRenderer.this + + def subVisitor: Visitor[T, T] = BaseCharRenderer.this + + def visitKey(index: Int): Visitor[T, T] = BaseCharRenderer.this + def visitKeyValue(s: Any): Unit = { elemBuilder.append(':') if (indent != -1) elemBuilder.append(' ') } + def visitValue(v: T, index: Int): Unit = { commaBuffered = true } - def visitEnd(index: Int) = { + + def visitEnd(index: Int): T = { commaBuffered = false depth -= 1 renderIndent() @@ -74,7 +83,7 @@ class BaseCharRenderer[T <: upickle.core.CharOps.Output] } } - def visitNull(index: Int) = { + def visitNull(index: Int): T = { flushBuffer() elemBuilder.ensureLength(4) elemBuilder.appendUnsafe('n') @@ -85,7 +94,7 @@ class BaseCharRenderer[T <: upickle.core.CharOps.Output] out } - def visitFalse(index: Int) = { + def visitFalse(index: Int): T = { flushBuffer() elemBuilder.ensureLength(5) elemBuilder.appendUnsafe('f') @@ -97,7 +106,7 @@ class BaseCharRenderer[T <: upickle.core.CharOps.Output] out } - def visitTrue(index: Int) = { + def visitTrue(index: Int): T = { flushBuffer() elemBuilder.ensureLength(4) elemBuilder.appendUnsafe('t') @@ -108,7 +117,7 @@ class BaseCharRenderer[T <: upickle.core.CharOps.Output] out } - def visitFloat64StringParts(s: CharSequence, decIndex: Int, expIndex: Int, index: Int) = { + def visitFloat64StringParts(s: CharSequence, decIndex: Int, expIndex: Int, index: Int): T = { flushBuffer() elemBuilder.ensureLength(s.length()) var i = 0 @@ -121,7 +130,7 @@ class BaseCharRenderer[T <: upickle.core.CharOps.Output] out } - override def visitFloat64(d: Double, index: Int) = { + override def visitFloat64(d: Double, index: Int): T = { d match{ case Double.PositiveInfinity => visitNonNullString("Infinity", -1) case Double.NegativeInfinity => visitNonNullString("-Infinity", -1) @@ -137,20 +146,20 @@ class BaseCharRenderer[T <: upickle.core.CharOps.Output] } - def visitString(s: CharSequence, index: Int) = { + def visitString(s: CharSequence, index: Int): T = { if (s eq null) visitNull(index) else visitNonNullString(s, index) } - def visitNonNullString(s: CharSequence, index: Int) = { + private def visitNonNullString(s: CharSequence, index: Int) = { flushBuffer() - upickle.core.RenderUtils.escapeChar(unicodeCharBuilder, elemBuilder, s, escapeUnicode) + upickle.core.RenderUtils.escapeChar(null, elemBuilder, s, escapeUnicode) flushCharBuilder() out } - final def renderIndent() = { + final def renderIndent(): Unit = { if (indent == -1) () else { var i = indent * depth diff --git a/sjsonnet/src/sjsonnet/Std.scala b/sjsonnet/src/sjsonnet/Std.scala index 32697407..3b90135b 100644 --- a/sjsonnet/src/sjsonnet/Std.scala +++ b/sjsonnet/src/sjsonnet/Std.scala @@ -1142,14 +1142,20 @@ class Std { builtinWithDefaults("manifestYamlStream", "v" -> null, "indent_array_in_object" -> Val.False(dummyPos), - "quote_keys" -> Val.True(dummyPos)){ (args, pos, ev) => + "c_document_end" -> Val.True(dummyPos), + "quote_keys" -> Val.True(dummyPos)){ (args, _, ev) => val v = args(0) val indentArrayInObject = args(1) match { case Val.False(_) => false case Val.True(_) => true case _ => Error.fail("indent_array_in_object has to be a boolean, got" + v.getClass) } - val quoteKeys = args(2) match { + val cDocumentEnd = args(2) match { + case Val.False(_) => false + case Val.True(_) => true + case _ => Error.fail("c_document_end has to be a boolean, got " + v.getClass) + } + val quoteKeys = args(3) match { case Val.False(_) => false case Val.True(_) => true case _ => Error.fail("quote_keys has to be a boolean, got " + v.getClass) @@ -1162,7 +1168,7 @@ class Std { new YamlRenderer(indentArrayInObject = indentArrayInObject, quoteKeys = quoteKeys) )(ev).toString() } - .mkString("---\n", "\n---\n", "\n...\n") + .mkString("---\n", "\n---\n", if (cDocumentEnd) "\n...\n" else "\n") case _ => Error.fail("manifestYamlStream only takes arrays, got " + v.getClass) } }, diff --git a/sjsonnet/src/sjsonnet/YamlRenderer.scala b/sjsonnet/src/sjsonnet/YamlRenderer.scala index 84c0700b..26e75822 100644 --- a/sjsonnet/src/sjsonnet/YamlRenderer.scala +++ b/sjsonnet/src/sjsonnet/YamlRenderer.scala @@ -1,9 +1,10 @@ package sjsonnet -import java.io.{StringWriter, Writer} +import java.io.StringWriter import java.util.regex.Pattern +import upickle.core.{ArrVisitor, ObjVisitor, SimpleVisitor, Visitor} -import upickle.core.{ArrVisitor, ObjVisitor} +import scala.util.Try @@ -13,14 +14,27 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI var dashBuffered = false var afterKey = false private var topLevel = true + private val outBuffer = _out.getBuffer + + private val yamlKeyVisitor = new SimpleVisitor[StringWriter, StringWriter]() { + override def expectedMsg = "Expected a string key" + override def visitString(s: CharSequence, index: Int): StringWriter = { + YamlRenderer.this.flushBuffer() + if (quoteKeys || !YamlRenderer.isSafeBareKey(s.toString)) { + upickle.core.RenderUtils.escapeChar(null, YamlRenderer.this.elemBuilder, s, unicode = true) + } else { + YamlRenderer.this.appendString(s.toString) + } + YamlRenderer.this.flushCharBuilder() + _out + } + } - private val outBuffer = _out.getBuffer() - - override def flushCharBuilder() = { + override def flushCharBuilder(): Unit = { elemBuilder.writeOutToIfLongerThan(_out, if (depth <= 0 || topLevel) 0 else 1000) } - private[this] def appendString(s: String) = { + private[this] def appendString(s: String): Unit = { val len = s.length var i = 0 elemBuilder.ensureLength(len) @@ -30,15 +44,6 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI } } - private[this] def removeQuoteKey(): Unit = { - // refer to quote_keys parameter in https://jsonnet.org/ref/stdlib.html, only unquote keys - if (!quoteKeys && !afterKey) { - val key = elemBuilder.makeString() - elemBuilder.reset() - elemBuilder.appendAll(key.toCharArray, 1, key.length - 2); - } - } - override def visitString(s: CharSequence, index: Int): StringWriter = { flushBuffer() val len = s.length() @@ -57,21 +62,20 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI } depth -= 1 } else { - upickle.core.RenderUtils.escapeChar(unicodeCharBuilder, elemBuilder, s, true) - removeQuoteKey() + upickle.core.RenderUtils.escapeChar(null, elemBuilder, s, unicode=true) } flushCharBuilder() _out } - override def visitFloat64(d: Double, index: Int) = { + override def visitFloat64(d: Double, index: Int): StringWriter = { flushBuffer() appendString(RenderUtils.renderDouble(d)) flushCharBuilder() _out } - override def flushBuffer() = { + override def flushBuffer(): Unit = { if (newlineBuffered) { // drop space between colon and newline elemBuilder.writeOutToIfLongerThan(_out, 0) @@ -91,7 +95,7 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI dashBuffered = false } - override def visitArray(length: Int, index: Int) = new ArrVisitor[StringWriter, StringWriter] { + override def visitArray(length: Int, index: Int): ArrVisitor[StringWriter, StringWriter] = new ArrVisitor[StringWriter, StringWriter] { var empty = true flushBuffer() @@ -101,19 +105,19 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI } topLevel = false - val dedentInObject = afterKey && !indentArrayInObject + private val dedentInObject = afterKey && !indentArrayInObject afterKey = false if (dedentInObject) depth -= 1 dashBuffered = true - def subVisitor = YamlRenderer.this + def subVisitor: Visitor[StringWriter, StringWriter] = YamlRenderer.this def visitValue(v: StringWriter, index: Int): Unit = { empty = false flushBuffer() newlineBuffered = true dashBuffered = true } - def visitEnd(index: Int) = { + def visitEnd(index: Int): StringWriter = { if (!dedentInObject) depth -= 1 if (empty) { elemBuilder.ensureLength(2) @@ -126,7 +130,8 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI _out } } - override def visitObject(length: Int, index: Int) = new ObjVisitor[StringWriter, StringWriter] { + + override def visitObject(length: Int, index: Int): ObjVisitor[StringWriter, StringWriter] = new ObjVisitor[StringWriter, StringWriter] { var empty = true flushBuffer() if (!topLevel) depth += 1 @@ -134,8 +139,10 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI if (afterKey) newlineBuffered = true - def subVisitor = YamlRenderer.this - def visitKey(index: Int) = YamlRenderer.this + def subVisitor: Visitor[StringWriter, StringWriter] = YamlRenderer.this + + def visitKey(index: Int): Visitor[StringWriter, StringWriter] = yamlKeyVisitor + def visitKeyValue(s: Any): Unit = { empty = false flushBuffer() @@ -146,11 +153,13 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI afterKey = true newlineBuffered = false } + def visitValue(v: StringWriter, index: Int): Unit = { newlineBuffered = true afterKey = false } - def visitEnd(index: Int) = { + + def visitEnd(index: Int): StringWriter = { if (empty) { elemBuilder.ensureLength(2) elemBuilder.append('{') @@ -165,9 +174,23 @@ class YamlRenderer(_out: StringWriter = new java.io.StringWriter(), indentArrayI } } object YamlRenderer{ - val newlinePattern = Pattern.compile("\n") + val newlinePattern: Pattern = Pattern.compile("\n") + private val safeYamlKeyPattern = Pattern.compile("^[a-zA-Z0-9/._-]+$") + private val yamlReserved = Set("true", "false", "null", "yes", "no", "on", "off", "y", "n", ".nan", + "+.inf", "-.inf", ".inf", "null", "-", "---", "''") + private val yamlTimestampPattern = Pattern.compile("^(?:[0-9]*-){2}[0-9]*$", Pattern.CASE_INSENSITIVE) + private val yamlBinaryPattern = Pattern.compile("^[-+]?0b[0-1_]+$") + private val yamlHexPattern = Pattern.compile("[-+]?0x[0-9a-fA-F_]+") + + private def isSafeBareKey(k: String) = { + val l = k.toLowerCase + !yamlReserved.contains(l) && safeYamlKeyPattern.matcher(k).matches() && + !yamlTimestampPattern.matcher(k).matches() && !yamlBinaryPattern.matcher(k).matches() && + !yamlHexPattern.matcher(k).matches() && (Try(l.replace("_", "").toLong).isFailure + && Try(l.replace("_", "").toDouble).isFailure) + } - def writeIndentation(out: upickle.core.CharBuilder, n: Int) = { + def writeIndentation(out: upickle.core.CharBuilder, n: Int): Unit = { out.ensureLength(n+1) out.append('\n') var i = n diff --git a/sjsonnet/test/resources/test_suite/stdlib.jsonnet b/sjsonnet/test/resources/test_suite/stdlib.jsonnet index 71a670e6..be936a10 100644 --- a/sjsonnet/test/resources/test_suite/stdlib.jsonnet +++ b/sjsonnet/test/resources/test_suite/stdlib.jsonnet @@ -738,15 +738,15 @@ std.assertEqual( + '"x":[1,2,3,true,false,null,"string\\nstring\\n"],"y":{"a":1,"b":2,"c":[1,2]}}' ) && -//std.assertEqual( -// std.manifestYamlDoc([{ x: [1, 2, 3] }], quote_keys=false) + '\n', -// ||| -// - x: -// - 1 -// - 2 -// - 3 -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc([{ x: [1, 2, 3] }], quote_keys=false) + '\n', + ||| + - x: + - 1 + - 2 + - 3 + ||| +) && std.assertEqual( std.manifestYamlDoc([{ x: [1, 2, 3] }]) + '\n', @@ -809,20 +809,20 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc({ x: [[[1, { f: 3, g: [1, 2] }, 1]]] }, quote_keys=false) + '\n', -// ||| -// x: -// - -// - -// - 1 -// - f: 3 -// g: -// - 1 -// - 2 -// - 1 -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc({ x: [[[1, { f: 3, g: [1, 2] }, 1]]] }, quote_keys=false) + '\n', + ||| + x: + - + - + - 1 + - f: 3 + g: + - 1 + - 2 + - 1 + ||| +) && std.assertEqual( std.manifestYamlDoc('hello\nworld\n') + '\n', @@ -851,14 +851,14 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc({ f: 'hello\nworld\n' }, quote_keys=false) + '\n', -// ||| -// f: | -// hello -// world -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc({ f: 'hello\nworld\n' }, quote_keys=false) + '\n', + ||| + f: | + hello + world + ||| +) && std.assertEqual( std.manifestYamlDoc(some_json) + '\n', @@ -890,35 +890,35 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc(some_json, quote_keys=false) + '\n', -// ||| -// "\"": null -// arr: -// - -// - [] -// emptyArray: [] -// emptyObject: {} -// objectInArray: -// - f: 3 -// x: -// - 1 -// - 2 -// - 3 -// - true -// - false -// - null -// - | -// string -// string -// "y": -// a: 1 -// b: 2 -// c: -// - 1 -// - 2 -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc(some_json, quote_keys=false) + '\n', + ||| + "\"": null + arr: + - + - [] + emptyArray: [] + emptyObject: {} + objectInArray: + - f: 3 + x: + - 1 + - 2 + - 3 + - true + - false + - null + - | + string + string + "y": + a: 1 + b: 2 + c: + - 1 + - 2 + ||| +) && std.assertEqual( std.manifestYamlDoc([{ x: [1, 2, 3] }], indent_array_in_object=true) + '\n', @@ -930,15 +930,15 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc([{ x: [1, 2, 3] }], indent_array_in_object=true, quote_keys=false) + '\n', -// ||| -// - x: -// - 1 -// - 2 -// - 3 -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc([{ x: [1, 2, 3] }], indent_array_in_object=true, quote_keys=false) + '\n', + ||| + - x: + - 1 + - 2 + - 3 + ||| +) && std.assertEqual( std.manifestYamlDoc({ x: [1, 2, 3] }, indent_array_in_object=true) + '\n', @@ -1048,172 +1048,172 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc(some_json, indent_array_in_object=true, quote_keys=false) + '\n', -// ||| -// "\"": null -// arr: -// - -// - [] -// emptyArray: [] -// emptyObject: {} -// objectInArray: -// - f: 3 -// x: -// - 1 -// - 2 -// - 3 -// - true -// - false -// - null -// - | -// string -// string -// "y": -// a: 1 -// b: 2 -// c: -// - 1 -// - 2 -// ||| -//) && - -//std.assertEqual( -// std.manifestYamlDoc(bare_yaml_test, quote_keys=false) + '\n', -// ||| -// "": "empty key" -// "+.inf": "positive infinity" -// "+685_230": "decimal" -// "-": "invalid bare key" -// "---": "triple dash key" -// "-.inf": "negative infinity" -// "-0.1_0_0": "negative float" -// -0B1010_0111_0100_1010_1110: "BARE_KEY" -// "-0b1010_0111_0100_1010_1110": "binary" -// "-0x_0A_74_AE": "negative hexadecimal" -// "-190:20:30": "negative sexagesimal" -// "-190:20:30.15": "negative sexagesimal" -// "-1_0": "negative integer" -// "-6.8523015e+5": "negative canonical" -// "-685.230_15E-03": "negative w/ negative exponential" -// "-685.230_15e+03": "negative exponential" -// "-685.230_15e-03": "negative w/ negative exponential" -// "-685_230.15": "negative fixed" -// ".NaN": "not a number" -// ".inf": "positive infinity" -// "02472256": "octal" -// 0X_0a_74_ae: "BARE_KEY" -// "0b1010_0111_0100_1010_1110": "binary" -// "0x_0A_74_AE": "hexadecimal" -// 1-234-567-8901: "BARE_KEY" -// "190:20:30": "sexagesimal" -// "190:20:30.15": "sexagesimal" -// 192.168.0.1: "BARE_KEY" -// "2001-12-14 21:59:43.10 -5": "space separated" -// "2001-12-14t21:59:43.10-05:00": "valid iso8601" -// "2001-12-15 2:59:43.10": "no time zone (Z)" -// "2001-12-15T02:59:43.1Z": "canonical" -// "2002-12-14": "date" -// "6.8523015e+5": "canonical" -// "6.8523015e-5": "canonical" -// "685.230_15e+03": "exponential" -// "685230": "canonical" -// "685_230.15": "fixed" -// "N": "boolean false" -// "NO": "boolean false" -// "NULL": "null word capital" -// "Null": "null word" -// "OFF": "boolean false" -// "On": "boolean true" -// "True": "boolean true" -// "Yes": "boolean true" -// __-0B1010_0111_0100_1010_1110: "BARE_KEY" -// __-0X_0a_74_ae: "BARE_KEY" -// b: "BARE_KEY" -// jsonnet.org/k8s-label-like: "BARE_KEY" -// just-letters-dashes: "BARE_KEY" -// just_letters_underscores: "BARE_KEY" -// "n": "boolean false" -// "null": "null word" -// "off": "boolean false" -// "on": "boolean true" -// "true": "boolean true" -// x: "BARE_KEY" -// "y": "boolean true" -// "yes": "boolean true" -// "~": "null key" -// ||| -//) && -// -//std.assertEqual( -// std.manifestYamlStream([bare_yaml_quoted, bare_yaml_unquoted], quote_keys=false), -// ||| -// --- -// "": "empty key" -// "+.inf": "positive infinity" -// "+685_230": "decimal" -// "-": "invalid bare key" -// "---": "triple dash key" -// "-.inf": "negative infinity" -// "-0.1_0_0": "negative float" -// "-0b1010_0111_0100_1010_1110": "binary" -// "-0x_0A_74_AE": "negative hexadecimal" -// "-190:20:30": "negative sexagesimal" -// "-190:20:30.15": "negative sexagesimal" -// "-1_0": "negative integer" -// "-6.8523015e+5": "negative canonical" -// "-685.230_15E-03": "negative w/ negative exponential" -// "-685.230_15e+03": "negative exponential" -// "-685.230_15e-03": "negative w/ negative exponential" -// "-685_230.15": "negative fixed" -// ".NaN": "not a number" -// ".inf": "positive infinity" -// "02472256": "octal" -// "0b1010_0111_0100_1010_1110": "binary" -// "0x_0A_74_AE": "hexadecimal" -// "190:20:30": "sexagesimal" -// "190:20:30.15": "sexagesimal" -// "2001-12-14 21:59:43.10 -5": "space separated" -// "2001-12-14t21:59:43.10-05:00": "valid iso8601" -// "2001-12-15 2:59:43.10": "no time zone (Z)" -// "2001-12-15T02:59:43.1Z": "canonical" -// "2002-12-14": "date" -// "6.8523015e+5": "canonical" -// "6.8523015e-5": "canonical" -// "685.230_15e+03": "exponential" -// "685230": "canonical" -// "685_230.15": "fixed" -// "N": "boolean false" -// "NO": "boolean false" -// "NULL": "null word capital" -// "Null": "null word" -// "OFF": "boolean false" -// "On": "boolean true" -// "True": "boolean true" -// "Yes": "boolean true" -// "n": "boolean false" -// "null": "null word" -// "off": "boolean false" -// "on": "boolean true" -// "true": "boolean true" -// "y": "boolean true" -// "yes": "boolean true" -// "~": "null key" -// --- -// -0B1010_0111_0100_1010_1110: "BARE_KEY" -// 0X_0a_74_ae: "BARE_KEY" -// 1-234-567-8901: "BARE_KEY" -// 192.168.0.1: "BARE_KEY" -// __-0B1010_0111_0100_1010_1110: "BARE_KEY" -// __-0X_0a_74_ae: "BARE_KEY" -// b: "BARE_KEY" -// jsonnet.org/k8s-label-like: "BARE_KEY" -// just-letters-dashes: "BARE_KEY" -// just_letters_underscores: "BARE_KEY" -// x: "BARE_KEY" -// ... -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc(some_json, indent_array_in_object=true, quote_keys=false) + '\n', + ||| + "\"": null + arr: + - + - [] + emptyArray: [] + emptyObject: {} + objectInArray: + - f: 3 + x: + - 1 + - 2 + - 3 + - true + - false + - null + - | + string + string + "y": + a: 1 + b: 2 + c: + - 1 + - 2 + ||| +) && + +std.assertEqual( + std.manifestYamlDoc(bare_yaml_test, quote_keys=false) + '\n', + ||| + "": "empty key" + "+.inf": "positive infinity" + "+685_230": "decimal" + "-": "invalid bare key" + "---": "triple dash key" + "-.inf": "negative infinity" + "-0.1_0_0": "negative float" + -0B1010_0111_0100_1010_1110: "BARE_KEY" + "-0b1010_0111_0100_1010_1110": "binary" + "-0x_0A_74_AE": "negative hexadecimal" + "-190:20:30": "negative sexagesimal" + "-190:20:30.15": "negative sexagesimal" + "-1_0": "negative integer" + "-6.8523015e+5": "negative canonical" + "-685.230_15E-03": "negative w/ negative exponential" + "-685.230_15e+03": "negative exponential" + "-685.230_15e-03": "negative w/ negative exponential" + "-685_230.15": "negative fixed" + ".NaN": "not a number" + ".inf": "positive infinity" + "02472256": "octal" + 0X_0a_74_ae: "BARE_KEY" + "0b1010_0111_0100_1010_1110": "binary" + "0x_0A_74_AE": "hexadecimal" + 1-234-567-8901: "BARE_KEY" + "190:20:30": "sexagesimal" + "190:20:30.15": "sexagesimal" + 192.168.0.1: "BARE_KEY" + "2001-12-14 21:59:43.10 -5": "space separated" + "2001-12-14t21:59:43.10-05:00": "valid iso8601" + "2001-12-15 2:59:43.10": "no time zone (Z)" + "2001-12-15T02:59:43.1Z": "canonical" + "2002-12-14": "date" + "6.8523015e+5": "canonical" + "6.8523015e-5": "canonical" + "685.230_15e+03": "exponential" + "685230": "canonical" + "685_230.15": "fixed" + "N": "boolean false" + "NO": "boolean false" + "NULL": "null word capital" + "Null": "null word" + "OFF": "boolean false" + "On": "boolean true" + "True": "boolean true" + "Yes": "boolean true" + __-0B1010_0111_0100_1010_1110: "BARE_KEY" + __-0X_0a_74_ae: "BARE_KEY" + b: "BARE_KEY" + jsonnet.org/k8s-label-like: "BARE_KEY" + just-letters-dashes: "BARE_KEY" + just_letters_underscores: "BARE_KEY" + "n": "boolean false" + "null": "null word" + "off": "boolean false" + "on": "boolean true" + "true": "boolean true" + x: "BARE_KEY" + "y": "boolean true" + "yes": "boolean true" + "~": "null key" + ||| +) && + +std.assertEqual( + std.manifestYamlStream([bare_yaml_quoted, bare_yaml_unquoted], quote_keys=false), + ||| + --- + "": "empty key" + "+.inf": "positive infinity" + "+685_230": "decimal" + "-": "invalid bare key" + "---": "triple dash key" + "-.inf": "negative infinity" + "-0.1_0_0": "negative float" + "-0b1010_0111_0100_1010_1110": "binary" + "-0x_0A_74_AE": "negative hexadecimal" + "-190:20:30": "negative sexagesimal" + "-190:20:30.15": "negative sexagesimal" + "-1_0": "negative integer" + "-6.8523015e+5": "negative canonical" + "-685.230_15E-03": "negative w/ negative exponential" + "-685.230_15e+03": "negative exponential" + "-685.230_15e-03": "negative w/ negative exponential" + "-685_230.15": "negative fixed" + ".NaN": "not a number" + ".inf": "positive infinity" + "02472256": "octal" + "0b1010_0111_0100_1010_1110": "binary" + "0x_0A_74_AE": "hexadecimal" + "190:20:30": "sexagesimal" + "190:20:30.15": "sexagesimal" + "2001-12-14 21:59:43.10 -5": "space separated" + "2001-12-14t21:59:43.10-05:00": "valid iso8601" + "2001-12-15 2:59:43.10": "no time zone (Z)" + "2001-12-15T02:59:43.1Z": "canonical" + "2002-12-14": "date" + "6.8523015e+5": "canonical" + "6.8523015e-5": "canonical" + "685.230_15e+03": "exponential" + "685230": "canonical" + "685_230.15": "fixed" + "N": "boolean false" + "NO": "boolean false" + "NULL": "null word capital" + "Null": "null word" + "OFF": "boolean false" + "On": "boolean true" + "True": "boolean true" + "Yes": "boolean true" + "n": "boolean false" + "null": "null word" + "off": "boolean false" + "on": "boolean true" + "true": "boolean true" + "y": "boolean true" + "yes": "boolean true" + "~": "null key" + --- + -0B1010_0111_0100_1010_1110: "BARE_KEY" + 0X_0a_74_ae: "BARE_KEY" + 1-234-567-8901: "BARE_KEY" + 192.168.0.1: "BARE_KEY" + __-0B1010_0111_0100_1010_1110: "BARE_KEY" + __-0X_0a_74_ae: "BARE_KEY" + b: "BARE_KEY" + jsonnet.org/k8s-label-like: "BARE_KEY" + just-letters-dashes: "BARE_KEY" + just_letters_underscores: "BARE_KEY" + x: "BARE_KEY" + ... + ||| +) && std.assertEqual( std.manifestYamlStream([some_json, some_json, {}, [], 3, '"']), @@ -1280,70 +1280,70 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlStream([some_json, some_json, {}, [], 3, '"'], quote_keys=false), -// ||| -// --- -// "\"": null -// arr: -// - -// - [] -// emptyArray: [] -// emptyObject: {} -// objectInArray: -// - f: 3 -// x: -// - 1 -// - 2 -// - 3 -// - true -// - false -// - null -// - | -// string -// string -// "y": -// a: 1 -// b: 2 -// c: -// - 1 -// - 2 -// --- -// "\"": null -// arr: -// - -// - [] -// emptyArray: [] -// emptyObject: {} -// objectInArray: -// - f: 3 -// x: -// - 1 -// - 2 -// - 3 -// - true -// - false -// - null -// - | -// string -// string -// "y": -// a: 1 -// b: 2 -// c: -// - 1 -// - 2 -// --- -// {} -// --- -// [] -// --- -// 3 -// --- -// "\"" -// ... -// ||| -//) && +std.assertEqual( + std.manifestYamlStream([some_json, some_json, {}, [], 3, '"'], quote_keys=false), + ||| + --- + "\"": null + arr: + - + - [] + emptyArray: [] + emptyObject: {} + objectInArray: + - f: 3 + x: + - 1 + - 2 + - 3 + - true + - false + - null + - | + string + string + "y": + a: 1 + b: 2 + c: + - 1 + - 2 + --- + "\"": null + arr: + - + - [] + emptyArray: [] + emptyObject: {} + objectInArray: + - f: 3 + x: + - 1 + - 2 + - 3 + - true + - false + - null + - | + string + string + "y": + a: 1 + b: 2 + c: + - 1 + - 2 + --- + {} + --- + [] + --- + 3 + --- + "\"" + ... + ||| +) && std.assertEqual( std.manifestYamlStream([some_json, some_json, {}, [], 3, '"'], indent_array_in_object=true), @@ -1410,19 +1410,19 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlStream([{}, [], 3, '"'], c_document_end=false), -// ||| -// --- -// {} -// --- -// [] -// --- -// 3 -// --- -// "\"" -// ||| -//) && +std.assertEqual( + std.manifestYamlStream([{}, [], 3, '"'], c_document_end=false), + ||| + --- + {} + --- + [] + --- + 3 + --- + "\"" + ||| +) && std.assertEqual(std.parseInt('01234567890'), 1234567890) && std.assertEqual(std.parseInt('9007199254740991'), 9007199254740991) && diff --git a/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet b/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet index 8c483e2d..498c0b0e 100644 --- a/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet +++ b/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet @@ -738,15 +738,15 @@ std.assertEqual( + '"x":[1,2,3,true,false,null,"string\\nstring\\n"],"y":{"a":1,"b":2,"c":[1,2]}}' ) && -//std.assertEqual( -// std.manifestYamlDoc([{ x: [1, 2, 3] }], quote_keys=false) + '\n', -// ||| -// - x: -// - 1 -// - 2 -// - 3 -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc([{ x: [1, 2, 3] }], quote_keys=false) + '\n', + ||| + - x: + - 1 + - 2 + - 3 + ||| +) && std.assertEqual( std.manifestYamlDoc([{ x: [1, 2, 3] }]) + '\n', @@ -809,20 +809,20 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc({ x: [[[1, { f: 3, g: [1, 2] }, 1]]] }, quote_keys=false) + '\n', -// ||| -// x: -// - -// - -// - 1 -// - f: 3 -// g: -// - 1 -// - 2 -// - 1 -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc({ x: [[[1, { f: 3, g: [1, 2] }, 1]]] }, quote_keys=false) + '\n', + ||| + x: + - + - + - 1 + - f: 3 + g: + - 1 + - 2 + - 1 + ||| +) && std.assertEqual( std.manifestYamlDoc('hello\nworld\n') + '\n', @@ -851,14 +851,14 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc({ f: 'hello\nworld\n' }, quote_keys=false) + '\n', -// ||| -// f: | -// hello -// world -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc({ f: 'hello\nworld\n' }, quote_keys=false) + '\n', + ||| + f: | + hello + world + ||| +) && std.assertEqual( std.manifestYamlDoc(some_json) + '\n', @@ -890,35 +890,35 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc(some_json, quote_keys=false) + '\n', -// ||| -// "\"": null -// arr: -// - -// - [] -// emptyArray: [] -// emptyObject: {} -// objectInArray: -// - f: 3 -// x: -// - 1 -// - 2 -// - 3 -// - true -// - false -// - null -// - | -// string -// string -// "y": -// a: 1 -// b: 2 -// c: -// - 1 -// - 2 -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc(some_json, quote_keys=false) + '\n', + ||| + "\"": null + arr: + - + - [] + emptyArray: [] + emptyObject: {} + objectInArray: + - f: 3 + x: + - 1 + - 2 + - 3 + - true + - false + - null + - | + string + string + "y": + a: 1 + b: 2 + c: + - 1 + - 2 + ||| +) && std.assertEqual( std.manifestYamlDoc([{ x: [1, 2, 3] }], indent_array_in_object=true) + '\n', @@ -930,15 +930,15 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc([{ x: [1, 2, 3] }], indent_array_in_object=true, quote_keys=false) + '\n', -// ||| -// - x: -// - 1 -// - 2 -// - 3 -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc([{ x: [1, 2, 3] }], indent_array_in_object=true, quote_keys=false) + '\n', + ||| + - x: + - 1 + - 2 + - 3 + ||| +) && std.assertEqual( std.manifestYamlDoc({ x: [1, 2, 3] }, indent_array_in_object=true) + '\n', @@ -1048,36 +1048,38 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlDoc(some_json, indent_array_in_object=true, quote_keys=false) + '\n', -// ||| -// "\"": null -// arr: -// - -// - [] -// emptyArray: [] -// emptyObject: {} -// objectInArray: -// - f: 3 -// x: -// - 1 -// - 2 -// - 3 -// - true -// - false -// - null -// - | -// string -// string -// "y": -// a: 1 -// b: 2 -// c: -// - 1 -// - 2 -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc(some_json, indent_array_in_object=true, quote_keys=false) + '\n', + ||| + "\"": null + arr: + - + - [] + emptyArray: [] + emptyObject: {} + objectInArray: + - f: 3 + x: + - 1 + - 2 + - 3 + - true + - false + - null + - | + string + string + "y": + a: 1 + b: 2 + c: + - 1 + - 2 + ||| +) && +// Scala native behaves differently from JVM regarding numerical separator like _. +// so for now, this test is disabled. //std.assertEqual( // std.manifestYamlDoc(bare_yaml_test, quote_keys=false) + '\n', // ||| @@ -1144,7 +1146,7 @@ std.assertEqual( // "~": "null key" // ||| //) && -// + //std.assertEqual( // std.manifestYamlStream([bare_yaml_quoted, bare_yaml_unquoted], quote_keys=false), // ||| @@ -1280,70 +1282,70 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlStream([some_json, some_json, {}, [], 3, '"'], quote_keys=false), -// ||| -// --- -// "\"": null -// arr: -// - -// - [] -// emptyArray: [] -// emptyObject: {} -// objectInArray: -// - f: 3 -// x: -// - 1 -// - 2 -// - 3 -// - true -// - false -// - null -// - | -// string -// string -// "y": -// a: 1 -// b: 2 -// c: -// - 1 -// - 2 -// --- -// "\"": null -// arr: -// - -// - [] -// emptyArray: [] -// emptyObject: {} -// objectInArray: -// - f: 3 -// x: -// - 1 -// - 2 -// - 3 -// - true -// - false -// - null -// - | -// string -// string -// "y": -// a: 1 -// b: 2 -// c: -// - 1 -// - 2 -// --- -// {} -// --- -// [] -// --- -// 3 -// --- -// "\"" -// ... -// ||| -//) && +std.assertEqual( + std.manifestYamlStream([some_json, some_json, {}, [], 3, '"'], quote_keys=false), + ||| + --- + "\"": null + arr: + - + - [] + emptyArray: [] + emptyObject: {} + objectInArray: + - f: 3 + x: + - 1 + - 2 + - 3 + - true + - false + - null + - | + string + string + "y": + a: 1 + b: 2 + c: + - 1 + - 2 + --- + "\"": null + arr: + - + - [] + emptyArray: [] + emptyObject: {} + objectInArray: + - f: 3 + x: + - 1 + - 2 + - 3 + - true + - false + - null + - | + string + string + "y": + a: 1 + b: 2 + c: + - 1 + - 2 + --- + {} + --- + [] + --- + 3 + --- + "\"" + ... + ||| +) && std.assertEqual( std.manifestYamlStream([some_json, some_json, {}, [], 3, '"'], indent_array_in_object=true), @@ -1410,19 +1412,19 @@ std.assertEqual( ||| ) && -//std.assertEqual( -// std.manifestYamlStream([{}, [], 3, '"'], c_document_end=false), -// ||| -// --- -// {} -// --- -// [] -// --- -// 3 -// --- -// "\"" -// ||| -//) && +std.assertEqual( + std.manifestYamlStream([{}, [], 3, '"'], c_document_end=false), + ||| + --- + {} + --- + [] + --- + 3 + --- + "\"" + ||| +) && std.assertEqual(std.parseInt('01234567890'), 1234567890) && std.assertEqual(std.parseInt('-01234567890'), -1234567890) && From d1a0282d54e57653c0422a0697ad5fcbcde6382f Mon Sep 17 00:00:00 2001 From: Stephen Amar Date: Wed, 11 Dec 2024 19:59:34 -0800 Subject: [PATCH 3/3] Use pure-regex implementation to validate yaml keys --- sjsonnet/src/sjsonnet/YamlRenderer.scala | 15 +- .../test_suite/stdlib_native.jsonnet | 272 +++++++++--------- 2 files changed, 145 insertions(+), 142 deletions(-) diff --git a/sjsonnet/src/sjsonnet/YamlRenderer.scala b/sjsonnet/src/sjsonnet/YamlRenderer.scala index 26e75822..d2b2b3c2 100644 --- a/sjsonnet/src/sjsonnet/YamlRenderer.scala +++ b/sjsonnet/src/sjsonnet/YamlRenderer.scala @@ -178,16 +178,21 @@ object YamlRenderer{ private val safeYamlKeyPattern = Pattern.compile("^[a-zA-Z0-9/._-]+$") private val yamlReserved = Set("true", "false", "null", "yes", "no", "on", "off", "y", "n", ".nan", "+.inf", "-.inf", ".inf", "null", "-", "---", "''") - private val yamlTimestampPattern = Pattern.compile("^(?:[0-9]*-){2}[0-9]*$", Pattern.CASE_INSENSITIVE) + private val yamlTimestampPattern = Pattern.compile("^(?:[0-9]*-){2}[0-9]*$") private val yamlBinaryPattern = Pattern.compile("^[-+]?0b[0-1_]+$") private val yamlHexPattern = Pattern.compile("[-+]?0x[0-9a-fA-F_]+") + private val yamlFloatPattern = Pattern.compile( "^-?([0-9_]*)*(\\.[0-9_]*)?(e[-+][0-9_]+)?$" ) + private val yamlIntPattern = Pattern.compile("^[-+]?[0-9_]+$") private def isSafeBareKey(k: String) = { val l = k.toLowerCase - !yamlReserved.contains(l) && safeYamlKeyPattern.matcher(k).matches() && - !yamlTimestampPattern.matcher(k).matches() && !yamlBinaryPattern.matcher(k).matches() && - !yamlHexPattern.matcher(k).matches() && (Try(l.replace("_", "").toLong).isFailure - && Try(l.replace("_", "").toDouble).isFailure) + !yamlReserved.contains(l) && + safeYamlKeyPattern.matcher(k).matches() && + !yamlTimestampPattern.matcher(l).matches() && + !yamlBinaryPattern.matcher(k).matches() && + !yamlHexPattern.matcher(k).matches() && + !yamlFloatPattern.matcher(l).matches() && + !yamlIntPattern.matcher(l).matches() } def writeIndentation(out: upickle.core.CharBuilder, n: Int): Unit = { diff --git a/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet b/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet index 498c0b0e..b7938da5 100644 --- a/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet +++ b/sjsonnet/test/resources/test_suite/stdlib_native.jsonnet @@ -1078,144 +1078,142 @@ std.assertEqual( ||| ) && -// Scala native behaves differently from JVM regarding numerical separator like _. -// so for now, this test is disabled. -//std.assertEqual( -// std.manifestYamlDoc(bare_yaml_test, quote_keys=false) + '\n', -// ||| -// "": "empty key" -// "+.inf": "positive infinity" -// "+685_230": "decimal" -// "-": "invalid bare key" -// "---": "triple dash key" -// "-.inf": "negative infinity" -// "-0.1_0_0": "negative float" -// -0B1010_0111_0100_1010_1110: "BARE_KEY" -// "-0b1010_0111_0100_1010_1110": "binary" -// "-0x_0A_74_AE": "negative hexadecimal" -// "-190:20:30": "negative sexagesimal" -// "-190:20:30.15": "negative sexagesimal" -// "-1_0": "negative integer" -// "-6.8523015e+5": "negative canonical" -// "-685.230_15E-03": "negative w/ negative exponential" -// "-685.230_15e+03": "negative exponential" -// "-685.230_15e-03": "negative w/ negative exponential" -// "-685_230.15": "negative fixed" -// ".NaN": "not a number" -// ".inf": "positive infinity" -// "02472256": "octal" -// 0X_0a_74_ae: "BARE_KEY" -// "0b1010_0111_0100_1010_1110": "binary" -// "0x_0A_74_AE": "hexadecimal" -// 1-234-567-8901: "BARE_KEY" -// "190:20:30": "sexagesimal" -// "190:20:30.15": "sexagesimal" -// 192.168.0.1: "BARE_KEY" -// "2001-12-14 21:59:43.10 -5": "space separated" -// "2001-12-14t21:59:43.10-05:00": "valid iso8601" -// "2001-12-15 2:59:43.10": "no time zone (Z)" -// "2001-12-15T02:59:43.1Z": "canonical" -// "2002-12-14": "date" -// "6.8523015e+5": "canonical" -// "6.8523015e-5": "canonical" -// "685.230_15e+03": "exponential" -// "685230": "canonical" -// "685_230.15": "fixed" -// "N": "boolean false" -// "NO": "boolean false" -// "NULL": "null word capital" -// "Null": "null word" -// "OFF": "boolean false" -// "On": "boolean true" -// "True": "boolean true" -// "Yes": "boolean true" -// __-0B1010_0111_0100_1010_1110: "BARE_KEY" -// __-0X_0a_74_ae: "BARE_KEY" -// b: "BARE_KEY" -// jsonnet.org/k8s-label-like: "BARE_KEY" -// just-letters-dashes: "BARE_KEY" -// just_letters_underscores: "BARE_KEY" -// "n": "boolean false" -// "null": "null word" -// "off": "boolean false" -// "on": "boolean true" -// "true": "boolean true" -// x: "BARE_KEY" -// "y": "boolean true" -// "yes": "boolean true" -// "~": "null key" -// ||| -//) && +std.assertEqual( + std.manifestYamlDoc(bare_yaml_test, quote_keys=false) + '\n', + ||| + "": "empty key" + "+.inf": "positive infinity" + "+685_230": "decimal" + "-": "invalid bare key" + "---": "triple dash key" + "-.inf": "negative infinity" + "-0.1_0_0": "negative float" + -0B1010_0111_0100_1010_1110: "BARE_KEY" + "-0b1010_0111_0100_1010_1110": "binary" + "-0x_0A_74_AE": "negative hexadecimal" + "-190:20:30": "negative sexagesimal" + "-190:20:30.15": "negative sexagesimal" + "-1_0": "negative integer" + "-6.8523015e+5": "negative canonical" + "-685.230_15E-03": "negative w/ negative exponential" + "-685.230_15e+03": "negative exponential" + "-685.230_15e-03": "negative w/ negative exponential" + "-685_230.15": "negative fixed" + ".NaN": "not a number" + ".inf": "positive infinity" + "02472256": "octal" + 0X_0a_74_ae: "BARE_KEY" + "0b1010_0111_0100_1010_1110": "binary" + "0x_0A_74_AE": "hexadecimal" + 1-234-567-8901: "BARE_KEY" + "190:20:30": "sexagesimal" + "190:20:30.15": "sexagesimal" + 192.168.0.1: "BARE_KEY" + "2001-12-14 21:59:43.10 -5": "space separated" + "2001-12-14t21:59:43.10-05:00": "valid iso8601" + "2001-12-15 2:59:43.10": "no time zone (Z)" + "2001-12-15T02:59:43.1Z": "canonical" + "2002-12-14": "date" + "6.8523015e+5": "canonical" + "6.8523015e-5": "canonical" + "685.230_15e+03": "exponential" + "685230": "canonical" + "685_230.15": "fixed" + "N": "boolean false" + "NO": "boolean false" + "NULL": "null word capital" + "Null": "null word" + "OFF": "boolean false" + "On": "boolean true" + "True": "boolean true" + "Yes": "boolean true" + __-0B1010_0111_0100_1010_1110: "BARE_KEY" + __-0X_0a_74_ae: "BARE_KEY" + b: "BARE_KEY" + jsonnet.org/k8s-label-like: "BARE_KEY" + just-letters-dashes: "BARE_KEY" + just_letters_underscores: "BARE_KEY" + "n": "boolean false" + "null": "null word" + "off": "boolean false" + "on": "boolean true" + "true": "boolean true" + x: "BARE_KEY" + "y": "boolean true" + "yes": "boolean true" + "~": "null key" + ||| +) && -//std.assertEqual( -// std.manifestYamlStream([bare_yaml_quoted, bare_yaml_unquoted], quote_keys=false), -// ||| -// --- -// "": "empty key" -// "+.inf": "positive infinity" -// "+685_230": "decimal" -// "-": "invalid bare key" -// "---": "triple dash key" -// "-.inf": "negative infinity" -// "-0.1_0_0": "negative float" -// "-0b1010_0111_0100_1010_1110": "binary" -// "-0x_0A_74_AE": "negative hexadecimal" -// "-190:20:30": "negative sexagesimal" -// "-190:20:30.15": "negative sexagesimal" -// "-1_0": "negative integer" -// "-6.8523015e+5": "negative canonical" -// "-685.230_15E-03": "negative w/ negative exponential" -// "-685.230_15e+03": "negative exponential" -// "-685.230_15e-03": "negative w/ negative exponential" -// "-685_230.15": "negative fixed" -// ".NaN": "not a number" -// ".inf": "positive infinity" -// "02472256": "octal" -// "0b1010_0111_0100_1010_1110": "binary" -// "0x_0A_74_AE": "hexadecimal" -// "190:20:30": "sexagesimal" -// "190:20:30.15": "sexagesimal" -// "2001-12-14 21:59:43.10 -5": "space separated" -// "2001-12-14t21:59:43.10-05:00": "valid iso8601" -// "2001-12-15 2:59:43.10": "no time zone (Z)" -// "2001-12-15T02:59:43.1Z": "canonical" -// "2002-12-14": "date" -// "6.8523015e+5": "canonical" -// "6.8523015e-5": "canonical" -// "685.230_15e+03": "exponential" -// "685230": "canonical" -// "685_230.15": "fixed" -// "N": "boolean false" -// "NO": "boolean false" -// "NULL": "null word capital" -// "Null": "null word" -// "OFF": "boolean false" -// "On": "boolean true" -// "True": "boolean true" -// "Yes": "boolean true" -// "n": "boolean false" -// "null": "null word" -// "off": "boolean false" -// "on": "boolean true" -// "true": "boolean true" -// "y": "boolean true" -// "yes": "boolean true" -// "~": "null key" -// --- -// -0B1010_0111_0100_1010_1110: "BARE_KEY" -// 0X_0a_74_ae: "BARE_KEY" -// 1-234-567-8901: "BARE_KEY" -// 192.168.0.1: "BARE_KEY" -// __-0B1010_0111_0100_1010_1110: "BARE_KEY" -// __-0X_0a_74_ae: "BARE_KEY" -// b: "BARE_KEY" -// jsonnet.org/k8s-label-like: "BARE_KEY" -// just-letters-dashes: "BARE_KEY" -// just_letters_underscores: "BARE_KEY" -// x: "BARE_KEY" -// ... -// ||| -//) && +std.assertEqual( + std.manifestYamlStream([bare_yaml_quoted, bare_yaml_unquoted], quote_keys=false), + ||| + --- + "": "empty key" + "+.inf": "positive infinity" + "+685_230": "decimal" + "-": "invalid bare key" + "---": "triple dash key" + "-.inf": "negative infinity" + "-0.1_0_0": "negative float" + "-0b1010_0111_0100_1010_1110": "binary" + "-0x_0A_74_AE": "negative hexadecimal" + "-190:20:30": "negative sexagesimal" + "-190:20:30.15": "negative sexagesimal" + "-1_0": "negative integer" + "-6.8523015e+5": "negative canonical" + "-685.230_15E-03": "negative w/ negative exponential" + "-685.230_15e+03": "negative exponential" + "-685.230_15e-03": "negative w/ negative exponential" + "-685_230.15": "negative fixed" + ".NaN": "not a number" + ".inf": "positive infinity" + "02472256": "octal" + "0b1010_0111_0100_1010_1110": "binary" + "0x_0A_74_AE": "hexadecimal" + "190:20:30": "sexagesimal" + "190:20:30.15": "sexagesimal" + "2001-12-14 21:59:43.10 -5": "space separated" + "2001-12-14t21:59:43.10-05:00": "valid iso8601" + "2001-12-15 2:59:43.10": "no time zone (Z)" + "2001-12-15T02:59:43.1Z": "canonical" + "2002-12-14": "date" + "6.8523015e+5": "canonical" + "6.8523015e-5": "canonical" + "685.230_15e+03": "exponential" + "685230": "canonical" + "685_230.15": "fixed" + "N": "boolean false" + "NO": "boolean false" + "NULL": "null word capital" + "Null": "null word" + "OFF": "boolean false" + "On": "boolean true" + "True": "boolean true" + "Yes": "boolean true" + "n": "boolean false" + "null": "null word" + "off": "boolean false" + "on": "boolean true" + "true": "boolean true" + "y": "boolean true" + "yes": "boolean true" + "~": "null key" + --- + -0B1010_0111_0100_1010_1110: "BARE_KEY" + 0X_0a_74_ae: "BARE_KEY" + 1-234-567-8901: "BARE_KEY" + 192.168.0.1: "BARE_KEY" + __-0B1010_0111_0100_1010_1110: "BARE_KEY" + __-0X_0a_74_ae: "BARE_KEY" + b: "BARE_KEY" + jsonnet.org/k8s-label-like: "BARE_KEY" + just-letters-dashes: "BARE_KEY" + just_letters_underscores: "BARE_KEY" + x: "BARE_KEY" + ... + ||| +) && std.assertEqual( std.manifestYamlStream([some_json, some_json, {}, [], 3, '"']),