Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

First cut port of the jsonar parser.

  • Loading branch information...
commit 6d0bba19f07fb3a6dd5249dde52758826fba54ae 1 parent c87b7fb
sean authored
View
6 project/build.scala
@@ -28,6 +28,12 @@ object build extends Build {
"org.scalaz" %% "scalaz-core" % "7.0-SNAPSHOT" withSources
, "org.scalacheck" %% "scalacheck" % "1.9" % "test" withSources
)
+ , initialCommands := """
+ |import com.ephox.argonaut._
+ |import scalaz._
+ |import Scalaz._
+ |import Json._
+ """.stripMargin
)
)
View
231 src/main/scala/com/ephox/argonaut/AltParser.scala
@@ -0,0 +1,231 @@
+package com.ephox.argonaut
+
+import annotation.tailrec
+import scalaz._
+import Scalaz._
+
+
+object AltParser {
+ sealed abstract class JSONToken {
+ def originalStringContent: String
+ }
+ abstract class OpenToken extends JSONToken
+ abstract class CloseToken extends JSONToken
+ case object ArrayOpenToken extends OpenToken { val originalStringContent = "[" }
+ case object ArrayCloseToken extends CloseToken { val originalStringContent = "]" }
+ case object ObjectOpenToken extends OpenToken { val originalStringContent = "{" }
+ case object ObjectCloseToken extends CloseToken { val originalStringContent = "}" }
+ case object EntrySeparatorToken extends JSONToken { val originalStringContent = "," }
+ case object FieldSeparatorToken extends JSONToken { val originalStringContent = ":" }
+ case object StringBoundsOpenToken extends OpenToken { val originalStringContent = "\"" }
+ case object StringBoundsCloseToken extends CloseToken { val originalStringContent = "\"" }
+ case class NumberToken(originalStringContent: String) extends JSONToken
+ abstract class BooleanToken extends JSONToken
+ case object BooleanTrueToken extends BooleanToken { val originalStringContent = "true" }
+ case object BooleanFalseToken extends BooleanToken { val originalStringContent = "false" }
+ case object NullToken extends JSONToken { val originalStringContent = "null" }
+ abstract class StringPartToken extends JSONToken {
+ def parsedStringContent: String
+ }
+ case class UnicodeCharacterToken(originalStringContent: String) extends StringPartToken {
+ def parsedStringContent = new java.lang.StringBuilder().appendCodePoint(Integer.valueOf(originalStringContent.takeRight(4), 16)).toString
+ }
+ case class EscapedCharacterToken(originalStringContent: String) extends StringPartToken {
+ def parsedStringContent = originalStringContent match {
+ case "\\r" => "\r"
+ case "\\n" => "\n"
+ case "\\t" => "\t"
+ case "\\b" => "\b"
+ case "\\f" => "\f"
+ case """\\""" => """\"""
+ case """\/""" => """/"""
+ case "\\\"" => "\""
+ case x => x.tail
+ }
+ }
+ case class NormalStringToken(originalStringContent: String) extends StringPartToken {
+ def parsedStringContent = originalStringContent
+ }
+ case class UnexpectedContentToken(originalStringContent: String) extends JSONToken
+
+ val UnicodeCharRegex = """(\\u[a-fA-F0-9]{4})""".r
+ val EscapedCharRegex = """(\\[\\/bfnrt"])""".r
+ val NormalStringRegex = """([^\"[\x00-\x1F]\\]+)""".r
+ val NumberRegex = """(-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)""".r
+
+ private[this] def excerpt(string: String, limit: Int = 50): String = {
+ if (string.size > limit) {
+ string.take(limit) + "..."
+ } else {
+ string
+ }
+ }
+
+ private[this] def excerpt(tokens: Stream[JSONToken]): String = excerpt(tokens.map(_.originalStringContent).mkString)
+
+ def parse(json: String): ValidationNEL[String, Json] = {
+ expectValue(tokenize(json)).flatMap{streamAndValue =>
+ if (streamAndValue._1.isEmpty) {
+ streamAndValue._2.successNel
+ } else {
+ "JSON contains invalid suffix content: %s".format(excerpt(streamAndValue._1)).failNel
+ }
+ }
+ }
+
+ def tokenize(json: String): Stream[JSONToken] = tokenize(none, json)
+
+ def expectedSpacerToken(stream: Stream[JSONToken], token: JSONToken, failMessage: String): ValidationNEL[String, Stream[JSONToken]] = {
+ stream match {
+ case `token` #:: streamTail => streamTail.successNel
+ case _ => "%s but found: %s".format(failMessage, excerpt(stream)).failNel
+ }
+ }
+
+ def expectStringOpen(stream: Stream[JSONToken]) = expectedSpacerToken(stream, StringBoundsOpenToken, "Expected string bounds")
+
+ def expectStringClose(stream: Stream[JSONToken]) = expectedSpacerToken(stream, StringBoundsCloseToken, "Expected string bounds")
+
+ def expectArrayOpen(stream: Stream[JSONToken]) = expectedSpacerToken(stream, ArrayOpenToken, "Expected array open token")
+
+ def expectArrayClose(stream: Stream[JSONToken]) = expectedSpacerToken(stream, ArrayCloseToken, "Expected array close token")
+
+ def expectObjectOpen(stream: Stream[JSONToken]) = expectedSpacerToken(stream, ObjectOpenToken, "Expected object open token")
+
+ def expectObjectClose(stream: Stream[JSONToken]) = expectedSpacerToken(stream, ObjectCloseToken, "Expected object close token")
+
+ def expectEntrySeparator(stream: Stream[JSONToken]) = expectedSpacerToken(stream, EntrySeparatorToken, "Expected entry separator token")
+
+ def expectFieldSeparator(stream: Stream[JSONToken]) = expectedSpacerToken(stream, FieldSeparatorToken, "Expected field separator token")
+
+ def expectObject(stream: Stream[JSONToken]): ValidationNEL[String, (Stream[JSONToken], JObject)] = {
+ for {
+ afterObjectOpen <- expectObjectOpen(stream)
+ streamAndFields <- expectObjectField(true, (afterObjectOpen, Vector[(JString, Json)]()).successNel)
+ mappedStreamAndFields = streamAndFields.copy(_2 = streamAndFields._2.map(pair => (pair._1.s, pair._2)))
+ } yield (streamAndFields._1, JObject(JsonObject(InsertionMap(mappedStreamAndFields._2: _*))))
+ }
+
+ def expectArray(stream: Stream[JSONToken]): ValidationNEL[String, (Stream[JSONToken], JArray)] = {
+ for {
+ afterArrayOpen <- expectArrayOpen(stream)
+ streamAndFields <- expectArrayField(true, (afterArrayOpen, Vector[Json]()).successNel)
+ } yield (streamAndFields._1, JArray(streamAndFields._2.toList))
+ }
+
+ def expectValue(stream: Stream[JSONToken]): ValidationNEL[String, (Stream[JSONToken], Json)] = {
+ stream.headOption match {
+ case Some(ArrayOpenToken) => expectArray(stream)
+ case Some(ObjectOpenToken) => expectObject(stream)
+ case Some(StringBoundsOpenToken) => expectString(stream)
+ case Some(BooleanTrueToken) => (stream.tail, JBool(true)).successNel
+ case Some(BooleanFalseToken) => (stream.tail, JBool(false)).successNel
+ case Some(NullToken) => (stream.tail, JNull).successNel
+ case Some(NumberToken(numberText)) => {
+ numberText
+ .parseDouble
+ .fold(nfe => "Value [%s] cannot be parsed into a number.".format(numberText).failNel,
+ doubleValue => (stream.tail, JNumber(JsonNumber(doubleValue))).successNel)
+ }
+ case Some(UnexpectedContentToken(excerpt)) => "Unexpected content found: %s".format(excerpt).failNel
+ case Some(unexpectedToken) => "Unexpected content found: %s".format(excerpt(stream)).failNel
+ case None => "JSON terminates unexpectedly".failNel
+ }
+ }
+
+ @tailrec def expectArrayField(first: Boolean, currentStream: ValidationNEL[String, (Stream[JSONToken], Seq[Json])]): ValidationNEL[String, (Stream[JSONToken], Seq[Json])] = {
+ currentStream match {
+ case Success((stream, fields)) => {
+ stream.headOption match {
+ case Some(ArrayCloseToken) => (stream.tail, fields).successNel
+ case _ => {
+ expectArrayField(false, for {
+ afterEntrySeparator <- if (first) stream.successNel[String] else expectEntrySeparator(stream)
+ streamAndValue <- expectValue(afterEntrySeparator)
+ } yield (streamAndValue._1, fields :+ streamAndValue._2))
+ }
+ }
+ }
+ case _ => currentStream
+ }
+ }
+
+ @tailrec def expectObjectField(first: Boolean, currentStream: ValidationNEL[String, (Stream[JSONToken], Seq[(JString, Json)])]): ValidationNEL[String, (Stream[JSONToken], Seq[(JString, Json)])] = {
+ currentStream match {
+ case Success((stream, fields)) => {
+ stream.headOption match {
+ case Some(ObjectCloseToken) => (stream.tail, fields).successNel
+ case _ => {
+ expectObjectField(false, for {
+ afterEntrySeparator <- if (first) stream.successNel[String] else expectEntrySeparator(stream)
+ streamAndKey <- expectString(afterEntrySeparator)
+ afterFieldSeperator <- expectFieldSeparator(streamAndKey._1)
+ streamAndValue <- expectValue(afterFieldSeperator)
+ } yield (streamAndValue._1, fields :+ (streamAndKey._2, streamAndValue._2)))
+ }
+ }
+ }
+ case _ => currentStream
+ }
+ }
+
+ def expectString(stream: Stream[JSONToken]): ValidationNEL[String, (Stream[JSONToken], JString)] = {
+ for {
+ afterOpen <- expectStringOpen(stream)
+ elements <- afterOpen.span(jsonToken => jsonToken.isInstanceOf[StringPartToken]).successNel[String]
+ afterClose <- expectStringClose(elements._2)
+ } yield (afterClose, JString(elements._1.collect{case stringPart: StringPartToken => stringPart.parsedStringContent}.mkString))
+ }
+
+ @inline def streamCons(token: JSONToken, jsonRemainder: String): Stream[JSONToken] = Stream.cons(token, tokenize(token.some, jsonRemainder))
+
+ @inline def unexpectedContent(json: String) = Stream.cons(UnexpectedContentToken(json.take(10)), Stream.empty)
+
+ @inline def parseStringSegments(json: String): Stream[JSONToken] = {
+ if (json.head == '"') {
+ streamCons(StringBoundsCloseToken, json.tail)
+ } else {
+ NormalStringRegex.findPrefixOf(json).map(normalStringContent => streamCons(NormalStringToken(normalStringContent), json.drop(normalStringContent.length)))
+ .orElse(EscapedCharRegex.findPrefixOf(json).map(escapedChar => streamCons(EscapedCharacterToken(escapedChar), json.drop(escapedChar.length))))
+ .orElse(UnicodeCharRegex.findPrefixOf(json).map(unicodeContent => streamCons(UnicodeCharacterToken(unicodeContent), json.drop(unicodeContent.length))))
+ .getOrElse(unexpectedContent(json))
+ }
+ }
+
+ @tailrec private[this] def tokenize(previousToken: Option[JSONToken], json: String): Stream[JSONToken] = {
+ if (json.isEmpty) Stream.empty
+ else {
+ previousToken match {
+ case Some(StringBoundsOpenToken) => parseStringSegments(json)
+ case Some(stringPartToken: StringPartToken) => parseStringSegments(json)
+ case _ => {
+ val jsonHead = json.head
+ jsonHead match {
+ case '[' => streamCons(ArrayOpenToken, json.tail)
+ case ']' => streamCons(ArrayCloseToken, json.tail)
+ case '{' => streamCons(ObjectOpenToken, json.tail)
+ case '}' => streamCons(ObjectCloseToken, json.tail)
+ case ':' => streamCons(FieldSeparatorToken, json.tail)
+ case ',' => streamCons(EntrySeparatorToken, json.tail)
+ case '"' => streamCons(StringBoundsOpenToken, json.tail)
+ case ' ' => tokenize(previousToken, json.tail)
+ case '\r' => tokenize(previousToken, json.tail)
+ case '\n' => tokenize(previousToken, json.tail)
+ case _ => {
+ json match {
+ case trueStartingJSON if trueStartingJSON.startsWith("true") => streamCons(BooleanTrueToken, json.drop(4))
+ case falseStartingJSON if falseStartingJSON.startsWith("false") => streamCons(BooleanFalseToken, json.drop(5))
+ case nullStartingJSON if nullStartingJSON.startsWith("null") => streamCons(NullToken, json.drop(4))
+ case _ => {
+ NumberRegex.findPrefixOf(json)
+ .map(numberString => streamCons(NumberToken(numberString), json.drop(numberString.length)))
+ .getOrElse(unexpectedContent(json))
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
View
5 src/main/scala/com/ephox/argonaut/JsonObject.scala
@@ -144,8 +144,9 @@ trait JsonObjects {
implicit val JsonObjectInstances: Equal[JsonObject] with Show[JsonObject] =
new Equal[JsonObject] with Show[JsonObject] {
- def equal(j1: JsonObject, j2: JsonObject) =
- j1.toMap == j2.toMap
+ def equal(j1: JsonObject, j2: JsonObject) = {
+ j1.toList === j2.toList
+ }
def show(a: JsonObject) = Show.showFromToString show a
}
View
27 src/main/scala/com/ephox/argonaut/PrettyParams.scala
@@ -79,18 +79,6 @@ sealed trait PrettyParams {
* Returns a `Vector[Char]` representation of a pretty-printed JSON value.
*/
def lpretty(j: Json): Vector[Char] = {
- def escape(c: Char): String =
- c match {
- case '\\' => "\\\\"
- case '"' => "\\\""
- case '\b' => "\\b"
- case '\f' => "\\f"
- case '\n' => "\\n"
- case '\r' => "\\r"
- case '\t' => "\\t"
- case _ => c.toString
- }
-
def trav(depth: Int, k: Json): Vector[Char] = {
val lbrace = lbraceLeft(depth).chars ++ Vector('{') ++ lbraceRight(depth + 1).chars
val rbrace = rbraceLeft(depth + 1).chars ++ Vector('}') ++ rbraceRight(depth).chars
@@ -99,6 +87,7 @@ sealed trait PrettyParams {
val comma = commaLeft(depth + 1).chars ++ Vector(',') ++ commaRight(depth + 1).chars
val colon = colonLeft(depth + 1).chars ++ Vector(':') ++ colonRight(depth + 1).chars
+ import StringEscaping._
k.fold(
Vector('n', 'u', 'l', 'l')
, if(_) Vector('t', 'r', 'u', 'e') else Vector('f', 'a', 'l', 's', 'e')
@@ -125,6 +114,20 @@ sealed trait PrettyParams {
}
}
+object StringEscaping {
+ def escape(c: Char): String =
+ c match {
+ case '\\' => "\\\\"
+ case '"' => "\\\""
+ case '\b' => "\\b"
+ case '\f' => "\\f"
+ case '\n' => "\\n"
+ case '\r' => "\\r"
+ case '\t' => "\\t"
+ case _ => c.toString
+ }
+}
+
object PrettyParams extends PrettyParamss {
def apply(
lbraceLeft0: Int => JsonWhitespaces
View
32 src/test/scala/com/ephox/argonaut/AltParserSpecification.scala
@@ -0,0 +1,32 @@
+package com.ephox.argonaut
+
+import org.scalacheck.Prop._
+import scalaz.Success
+import org.scalacheck._
+import org.scalacheck.Shrink._
+import scalaz._
+import Scalaz._
+
+object AltParserTest extends Properties("AltParser") {
+ /*
+ def validResultsSpec = KnownResults.validResultPairings |> {(json, expectedJSONValue) =>
+ val actualParseResult = AltParser.parse(json)
+ actualParseResult must_== expectedJSONValue.successNel[JSONError]
+ }
+ def invalidResultsSpec = KnownResults.parseFailures |> {(json, parseResult) =>
+ val actualParseResult = Parser.parse(json)
+ actualParseResult === parseResult
+ }
+ */
+ property("Parsed, printed and then parsed again generates the same structure") =
+ forAll(JSONGenerators.arrayOrObjectGenerator.map(_.toString).label("arrayOrObject")){json =>
+ val firstParsed = AltParser.parse(json)
+ ("firstParsed = " + firstParsed) |: {
+ val printedJSON = firstParsed.map(jsonValue => jsonValue.nospaces)
+ ("printedJSON = " + printedJSON) |: {
+ val secondParsed = printedJSON.flatMap(secondJSON => AltParser.parse(secondJSON))
+ ("secondParsed = " + secondParsed) |: (firstParsed === secondParsed && secondParsed.isSuccess)
+ }
+ }
+ }
+}
View
131 src/test/scala/com/ephox/argonaut/JSONGenerators.scala
@@ -0,0 +1,131 @@
+package com.ephox.argonaut
+
+import org.scalacheck.Gen._
+import org.scalacheck.Prop
+import org.scalacheck.Arbitrary.{arbBigDecimal => _, _}
+import org.scalacheck.Arbitrary
+import org.scalacheck.Gen
+import scalaz._
+import Scalaz._
+import scala.util.Random.shuffle
+import java.math.MathContext._
+import java.math.{BigDecimal => JavaBigDecimal}
+
+object JSONGenerators {
+ val maxJSONStructureDepth = 5
+
+ def codePointStream(string: String): Stream[Int] = {
+ // Try to remove anything that could be misconstrued as an escape character.
+ val filteredString = string.flatMap(char => StringEscaping.escape(char)).filter(_ != '\\')
+ def codePointStream(offset: Int): Stream[Int] = {
+ if (offset > filteredString.length - 1) Stream.empty
+ else {
+ val codePoint = filteredString.codePointAt(offset)
+ Stream.cons(codePoint, codePointStream(offset + Character.charCount(codePoint)))
+ }
+ }
+ codePointStream(0)
+ }
+ def isValidUnicodeCodePoint(codePoint: Int): Boolean = {
+ Character.isLetterOrDigit(codePoint) || Character.isWhitespace(codePoint) || Character.isISOControl(codePoint)
+ }
+
+ val intGenerator: Gen[StringBuilder] = arbitrary[Long].map(long => new StringBuilder().append(long))
+ val jsonNumberGenerator: Gen[JNumber] = arbitrary[Double].map(number => JNumber(JsonNumber(number)))
+ val doubleGenerator: Gen[StringBuilder] = arbitrary[Double].map(double => new StringBuilder().append(double))
+ val numberGenerator: Gen[StringBuilder] = oneOf(intGenerator, doubleGenerator)
+ val stringGenerator: Gen[StringBuilder] = arbitrary[String].map{string =>
+ val codePoints = codePointStream(string).filter(isValidUnicodeCodePoint)
+ val builder = codePoints.foldLeft(new java.lang.StringBuilder()){(builder, codePoint) =>
+ if (codePoint <= 0xffff) {
+ builder.append(codePoint.toChar)
+ } else {
+ builder.appendCodePoint(codePoint)
+ }
+ }
+ new StringBuilder().append(builder)
+ }
+ val quotedStringGenerator: Gen[StringBuilder] = stringGenerator.map(builder => new StringBuilder().append("\"").append(builder).append("\""))
+ val jsonStringGenerator: Gen[JString] = stringGenerator.map(stringBuilder => JString(stringBuilder.toString))
+ val booleanGenerator: Gen[StringBuilder] = arbitrary[Boolean].map(boolean => new StringBuilder().append(if (boolean) "true" else "false"))
+ val jsonBoolGenerator: Gen[JBool] = oneOf(JBool(true), JBool(false))
+ val nothingGenerator: Gen[StringBuilder] = value(new StringBuilder().append("null"))
+ val jsonNothingGenerator: Gen[Json] = value(JNull)
+ def arrayGenerator(depth: Int = 5): Gen[StringBuilder] = listOfN(5, valueGenerator(depth - 1)).map{values =>
+ val builder = new StringBuilder()
+ builder.append('[')
+ values.headOption.foreach(builder.append)
+ if (!values.isEmpty) {
+ values.tail.foreach{tailElement =>
+ builder.append(',')
+ builder.append(tailElement)
+ }
+ }
+ builder.append(']')
+ }
+ def jsonArrayItemsGenerator(depth: Int = maxJSONStructureDepth): Gen[Seq[Json]] = listOfN(5, jsonValueGenerator(depth - 1))
+ def jsonArrayGenerator(depth: Int = maxJSONStructureDepth): Gen[JArray] = jsonArrayItemsGenerator(depth).map{values => JArray(values.toList)}
+ def objectGenerator(depth: Int = maxJSONStructureDepth): Gen[StringBuilder] = arbImmutableMap(Arbitrary(quotedStringGenerator), Arbitrary(valueGenerator(depth - 1))).arbitrary.map{map =>
+ val builder = new StringBuilder()
+ def addPair(builder: StringBuilder, pair: (StringBuilder, StringBuilder)): StringBuilder = {
+ builder.append(pair._1)
+ builder.append(':')
+ builder.append(pair._2)
+ }
+ builder.append('{')
+ map.headOption.foreach(pair => addPair(builder, pair))
+ if (!map.isEmpty) {
+ map.tail.foreach{pair =>
+ builder.append(',')
+ addPair(builder, pair)
+ }
+ }
+ "{%s}".format(map.take(10).map(pair => "%s:%s".format(pair._1, pair._2)).mkString(","))
+ builder.append('}')
+ }
+ def jsonObjectFieldsGenerator(depth: Int = maxJSONStructureDepth): Gen[Seq[(JString, Json)]] = listOfN(5, arbTuple2(Arbitrary(jsonStringGenerator), Arbitrary(jsonValueGenerator(depth - 1))).arbitrary)
+ def jsonObjectGenerator(depth: Int = maxJSONStructureDepth): Gen[JObject] = arbImmutableMap(Arbitrary(arbitrary[String]), Arbitrary(jsonValueGenerator(depth - 1))).arbitrary.map{map =>
+ JObject(JsonObject(InsertionMap(map.toSeq: _*)))
+ }
+ def valueGenerator(depth: Int = maxJSONStructureDepth): Gen[StringBuilder] = {
+ if (depth > 1) {
+ oneOf(numberGenerator, quotedStringGenerator, booleanGenerator, nothingGenerator, arrayGenerator(depth - 1), objectGenerator(depth - 1))
+ } else {
+ oneOf(numberGenerator, quotedStringGenerator, booleanGenerator, nothingGenerator)
+ }
+ }
+ val nonJSONObjectGenerator = oneOf(jsonNumberGenerator, jsonStringGenerator, jsonBoolGenerator, jsonNothingGenerator, jsonArrayGenerator())
+ def jsonValueGenerator(depth: Int = maxJSONStructureDepth): Gen[Json] = {
+ if (depth > 1) {
+ oneOf(jsonNumberGenerator, jsonStringGenerator, jsonBoolGenerator, jsonNothingGenerator, jsonArrayGenerator(depth - 1), jsonObjectGenerator(depth - 1))
+ } else {
+ oneOf(jsonNumberGenerator, jsonStringGenerator, jsonBoolGenerator, jsonNothingGenerator)
+ }
+ }
+ val arrayOrObjectGenerator = oneOf(arrayGenerator(), objectGenerator())
+
+ def objectsOfObjectsGenerator(depth: Int = maxJSONStructureDepth): Gen[Json] = {
+ if (depth > 1) {
+ listOfN(2, arbTuple2(Arbitrary(arbitrary[String]), Arbitrary(objectsOfObjectsGenerator(depth - 1))).arbitrary).map(fields => JObject(JsonObject(InsertionMap(fields: _*))))
+ } else {
+ oneOf(jsonNumberGenerator, jsonStringGenerator, jsonBoolGenerator, jsonNothingGenerator)
+ }
+ }
+
+ val arrayOrObjectAndPathGenerator: Gen[(Seq[String], Json, Json)] = objectsOfObjectsGenerator().map{jsonvalue =>
+ def buildPath(currentPath: Seq[String], original: Json, jsonValue: Json): (Seq[String], Json, Json) = {
+ jsonValue match {
+ case jsonObject: JObject => {
+ shuffle(jsonObject.o.toMap.toList.collect{case pair@ (innerString: String, innerValue: Json) => pair}.toList)
+ .headOption
+ .map{innerPair =>
+ buildPath(currentPath :+ innerPair._1, original, innerPair._2)
+ }
+ .getOrElse((currentPath, original, jsonObject))
+ }
+ case other => (currentPath, original, other)
+ }
+ }
+ buildPath(Seq(), jsonvalue, jsonvalue)
+ }
+}
View
42 src/test/scala/com/ephox/argonaut/KnownResults.scala
@@ -0,0 +1,42 @@
+package com.ephox.argonaut
+
+import scalaz._
+import Scalaz._
+
+// TODO: Fixme.
+object KnownResults{} /* extends DataTables {
+ def validResultPairings =
+ "JSON" | "JSONValue" |
+ """[]""" ! JSONArray() |
+ """{}""" ! JSONObject() |
+ """[10]""" ! JSONArray(Seq(JSONNumber(10))) |
+ """{"number":20}""" ! JSONObject(Map(JSONString("number") -> JSONNumber(20))) |
+ """{"firstKey":100,"secondKey":"secondValue"}""" ! new JSONObject(JSONString("firstKey") -> JSONNumber(100), JSONString("secondKey") -> JSONString("secondValue")) |
+ """[100,"secondValue"]""" ! JSONArray(Seq(JSONNumber(100), JSONString("secondValue"))) |
+ """[[]]""" ! JSONArray(Seq(JSONArray())) |
+ """[[[]]]""" ! JSONArray(Seq(JSONArray(Seq(JSONArray())))) |
+ """[[],[]]""" ! JSONArray(Seq(JSONArray(), JSONArray())) |
+ """[{},{}]""" ! JSONArray(Seq(JSONObject(), JSONObject())) |
+ """[[{}],[{}]]""" ! JSONArray(Seq(JSONArray(Seq(JSONObject())), JSONArray(Seq(JSONObject())))) |
+ """"\t"""" ! JSONString("\t") |
+ """"\b"""" ! JSONString("\b") |
+ """"\f"""" ! JSONString("\f") |
+ """"\n"""" ! JSONString("\n") |
+ """"\r"""" ! JSONString("\r") |
+ """"\\"""" ! JSONString("\\") |
+ """"\/"""" ! JSONString("/") |
+ """"\""""" ! JSONString("\"") |
+ "158699798998941697" ! new JSONNumber(BigInt(158699798998941697l))
+
+ def parseFailures =
+ "JSON" | "parse result" |
+ """[][]""" ! parseError("JSON contains invalid suffix content: []").failNel[JSONValue] |
+ """{}{}""" ! parseError("JSON contains invalid suffix content: {}").failNel[JSONValue] |
+ "\"\"\"\"" ! parseError("JSON contains invalid suffix content: \"\"").failNel[JSONValue] |
+ "\"test" ! parseError("Expected string bounds but found: ").failNel[JSONValue] |
+ "[7,,]" ! parseError("Unexpected content found: ,]").failNel[JSONValue] |
+ """{"firstKey":100,"secondKey":}""" ! parseError("Unexpected content found: }").failNel[JSONValue] |
+ """{"firstKey":}""" ! parseError("Unexpected content found: }").failNel[JSONValue] |
+ """{"firstKey"}""" ! parseError("Expected field separator token but found: }").failNel[JSONValue] |
+ """[[}]""" ! parseError("Unexpected content found: }]").failNel[JSONValue]
+}*/
Please sign in to comment.
Something went wrong with that request. Please try again.