github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/cmd/generates/sources/annotations.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package sources 19 20 import ( 21 "bufio" 22 "bytes" 23 "fmt" 24 "github.com/aacfactory/errors" 25 "io" 26 "strings" 27 ) 28 29 func NewAnnotation(name string, params ...string) Annotation { 30 var pp []string 31 if len(params) > 0 { 32 pp = params 33 } 34 return Annotation{ 35 Name: name, 36 Params: pp, 37 } 38 } 39 40 type Annotation struct { 41 Name string 42 Params []string 43 } 44 45 type Annotations []Annotation 46 47 func (annotations *Annotations) Get(name string) (annotation Annotation, has bool) { 48 ss := *annotations 49 for _, target := range ss { 50 if target.Name == name { 51 annotation = target 52 has = true 53 return 54 } 55 } 56 return 57 } 58 59 func (annotations *Annotations) FirstParam(name string) (value string, has bool) { 60 ss := *annotations 61 for _, target := range ss { 62 if target.Name == name { 63 if len(target.Params) > 0 { 64 value = target.Params[0] 65 has = true 66 } 67 return 68 } 69 } 70 return 71 } 72 73 func (annotations *Annotations) Value(name string) (value string, has bool) { 74 ss := *annotations 75 for _, target := range ss { 76 if target.Name == name { 77 if len(target.Params) > 0 { 78 for _, param := range target.Params { 79 value = value + " " + param 80 } 81 value = strings.TrimSpace(value) 82 has = true 83 } 84 return 85 } 86 } 87 return 88 } 89 90 func (annotations *Annotations) Add(name string, param string) { 91 ss := *annotations 92 for i, s := range ss { 93 if s.Name == name { 94 if param == "" { 95 return 96 } 97 s.Params = append(s.Params, param) 98 ss[i] = s 99 *annotations = ss 100 return 101 } 102 } 103 params := make([]string, 0, 1) 104 if param != "" { 105 params = append(params, param) 106 } 107 ss = append(ss, Annotation{ 108 Name: name, 109 Params: params, 110 }) 111 *annotations = ss 112 } 113 114 func (annotations *Annotations) Set(name string, param string) { 115 if param != "" { 116 param, _ = strings.CutSuffix(param, "\n") 117 param = strings.ReplaceAll(param, "'>>>'", ">>>") 118 param = strings.ReplaceAll(param, "'<<<'", "<<<") 119 param = strings.TrimSpace(param) 120 } 121 ss := *annotations 122 for i, s := range ss { 123 if s.Name == name { 124 params := make([]string, 0, 1) 125 if param != "" { 126 params = append(params, param) 127 } 128 s.Params = params 129 ss[i] = s 130 *annotations = ss 131 return 132 } 133 } 134 params := make([]string, 0, 1) 135 if param != "" { 136 params = append(params, param) 137 } 138 ss = append(ss, Annotation{ 139 Name: name, 140 Params: params, 141 }) 142 *annotations = ss 143 } 144 145 func ParseAnnotations(s string) (annotations Annotations, err error) { 146 annotations = make(Annotations, 0, 1) 147 if s == "" || !strings.Contains(s, "@") { 148 return 149 } 150 reader := bufio.NewReader(bytes.NewReader([]byte(s))) 151 for { 152 line, _, readErr := reader.ReadLine() 153 if readErr != nil { 154 if readErr == io.EOF { 155 break 156 } 157 err = errors.Warning("sources: parse annotations failed").WithCause(readErr).WithMeta("source", s) 158 return 159 } 160 if len(line) == 0 { 161 continue 162 } 163 line = bytes.TrimSpace(line) 164 if len(line) == 0 { 165 continue 166 } 167 if line[0] != '@' { 168 continue 169 } 170 name := "" 171 172 content := line[1:] 173 paramsIdx := bytes.IndexByte(content, ' ') 174 if paramsIdx < 1 { 175 // no params 176 name = string(content) 177 _, has := annotations.Get(name) 178 if has { 179 err = errors.Warning("sources: parse annotations failed").WithCause(fmt.Errorf("@%s is duplicated", name)).WithMeta("source", s) 180 return 181 } 182 annotations.Set(name, "") 183 continue 184 } else { 185 name = strings.TrimSpace(string(content[0:paramsIdx])) 186 _, has := annotations.Get(name) 187 if has { 188 err = errors.Warning("sources: parse annotations failed").WithCause(fmt.Errorf("@%s is duplicated", name)).WithMeta("source", s) 189 return 190 } 191 content = bytes.TrimSpace(content[paramsIdx:]) 192 if bytes.Index(content, []byte(">>>")) == 0 { 193 // block 194 block := bytes.NewBuffer(make([]byte, 0, 1)) 195 block.Write([]byte{'\n'}) 196 content = bytes.TrimSpace(content[3:]) 197 if endIdx := bytes.Index(content, []byte("<<<")); endIdx > -1 { 198 content = bytes.TrimSpace(content[0:endIdx]) 199 block.Write(content) 200 continue 201 } 202 if len(content) > 0 { 203 block.Write(content) 204 } 205 for { 206 line, _, readErr = reader.ReadLine() 207 if readErr != nil { 208 err = errors.Warning("sources: parse annotations failed").WithCause(fmt.Errorf("@%s is incompleted", name)).WithMeta("source", s) 209 return 210 } 211 content = bytes.TrimSpace(line) 212 if len(content) == 0 { 213 block.Write([]byte{'\n'}) 214 continue 215 } 216 if content[0] == '@' { 217 err = errors.Warning("sources: parse annotations failed").WithCause(fmt.Errorf("@%s is incompleted", name)).WithMeta("source", s) 218 return 219 } 220 if bytes.Index(content, []byte("<<<")) > -1 { 221 content, _ = bytes.CutSuffix(content, []byte("<<<")) 222 content = bytes.TrimSpace(content) 223 block.Write([]byte{'\n'}) 224 block.Write(content) 225 break 226 } 227 block.Write([]byte{'\n'}) 228 block.Write(content) 229 } 230 annotations.Set(name, block.String()[1:]) 231 } else { 232 params := strings.Split(string(content), " ") 233 for _, param := range params { 234 param = strings.TrimSpace(param) 235 annotations.Add(name, param) 236 } 237 } 238 } 239 } 240 return 241 }