in load.go [327:388]
func (s *Spec) UnmarshalYAML(dt []byte) error {
parsed, err := parser.ParseBytes(dt, parser.ParseComments)
if err != nil {
return errors.Wrapf(err, "error parsing yaml: \n%s", string(dt))
}
if len(parsed.Docs) != 1 {
return errors.New("expected exactly one yaml document")
}
// Remove extension nodes from the main AST and store them so we can unmarshal
// them separately.
body := parsed.Docs[0].Body.(*ast.MappingNode)
var extNodes []*ast.MappingValueNode
for i := 0; i < len(body.Values); i++ {
node := body.Values[i]
p := node.GetPath()
if !strings.HasPrefix(p, "$.x-") && !strings.HasPrefix(p, "$.X-") {
continue
}
// Delete the extension node from the AST.
body.Values = append(body.Values[:i], body.Values[i+1:]...)
i--
extNodes = append(extNodes, node)
}
parsed, err = parser.ParseBytes([]byte(parsed.String()), parser.ParseComments)
if err != nil {
return errors.Wrapf(err, "error parsing yaml: \n%s", parsed.String())
}
// Use an internal type to avoid infinite recursion of UnmarshalYAML.
type internalSpec Spec
var s2 internalSpec
dec := yaml.NewDecoder(parsed, yaml.Strict())
if err := dec.Decode(&s2); err != nil {
return fmt.Errorf("%w:\n\n%s", errors.Wrap(err, "error unmarshalling parsed document"), parsed.String())
}
*s = Spec(s2)
if len(extNodes) > 0 {
// Unmarshal all the extension nodes.
node := ast.Mapping(token.MappingStart("", &token.Position{}), false, extNodes...)
doc := ast.Document(&token.Token{Position: &token.Position{}}, node)
var ext extensionFields
if err := yaml.NewDecoder(doc).Decode(&ext); err != nil {
return errors.Wrap(err, "error unmarshalling extension nodes")
}
s.extensions = ext
if len(ext) == 0 {
panic("ext should not be empty")
}
}
return nil
}