Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hello, scalafmt #41

Merged
merged 2 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ jobs:
- name: Check binary compatibility
run: sbt ++${{ matrix.scala }} mimaReportBinaryIssues

- name: Check formatting
run: sbt ++${{ matrix.scala }} scalafmtCheckAll

- name: Check that workflows are up to date
run: sbt ++${{ matrix.scala }} githubWorkflowCheck

Expand Down
18 changes: 18 additions & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version = 2.7.5

style = default

maxColumn = 100

// Vertical alignment is pretty, but leads to bigger diffs
align.preset = none

danglingParentheses.preset = false

rewrite.rules = [
AvoidInfix
RedundantBraces
RedundantParens
AsciiSortImports
PreferCurlyFors
]
27 changes: 17 additions & 10 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ mimaPreviousArtifacts := Set("org.sangria-graphql" %% "sangria-play-json" % "2.0

description := "Sangria play-json marshalling"
homepage := Some(url("http://sangria-graphql.org"))
licenses := Seq("Apache License, ASL Version 2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0"))
licenses := Seq(
"Apache License, ASL Version 2.0" -> url("http://www.apache.org/licenses/LICENSE-2.0"))

ThisBuild / crossScalaVersions := Seq("2.12.13", "2.13.4")
ThisBuild / scalaVersion := crossScalaVersions.value.last
ThisBuild / githubWorkflowPublishTargetBranches := List()
ThisBuild / githubWorkflowBuildPreamble ++= List(
WorkflowStep.Sbt(List("mimaReportBinaryIssues"), name = Some("Check binary compatibility"))
WorkflowStep.Sbt(List("mimaReportBinaryIssues"), name = Some("Check binary compatibility")),
WorkflowStep.Sbt(List("scalafmtCheckAll"), name = Some("Check formatting"))
)

scalacOptions += "-target:jvm-1.8"
Expand All @@ -21,9 +23,9 @@ scalacOptions ++= Seq("-deprecation", "-feature")
libraryDependencies ++= Seq(
"org.sangria-graphql" %% "sangria-marshalling-api" % "1.0.5",
"com.typesafe.play" %% "play-json" % "2.9.2",

"org.sangria-graphql" %% "sangria-marshalling-testkit" % "1.0.3" % Test,
"org.scalatest" %% "scalatest" % "3.2.3" % Test)
"org.scalatest" %% "scalatest" % "3.2.3" % Test
)

// Publishing

Expand All @@ -34,15 +36,20 @@ publishArtifact in Test := false
pomIncludeRepository := (_ => false)
publishTo := Some(
if (version.value.trim.endsWith("SNAPSHOT"))
"snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
"snapshots".at("https://oss.sonatype.org/content/repositories/snapshots")
else
"releases" at "https://oss.sonatype.org/service/local/staging/deploy/maven2")
"releases".at("https://oss.sonatype.org/service/local/staging/deploy/maven2"))
startYear := Some(2016)
organizationHomepage := Some(url("https://github.com/sangria-graphql"))
developers := Developer("OlegIlyenko", "Oleg Ilyenko", "", url("https://github.com/OlegIlyenko")) :: Nil
scmInfo := Some(ScmInfo(
browseUrl = url("https://github.com/sangria-graphql/sangria-play-json.git"),
connection = "scm:git:[email protected]:sangria-graphql/sangria-play-json.git"))
developers := Developer(
"OlegIlyenko",
"Oleg Ilyenko",
"",
url("https://github.com/OlegIlyenko")) :: Nil
scmInfo := Some(
ScmInfo(
browseUrl = url("https://github.com/sangria-graphql/sangria-play-json.git"),
connection = "scm:git:[email protected]:sangria-graphql/sangria-play-json.git"))

// nice *magenta* prompt!

Expand Down
1 change: 1 addition & 0 deletions project/plugins.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ addSbtPlugin("com.typesafe" % "sbt-mima-plugin" % "0.8.1")
addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.6.1")
addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.7")
addSbtPlugin("com.codecommit" % "sbt-github-actions" % "0.10.1")
addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.4.2")
50 changes: 29 additions & 21 deletions src/main/scala/sangria/marshalling/playJson.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ object playJson extends PlayJsonSupportLowPrioImplicits {
type MapBuilder = ArrayMapBuilder[Node]

override def emptyMapNode(keys: Seq[String]): MapBuilder = new ArrayMapBuilder[Node](keys)
override def addMapNodeElem(builder: MapBuilder, key: String, value: Node, optional: Boolean): MapBuilder = builder.add(key, value)
override def addMapNodeElem(
builder: MapBuilder,
key: String,
value: Node,
optional: Boolean): MapBuilder = builder.add(key, value)

override def mapNode(builder: MapBuilder): Node = JsObject(builder.toSeq)
override def mapNode(keyValues: Seq[(String, JsValue)]): Node = JsObject(keyValues)
Expand All @@ -22,18 +26,19 @@ object playJson extends PlayJsonSupportLowPrioImplicits {
case None => nullNode
}

override def scalarNode(value: Any, typeName: String, info: Set[ScalarValueInfo]): Node = value match {
case v: String => JsString(v)
case true => JsTrue
case false => JsFalse
case v: Int => JsNumber(BigDecimal(v))
case v: Long => JsNumber(BigDecimal(v))
case v: Float => JsNumber(BigDecimal(v.toDouble))
case v: Double => JsNumber(BigDecimal(v))
case v: BigInt => JsNumber(BigDecimal(v))
case v: BigDecimal => JsNumber(v)
case v => throw new IllegalArgumentException("Unsupported scalar value: " + v)
}
override def scalarNode(value: Any, typeName: String, info: Set[ScalarValueInfo]): Node =
value match {
case v: String => JsString(v)
case true => JsTrue
case false => JsFalse
case v: Int => JsNumber(BigDecimal(v))
case v: Long => JsNumber(BigDecimal(v))
case v: Float => JsNumber(BigDecimal(v.toDouble))
case v: Double => JsNumber(BigDecimal(v))
case v: BigInt => JsNumber(BigDecimal(v))
case v: BigDecimal => JsNumber(v)
case v => throw new IllegalArgumentException("Unsupported scalar value: " + v)
}

override def enumNode(value: String, typeName: String): Node = JsString(value)

Expand All @@ -48,19 +53,21 @@ object playJson extends PlayJsonSupportLowPrioImplicits {
}

implicit object PlayJsonInputUnmarshaller extends InputUnmarshaller[JsValue] {
override def getRootMapValue(node: JsValue, key: String): Option[JsValue] = node.asInstanceOf[JsObject].value get key
override def getRootMapValue(node: JsValue, key: String): Option[JsValue] =
node.asInstanceOf[JsObject].value.get(key)

override def isListNode(node: JsValue) = node.isInstanceOf[JsArray]
override def getListValue(node: JsValue): Seq[JsValue] = node.asInstanceOf[JsArray].value.toSeq

override def isMapNode(node: JsValue): Boolean = node.isInstanceOf[JsObject]
override def getMapValue(node: JsValue, key: String): Option[JsValue] = node.asInstanceOf[JsObject].value get key
override def getMapValue(node: JsValue, key: String): Option[JsValue] =
node.asInstanceOf[JsObject].value.get(key)
override def getMapKeys(node: JsValue): Iterable[String] = node.asInstanceOf[JsObject].keys

override def isDefined(node: JsValue): Boolean = node != JsNull
override def getScalarValue(node: JsValue): Any = node match {
case JsBoolean(b) => b
case JsNumber(d) => d.toBigIntExact getOrElse d
case JsNumber(d) => d.toBigIntExact.getOrElse(d)
case JsString(s) => s
case _ => throw new IllegalStateException(s"$node is not a scalar value")
}
Expand All @@ -75,7 +82,8 @@ object playJson extends PlayJsonSupportLowPrioImplicits {
}

override def isVariableNode(node: JsValue): Boolean = false
override def getVariableName(node: JsValue): String = throw new IllegalArgumentException("variables are not supported")
override def getVariableName(node: JsValue): String = throw new IllegalArgumentException(
"variables are not supported")

override def render(node: JsValue): String = Json.stringify(node)
}
Expand All @@ -87,7 +95,7 @@ object playJson extends PlayJsonSupportLowPrioImplicits {
implicit def playJsonToInput[T <: JsValue]: ToInput[T, JsValue] =
PlayJsonToInput.asInstanceOf[ToInput[T, JsValue]]

implicit def playJsonWriterToInput[T : Writes]: ToInput[T, JsValue] =
implicit def playJsonWriterToInput[T: Writes]: ToInput[T, JsValue] =
new ToInput[T, JsValue] {
def toInput(value: T) = implicitly[Writes[T]].writes(value) -> PlayJsonInputUnmarshaller
}
Expand All @@ -100,14 +108,14 @@ object playJson extends PlayJsonSupportLowPrioImplicits {
implicit def playJsonFromInput[T <: JsValue]: FromInput[T] =
PlayJsonFromInput.asInstanceOf[FromInput[T]]

implicit def playJsonReaderFromInput[T : Reads]: FromInput[T] =
implicit def playJsonReaderFromInput[T: Reads]: FromInput[T] =
new FromInput[T] {
val marshaller = PlayJsonResultMarshaller
def fromResult(node: marshaller.Node) = implicitly[Reads[T]].reads(node) match {
case JsSuccess(v, _) => v
case JsError(errors) =>
val formattedErrors = errors.toVector.flatMap {
case (JsPath(nodes), es) => es.map(e => s"At path '${nodes mkString "."}': ${e.message}")
val formattedErrors = errors.toVector.flatMap { case (JsPath(nodes), es) =>
es.map(e => s"At path '${nodes.mkString(".")}': ${e.message}")
}

throw InputParsingError(formattedErrors)
Expand Down
60 changes: 31 additions & 29 deletions src/test/scala/sangria/marshalling/PlayJsonSupportSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,60 +7,62 @@ import sangria.marshalling.playJson._
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec


class PlayJsonSupportSpec extends AnyWordSpec with Matchers with MarshallingBehaviour with InputHandlingBehaviour with ParsingBehaviour {
class PlayJsonSupportSpec
extends AnyWordSpec
with Matchers
with MarshallingBehaviour
with InputHandlingBehaviour
with ParsingBehaviour {
implicit val commentFormat = Json.format[Comment]
implicit val articleFormat = Json.format[Article]

"PlayJson integration" should {
behave like `value (un)marshaller` (PlayJsonResultMarshaller)

behave like `AST-based input unmarshaller` (playJsonFromInput[JsValue])
behave like `AST-based input marshaller` (PlayJsonResultMarshaller)

behave like `case class input unmarshaller`
behave like `case class input marshaller` (PlayJsonResultMarshaller)

behave like `input parser` (ParseTestSubjects(
complex = """{"a": [null, 123, [{"foo": "bar"}]], "b": {"c": true, "d": null}}""",
simpleString = "\"bar\"",
simpleInt = "12345",
simpleNull = "null",
list = "[\"bar\", 1, null, true, [1, 2, 3]]",
syntaxError = List("[123, \"FOO\" \"BAR\"")
))
behave.like(`value (un)marshaller`(PlayJsonResultMarshaller))

behave.like(`AST-based input unmarshaller`(playJsonFromInput[JsValue]))
behave.like(`AST-based input marshaller`(PlayJsonResultMarshaller))

behave.like(`case class input unmarshaller`)
behave.like(`case class input marshaller`(PlayJsonResultMarshaller))

behave.like(
`input parser`(ParseTestSubjects(
complex = """{"a": [null, 123, [{"foo": "bar"}]], "b": {"c": true, "d": null}}""",
simpleString = "\"bar\"",
simpleInt = "12345",
simpleNull = "null",
list = "[\"bar\", 1, null, true, [1, 2, 3]]",
syntaxError = List("[123, \"FOO\" \"BAR\"")
)))
}

val toRender = Json.obj(
"a" -> Json.arr(JsNull, JsNumber(123), Json.arr(Json.obj("foo" -> JsString("bar")))),
"b" -> Json.obj(
"c" -> JsBoolean(true),
"d" -> JsNull))
"b" -> Json.obj("c" -> JsBoolean(true), "d" -> JsNull))

"InputUnmarshaller" should {
"throw an exception on invalid scalar values" in {
an [IllegalStateException] should be thrownBy
PlayJsonInputUnmarshaller.getScalarValue(Json.obj())
an[IllegalStateException] should be thrownBy
PlayJsonInputUnmarshaller.getScalarValue(Json.obj())
}

"throw an exception on variable names" in {
an [IllegalArgumentException] should be thrownBy
PlayJsonInputUnmarshaller.getVariableName(JsString("$foo"))
an[IllegalArgumentException] should be thrownBy
PlayJsonInputUnmarshaller.getVariableName(JsString("$foo"))
}

"render JSON values" in {
val rendered = PlayJsonInputUnmarshaller.render(toRender)

rendered should be ("""{"a":[null,123,[{"foo":"bar"}]],"b":{"c":true,"d":null}}""")
rendered should be("""{"a":[null,123,[{"foo":"bar"}]],"b":{"c":true,"d":null}}""")
}
}

"ResultMarshaller" should {
"render pretty JSON values" in {
val rendered = PlayJsonResultMarshaller.renderPretty(toRender)

rendered.replaceAll("\r", "") should be (
"""{
rendered.replaceAll("\r", "") should be("""{
| "a" : [ null, 123, [ {
| "foo" : "bar"
| } ] ],
Expand All @@ -74,7 +76,7 @@ class PlayJsonSupportSpec extends AnyWordSpec with Matchers with MarshallingBeha
"render compact JSON values" in {
val rendered = PlayJsonResultMarshaller.renderCompact(toRender)

rendered should be ("""{"a":[null,123,[{"foo":"bar"}]],"b":{"c":true,"d":null}}""")
rendered should be("""{"a":[null,123,[{"foo":"bar"}]],"b":{"c":true,"d":null}}""")
}
}
}