1// SPDX-License-Identifier: MIT
2
3package expr_test
4
5import (
6 "context"
7 "errors"
8 "fmt"
9
10 "bnema.dev/ermite-actions/expr"
11)
12
13func ExampleParse() {
14 node, err := expr.Parse("contains(github.ref, 'main') && !failure()",
15 []string{"github"},
16 []expr.FuncInfo{{Name: "failure", MinArgs: 0, MaxArgs: 0}})
17 fmt.Println(node != nil, err)
18
19 // Unknown names and wrong argument counts are rejected when parsing,
20 // with the messages of GitHub's implementation.
21 for _, src := range []string{"secrets.TOKEN", "contains('a')", "github.ref ==", "nope()"} {
22 _, err := expr.Parse(src, []string{"github"}, nil)
23 var pe *expr.Error
24 if errors.As(err, &pe) {
25 fmt.Printf("%s -> %s (line %d, column %d)\n", src, pe.Message, pe.Pos.Line, pe.Pos.Column)
26 }
27 }
28 // Output:
29 // true <nil>
30 // secrets.TOKEN -> Unrecognized named-value: 'secrets'. Located at position 1 within expression: secrets.TOKEN (line 0, column 0)
31 // contains('a') -> Too few parameters supplied: '('. Located at position 9 within expression: contains('a') (line 0, column 8)
32 // github.ref == -> Unexpected end of expression: '=='. Located at position 12 within expression: github.ref == (line 0, column 11)
33 // nope() -> Unrecognized function: 'nope'. Located at position 1 within expression: nope() (line 0, column 0)
34}
35
36func ExampleEvaluate() {
37 event, err := expr.FromJSON([]byte(`{"ref": "refs/heads/main", "labels": [{"name": "Bug"}, {"name": "docs"}]}`))
38 if err != nil {
39 panic(err)
40 }
41 ec := expr.EvalContext{
42 Contexts: map[string]expr.Value{"github": event},
43 Funcs: map[string]expr.Func{
44 "always": func(context.Context, []expr.Value) (expr.Value, error) { return expr.Boolean(true), nil },
45 },
46 }
47 funcs := []expr.FuncInfo{{Name: "always", MinArgs: 0, MaxArgs: 0}}
48
49 for _, src := range []string{
50 "github.ref == 'refs/heads/main' && 'release' || 'dev'",
51 "contains(github.labels.*.name, 'bug')",
52 "join(github.labels.*.name, ', ')",
53 "format('{0} has {1} labels', github.ref, 2)",
54 "always() && github.missing",
55 "fromJSON('{')",
56 } {
57 node, err := expr.Parse(src, []string{"github"}, funcs)
58 if err != nil {
59 panic(err)
60 }
61 v, err := expr.Evaluate(context.Background(), node, ec)
62 if err != nil {
63 fmt.Printf("%s -> error: %v\n", src, err)
64 continue
65 }
66 fmt.Printf("%s -> %s (truthy: %t)\n", src, expr.CoerceString(v), expr.Truthy(v))
67 }
68 // Output:
69 // github.ref == 'refs/heads/main' && 'release' || 'dev' -> release (truthy: true)
70 // contains(github.labels.*.name, 'bug') -> true (truthy: true)
71 // join(github.labels.*.name, ', ') -> Bug, docs (truthy: true)
72 // format('{0} has {1} labels', github.ref, 2) -> refs/heads/main has 2 labels (truthy: true)
73 // always() && github.missing -> (truthy: false)
74 // fromJSON('{') -> error: Error reading JObject from JsonReader. Path '', line 1, position 1.
75}
76
77func ExampleToJSON() {
78 d := expr.NewDictionary()
79 d.Add("name", expr.String("octo"))
80 d.Add("tags", expr.NewArray(expr.Number(1), expr.Null{}, expr.Number(0.5)))
81 fmt.Println(expr.ToJSON(d))
82 // Output:
83 // {
84 // "name": "octo",
85 // "tags": [
86 // 1,
87 // null,
88 // 0.5
89 // ]
90 // }
91}