bring back yahoo pipes!
1package transforms
2
3import (
4 "context"
5 "fmt"
6 "regexp"
7
8 "github.com/kierank/pipes/nodes"
9)
10
11type RegexNode struct{}
12
13func (n *RegexNode) Type() string { return "regex" }
14func (n *RegexNode) Label() string { return "Regex Replace" }
15func (n *RegexNode) Description() string { return "Search and replace text using regex" }
16func (n *RegexNode) Category() string { return "transform" }
17func (n *RegexNode) Inputs() int { return 1 }
18func (n *RegexNode) Outputs() int { return 1 }
19
20func (n *RegexNode) Execute(ctx context.Context, config map[string]interface{}, inputs [][]interface{}, execCtx *nodes.Context) ([]interface{}, error) {
21 if len(inputs) == 0 || len(inputs[0]) == 0 {
22 return []interface{}{}, nil
23 }
24
25 items := inputs[0]
26 field, _ := config["field"].(string)
27 pattern, _ := config["pattern"].(string)
28 replacement, _ := config["replacement"].(string)
29
30 if field == "" || pattern == "" {
31 return items, nil
32 }
33
34 re, err := regexp.Compile(pattern)
35 if err != nil {
36 return nil, fmt.Errorf("invalid regex: %w", err)
37 }
38
39 var result []interface{}
40 modified := 0
41
42 for _, item := range items {
43 itemMap, ok := item.(map[string]interface{})
44 if !ok {
45 result = append(result, item)
46 continue
47 }
48
49 newItem := make(map[string]interface{})
50 for k, v := range itemMap {
51 newItem[k] = v
52 }
53
54 if val, ok := newItem[field].(string); ok {
55 newVal := re.ReplaceAllString(val, replacement)
56 if newVal != val {
57 modified++
58 }
59 newItem[field] = newVal
60 }
61
62 result = append(result, newItem)
63 }
64
65 execCtx.Log("regex", "info", fmt.Sprintf("Modified %d of %d items", modified, len(result)))
66 return result, nil
67}
68
69func (n *RegexNode) ValidateConfig(config map[string]interface{}) error {
70 pattern, _ := config["pattern"].(string)
71 if pattern != "" {
72 if _, err := regexp.Compile(pattern); err != nil {
73 return fmt.Errorf("invalid regex pattern: %w", err)
74 }
75 }
76 return nil
77}
78
79func (n *RegexNode) GetConfigSchema() *nodes.ConfigSchema {
80 return &nodes.ConfigSchema{
81 Fields: []nodes.ConfigField{
82 {
83 Name: "field",
84 Label: "Field",
85 Type: "text",
86 Required: true,
87 Placeholder: "title",
88 HelpText: "Field to apply regex to",
89 },
90 {
91 Name: "pattern",
92 Label: "Pattern",
93 Type: "text",
94 Required: true,
95 Placeholder: "\\[.*?\\]",
96 HelpText: "Regex pattern to match",
97 },
98 {
99 Name: "replacement",
100 Label: "Replacement",
101 Type: "text",
102 Required: false,
103 Placeholder: "",
104 HelpText: "Text to replace matches with (use $1, $2 for groups)",
105 },
106 },
107 }
108}