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 }