func()

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
}