github.com/google/yamlfmt@v0.12.2-0.20240514121411-7f77800e2681/metadata.go (about)

     1  // Copyright 2024 Google LLC
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package yamlfmt
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"strings"
    21  	"unicode"
    22  
    23  	"github.com/google/yamlfmt/internal/collections"
    24  )
    25  
    26  const MetadataIdentifier = "!yamlfmt!"
    27  
    28  type MetadataType string
    29  
    30  const (
    31  	MetadataIgnore MetadataType = "ignore"
    32  )
    33  
    34  func IsMetadataType(mdValueStr string) bool {
    35  	mdTypes := collections.Set[MetadataType]{}
    36  	mdTypes.Add(MetadataIgnore)
    37  	return mdTypes.Contains(MetadataType(mdValueStr))
    38  }
    39  
    40  type Metadata struct {
    41  	Type    MetadataType
    42  	LineNum int
    43  }
    44  
    45  var (
    46  	ErrMalformedMetadata    = errors.New("metadata: malformed string")
    47  	ErrUnrecognizedMetadata = errors.New("metadata: unrecognized type")
    48  )
    49  
    50  type MetadataError struct {
    51  	err     error
    52  	path    string
    53  	lineNum int
    54  	lineStr string
    55  }
    56  
    57  func (e *MetadataError) Error() string {
    58  	return fmt.Sprintf(
    59  		"%v: %s:%d:%s",
    60  		e.err,
    61  		e.path,
    62  		e.lineNum,
    63  		e.lineStr,
    64  	)
    65  }
    66  
    67  func (e *MetadataError) Unwrap() error {
    68  	return e.err
    69  }
    70  
    71  func ReadMetadata(content []byte, path string) (collections.Set[Metadata], collections.Errors) {
    72  	metadata := collections.Set[Metadata]{}
    73  	mdErrs := collections.Errors{}
    74  	// This could be `\r\n` but it won't affect the outcome of this operation.
    75  	contentLines := strings.Split(string(content), "\n")
    76  	for i, line := range contentLines {
    77  		mdidIndex := strings.Index(line, MetadataIdentifier)
    78  		if mdidIndex == -1 {
    79  			continue
    80  		}
    81  		mdStr := scanMetadata(line, mdidIndex)
    82  		mdComponents := strings.Split(mdStr, ":")
    83  		if len(mdComponents) != 2 {
    84  			mdErrs = append(mdErrs, &MetadataError{
    85  				path:    path,
    86  				lineNum: i + 1,
    87  				err:     ErrMalformedMetadata,
    88  				lineStr: line,
    89  			})
    90  			continue
    91  		}
    92  		if IsMetadataType(mdComponents[1]) {
    93  			metadata.Add(Metadata{LineNum: i + 1, Type: MetadataType(mdComponents[1])})
    94  		} else {
    95  			mdErrs = append(mdErrs, &MetadataError{
    96  				path:    path,
    97  				lineNum: i + 1,
    98  				err:     ErrUnrecognizedMetadata,
    99  				lineStr: line,
   100  			})
   101  		}
   102  	}
   103  	return metadata, mdErrs
   104  }
   105  
   106  func scanMetadata(line string, index int) string {
   107  	mdBytes := []byte{}
   108  	i := index
   109  	for i < len(line) && !unicode.IsSpace(rune(line[i])) {
   110  		mdBytes = append(mdBytes, line[i])
   111  		i++
   112  	}
   113  	return string(mdBytes)
   114  }