• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

davidhoo / jsonpath / 25475134996

07 May 2026 03:53AM UTC coverage: 79.756% (-0.7%) from 80.502%
25475134996

push

github

davidhoo
fix: remove unused functions (hasStartAnchor, hasEndAnchor, nodeListEqualWithLocation)

273 of 371 new or added lines in 4 files covered. (73.58%)

13 existing lines in 1 file now uncovered.

2939 of 3685 relevant lines covered (79.76%)

653.91 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.83
/parser.go
1
package jsonpath
2

3
import (
4
        "fmt"
5
        "regexp"
6
        "strconv"
7
        "strings"
8
)
9

10
// 解析 JSONPath 表达式
11
func parse(path string) ([]segment, error) {
5,910✔
12
        // 处理空路径
5,910✔
13
        if path == "" {
5,910✔
14
                return nil, nil
×
15
        }
×
16

17
        // 检查是否是函数调用格式: functionName(arg1, arg2, ...)
18
        // 这是 RFC 9535 的 match() 和 search() 函数语法
19
        if idx := strings.Index(path, "("); idx > 0 && strings.HasSuffix(path, ")") {
6,026✔
20
                funcName := path[:idx]
116✔
21
                // 验证函数名是有效的标识符
116✔
22
                if isValidFunctionName(funcName) {
148✔
23
                        argsStr := path[idx+1 : len(path)-1]
32✔
24
                        return parseTopLevelFunctionCall(funcName, argsStr)
32✔
25
                }
32✔
26
        }
27

28
        // 检查并移除 $ 前缀
29
        if !strings.HasPrefix(path, "$") {
5,886✔
30
                return nil, NewError(ErrSyntax, "path must start with $", path)
8✔
31
        }
8✔
32
        path = strings.TrimPrefix(path, "$")
5,870✔
33

5,870✔
34
        // 如果路径只有 $,返回空段列表
5,870✔
35
        if path == "" {
5,878✔
36
                return nil, nil
8✔
37
        }
8✔
38

39
        // 移除前导点
40
        path = strings.TrimPrefix(path, ".")
5,862✔
41

5,862✔
42
        // 处理递归下降
5,862✔
43
        if strings.HasPrefix(path, ".") {
6,020✔
44
                return parseRecursive(path[1:])
158✔
45
        }
158✔
46

47
        // 处理常规路径
48
        return parseRegular(path)
5,704✔
49
}
50

51
// isValidFunctionName 检查是否是有效的函数名
52
func isValidFunctionName(name string) bool {
676✔
53
        if name == "" {
676✔
54
                return false
×
55
        }
×
56
        for i, r := range name {
3,612✔
57
                if i == 0 {
3,612✔
58
                        if !((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || r == '_') {
862✔
59
                                return false
186✔
60
                        }
186✔
61
                } else {
2,260✔
62
                        if !((r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '_') {
2,260✔
63
                                return false
×
64
                        }
×
65
                }
66
        }
67
        return true
490✔
68
}
69

70
// parseTopLevelFunctionCall 解析顶层函数调用
71
func parseTopLevelFunctionCall(funcName, argsStr string) ([]segment, error) {
32✔
72
        // 解析参数
32✔
73
        args, err := parseFunctionArgsList(argsStr)
32✔
74
        if err != nil {
32✔
75
                return nil, err
×
76
        }
×
77

78
        // 创建函数段
79
        return []segment{&functionSegment{name: funcName, args: args}}, nil
32✔
80
}
81

82
// parseFunctionArgsList 解析函数参数列表
83
func parseFunctionArgsList(argsStr string) ([]interface{}, error) {
490✔
84
        if strings.TrimSpace(argsStr) == "" {
490✔
85
                return nil, nil
×
86
        }
×
87

88
        var args []interface{}
490✔
89
        var currentArg strings.Builder
490✔
90
        var inQuote bool
490✔
91
        var quoteChar rune
490✔
92
        depth := 0
490✔
93

490✔
94
        for i := 0; i < len(argsStr); i++ {
5,848✔
95
                ch := rune(argsStr[i])
5,358✔
96

5,358✔
97
                switch {
5,358✔
98
                case (ch == '\'' || ch == '"') && !inQuote:
362✔
99
                        // 开始引号
362✔
100
                        inQuote = true
362✔
101
                        quoteChar = ch
362✔
102
                        // 不将引号写入 currentArg
103
                case ch == quoteChar && inQuote:
362✔
104
                        // 结束引号
362✔
105
                        inQuote = false
362✔
106
                        quoteChar = 0
362✔
107
                        // 不将引号写入 currentArg
108
                case ch == '\\' && inQuote && i+1 < len(argsStr):
86✔
109
                        // 处理转义字符
86✔
110
                        nextCh := rune(argsStr[i+1])
86✔
111
                        if nextCh == quoteChar || nextCh == '\\' {
172✔
112
                                // 转义的引号或反斜杠
86✔
113
                                currentArg.WriteRune(nextCh)
86✔
114
                                i++ // 跳过下一个字符
86✔
115
                        } else {
86✔
116
                                // 其他转义序列,保持原样
×
117
                                currentArg.WriteRune(ch)
×
118
                        }
×
119
                case ch == '(' && !inQuote:
72✔
120
                        depth++
72✔
121
                        currentArg.WriteRune(ch)
72✔
122
                case ch == ')' && !inQuote:
72✔
123
                        depth--
72✔
124
                        currentArg.WriteRune(ch)
72✔
125
                case ch == ',' && !inQuote && depth == 0:
412✔
126
                        arg := strings.TrimSpace(currentArg.String())
412✔
127
                        if arg != "" {
824✔
128
                                parsedArg, err := parseSingleFunctionArg(arg)
412✔
129
                                if err != nil {
412✔
130
                                        return nil, err
×
131
                                }
×
132
                                args = append(args, parsedArg)
412✔
133
                        }
134
                        currentArg.Reset()
412✔
135
                default:
3,992✔
136
                        currentArg.WriteRune(ch)
3,992✔
137
                }
138
        }
139

140
        // 处理最后一个参数
141
        arg := strings.TrimSpace(currentArg.String())
490✔
142
        if arg != "" {
980✔
143
                parsedArg, err := parseSingleFunctionArg(arg)
490✔
144
                if err != nil {
490✔
145
                        return nil, err
×
146
                }
×
147
                args = append(args, parsedArg)
490✔
148
        }
149

150
        return args, nil
490✔
151
}
152

153
// parseSingleFunctionArg 解析单个函数参数
154
func parseSingleFunctionArg(arg string) (interface{}, error) {
902✔
155
        arg = strings.TrimSpace(arg)
902✔
156

902✔
157
        // 尝试解析为数字
902✔
158
        if num, err := strconv.ParseFloat(arg, 64); err == nil {
938✔
159
                return num, nil
36✔
160
        }
36✔
161

162
        // 处理布尔值
163
        if arg == "true" {
866✔
164
                return true, nil
×
165
        }
×
166
        if arg == "false" {
866✔
167
                return false, nil
×
168
        }
×
169

170
        // 处理 null
171
        if arg == "null" {
866✔
172
                return nil, nil
×
173
        }
×
174

175
        // 如果以 $ 开头,它是一个路径引用
176
        if strings.HasPrefix(arg, "$") {
914✔
177
                return arg, nil
48✔
178
        }
48✔
179

180
        // 处理 @ 引用(在过滤器上下文中)
181
        if strings.HasPrefix(arg, "@") {
1,276✔
182
                return arg, nil
458✔
183
        }
458✔
184

185
        // 其他情况都作为字符串处理(包括正则表达式模式)
186
        return arg, nil
360✔
187
}
188

189
// 解析递归下降路径
190
func parseRecursive(path string) ([]segment, error) {
172✔
191
        var segments []segment
172✔
192
        segments = append(segments, &recursiveSegment{})
172✔
193

172✔
194
        // 如果路径为空,直接返回
172✔
195
        if path == "" {
182✔
196
                return segments, nil
10✔
197
        }
10✔
198

199
        // 移除前导点
200
        path = strings.TrimPrefix(path, ".")
162✔
201

162✔
202
        // 如果还有路径,继续解析
162✔
203
        if path != "" {
324✔
204
                remainingSegments, err := parseRegular(path)
162✔
205
                if err != nil {
164✔
206
                        return nil, err
2✔
207
                }
2✔
208
                segments = append(segments, remainingSegments...)
160✔
209
        }
210

211
        return segments, nil
160✔
212
}
213

214
// 解析常规路径
215
func parseRegular(path string) ([]segment, error) {
5,866✔
216
        var segments []segment
5,866✔
217
        var current string
5,866✔
218
        var inBracket bool
5,866✔
219
        var bracketContent string
5,866✔
220
        var bracketDepth int
5,866✔
221

5,866✔
222
        // Use rune iteration to properly handle multi-byte UTF-8 characters
5,866✔
223
        for _, r := range path {
78,094✔
224
                switch {
72,228✔
225
                case r == '[':
5,992✔
226
                        if inBracket {
6,440✔
227
                                // Inside bracket, nested brackets are allowed for filter expressions
448✔
228
                                // (e.g., $[?@.list[0]])
448✔
229
                                bracketDepth++
448✔
230
                                bracketContent += string(r)
448✔
231
                        } else {
5,992✔
232
                                if current != "" {
5,718✔
233
                                        seg, err := createDotSegment(current)
174✔
234
                                        if err != nil {
174✔
NEW
235
                                                return nil, err
×
NEW
236
                                        }
×
237
                                        segments = append(segments, seg)
174✔
238
                                        current = ""
174✔
239
                                }
240
                                inBracket = true
5,544✔
241
                                bracketDepth = 0
5,544✔
242
                        }
243

244
                case r == ']':
5,976✔
245
                        if !inBracket {
5,976✔
246
                                return nil, NewError(ErrSyntax, "unexpected closing bracket", path)
×
247
                        }
×
248
                        if bracketDepth > 0 {
6,424✔
249
                                // Closing a nested bracket inside the filter
448✔
250
                                bracketDepth--
448✔
251
                                bracketContent += string(r)
448✔
252
                        } else {
5,976✔
253
                                // Closing the outer bracket
5,528✔
254
                                seg, err := parseBracketSegment(bracketContent)
5,528✔
255
                                if err != nil {
6,728✔
256
                                        return nil, err
1,200✔
257
                                }
1,200✔
258
                                segments = append(segments, seg)
4,328✔
259
                                bracketContent = ""
4,328✔
260
                                inBracket = false
4,328✔
261
                        }
262

263
                case r == '.' && !inBracket:
180✔
264
                        if current != "" {
350✔
265
                                seg, err := createDotSegment(current)
170✔
266
                                if err != nil {
170✔
267
                                        return nil, err
×
268
                                }
×
269
                                segments = append(segments, seg)
170✔
270
                                current = ""
170✔
271
                        }
272

273
                default:
60,080✔
274
                        if inBracket {
117,812✔
275
                                bracketContent += string(r)
57,732✔
276
                        } else {
60,080✔
277
                                current += string(r)
2,348✔
278
                        }
2,348✔
279
                }
280
        }
281

282
        // 处理最后一个段
283
        if inBracket {
4,682✔
284
                return nil, NewError(ErrSyntax, "unclosed bracket", path)
16✔
285
        }
16✔
286
        if current != "" {
5,058✔
287
                seg, err := createDotSegment(current)
408✔
288
                if err != nil {
408✔
289
                        return nil, err
×
290
                }
×
291
                segments = append(segments, seg)
408✔
292
        }
293

294
        return segments, nil
4,650✔
295
}
296

297
// 创建点表示法段
298
func createDotSegment(name string) (segment, error) {
752✔
299
        if name == "*" {
820✔
300
                return &wildcardSegment{}, nil
68✔
301
        }
68✔
302
        return &nameSegment{name: name}, nil
684✔
303
}
304

305
// 解析方括号段
306
func parseBracketSegment(content string) (segment, error) {
5,528✔
307
        // RFC 9535: whitespace is allowed around selectors in brackets
5,528✔
308
        content = strings.TrimSpace(content)
5,528✔
309

5,528✔
310
        // 处理通配符
5,528✔
311
        if content == "*" {
5,568✔
312
                return &wildcardSegment{}, nil
40✔
313
        }
40✔
314

315
        // 处理过滤器表达式
316
        if strings.HasPrefix(content, "?") {
8,620✔
317
                return parseFilterSegment(content[1:])
3,132✔
318
        }
3,132✔
319

320
        // 处理多索引选择或多字段选择
321
        if strings.Contains(content, ",") ||
2,356✔
322
                ((strings.HasPrefix(content, "'") && strings.HasSuffix(content, "'")) && strings.Contains(content[1:len(content)-1], "','")) ||
2,356✔
323
                ((strings.HasPrefix(content, "\"") && strings.HasSuffix(content, "\"")) && strings.Contains(content[1:len(content)-1], "\",\"")) {
2,552✔
324
                return parseMultiIndexSegment(content)
196✔
325
        }
196✔
326

327
        // 处理切片表达式
328
        if strings.Contains(content, ":") {
2,880✔
329
                return parseSliceSegment(content)
720✔
330
        }
720✔
331

332
        // 处理索引或名称
333
        return parseIndexOrName(content)
1,440✔
334
}
335

336
// 标准化过滤器表达式
337
func normalizeFilterExpression(expr string) string {
2,188✔
338
        expr = strings.TrimSpace(expr)
2,188✔
339
        return expr
2,188✔
340
}
2,188✔
341

342
// expressionParser is a recursive descent parser for filter expressions
343
type expressionParser struct {
344
        input string
345
        pos   int
346
}
347

348
// parseFilterExpression parses a filter expression string into an expression tree
349
func parseFilterExpression(input string) (exprNode, error) {
2,200✔
350
        p := &expressionParser{input: input, pos: 0}
2,200✔
351
        node, err := p.parseOr()
2,200✔
352
        if err != nil {
2,574✔
353
                return nil, err
374✔
354
        }
374✔
355
        p.skipSpaces()
1,826✔
356
        if p.pos < len(p.input) {
1,826✔
357
                return nil, NewError(ErrInvalidFilter, fmt.Sprintf("unexpected character at position %d: %c", p.pos, p.input[p.pos]), input)
×
358
        }
×
359
        return node, nil
1,826✔
360
}
361

362
func (p *expressionParser) skipSpaces() {
11,324✔
363
        for p.pos < len(p.input) && p.input[p.pos] == ' ' {
11,580✔
364
                p.pos++
256✔
365
        }
256✔
366
}
367

368
func (p *expressionParser) parseOr() (exprNode, error) {
2,220✔
369
        left, err := p.parseAnd()
2,220✔
370
        if err != nil {
2,594✔
371
                return nil, err
374✔
372
        }
374✔
373

374
        children := []exprNode{left}
1,846✔
375
        for {
3,880✔
376
                p.skipSpaces()
2,034✔
377
                if p.pos+1 < len(p.input) && p.input[p.pos:p.pos+2] == "||" {
2,222✔
378
                        p.pos += 2
188✔
379
                        right, err := p.parseAnd()
188✔
380
                        if err != nil {
188✔
381
                                return nil, err
×
382
                        }
×
383
                        children = append(children, right)
188✔
384
                } else {
1,846✔
385
                        break
1,846✔
386
                }
387
        }
388

389
        if len(children) == 1 {
3,546✔
390
                return children[0], nil
1,700✔
391
        }
1,700✔
392
        return &orNode{children: children}, nil
146✔
393
}
394

395
func (p *expressionParser) parseAnd() (exprNode, error) {
2,408✔
396
        left, err := p.parseUnary()
2,408✔
397
        if err != nil {
2,782✔
398
                return nil, err
374✔
399
        }
374✔
400

401
        children := []exprNode{left}
2,034✔
402
        for {
4,266✔
403
                p.skipSpaces()
2,232✔
404
                if p.pos+1 < len(p.input) && p.input[p.pos:p.pos+2] == "&&" {
2,430✔
405
                        p.pos += 2
198✔
406
                        right, err := p.parseUnary()
198✔
407
                        if err != nil {
198✔
408
                                return nil, err
×
409
                        }
×
410
                        children = append(children, right)
198✔
411
                } else {
2,034✔
412
                        break
2,034✔
413
                }
414
        }
415

416
        if len(children) == 1 {
3,912✔
417
                return children[0], nil
1,878✔
418
        }
1,878✔
419
        return &andNode{children: children}, nil
156✔
420
}
421

422
func (p *expressionParser) parseUnary() (exprNode, error) {
2,606✔
423
        p.skipSpaces()
2,606✔
424
        if p.pos < len(p.input) && p.input[p.pos] == '!' {
2,734✔
425
                p.pos++
128✔
426
                inner, err := p.parsePrimary()
128✔
427
                if err != nil {
152✔
428
                        return nil, err
24✔
429
                }
24✔
430
                return negateNode(inner)
104✔
431
        }
432
        return p.parsePrimary()
2,478✔
433
}
434

435
func (p *expressionParser) parsePrimary() (exprNode, error) {
2,606✔
436
        p.skipSpaces()
2,606✔
437

2,606✔
438
        if p.pos >= len(p.input) {
2,606✔
439
                return nil, NewError(ErrInvalidFilter, "unexpected end of expression", p.input)
×
440
        }
×
441

442
        // Handle parenthesized expression
443
        if p.input[p.pos] == '(' {
2,626✔
444
                p.pos++ // skip '('
20✔
445
                node, err := p.parseOr()
20✔
446
                if err != nil {
20✔
447
                        return nil, err
×
448
                }
×
449
                p.skipSpaces()
20✔
450
                if p.pos >= len(p.input) || p.input[p.pos] != ')' {
20✔
451
                        return nil, NewError(ErrInvalidFilter, "missing closing parenthesis", p.input)
×
452
                }
×
453
                p.pos++ // skip ')'
20✔
454
                return node, nil
20✔
455
        }
456

457
        // Parse atomic condition (everything until next &&, ||, or unmatched ))
458
        start := p.pos
2,586✔
459
        depth := 0
2,586✔
460
        inQuotes := false
2,586✔
461
        inSingleQuotes := false
2,586✔
462

2,586✔
463
        for p.pos < len(p.input) {
22,300✔
464
                ch := p.input[p.pos]
19,714✔
465

19,714✔
466
                if ch == '"' && !inSingleQuotes {
20,006✔
467
                        inQuotes = !inQuotes
292✔
468
                        p.pos++
292✔
469
                        continue
292✔
470
                }
471
                if ch == '\'' && !inQuotes {
20,198✔
472
                        inSingleQuotes = !inSingleQuotes
776✔
473
                        p.pos++
776✔
474
                        continue
776✔
475
                }
476

477
                if inQuotes || inSingleQuotes {
19,842✔
478
                        p.pos++
1,196✔
479
                        continue
1,196✔
480
                }
481

482
                if ch == '(' {
17,514✔
483
                        depth++
64✔
484
                        p.pos++
64✔
485
                        continue
64✔
486
                }
487
                if ch == ')' {
17,470✔
488
                        if depth == 0 {
104✔
489
                                break
20✔
490
                        }
491
                        depth--
64✔
492
                        p.pos++
64✔
493
                        continue
64✔
494
                }
495

496
                // Check for top-level && or ||
497
                if depth == 0 && p.pos+1 < len(p.input) {
32,454✔
498
                        op := p.input[p.pos : p.pos+2]
15,152✔
499
                        if op == "&&" || op == "||" {
15,536✔
500
                                break
384✔
501
                        }
502
                }
503

504
                p.pos++
16,918✔
505
        }
506

507
        condStr := strings.TrimSpace(p.input[start:p.pos])
2,586✔
508
        if condStr == "" {
2,586✔
509
                return nil, NewError(ErrInvalidFilter, "empty condition", p.input)
×
510
        }
×
511

512
        cond, err := parseFilterCondition(condStr)
2,586✔
513
        if err != nil {
2,928✔
514
                return nil, err
342✔
515
        }
342✔
516
        return &conditionNode{cond: cond}, nil
2,244✔
517
}
518

519
// negateNode applies negation to an expression node
520
func negateNode(node exprNode) (exprNode, error) {
120✔
521
        switch n := node.(type) {
120✔
522
        case *conditionNode:
118✔
523
                newCond := n.cond
118✔
524
                switch newCond.operator {
118✔
525
                case "==":
22✔
526
                        newCond.operator = "!="
22✔
527
                case "!=":
×
528
                        newCond.operator = "=="
×
529
                case "<":
×
530
                        newCond.operator = ">="
×
531
                case "<=":
×
532
                        newCond.operator = ">"
×
533
                case ">":
2✔
534
                        newCond.operator = "<="
2✔
535
                case ">=":
×
536
                        newCond.operator = "<"
×
537
                case "exists":
62✔
538
                        newCond.operator = "not_exists"
62✔
539
                case "not_exists":
×
540
                        newCond.operator = "exists"
×
541
                default:
32✔
542
                        return nil, NewError(ErrInvalidFilter, fmt.Sprintf("cannot negate operator: %s", newCond.operator), "")
32✔
543
                }
544
                return &conditionNode{cond: newCond}, nil
86✔
545
        case *andNode:
×
546
                children := make([]exprNode, len(n.children))
×
547
                for i, child := range n.children {
×
548
                        negated, err := negateNode(child)
×
549
                        if err != nil {
×
550
                                return nil, err
×
551
                        }
×
552
                        children[i] = negated
×
553
                }
554
                return &orNode{children: children}, nil
×
555
        case *orNode:
2✔
556
                children := make([]exprNode, len(n.children))
2✔
557
                for i, child := range n.children {
6✔
558
                        negated, err := negateNode(child)
4✔
559
                        if err != nil {
4✔
560
                                return nil, err
×
561
                        }
×
562
                        children[i] = negated
4✔
563
                }
564
                return &andNode{children: children}, nil
2✔
565
        default:
×
566
                return nil, NewError(ErrInvalidFilter, "cannot negate expression", "")
×
567
        }
568
}
569

570
// 解析过滤器表达式
571
func parseFilterSegment(content string) (segment, error) {
3,132✔
572
        // RFC 9535: allow whitespace in filter expressions
3,132✔
573
        content = strings.TrimSpace(content)
3,132✔
574

3,132✔
575
        // 检查是否是函数调用格式: functionName(arg1, arg2)
3,132✔
576
        // 这是 RFC 9535 的 match() 和 search() 函数语法
3,132✔
577
        if idx := strings.Index(content, "("); idx > 0 && strings.HasSuffix(content, ")") {
3,652✔
578
                funcName := content[:idx]
520✔
579
                if isValidFunctionName(funcName) {
946✔
580
                        // 这是一个函数调用,解析为过滤器表达式
426✔
581
                        argsStr := content[idx+1 : len(content)-1]
426✔
582
                        cond, err := parseFilterFunctionCall(funcName, argsStr)
426✔
583
                        if err != nil {
474✔
584
                                return nil, NewError(ErrInvalidFilter, fmt.Sprintf("invalid filter syntax: %s", content), content)
48✔
585
                        }
48✔
586
                        return &filterSegment{expr: &conditionNode{cond: cond}}, nil
378✔
587
                }
588
        }
589

590
        // 检查语法 - 支持 @, $, 和函数调用作为过滤器表达式的开头
591
        trimmed := strings.TrimSpace(content)
2,706✔
592
        if !strings.HasPrefix(trimmed, "@") && !strings.HasPrefix(trimmed, "$") &&
2,706✔
593
                !strings.HasPrefix(trimmed, "(@") && !strings.HasPrefix(trimmed, "($") &&
2,706✔
594
                !strings.HasPrefix(trimmed, "!") && !strings.HasPrefix(trimmed, "(!") &&
2,706✔
595
                !strings.HasPrefix(trimmed, "(") {
3,204✔
596
                return nil, NewError(ErrInvalidFilter, fmt.Sprintf("invalid filter syntax: %s", content), content)
498✔
597
        }
498✔
598

599
        // 取过滤器内容
600
        var filterContent string
2,208✔
601

2,208✔
602
        switch {
2,208✔
603
        case strings.HasPrefix(content, "(!"):
×
604
                if !strings.HasSuffix(content, ")") {
×
605
                        return nil, NewError(ErrInvalidFilter, "invalid filter syntax: missing closing parenthesis", content)
×
606
                }
×
607
                filterContent = content[2 : len(content)-1]
×
608
                // Apply De Morgan's laws: !(A && B) => !A || !B, !(A || B) => !A && !B
×
609
                expr, err := parseFilterExpression(filterContent)
×
610
                if err != nil {
×
611
                        return nil, NewError(ErrInvalidFilter, fmt.Sprintf("error parsing filter expression: %v", err), content)
×
612
                }
×
613
                negated, err := negateNode(expr)
×
614
                if err != nil {
×
615
                        return nil, NewError(ErrInvalidFilter, fmt.Sprintf("error negating expression: %v", err), content)
×
616
                }
×
617
                return &filterSegment{expr: negated}, nil
×
618
        case strings.HasPrefix(content, "!@"):
32✔
619
                // Keep the ! in the content for the parser to handle as unary operator
32✔
620
                filterContent = content
32✔
621
        case strings.HasPrefix(content, "(@"):
212✔
622
                if !strings.HasSuffix(content, ")") {
220✔
623
                        return nil, NewError(ErrInvalidFilter, "invalid filter syntax: missing closing parenthesis", content)
8✔
624
                }
8✔
625
                filterContent = content[2 : len(content)-1]
204✔
626
        case strings.HasPrefix(content, "($"):
120✔
627
                if !strings.HasSuffix(content, ")") {
120✔
NEW
628
                        return nil, NewError(ErrInvalidFilter, "invalid filter syntax: missing closing parenthesis", content)
×
NEW
629
                }
×
630
                filterContent = content[2 : len(content)-1]
120✔
631
        case strings.HasPrefix(content, "@"):
1,710✔
632
                filterContent = content
1,710✔
633
        case strings.HasPrefix(content, "$"):
24✔
634
                filterContent = content
24✔
635
        case strings.HasPrefix(content, "!"):
108✔
636
                // Keep the ! in the content for the parser to handle as unary operator
108✔
637
                filterContent = content
108✔
638
                // Check for !(expr) pattern
108✔
639
                if len(content) > 1 && content[1] == '(' {
120✔
640
                        if !strings.HasSuffix(content, ")") {
12✔
641
                                return nil, NewError(ErrInvalidFilter, "invalid filter syntax: missing closing parenthesis", content)
×
642
                        }
×
643
                        // Apply De Morgan's laws for !(expr)
644
                        innerContent := content[2 : len(content)-1]
12✔
645
                        expr, err := parseFilterExpression(innerContent)
12✔
646
                        if err != nil {
12✔
647
                                return nil, NewError(ErrInvalidFilter, fmt.Sprintf("error parsing filter expression: %v", err), content)
×
648
                        }
×
649
                        negated, err := negateNode(expr)
12✔
650
                        if err != nil {
12✔
651
                                return nil, NewError(ErrInvalidFilter, fmt.Sprintf("error negating expression: %v", err), content)
×
652
                        }
×
653
                        return &filterSegment{expr: negated}, nil
12✔
654
                }
655
        case strings.HasPrefix(content, "("):
2✔
656
                if !strings.HasSuffix(content, ")") {
2✔
657
                        return nil, NewError(ErrInvalidFilter, "invalid filter syntax: missing closing parenthesis", content)
×
658
                }
×
659
                filterContent = content[1 : len(content)-1]
2✔
660
        default:
×
661
                filterContent = content
×
662
        }
663

664
        // 标准化表达式
665
        filterContent = normalizeFilterExpression(filterContent)
2,188✔
666

2,188✔
667
        // 解析表达式为树结构
2,188✔
668
        expr, err := parseFilterExpression(filterContent)
2,188✔
669
        if err != nil {
2,562✔
670
                return nil, NewError(ErrInvalidFilter, fmt.Sprintf("error parsing filter expression: %v", err), content)
374✔
671
        }
374✔
672

673
        return &filterSegment{expr: expr}, nil
1,814✔
674
}
675

676
// 解析过滤器条件
677
func parseFilterCondition(content string) (filterCondition, error) {
2,586✔
678
        // 检查是否是函数调用格式: functionName(arg1, arg2)
2,586✔
679
        // 这是 RFC 9535 的 match() 和 search() 函数语法
2,586✔
680
        if idx := strings.Index(content, "("); idx > 0 && strings.HasSuffix(content, ")") {
2,626✔
681
                funcName := content[:idx]
40✔
682
                if isValidFunctionName(funcName) {
72✔
683
                        argsStr := content[idx+1 : len(content)-1]
32✔
684
                        return parseFilterFunctionCall(funcName, argsStr)
32✔
685
                }
32✔
686
        }
687

688
        // 确保条件以 @ 或 $ 开头
689
        isRoot := false
2,554✔
690
        if strings.HasPrefix(content, "$") {
2,578✔
691
                isRoot = true
24✔
692
        } else if !strings.HasPrefix(content, "@") {
2,902✔
693
                if strings.HasPrefix(content, ".") {
480✔
694
                        content = "@" + content
132✔
695
                } else {
348✔
696
                        return filterCondition{}, NewError(ErrInvalidFilter, fmt.Sprintf("invalid condition: %s", content), content)
216✔
697
                }
216✔
698
        }
699

700
        // 检查是否是旧式方法调用: @.field.match(pattern)
701
        if strings.Contains(content, ".match(") {
2,338✔
702
                parts := strings.Split(content, ".match(")
×
703
                if len(parts) != 2 || !strings.HasSuffix(parts[1], ")") {
×
704
                        return filterCondition{}, NewError(ErrInvalidFilter, "invalid match function syntax", content)
×
705
                }
×
706

707
                field := strings.TrimSpace(parts[0])
×
708
                pattern := strings.TrimSpace(parts[1][:len(parts[1])-1])
×
709

×
710
                // 验证字段格式
×
NEW
711
                if !strings.HasPrefix(field, "@") && !strings.HasPrefix(field, "$") {
×
NEW
712
                        return filterCondition{}, NewError(ErrInvalidFilter, "filter condition must start with @ or $", content)
×
UNCOV
713
                }
×
714

715
                // 移除引号
716
                pattern = strings.Trim(pattern, "\"'")
×
717

×
NEW
718
                fieldIsRoot := strings.HasPrefix(field, "$")
×
719
                return filterCondition{
×
NEW
720
                        field:    strings.TrimPrefix(strings.TrimPrefix(field, "@."), "$."),
×
721
                        operator: "match",
×
722
                        value:    pattern,
×
NEW
723
                        isRoot:   fieldIsRoot,
×
UNCOV
724
                }, nil
×
725
        }
726

727
        // 查找比较操作符
728
        var operator string
2,338✔
729
        var operatorIndex int
2,338✔
730
        var operatorFound bool
2,338✔
731

2,338✔
732
        // 按长度排序的操作符列表,确保先匹配较长的操作符
2,338✔
733
        operators := []string{"<=", ">=", "==", "!=", "<", ">"}
2,338✔
734
        for _, op := range operators {
12,470✔
735
                idx := strings.Index(content, op)
10,132✔
736
                if idx != -1 {
11,618✔
737
                        // 确保这是一个独立的操作符,不是符串值的一部分
1,486✔
738
                        inQuotes := false
1,486✔
739
                        inParens := 0
1,486✔
740
                        isValid := true
1,486✔
741
                        for i := 0; i < idx; i++ {
6,474✔
742
                                switch content[i] {
4,988✔
743
                                case '"':
×
744
                                        inQuotes = !inQuotes
×
745
                                case '(':
×
746
                                        inParens++
×
747
                                case ')':
×
748
                                        inParens--
×
749
                                }
750
                        }
751
                        if inQuotes || inParens > 0 {
1,486✔
752
                                isValid = false
×
753
                        }
×
754
                        if isValid {
2,972✔
755
                                operator = op
1,486✔
756
                                operatorIndex = idx
1,486✔
757
                                operatorFound = true
1,486✔
758
                                break
1,486✔
759
                        }
760
                }
761
        }
762

763
        if !operatorFound {
3,190✔
764
                // No operator found - validate that this is a valid field path
852✔
765
                field := strings.TrimSpace(content)
852✔
766
                // Check for invalid operator-like characters
852✔
767
                if strings.ContainsAny(field, "=<>!") {
854✔
768
                        return filterCondition{}, NewError(ErrInvalidFilter, fmt.Sprintf("no valid operator found in condition: %s", content), content)
2✔
769
                }
2✔
770
                // Strip field prefix (@ or $)
771
                field = strings.TrimPrefix(field, "@.")
850✔
772
                field = strings.TrimPrefix(field, "$.")
850✔
773
                field = strings.TrimPrefix(field, "@")
850✔
774
                field = strings.TrimPrefix(field, "$")
850✔
775
                return filterCondition{
850✔
776
                        field:    field,
850✔
777
                        operator: "exists",
850✔
778
                        value:    nil,
850✔
779
                        isRoot:   isRoot,
850✔
780
                }, nil
850✔
781
        }
782

783
        // 分割路径和值
784
        field := strings.TrimSpace(content[:operatorIndex])
1,486✔
785
        value := strings.TrimSpace(content[operatorIndex+len(operator):])
1,486✔
786

1,486✔
787
        // 解析值
1,486✔
788
        parsedValue, err := parseFilterValue(value)
1,486✔
789
        if err != nil {
1,610✔
790
                return filterCondition{}, NewError(ErrInvalidFilter, fmt.Sprintf("invalid value: %s", value), content)
124✔
791
        }
124✔
792

793
        // Strip field prefix (@ or $)
794
        field = strings.TrimPrefix(field, "@.")
1,362✔
795
        field = strings.TrimPrefix(field, "$.")
1,362✔
796
        field = strings.TrimPrefix(field, "@")
1,362✔
797
        field = strings.TrimPrefix(field, "$")
1,362✔
798

1,362✔
799
        return filterCondition{
1,362✔
800
                field:    field,
1,362✔
801
                operator: operator,
1,362✔
802
                value:    parsedValue,
1,362✔
803
                isRoot:   isRoot,
1,362✔
804
        }, nil
1,362✔
805
}
806

807
// parseFilterFunctionCall 解析过滤器中的函数调用
808
func parseFilterFunctionCall(funcName, argsStr string) (filterCondition, error) {
458✔
809
        // 解析参数
458✔
810
        args, err := parseFunctionArgsList(argsStr)
458✔
811
        if err != nil {
458✔
812
                return filterCondition{}, NewError(ErrInvalidFilter, fmt.Sprintf("invalid function arguments: %v", err), funcName+"("+argsStr+")")
×
813
        }
×
814

815
        // 对于 match 和 search 函数,需要两个参数
816
        if funcName == "match" || funcName == "search" {
844✔
817
                if len(args) != 2 {
402✔
818
                        return filterCondition{}, NewError(ErrInvalidFilter, fmt.Sprintf("%s() requires exactly 2 arguments", funcName), funcName+"("+argsStr+")")
16✔
819
                }
16✔
820

821
                // 第一个参数是字段路径
822
                field, ok := args[0].(string)
370✔
823
                if !ok {
386✔
824
                        return filterCondition{}, NewError(ErrInvalidFilter, fmt.Sprintf("%s() first argument must be a string", funcName), funcName+"("+argsStr+")")
16✔
825
                }
16✔
826

827
                // 第二个参数是模式
828
                pattern, ok := args[1].(string)
354✔
829
                if !ok {
370✔
830
                        return filterCondition{}, NewError(ErrInvalidFilter, fmt.Sprintf("%s() second argument must be a string", funcName), funcName+"("+argsStr+")")
16✔
831
                }
16✔
832

833
                return filterCondition{
338✔
834
                        field:    strings.TrimPrefix(field, "@."),
338✔
835
                        operator: funcName,
338✔
836
                        value:    pattern,
338✔
837
                }, nil
338✔
838
        }
839

840
        // 对于其他函数,创建一个通用的函数调用条件
841
        return filterCondition{
72✔
842
                field:    "",
72✔
843
                operator: "function:" + funcName,
72✔
844
                value:    args,
72✔
845
        }, nil
72✔
846
}
847

848
// compareValues compares two values based on the operator
849
func compareValues(value1 interface{}, operator string, value2 interface{}) (bool, error) {
3,000✔
850
        // 检查操作符是否有效
3,000✔
851
        validOperators := map[string]bool{
3,000✔
852
                "==":    true,
3,000✔
853
                "!=":    true,
3,000✔
854
                ">":     true,
3,000✔
855
                "<":     true,
3,000✔
856
                ">=":    true,
3,000✔
857
                "<=":    true,
3,000✔
858
                "match": true,
3,000✔
859
        }
3,000✔
860
        if !validOperators[operator] {
3,050✔
861
                return false, fmt.Errorf("invalid operator: %s", operator)
50✔
862
        }
50✔
863

864
        // 处理 nil 值
865
        if value1 == nil || value2 == nil {
3,076✔
866
                switch operator {
126✔
867
                case "==":
62✔
868
                        return value1 == value2, nil
62✔
869
                case "!=":
32✔
870
                        return value1 != value2, nil
32✔
871
                default:
32✔
872
                        return false, fmt.Errorf("invalid operator for nil values: %s", operator)
32✔
873
                }
874
        }
875

876
        // 处理数字类型
877
        num1, num2, isNum := normalizeNumbers(value1, value2)
2,824✔
878
        if isNum {
4,390✔
879
                switch operator {
1,566✔
880
                case "==":
486✔
881
                        return num1 == num2, nil
486✔
882
                case "!=":
152✔
883
                        return num1 != num2, nil
152✔
884
                case ">":
242✔
885
                        return num1 > num2, nil
242✔
886
                case "<":
238✔
887
                        return num1 < num2, nil
238✔
888
                case ">=":
226✔
889
                        return num1 >= num2, nil
226✔
890
                case "<=":
222✔
891
                        return num1 <= num2, nil
222✔
892
                default:
×
893
                        return false, fmt.Errorf("invalid operator for numbers: %s", operator)
×
894
                }
895
        }
896

897
        // 处理字符串类型
898
        if str1, ok := value1.(string); ok {
2,190✔
899
                if str2, ok := value2.(string); ok {
1,632✔
900
                        switch operator {
700✔
901
                        case "==":
394✔
902
                                return str1 == str2, nil
394✔
903
                        case "!=":
140✔
904
                                return str1 != str2, nil
140✔
905
                        case ">":
54✔
906
                                return str1 > str2, nil
54✔
907
                        case "<":
32✔
908
                                return str1 < str2, nil
32✔
909
                        case ">=":
48✔
910
                                return str1 >= str2, nil
48✔
911
                        case "<=":
32✔
912
                                return str1 <= str2, nil
32✔
913
                        case "match":
×
914
                                re, err := regexp.Compile(str2)
×
915
                                if err != nil {
×
916
                                        return false, fmt.Errorf("invalid regex pattern: %s", str2)
×
917
                                }
×
918
                                return re.MatchString(str1), nil
×
919
                        default:
×
920
                                return false, fmt.Errorf("invalid operator for strings: %s", operator)
×
921
                        }
922
                }
923
                if operator == "match" {
232✔
924
                        return false, fmt.Errorf("pattern must be a string")
×
925
                }
×
926
        }
927
        if operator == "match" {
558✔
928
                return false, fmt.Errorf("value must be a string")
×
929
        }
×
930

931
        // 处理布尔类型
932
        if bool1, ok := value1.(bool); ok {
724✔
933
                if bool2, ok := value2.(bool); ok {
284✔
934
                        switch operator {
118✔
935
                        case "==":
38✔
936
                                return bool1 == bool2, nil
38✔
937
                        case "!=":
16✔
938
                                return bool1 != bool2, nil
16✔
939
                        default:
64✔
940
                                return false, fmt.Errorf("invalid operator for booleans: %s", operator)
64✔
941
                        }
942
                }
943
        }
944

945
        // 处理数组类型 - RFC 9535 支持深度比较
946
        if arr1, ok := value1.([]interface{}); ok {
512✔
947
                if arr2, ok := value2.([]interface{}); ok {
144✔
948
                        switch operator {
72✔
949
                        case "==":
72✔
950
                                return deepCompareValues(arr1, arr2), nil
72✔
NEW
951
                        case "!=":
×
NEW
952
                                return !deepCompareValues(arr1, arr2), nil
×
NEW
953
                        default:
×
NEW
954
                                return false, nil
×
955
                        }
956
                }
957
        }
958

959
        // 处理对象类型 - RFC 9535 支持深度比较
960
        if obj1, ok := value1.(map[string]interface{}); ok {
408✔
961
                if obj2, ok := value2.(map[string]interface{}); ok {
80✔
962
                        switch operator {
40✔
963
                        case "==":
40✔
964
                                return deepCompareValues(obj1, obj2), nil
40✔
NEW
965
                        case "!=":
×
NEW
966
                                return !deepCompareValues(obj1, obj2), nil
×
NEW
967
                        default:
×
NEW
968
                                return false, nil
×
969
                        }
970
                }
971
        }
972

973
        // RFC 9535: comparison between incompatible types
974
        // == returns false, != returns true
975
        if operator == "!=" {
392✔
976
                return true, nil
64✔
977
        }
64✔
978
        return false, nil
264✔
979
}
980

981
// deepCompareValues performs deep comparison of two values
982
func deepCompareValues(a, b interface{}) bool {
552✔
983
        switch v1 := a.(type) {
552✔
984
        case []interface{}:
152✔
985
                v2, ok := b.([]interface{})
152✔
986
                if !ok || len(v1) != len(v2) {
160✔
987
                        return false
8✔
988
                }
8✔
989
                for i := range v1 {
464✔
990
                        if !deepCompareValues(v1[i], v2[i]) {
352✔
991
                                return false
32✔
992
                        }
32✔
993
                }
994
                return true
112✔
995
        case map[string]interface{}:
104✔
996
                v2, ok := b.(map[string]interface{})
104✔
997
                if !ok || len(v1) != len(v2) {
112✔
998
                        return false
8✔
999
                }
8✔
1000
                for k, val1 := range v1 {
216✔
1001
                        val2, exists := v2[k]
120✔
1002
                        if !exists || !deepCompareValues(val1, val2) {
136✔
1003
                                return false
16✔
1004
                        }
16✔
1005
                }
1006
                return true
80✔
1007
        default:
296✔
1008
                return a == b
296✔
1009
        }
1010
}
1011

1012
// normalizeNumbers 将两个值转换为 float64 类型
1013
func normalizeNumbers(value1, value2 interface{}) (float64, float64, bool) {
2,824✔
1014
        var num1, num2 float64
2,824✔
1015
        var ok1, ok2 bool
2,824✔
1016

2,824✔
1017
        // 尝试将 value1 转换为 float64
2,824✔
1018
        switch v := value1.(type) {
2,824✔
1019
        case float64:
1,574✔
1020
                num1, ok1 = v, true
1,574✔
1021
        case int64:
×
1022
                num1, ok1 = float64(v), true
×
1023
        case int:
40✔
1024
                num1, ok1 = float64(v), true
40✔
1025
        }
1026

1027
        // 尝试将 value2 转换为 float64
1028
        switch v := value2.(type) {
2,824✔
1029
        case float64:
1,766✔
1030
                num2, ok2 = v, true
1,766✔
1031
        case int64:
×
1032
                num2, ok2 = float64(v), true
×
1033
        case int:
×
1034
                num2, ok2 = float64(v), true
×
1035
        }
1036

1037
        return num1, num2, ok1 && ok2
2,824✔
1038
}
1039

1040
// compareStrings compares two strings using the specified operator
1041
func compareStrings(a string, operator string, b string) bool {
40✔
1042
        return standardCompareStrings(a, operator, b)
40✔
1043
}
40✔
1044

1045
// getFieldValue 获取对象中指定字段的值
1046
func getFieldValue(obj interface{}, field string) (interface{}, error) {
7,632✔
1047
        // 移除 @ 和前导点
7,632✔
1048
        field = strings.TrimPrefix(field, "@")
7,632✔
1049
        field = strings.TrimPrefix(field, ".")
7,632✔
1050

7,632✔
1051
        // 如果字段为空,返回对象本身
7,632✔
1052
        if field == "" {
9,042✔
1053
                return obj, nil
1,410✔
1054
        }
1,410✔
1055

1056
        // 分割字段路径
1057
        parts := strings.Split(field, ".")
6,222✔
1058
        current := obj
6,222✔
1059

6,222✔
1060
        for _, part := range parts {
12,456✔
1061
                // 确保当前是对象
6,234✔
1062
                m, ok := current.(map[string]interface{})
6,234✔
1063
                if !ok {
6,512✔
1064
                        return nil, fmt.Errorf("value is not an object")
278✔
1065
                }
278✔
1066

1067
                // 获取下一级字段值
1068
                var exists bool
5,956✔
1069
                current, exists = m[part]
5,956✔
1070
                if !exists {
7,054✔
1071
                        return nil, fmt.Errorf("field %s not found", part)
1,098✔
1072
                }
1,098✔
1073
        }
1074

1075
        return current, nil
4,846✔
1076
}
1077

1078
// isValidIdentifier 检查字符串是否是有效的标识符
UNCOV
1079
func isValidIdentifier(s string) bool {
×
UNCOV
1080
        if s == "" {
×
1081
                return false
×
1082
        }
×
1083

1084
        // 检查第一个字符是否是字母或下划线
UNCOV
1085
        first := s[0]
×
UNCOV
1086
        if !((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z') || first == '_') {
×
UNCOV
1087
                return false
×
UNCOV
1088
        }
×
1089

1090
        // 检查其余字符是否是字母、数字或下划线
UNCOV
1091
        for i := 1; i < len(s); i++ {
×
UNCOV
1092
                c := s[i]
×
UNCOV
1093
                if !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_') {
×
1094
                        return false
×
1095
                }
×
1096
        }
1097

UNCOV
1098
        return true
×
1099
}
1100

1101
// 解析多索引选择 - RFC 9535 支持混合选择器类型
1102
func parseMultiIndexSegment(content string) (segment, error) {
224✔
1103
        // 检查前导和尾随逗号
224✔
1104
        if strings.HasPrefix(content, ",") {
234✔
1105
                return nil, NewError(ErrInvalidPath, "leading comma in multi-index segment", content)
10✔
1106
        }
10✔
1107
        if strings.HasSuffix(content, ",") {
224✔
1108
                return nil, NewError(ErrInvalidPath, "trailing comma in multi-index segment", content)
10✔
1109
        }
10✔
1110

1111
        parts := strings.Split(content, ",")
204✔
1112

204✔
1113
        // 检查空索引
204✔
1114
        for _, part := range parts {
632✔
1115
                if strings.TrimSpace(part) == "" {
430✔
1116
                        return nil, NewError(ErrInvalidPath, "empty index in multi-index segment", content)
2✔
1117
                }
2✔
1118
        }
1119

1120
        // RFC 9535: 每个部分独立解析,支持混合选择器类型
1121
        // 先尝试解析每个部分
1122
        selectors := make([]segment, 0, len(parts))
202✔
1123
        allIndices := true
202✔
1124
        allNames := true
202✔
1125

202✔
1126
        for _, part := range parts {
626✔
1127
                trimmed := strings.TrimSpace(part)
424✔
1128

424✔
1129
                // 检查是否是通配符
424✔
1130
                if trimmed == "*" {
464✔
1131
                        selectors = append(selectors, &wildcardSegment{})
40✔
1132
                        allIndices = false
40✔
1133
                        allNames = false
40✔
1134
                        continue
40✔
1135
                }
1136

1137
                // 检查是否是切片
1138
                if strings.Contains(trimmed, ":") {
416✔
1139
                        slice, err := parseSliceSegment(trimmed)
32✔
1140
                        if err != nil {
32✔
NEW
1141
                                return nil, err
×
UNCOV
1142
                        }
×
1143
                        selectors = append(selectors, slice)
32✔
1144
                        allIndices = false
32✔
1145
                        allNames = false
32✔
1146
                        continue
32✔
1147
                }
1148

1149
                // 检查是否是带引号的字符串
1150
                if (strings.HasPrefix(trimmed, "'") && strings.HasSuffix(trimmed, "'")) ||
352✔
1151
                        (strings.HasPrefix(trimmed, "\"") && strings.HasSuffix(trimmed, "\"")) {
574✔
1152
                        name := trimmed[1 : len(trimmed)-1]
222✔
1153
                        selectors = append(selectors, &nameSegment{name: name})
222✔
1154
                        allIndices = false
222✔
1155
                        continue
222✔
1156
                }
1157

1158
                // 尝试解析为数字索引
1159
                if idx, err := strconv.Atoi(trimmed); err == nil {
246✔
1160
                        selectors = append(selectors, &indexSegment{index: idx})
116✔
1161
                        allNames = false
116✔
1162
                        continue
116✔
1163
                }
1164

1165
                // 不是数字也不是带引号的字符串,可能是不带引号的字段名
1166
                selectors = append(selectors, &nameSegment{name: trimmed})
14✔
1167
                allIndices = false
14✔
1168
        }
1169

1170
        // 如果所有部分都是索引,返回多索引段
1171
        if allIndices {
228✔
1172
                indices := make([]int, len(selectors))
26✔
1173
                for i, sel := range selectors {
88✔
1174
                        indices[i] = sel.(*indexSegment).index
62✔
1175
                }
62✔
1176
                return &multiIndexSegment{indices: indices}, nil
26✔
1177
        }
1178

1179
        // 如果所有部分都是名称,返回多名称段
1180
        if allNames {
276✔
1181
                names := make([]string, len(selectors))
100✔
1182
                for i, sel := range selectors {
298✔
1183
                        names[i] = sel.(*nameSegment).name
198✔
1184
                }
198✔
1185
                return &multiNameSegment{names: names}, nil
100✔
1186
        }
1187

1188
        // 混合类型,返回联合段
1189
        return &unionSegment{selectors: selectors}, nil
76✔
1190
}
1191

1192
// 解析切片表达式
1193
func parseSliceSegment(content string) (segment, error) {
780✔
1194
        parts := strings.Split(content, ":")
780✔
1195
        if len(parts) > 3 {
790✔
1196
                return nil, fmt.Errorf("invalid slice syntax")
10✔
1197
        }
10✔
1198

1199
        slice := &sliceSegment{start: 0, end: 0, step: 1}
770✔
1200

770✔
1201
        // 解析起始索引
770✔
1202
        if parts[0] != "" {
1,294✔
1203
                start, err := strconv.Atoi(parts[0])
524✔
1204
                if err != nil {
590✔
1205
                        return nil, fmt.Errorf("invalid start index: %s", parts[0])
66✔
1206
                }
66✔
1207
                slice.start = start
458✔
1208
        }
1209

1210
        // 解析结束索引
1211
        if len(parts) > 1 && parts[1] != "" {
1,170✔
1212
                end, err := strconv.Atoi(parts[1])
466✔
1213
                if err != nil {
564✔
1214
                        return nil, fmt.Errorf("invalid end index: %s", parts[1])
98✔
1215
                }
98✔
1216
                slice.end = end
368✔
1217
        }
1218

1219
        // 解析步长
1220
        if len(parts) > 2 && parts[2] != "" {
898✔
1221
                step, err := strconv.Atoi(parts[2])
292✔
1222
                if err != nil {
366✔
1223
                        return nil, fmt.Errorf("invalid step: %s", parts[2])
74✔
1224
                }
74✔
1225
                if step == 0 {
236✔
1226
                        return nil, fmt.Errorf("step cannot be zero")
18✔
1227
                }
18✔
1228
                slice.step = step
200✔
1229
        }
1230

1231
        return slice, nil
514✔
1232
}
1233

1234
// 解析索引或名称
1235
func parseIndexOrName(content string) (segment, error) {
1,500✔
1236
        // 处理函数调用
1,500✔
1237
        if strings.HasSuffix(content, ")") {
1,508✔
1238
                return parseFunctionCall(content)
8✔
1239
        }
8✔
1240

1241
        // 尝试解析为数字索引
1242
        if idx, err := strconv.Atoi(content); err == nil {
1,636✔
1243
                return &indexSegment{index: idx}, nil
144✔
1244
        }
144✔
1245

1246
        // 处理字符串字面量
1247
        if strings.HasPrefix(content, "'") && strings.HasSuffix(content, "'") && len(content) > 1 {
1,938✔
1248
                return &nameSegment{name: content[1 : len(content)-1]}, nil
590✔
1249
        }
590✔
1250

1251
        // 处理双引号字符串字面量
1252
        if strings.HasPrefix(content, "\"") && strings.HasSuffix(content, "\"") && len(content) > 1 {
1,434✔
1253
                return &nameSegment{name: content[1 : len(content)-1]}, nil
676✔
1254
        }
676✔
1255

1256
        return &nameSegment{name: content}, nil
82✔
1257
}
1258

1259
// 解析函数调用
1260
func parseFunctionCall(content string) (segment, error) {
52✔
1261
        // 找到函数名和参数列表
52✔
1262
        openParen := strings.Index(content, "(")
52✔
1263
        if openParen == -1 {
54✔
1264
                return nil, fmt.Errorf("invalid function call syntax: missing opening parenthesis")
2✔
1265
        }
2✔
1266

1267
        // 检查闭合括号
1268
        if !strings.HasSuffix(content, ")") {
52✔
1269
                return nil, fmt.Errorf("invalid function call syntax: missing closing parenthesis")
2✔
1270
        }
2✔
1271

1272
        name := content[:openParen]
48✔
1273
        argsStr := content[openParen+1 : len(content)-1]
48✔
1274

48✔
1275
        // 解析参数
48✔
1276
        args := make([]interface{}, 0)
48✔
1277
        if argsStr != "" {
88✔
1278
                // 简单参数解析,暂时只支持数字和字符串
40✔
1279
                argParts := strings.Split(argsStr, ",")
40✔
1280
                for _, arg := range argParts {
108✔
1281
                        arg = strings.TrimSpace(arg)
68✔
1282
                        if arg == "" {
70✔
1283
                                continue // 跳过空参数
2✔
1284
                        }
1285
                        // 尝试解析为数字
1286
                        if num, err := strconv.ParseFloat(arg, 64); err == nil {
100✔
1287
                                args = append(args, num)
34✔
1288
                                continue
34✔
1289
                        }
1290
                        // 处理字符串参数
1291
                        if strings.HasPrefix(arg, "'") && strings.HasSuffix(arg, "'") {
58✔
1292
                                // 处理转义引号
26✔
1293
                                str := arg[1 : len(arg)-1]
26✔
1294
                                str = strings.ReplaceAll(str, "''", "'")
26✔
1295
                                args = append(args, str)
26✔
1296
                                continue
26✔
1297
                        }
1298
                        return nil, fmt.Errorf("unsupported argument type: %s", arg)
6✔
1299
                }
1300
        }
1301

1302
        return &functionSegment{name: name, args: args}, nil
42✔
1303
}
1304

1305
// parseFilterValue parses a filter value string into an appropriate type
1306
func parseFilterValue(valueStr string) (interface{}, error) {
1,486✔
1307
        valueStr = strings.TrimSpace(valueStr)
1,486✔
1308

1,486✔
1309
        // 处理 null
1,486✔
1310
        if valueStr == "null" {
1,560✔
1311
                return nil, nil
74✔
1312
        }
74✔
1313

1314
        // 处理布尔值
1315
        if valueStr == "true" {
1,466✔
1316
                return true, nil
54✔
1317
        }
54✔
1318
        if valueStr == "false" {
1,406✔
1319
                return false, nil
48✔
1320
        }
48✔
1321

1322
        // 处理字符串(带引号)
1323
        if (strings.HasPrefix(valueStr, "'") && strings.HasSuffix(valueStr, "'")) ||
1,310✔
1324
                (strings.HasPrefix(valueStr, "\"") && strings.HasSuffix(valueStr, "\"")) {
1,612✔
1325
                return valueStr[1 : len(valueStr)-1], nil
302✔
1326
        }
302✔
1327

1328
        // 尝试解析为数字
1329
        if num, err := strconv.ParseFloat(valueStr, 64); err == nil {
1,460✔
1330
                return num, nil
452✔
1331
        }
452✔
1332

1333
        // 处理 $ 引用(根节点)
1334
        if valueStr == "$" {
564✔
1335
                return "$", nil
8✔
1336
        }
8✔
1337

1338
        // 处理 @ 引用(当前元素)
1339
        if valueStr == "@" {
556✔
1340
                return "@", nil
8✔
1341
        }
8✔
1342

1343
        // 处理 $.path 引用(根节点路径)
1344
        if strings.HasPrefix(valueStr, "$.") || strings.HasPrefix(valueStr, "$[") {
540✔
NEW
1345
                return valueStr, nil
×
NEW
1346
        }
×
1347

1348
        // 处理 @.path 引用(当前元素路径)
1349
        if strings.HasPrefix(valueStr, "@.") || strings.HasPrefix(valueStr, "@[") {
956✔
1350
                return valueStr, nil
416✔
1351
        }
416✔
1352

1353
        // 如果不是其他类型,返回错误
1354
        return nil, fmt.Errorf("invalid value: %s", valueStr)
124✔
1355
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc