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

Add module that uses snakeyaml-engine, which only handles yaml 1.2 #303

Merged
merged 7 commits into from
Nov 14, 2022

Conversation

sideeffffect
Copy link
Collaborator

@sideeffffect sideeffffect commented Jun 21, 2022

closes #300
closes #301
closes #302

/cc @oyvindberg

@oyvindberg
Copy link

Note that i made that commit two minutes after I got it to compile. I gave also never used circe-yaml or snakeyaml before. As such I'd expect it will take some work to finish it. Tests are not green.

Also this seems to be breaking public api, and a breaking change to yaml format. This should at the minimum get a new major version, perhaps it should be a separate artifact, or even a separate library.

@sideeffffect
Copy link
Collaborator Author

Maybe we could find a way to do this that does not break the public API.
The circe-yaml library would then still be not well configurable, but maybe it's better to have API continuity than configurability 👍

@oyvindberg
Copy link

I'd say the opposite, let's make it very obvious and clear. This update can and will interpret arbitrary yaml differently

Also the new snakeyaml library is very configurable with config objects. Let's rather use those, so for instance the printer can become much simpler.

The only thing we really need to provide is a Node <-> JSON bijection and some syntax

@sideeffffect
Copy link
Collaborator Author

Related issue on BitBucket: snakeyaml-engine Cannot parse integers encoded in hexadecimal
https://bitbucket.org/snakeyaml/snakeyaml-engine/issues/38/cannot-parse-integers-encoded-in

@codecov-commenter
Copy link

codecov-commenter commented Sep 14, 2022

Codecov Report

Base: 87.30% // Head: 87.35% // Increases project coverage by +0.05% 🎉

Coverage data is based on head (cbfd4b0) compared to base (9df6d5c).
Patch coverage: 90.83% of modified lines in pull request are covered.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #303      +/-   ##
==========================================
+ Coverage   87.30%   87.35%   +0.05%     
==========================================
  Files           5       14       +9     
  Lines         126      253     +127     
  Branches        9       13       +4     
==========================================
+ Hits          110      221     +111     
- Misses         16       32      +16     
Impacted Files Coverage Δ
...rce-yaml/src/main/scala/io/circe/yaml/Parser.scala 89.09% <ø> (ø)
.../src/main/scala/io/circe/yaml/parser/package.scala 35.71% <ø> (ø)
.../src/main/scala/io/circe/yaml/syntax/package.scala 100.00% <ø> (ø)
.../main/scala/io/circe/yaml/v12/parser/package.scala 50.00% <50.00%> (ø)
.../src/main/scala/io/circe/yaml/v12/ParserImpl.scala 84.74% <84.74%> (ø)
...-v12/src/main/scala/io/circe/yaml/v12/Parser.scala 100.00% <100.00%> (ø)
...v12/src/main/scala/io/circe/yaml/v12/Printer.scala 100.00% <100.00%> (ø)
...src/main/scala/io/circe/yaml/v12/PrinterImpl.scala 100.00% <100.00%> (ø)
...v12/src/main/scala/io/circe/yaml/v12/package.scala 100.00% <100.00%> (ø)
...main/scala/io/circe/yaml/v12/printer/package.scala 100.00% <100.00%> (ø)
... and 6 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report at Codecov.
📢 Do you have feedback about the report comment? Let us know in this issue.

@sideeffffect
Copy link
Collaborator Author

Hi @jeffmay , would you like to merge this yourself of can I do it?
Just make sure, are you aware that this is a breaking change for the library, right?

build.sbt Outdated Show resolved Hide resolved
def flatten(node: MappingNode): MappingNode = {
flattenMapping(node)
node
}

def construct(node: ScalarNode): Object =
getConstructor(node).construct(node)
super.construct(node)
}

private[this] def yamlToJson(node: Node): Either[ParsingFailure, Json] = {
// Isn't thread-safe internally, may hence not be shared
Copy link

@LeifW LeifW Oct 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this thread-safety comment still apply?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know, to be honest. And since I don't know, I'm picking the conservative option of keeping things as they were.

}

private[this] def yamlToJson(node: Node): Either[ParsingFailure, Json] = {
// Isn't thread-safe internally, may hence not be shared
val flattener: FlatteningConstructor = new FlatteningConstructor
val flattener: FlatteningConstructor = new FlatteningConstructor(settings)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the if node.getValue.startsWith("0x") || node.getValue.contains("_") check below - snakeyaml-engine doesn't seem handle hexadecimal-formatted numbers as far as I can tell. Those just get tagged / handled as string.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (ot.isPresent) Some(ot.get()) else None

private[this] def createComposer(reader: Reader) =
new Composer(settings, new ParserImpl(settings, new StreamReader(settings, reader)))
Copy link

@LeifW LeifW Oct 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  new Compose(settings).composeReader(reader)

There's a util method that defines all this + the .getSingleNode call in the form of Compose.composeReader

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that returns Optional[Node] instead of a Composer...

@sideeffffect
Copy link
Collaborator Author

I wasn't able to implement all the suggestions from the comments, so I've at least explained the reason in the comments.

Otherwise this is ready to be merged @jeffmay

@sideeffffect sideeffffect changed the title use snakeyaml-engine, which only handles yaml 1.2 [WIP] use snakeyaml-engine, which only handles yaml 1.2 Oct 17, 2022
@sideeffffect
Copy link
Collaborator Author

I'll rework this into 2 separate modules, one for 1.1, the other for 1.2.

@sideeffffect sideeffffect force-pushed the snakeyaml-engine branch 3 times, most recently from c9d9707 to f15ce82 Compare October 17, 2022 21:09
@sideeffffect sideeffffect changed the title [WIP] use snakeyaml-engine, which only handles yaml 1.2 Add module that uses snakeyaml-engine, which only handles yaml 1.2 Oct 17, 2022
@sideeffffect
Copy link
Collaborator Author

sideeffffect commented Oct 17, 2022

@jeffmay This is ready. Can you please merge this and release an RC version (0.14.2-RC1)? (I think all this should be 100 % backwards compatible.)


def convertScalarNode(node: ScalarNode) = Either
.catchNonFatal(node.getTag match {
case Tag.INT if node.getValue.startsWith("0x") || node.getValue.contains("_") =>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As the snakeyaml-engine readme says, "Only JSON Schema is supported." - that is, it doesn't support any literal formats beyond what's already in JSON. You can inspect the snakeyaml-engine impl of construct here and see that it's not doing anything fancier than e.g. String.toInt. So we can remove this entire case Tag.INT if node.getValue ... => block - it's not doing anything other than wasting CPU cycles and confusing / misleading future maintainers.
https://bitbucket.org/snakeyaml/snakeyaml-engine/src/master/#markdown-header-snakeyaml-engine-features

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this code would be useful once we add Core Schema support to snakeyaml-engine?
https://bitbucket.org/snakeyaml/snakeyaml-engine/issues/38/cannot-parse-integers-encoded-in

throw new NumberFormatException(s"Invalid numeric string ${node.getValue}")
}
case Tag.BOOL =>
Json.fromBoolean(flattener.construct(node) match {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above on how snakeyaml-engine "only supports JSON schema". We have no need for callingconstruct method on literals, as snakeyaml-engine doesn't support any more literal formats than JSON itself already does.

@sideeffffect
Copy link
Collaborator Author

I'll go ahead and merge this before any more merge conflicts appear. We can keep polishing this after it is in master

@sideeffffect sideeffffect merged commit d3d0907 into circe:master Nov 14, 2022
@sideeffffect sideeffffect deleted the snakeyaml-engine branch November 14, 2022 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants