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

asciimoth / pasta / 29280923334

13 Jul 2026 08:03PM UTC coverage: 78.067% (+0.7%) from 77.33%
29280923334

push

github

asciimoth
feat(std): switch menus of constant nodes from realtime input to apply forms

29 of 41 new or added lines in 6 files covered. (70.73%)

8265 of 10587 relevant lines covered (78.07%)

406.54 hits per line

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

80.53
/pasta/std/node_string_constant.go
1
package std
2

3
import (
4
        "github.com/asciimoth/configer/configer"
5
        "github.com/asciimoth/formular"
6
        "github.com/asciimoth/pasta/pasta"
7
)
8

9
// NodeTypeStringConstant is the class name for StringConstantClass.
10
const NodeTypeStringConstant = "pasta/StringConstant"
11

12
// StringConstantClass creates nodes with one editable string value and one
13
// right-directed pasta/string output port.
14
type StringConstantClass struct{}
15

16
func (StringConstantClass) ClassName() string        { return NodeTypeStringConstant }
372✔
17
func (StringConstantClass) ShortDescription() string { return "String constant" }
335✔
18
func (StringConstantClass) LongDescription() string {
×
NEW
19
        return "Outputs an editable string value on one pasta/string right-directed port. The value changes when the menu form is applied."
×
20
}
×
21
func (StringConstantClass) DefaultNodeParams() pasta.NodeClassParams {
448✔
22
        return pasta.NodeClassParams{PrimaryType: TypeString, InitialPorts: []pasta.Port{rightPort(TypeString)}}
448✔
23
}
448✔
24
func (StringConstantClass) NewNode(cfg configer.Config, _ ...*pasta.NodeClassState) (pasta.Node, error) {
26✔
25
        return newStringConstantNode(readString(cfg, "")), nil
26✔
26
}
26✔
27

28
type stringConstantNode struct {
29
        pasta.BasicNode
30

31
        value string
32
        w     *pasta.Workspace
33
        id    uint64
34
        out   uint64
35
}
36

37
func newStringConstantNode(value string) *stringConstantNode {
26✔
38
        return &stringConstantNode{value: value}
26✔
39
}
26✔
40

41
func (n *stringConstantNode) OnInit(w *pasta.Workspace, _ pasta.Logger, id uint64, _ string, restored *pasta.NodeInitData, _, _, _, _ bool) error {
26✔
42
        n.w = w
26✔
43
        n.id = id
26✔
44
        if restored != nil && len(restored.RightPorts) > 0 {
52✔
45
                n.out = restored.RightPorts[0]
26✔
46
        }
26✔
47
        if err := n.w.SetNodePrimaryLocked(n.id, TypeString); err != nil {
26✔
48
                return err
×
49
        }
×
50
        if err := n.updateLabel(); err != nil {
26✔
51
                return err
×
52
        }
×
53
        n.sendMenuSnapshot()
26✔
54
        return nil
26✔
55
}
56

57
func (n *stringConstantNode) OnReady() error {
26✔
58
        n.sendAll()
26✔
59
        return nil
26✔
60
}
26✔
61

62
func (n *stringConstantNode) PreLinkAdd(port uint64, linkType, _ string) error {
28✔
63
        if port != n.out || linkType != TypeString {
28✔
64
                return pasta.LinkTypeErr(linkType)
×
65
        }
×
66
        return nil
28✔
67
}
68

69
func (n *stringConstantNode) OnLinkAdd(link, port uint64, _, _ string) error {
28✔
70
        if port == n.out {
56✔
71
                n.sendToLink(link)
28✔
72
        }
28✔
73
        return nil
28✔
74
}
75

76
func (n *stringConstantNode) OnEvent(event pasta.Event, linkType string, _ []string, receiverPortDirection string) error {
35✔
77
        if event.ReceiverPort != n.out || receiverPortDirection != "right" || linkType != TypeString || !isValueRequest(event.Payload) {
35✔
78
                return nil
×
79
        }
×
80
        n.w.SendEventLocked(pasta.Event{SenderNode: n.id, SenderPort: n.out, ReceiverNode: event.SenderNode, ReceiverPort: event.SenderPort, Payload: String(n.value)})
35✔
81
        return nil
35✔
82
}
83

84
func (n *stringConstantNode) OnFormularMsg(message any) error {
23✔
85
        msg, ok := message.(formular.FormApplyMessage)
23✔
86
        if !ok || msg.MenuID != pasta.NodeMenuID(n.id) || msg.BlockID != "state" {
24✔
87
                return nil
1✔
88
        }
1✔
89
        // The frontend may send field updates while a form value is being edited;
90
        // only an explicit apply commits the constant and propagates it.
91
        next, ok := parseStringAny(msg.Values["value"])
22✔
92
        if !ok {
22✔
NEW
93
                n.sendMenuSnapshotWithForce(true)
×
NEW
94
                return nil
×
NEW
95
        }
×
96
        if next == n.value {
23✔
97
                return nil
1✔
98
        }
1✔
99
        n.value = next
21✔
100
        if err := n.updateLabel(); err != nil {
21✔
101
                return err
×
102
        }
×
103
        n.sendMenuBlock()
21✔
104
        n.sendAll()
21✔
105
        return nil
21✔
106
}
107

108
func (n *stringConstantNode) OnSave(cfg configer.Config) error {
8✔
109
        if err := pasta.DeleteNodeOwnedConfigKeys(cfg); err != nil {
8✔
110
                return err
×
111
        }
×
112
        return cfg.Set(configer.Path{"value"}, n.value)
8✔
113
}
114

115
func (n *stringConstantNode) updateLabel() error {
47✔
116
        return n.w.SetNodeLabelLocked(n.id, n.value)
47✔
117
}
47✔
118

119
func (n *stringConstantNode) sendAll() {
47✔
120
        port, ok := n.w.PortSnapshotLocked(n.out)
47✔
121
        if !ok {
47✔
122
                return
×
123
        }
×
124
        for _, link := range port.Links {
59✔
125
                n.sendToLink(link)
12✔
126
        }
12✔
127
}
128

129
func (n *stringConstantNode) sendToLink(link uint64) {
40✔
130
        snapshot, ok := n.w.LinkSnapshotLocked(link)
40✔
131
        if !ok {
40✔
132
                return
×
133
        }
×
134
        receiverNode, receiverPort := otherEndpoint(snapshot, n.out)
40✔
135
        n.w.SendEventLocked(pasta.Event{SenderNode: n.id, SenderPort: n.out, ReceiverNode: receiverNode, ReceiverPort: receiverPort, Payload: String(n.value)})
40✔
136
}
137

138
func (n *stringConstantNode) sendMenuSnapshot() {
26✔
139
        n.sendMenuSnapshotWithForce(false)
26✔
140
}
26✔
141

142
func (n *stringConstantNode) sendMenuSnapshotWithForce(force bool) {
26✔
143
        n.w.SendNodeMenuMsgLocked(n.id, formular.MenuSnapshotMessage{
26✔
144
                MessageBase: formular.MessageBase{Type: formular.MessageMenuSnapshot, MenuID: pasta.NodeMenuID(n.id), MenuGeneration: 1},
26✔
145
                Force:       force,
26✔
146
                Blocks:      []formular.Block{n.menuBlock()},
26✔
147
        })
26✔
148
}
26✔
149

150
func (n *stringConstantNode) sendMenuBlock() {
21✔
151
        n.w.SendNodeMenuMsgLocked(n.id, formular.BlockSnapshotMessage{
21✔
152
                MessageBase: formular.MessageBase{Type: formular.MessageBlockSnapshot, MenuID: pasta.NodeMenuID(n.id), MenuGeneration: 1, BlockGeneration: 1},
21✔
153
                Block:       n.menuBlock(),
21✔
154
        })
21✔
155
}
21✔
156

157
func (n *stringConstantNode) menuBlock() formular.Block {
47✔
158
        return formular.Block{
47✔
159
                ID: "state", Order: 10, Generation: 1, Form: true,
47✔
160
                Items: []formular.Item{{Type: formular.ItemField, ID: "value", Label: "Value", Field: &formular.Field{Kind: formular.FieldText, Value: n.value}}},
47✔
161
        }
47✔
162
}
47✔
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