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

mobalazs / rotor-framework / 18919729013

29 Oct 2025 07:21PM UTC coverage: 85.379% (-0.1%) from 85.479%
18919729013

push

github

mobalazs
fix: update debug setting in bsconfig to enable debugging

1781 of 2086 relevant lines covered (85.38%)

1.16 hits per line

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

88.57
/src/source/plugins/FieldsPlugin.bs
1
import "../base/BasePlugin.bs"
2

3
namespace Rotor
4

5
    ' =====================================================================
6
    ' FieldsPlugin - Handles dynamic field expressions and interpolation
7
    '
8
    ' Rotor Framework plugin for handling dynamic field expressions and interpolation.
9
    '
10
    ' Key Features:
11
    '   - Evaluates function-based field values
12
    '   - Interpolates @-prefixed expressions (e.g., @viewModelState.value)
13
    '   - Supports dynamic field resolution from widget context
14
    '   - Automatically updates fields on widget lifecycle changes
15
    '
16
    ' Expression Syntax:
17
    '   @key.path - Resolves from widget.viewModelState
18
    '
19
    ' =====================================================================
20
    class FieldsPlugin extends Rotor.BasePlugin
21

22
        ' =============================================================
23
        ' MEMBER VARIABLES
24
        ' =============================================================
25

26
        ' Regex pattern for matching @-prefixed expressions
27
        ' Matches: @ followed by any characters except space, @, or comma
28
        configRegex = /(\@)([^\s\@\,]*)/i
29

30
        ' =============================================================
31
        ' CONSTRUCTOR
32
        ' =============================================================
33

34
        ' ---------------------------------------------------------------------
35
        ' new - Initializes the FieldsPlugin instance
36
        '
37
        ' @param {string} key - Plugin identifier (default: "fields")
38
        ' @param {object} params - Additional parameters (unused)
39
        '
40
        sub new(key = "fields" as string, params = invalid as object)
41
            super(key)
1✔
42
        end sub
43

44
        ' =============================================================
45
        ' LIFECYCLE HOOKS
46
        ' =============================================================
47

48
        hooks = {
49
            ' ---------------------------------------------------------------------
50
            ' beforeMount - Sets custom fields when widget is mounted
51
            '
52
            ' Evaluates and applies all field expressions after widget creation.
53
            '
54
            ' @param {object} scope - Plugin instance (m)
55
            ' @param {object} widget - Widget being mounted
56
            '
57
            beforeMount: sub(scope as object, widget as object)
58
                value = widget[scope.key]
1✔
59
                scope.setCustomFields(widget, value)
1✔
60
            end sub,
61

62
            ' ---------------------------------------------------------------------
63
            ' beforeUpdate - Updates custom fields when widget config changes
64
            '
65
            ' Merges new field config with existing config and re-evaluates all fields.
66
            '
67
            ' @param {object} scope - Plugin instance (m)
68
            ' @param {object} widget - Widget being updated
69
            ' @param {object} newValue - New field configuration
70
            ' @param {object} oldValue - Previous field configuration
71
            '
72
            beforeUpdate: sub(scope as object, widget as object, newValue = {}, oldValue = {})
73
                ' Extend old config with new values
74
                Rotor.Utils.deepExtendAA(widget[scope.key], newValue)
1✔
75
                scope.setCustomFields(widget, newValue)
1✔
76
            end sub,
77

78
            ' ---------------------------------------------------------------------
79
            ' beforeDestroy - Clears field configuration on destruction
80
            '
81
            ' @param {object} scope - Plugin instance (m)
82
            ' @param {object} widget - Widget being destroyed
83
            '
84
            beforeDestroy: sub(scope as object, widget as object)
85
                widget[scope.key].Clear()
1✔
86
            end sub
87
        }
88

89
        ' =============================================================
90
        ' FIELD PROCESSING
91
        ' =============================================================
92

93
        ' ---------------------------------------------------------------------
94
        ' setCustomFields - Evaluates and applies fields to widget node
95
        '
96
        ' Parses field expressions and sets the resolved values on the widget's SceneGraph node.
97
        '
98
        ' @param {object} widget - Widget instance
99
        ' @param {object} fields - Field configuration object
100
        '
101
        sub setCustomFields(widget as object, fields)
102
            parsedFields = m.parseFields(widget, fields)
1✔
103
            node = widget.node
1✔
104
            Rotor.Utils.setCustomFields(node, parsedFields, true)
1✔
105
        end sub
106

107
        ' ---------------------------------------------------------------------
108
        ' parseFields - Parses and resolves field expressions
109
        '
110
        ' Processes field values through multiple resolution strategies:
111
        '   1. Function values - Executes function in widget scope
112
        '   2. String interpolation - Resolves @-prefixed expressions
113
        '   3. Direct values - Passes through unchanged
114
        '
115
        ' Expression Resolution:
116
        '   - @key.path resolves from widget.viewModelState
117
        '   - If result is string, performs string interpolation
118
        '   - If result is non-string, replaces entire value
119
        '
120
        ' @param {object} widget - Widget instance providing context
121
        ' @param {object} fields - Field configuration to parse
122
        ' @returns {object} Parsed fields with resolved values
123
        '
124
        function parseFields(widget as object, fields as object) as object
125
            parsedFields = {}
1✔
126

127
            for each fieldId in fields
1✔
128
                value = fields[fieldId]
1✔
129

130
                ' Step 1: Resolve function-based values
131
                if Rotor.Utils.isFunction(value)
3✔
132
                    parsedFields[fieldId] = Rotor.Utils.callbackScoped(value, widget)
1✔
133
                    value = parsedFields[fieldId]
1✔
134
                end if
135

136
                ' Step 2: Process string interpolation
137
                if Rotor.Utils.isString(value)
3✔
138
                    results = m.configRegex.MatchAll(value)
1✔
139

140
                    if results.Count() > 0
2✔
141
                        for each result in results
1✔
142
                            matchKey = result[2]        ' The key path after @
1✔
143
                            sourceTypeOperator = result[1]  ' The @ symbol
1✔
144

145
                            ' Determine source based on operator
146
                            if sourceTypeOperator = "@"
3✔
147
                                source = widget.viewModelState
1✔
148
                            else
×
149
                                source = widget
×
150
                            end if
151

152
                            ' Resolve value from key path
153
                            asset = Rotor.Utils.getValueByKeyPath(source, matchKey)
1✔
154

155
                            ' Handle string vs non-string results
156
                            if Rotor.Utils.isString(asset)
3✔
157
                                ' String interpolation - replace in original string
158
                                replaceRegex = CreateObject("roRegex", sourceTypeOperator + matchKey, "ig")
1✔
159
                                value = replaceRegex.ReplaceAll(value, asset)
1✔
160
                            else
161
                                ' Non-string value - replace entire field value
×
162
                                value = asset
×
163
                                exit for
164
                            end if
165
                        end for
166
                    end if
167

168
                    parsedFields[fieldId] = value
1✔
169
                else
170
                    ' Step 3: Direct value assignment
3✔
171
                    parsedFields[fieldId] = value
1✔
172
                end if
173
            end for
174

175
            return parsedFields
1✔
176
        end function
177

178
    end class
179

180
end namespace
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