yaml / yaml-test-suite

Comprehensive, language independent Test Suite for YAML
MIT License
172 stars 58 forks source link

Does the error case QLJ7 indicate a breaking change between 1.1 and 1.2? #45

Open am11 opened 4 years ago

am11 commented 4 years ago

Hello @perlpunk, I just wanted to confirm whether this was a breaking change from YAML 1.1 in 1.2?

1.1 spec states (https://yaml.org/spec/1.1/#l-first-document):

If the document does specify any directives, all directives of previous documents, if any, are ignored.

1.2 spec states (https://yaml.org/spec/1.2/spec.html#id2784064):

The choice of tag handle is a presentation detail and must not be used to convey content information. In particular, the tag handle may be discarded once parsing is completed.

My current understanding is:

%YAML 1.1
%TAG !x! tag:example.com,2014:
--- !x!foo
x: 0
--- !x!bar
x: 1

should parse, but by replacing 1.1 with 1.2, it should fail.

Thanks!

perlpunk commented 4 years ago

Yes, this is actually something that changed. @eemeli explained it here: https://github.com/eemeli/yaml/issues/109#issuecomment-489315366 and quoted the relevant parts from the specification. It is hard to find out because the documentation about tag shorthands doesn't document that explicitly in 1.2, but only says

A YAML character stream may contain several documents. Each document is completely independent from the rest.

The point is probably, that you should be able to take out a YAML document of a file or stream and put it elsewhere, and it should work the same. But I think this is something that a YAML processor could actually make configurable. I understand if there are many small documents, repeating the tag directive can be very noisy.

am11 commented 4 years ago

Thank you for the explanation. I have two follow-up questions:

Each document is completely independent from the rest.

Given:

%YAML 1.1
---
x: 0
---
x: 1

is it so that the first document version is explicitly v1.1 and second is implicitly v1.2 (provided the implementation uses 1.2 as default version)? And to make this implicit v1.2 inference of second document explicitly clear, it would require explicit <document end> indicator:

%YAML 1.1
---
x: 0
...
%YAML 1.2
---
x: 1
...

this is something that a YAML processor could actually make configurable.

Lets say that processor has a configuration option called AllowSharedGlobalDirectivesInCharacterStream, would it exempt us from comparing the version? i.e. regardless of versions, the processor option will be honored OR the option is ON and not configurable for v1.1, and OFF for v1.2 and configurable.

eemeli commented 4 years ago

The spec doesn't actually cover how a stream of documents from more than one YAML version should be handled, so your examples are getting into implementation-specific behaviour.

Speaking on behalf of yaml, its default version is YAML 1.2, but that is configurable. Because of this YAML 1.1 peculiarity, however, the preceding documents' headers are tracked and what you want should work out of the box, even if the parser is explicitly todl to expect YAML 1.2:

import YAML from 'yaml'

const src11 = `
%YAML 1.1
---
x: 0
---
x: 1`

const stream = YAML.parseAllDocuments(src11, { version: '1.2' )
stream.map(doc => doc.version) // [ '1.1', '1.1' ]
stream.map(doc => doc.toJSON()) // [ { x: 0 }, { x: 1 } ]

For YAML 1.2, that doesn't work though, because its spec doesn't consider preceding documents:

const src12 = `
%YAML 1.2
---
x: 0
---
x: 1`

const stream = YAML.parseAllDocuments(src12, { version: '1.1' )
stream.map(doc => doc.version) // [ '1.2', null ]
stream.map(doc => doc.schema.name) // [ 'core', 'yaml-1.1' ]
stream.map(doc => doc.toJSON()) // [ { x: 0 }, { x: 1 } ]