Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/sclevine/spec/parser.go
2875 views
1
package spec
2
3
import (
4
"math/rand"
5
"strings"
6
"testing"
7
)
8
9
type node struct {
10
text []string
11
loc []int
12
seed int64
13
order order
14
scope scope
15
nest nest
16
pend bool
17
focus bool
18
nodes tree
19
}
20
21
func (n *node) parse(f func(*testing.T, G, S)) Plan {
22
// TODO: validate Options
23
plan := Plan{
24
Text: strings.Join(n.text, "/"),
25
Seed: n.seed,
26
}
27
f(nil, func(text string, f func(), opts ...Option) {
28
cfg := options(opts).apply()
29
n.add(text, cfg, tree{})
30
parent := n
31
n = n.last()
32
plan.update(n)
33
defer func() {
34
n.level()
35
n.sort()
36
n = parent
37
}()
38
f()
39
}, func(text string, _ func(), opts ...Option) {
40
cfg := options(opts).apply()
41
if cfg.before || cfg.after || cfg.out != nil {
42
return
43
}
44
n.add(text, cfg, nil)
45
plan.update(n.last())
46
})
47
n.level()
48
n.sort()
49
return plan
50
}
51
52
func (p *Plan) update(n *node) {
53
if n.focus && !n.pend {
54
p.HasFocus = true
55
}
56
if n.order == orderRandom {
57
p.HasRandom = true
58
}
59
if n.nodes == nil {
60
p.Total++
61
if n.focus && !n.pend {
62
p.Focused++
63
} else if n.pend {
64
p.Pending++
65
}
66
}
67
}
68
69
func (n *node) add(text string, cfg *config, nodes tree) {
70
name := n.text
71
if n.nested() {
72
name = nil
73
}
74
n.nodes = append(n.nodes, node{
75
text: append(append([]string(nil), name...), text),
76
loc: append(append([]int(nil), n.loc...), len(n.nodes)),
77
seed: n.seed,
78
order: cfg.order.or(n.order),
79
scope: cfg.scope.or(n.scope),
80
nest: cfg.nest.or(n.nest),
81
pend: cfg.pend || n.pend,
82
focus: cfg.focus || n.focus,
83
nodes: nodes,
84
})
85
}
86
87
func (n *node) sort() {
88
nodes := n.nodes
89
switch n.order {
90
case orderRandom:
91
r := rand.New(rand.NewSource(n.seed))
92
for i := len(nodes) - 1; i > 0; i-- {
93
j := r.Intn(i + 1)
94
nodes[i], nodes[j] = nodes[j], nodes[i]
95
}
96
case orderReverse:
97
last := len(nodes) - 1
98
for i := 0; i < len(nodes)/2; i++ {
99
nodes[i], nodes[last-i] = nodes[last-i], nodes[i]
100
}
101
}
102
}
103
104
func (n *node) level() {
105
nodes := n.nodes
106
switch n.scope {
107
case scopeGlobal:
108
var flat tree
109
for _, child := range nodes {
110
if child.nodes == nil || child.scope == scopeLocal {
111
flat = append(flat, child)
112
} else {
113
flat = append(flat, child.nodes...)
114
}
115
}
116
n.nodes = flat
117
}
118
}
119
120
func (n *node) last() *node {
121
return &n.nodes[len(n.nodes)-1]
122
}
123
124
func (n *node) nested() bool {
125
return n.nest == nestOn || len(n.loc) == 0
126
}
127
128
func (n node) run(t *testing.T, f func(*testing.T, node)) bool {
129
t.Helper()
130
name := strings.Join(n.text, "/")
131
switch {
132
case n.nodes == nil:
133
return t.Run(name, func(t *testing.T) { f(t, n) })
134
case n.nested():
135
return t.Run(name, func(t *testing.T) { n.nodes.run(t, f) })
136
default:
137
return n.nodes.run(t, f)
138
}
139
}
140
141
type tree []node
142
143
func (ns tree) run(t *testing.T, f func(*testing.T, node)) bool {
144
t.Helper()
145
ok := true
146
for _, n := range ns {
147
ok = n.run(t, f) && ok
148
}
149
return ok
150
}
151
152