github.com/GuanceCloud/cliutils@v1.1.21/pipeline/ptinput/funcs/fn_json.go (about) 1 // Unless explicitly stated otherwise all files in this repository are licensed 2 // under the MIT License. 3 // This product includes software developed at Guance Cloud (https://www.guance.com/). 4 // Copyright 2021-present Guance, Inc. 5 6 package funcs 7 8 import ( 9 "encoding/json" 10 "fmt" 11 "reflect" 12 "strings" 13 14 "github.com/GuanceCloud/cliutils/pipeline/ptinput" 15 "github.com/GuanceCloud/platypus/pkg/ast" 16 "github.com/GuanceCloud/platypus/pkg/engine/runtime" 17 "github.com/GuanceCloud/platypus/pkg/errchain" 18 ) 19 20 func JSONChecking(ctx *runtime.Task, funcExpr *ast.CallExpr) *errchain.PlError { 21 if err := normalizeFuncArgsDeprecated(funcExpr, []string{ 22 "input", "json_path", "newkey", 23 "trim_space", "delete_after_extract", 24 }, 2); err != nil { 25 return runtime.NewRunError(ctx, err.Error(), funcExpr.NamePos) 26 } 27 28 if _, err := getKeyName(funcExpr.Param[0]); err != nil { 29 return runtime.NewRunError(ctx, err.Error(), funcExpr.Param[0].StartPos()) 30 } 31 32 lastIdxExpr := false 33 switch funcExpr.Param[1].NodeType { //nolint:exhaustive 34 case ast.TypeAttrExpr, ast.TypeIdentifier, ast.TypeIndexExpr: 35 var err error 36 lastIdxExpr, err = lastIsIndex(funcExpr.Param[1]) 37 if err != nil { 38 return runtime.NewRunError(ctx, err.Error(), funcExpr.Param[1].StartPos()) 39 } 40 default: 41 return runtime.NewRunError(ctx, fmt.Sprintf("expect AttrExpr, IndexExpr or Identifier, got %s", 42 funcExpr.Param[1].NodeType), funcExpr.Param[1].StartPos()) 43 } 44 45 if funcExpr.Param[2] != nil { 46 switch funcExpr.Param[2].NodeType { //nolint:exhaustive 47 case ast.TypeAttrExpr, ast.TypeIdentifier, ast.TypeStringLiteral: 48 default: 49 return runtime.NewRunError(ctx, fmt.Sprintf("expect AttrExpr or Identifier, got %s", 50 funcExpr.Param[2].NodeType), funcExpr.Param[2].StartPos()) 51 } 52 } 53 54 if funcExpr.Param[3] != nil { 55 switch funcExpr.Param[3].NodeType { //nolint:exhaustive 56 case ast.TypeBoolLiteral: 57 default: 58 return runtime.NewRunError(ctx, fmt.Sprintf("expect BoolLiteral, got %s", 59 funcExpr.Param[3].NodeType), funcExpr.Param[3].StartPos()) 60 } 61 } 62 63 if funcExpr.Param[4] != nil { 64 switch funcExpr.Param[4].NodeType { //nolint:exhaustive 65 case ast.TypeBoolLiteral: 66 if funcExpr.Param[4].BoolLiteral().Val == lastIdxExpr { 67 return runtime.NewRunError(ctx, "does not support deleting elements in the list", 68 funcExpr.Param[4].StartPos()) 69 } 70 default: 71 return runtime.NewRunError(ctx, fmt.Sprintf("expect BoolLiteral, got %s", 72 funcExpr.Param[3].NodeType), funcExpr.Param[4].StartPos()) 73 } 74 } 75 76 return nil 77 } 78 79 func JSON(ctx *runtime.Task, funcExpr *ast.CallExpr) *errchain.PlError { 80 var jpath *ast.Node 81 82 srcKey, err := getKeyName(funcExpr.Param[0]) 83 if err != nil { 84 return runtime.NewRunError(ctx, err.Error(), funcExpr.Param[0].StartPos()) 85 } 86 87 switch funcExpr.Param[1].NodeType { //nolint:exhaustive 88 case ast.TypeAttrExpr, ast.TypeIdentifier, ast.TypeIndexExpr: 89 jpath = funcExpr.Param[1] 90 // TODO StringLiteral 91 default: 92 return runtime.NewRunError(ctx, fmt.Sprintf("expect AttrExpr or Identifier, got %s", 93 funcExpr.Param[1].NodeType), funcExpr.Param[1].StartPos()) 94 } 95 96 targetKey, _ := getKeyName(jpath) 97 98 if funcExpr.Param[2] != nil { 99 switch funcExpr.Param[2].NodeType { //nolint:exhaustive 100 case ast.TypeAttrExpr, ast.TypeIdentifier, ast.TypeStringLiteral: 101 targetKey, _ = getKeyName(funcExpr.Param[2]) 102 default: 103 return runtime.NewRunError(ctx, fmt.Sprintf("expect AttrExpr or Identifier, got %s", 104 funcExpr.Param[2].NodeType), funcExpr.Param[2].StartPos()) 105 } 106 } 107 108 cont, err := ctx.GetKeyConv2Str(srcKey) 109 if err != nil { 110 l.Debug(err) 111 return nil 112 } 113 114 deleteAfterExtract := false 115 if funcExpr.Param[4] != nil { 116 switch funcExpr.Param[4].NodeType { //nolint:exhaustive 117 case ast.TypeBoolLiteral: 118 deleteAfterExtract = funcExpr.Param[4].BoolLiteral().Val 119 default: 120 return runtime.NewRunError(ctx, fmt.Sprintf("expect BoolLiteral, got %s", 121 funcExpr.Param[3].NodeType), funcExpr.Param[4].StartPos()) 122 } 123 } 124 125 v, dstS, err := GsonGet(cont, jpath, deleteAfterExtract) 126 if err != nil { 127 l.Debug(err) 128 return nil 129 } 130 131 trimSpace := true 132 if funcExpr.Param[3] != nil { 133 switch funcExpr.Param[3].NodeType { //nolint:exhaustive 134 case ast.TypeBoolLiteral: 135 trimSpace = funcExpr.Param[3].BoolLiteral().Val 136 default: 137 return runtime.NewRunError(ctx, fmt.Sprintf("expect BoolLiteral, got %s", 138 funcExpr.Param[3].NodeType), funcExpr.Param[3].StartPos()) 139 } 140 } 141 142 if vStr, ok := v.(string); ok && trimSpace { 143 v = strings.TrimSpace(vStr) 144 } 145 146 var dtype ast.DType 147 switch v.(type) { 148 case bool: 149 dtype = ast.Bool 150 case float64: 151 dtype = ast.Float 152 case string: 153 dtype = ast.String 154 case []any: 155 dtype = ast.List 156 case map[string]any: 157 dtype = ast.Map 158 default: 159 return nil 160 } 161 if ok := addKey2PtWithVal(ctx.InData(), targetKey, v, dtype, ptinput.KindPtDefault); !ok { 162 return nil 163 } 164 165 if deleteAfterExtract { 166 _ = addKey2PtWithVal(ctx.InData(), srcKey, dstS, ast.String, ptinput.KindPtDefault) 167 } 168 169 return nil 170 } 171 172 func GsonGet(s string, node *ast.Node, deleteAfter bool) (any, string, error) { 173 var m any 174 175 err := json.Unmarshal([]byte(s), &m) 176 if err != nil { 177 return "", "", err 178 } 179 180 val, err := jsonGet(m, node, deleteAfter) 181 if err != nil { 182 return "", "", err 183 } 184 185 dst := s 186 if deleteAfter { 187 dstB, err := json.Marshal(m) 188 if err != nil { 189 return "", "", err 190 } 191 dst = string(dstB) 192 } 193 return val, dst, nil 194 } 195 196 func jsonGet(val any, node *ast.Node, deleteAfter bool) (any, error) { 197 switch node.NodeType { //nolint:exhaustive 198 case ast.TypeStringLiteral: 199 return getByIdentifier(val, &ast.Identifier{ 200 Name: node.StringLiteral().Val, 201 }, deleteAfter) 202 case ast.TypeAttrExpr: 203 return getByAttr(val, node.AttrExpr(), deleteAfter) 204 205 case ast.TypeIdentifier: 206 return getByIdentifier(val, node.Identifier(), deleteAfter) 207 208 case ast.TypeIndexExpr: 209 child, err := getByIdentifier(val, node.IndexExpr().Obj, false) 210 if err != nil { 211 return nil, err 212 } 213 return getByIndex(child, node.IndexExpr(), 0, deleteAfter) 214 default: 215 return nil, fmt.Errorf("json unsupport get from %s", node.NodeType) 216 } 217 } 218 219 func getByAttr(val any, i *ast.AttrExpr, deleteAfter bool) (any, error) { 220 if i.Attr != nil { 221 child, err := jsonGet(val, i.Obj, false) 222 if err != nil { 223 return nil, err 224 } 225 return jsonGet(child, i.Attr, deleteAfter) 226 } else { 227 child, err := jsonGet(val, i.Obj, deleteAfter) 228 if err != nil { 229 return nil, err 230 } 231 return child, nil 232 } 233 } 234 235 func getByIdentifier(val any, i *ast.Identifier, deleteAfter bool) (any, error) { 236 if i == nil { 237 return val, nil 238 } 239 240 switch v := val.(type) { 241 case map[string]any: 242 if child, ok := v[i.Name]; !ok { 243 return nil, fmt.Errorf("%v not found", i.Name) 244 } else { 245 if deleteAfter { 246 delete(v, i.Name) 247 } 248 return child, nil 249 } 250 default: 251 return nil, fmt.Errorf("%v unsupport identifier get", reflect.TypeOf(v)) 252 } 253 } 254 255 func getByIndex(val any, i *ast.IndexExpr, dimension int, deleteAfter bool) (any, error) { 256 switch v := val.(type) { 257 case []any: 258 if dimension >= len(i.Index) { 259 return nil, fmt.Errorf("dimension exceed") 260 } 261 262 var index int 263 264 switch i.Index[dimension].NodeType { //nolint:exhaustive 265 case ast.TypeIntegerLiteral: 266 index = int(i.Index[dimension].IntegerLiteral().Val) 267 case ast.TypeFloatLiteral: 268 index = int(i.Index[dimension].FloatLiteral().Val) 269 270 default: 271 return nil, fmt.Errorf("index value is not int") 272 } 273 274 if index < 0 { 275 index = len(v) + index 276 } 277 278 if index < 0 || index >= len(v) { 279 return nil, fmt.Errorf("index out of range") 280 } 281 282 child := v[index] 283 if dimension == len(i.Index)-1 { 284 return child, nil 285 } else { 286 return getByIndex(child, i, dimension+1, deleteAfter) 287 } 288 default: 289 return nil, fmt.Errorf("%v unsupport index get", reflect.TypeOf(v)) 290 } 291 } 292 293 func lastIsIndex(expr *ast.Node) (bool, error) { 294 switch expr.NodeType { //nolint:exhaustive 295 case ast.TypeAttrExpr: 296 return lastIsIndex(expr.AttrExpr().Attr) 297 case ast.TypeIdentifier: 298 return false, nil 299 case ast.TypeIndexExpr: 300 return true, nil 301 default: 302 return false, fmt.Errorf("expect AttrExpr, IndexExpr or Identifier, got %s", 303 expr.NodeType) 304 } 305 }