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

rokucommunity / brs / #213

27 Jan 2025 05:30PM UTC coverage: 86.996% (-2.2%) from 89.205%
#213

push

web-flow
Implemented several improvements to SceneGraph (#87)

* Implemented several improvements to SceneGraph

* Fixed most test cases

* Reduced unnecessary code

* Fixed typo

* Added Warning when trying to create a non-existent Node

* Fixed parser

* Fixed unit tests

* Implemented support for `infoFields`

* Prettier fix

* Simplified execute callback code and matched behavior with Roku

* Adding comment to clarify the exception

2240 of 2807 branches covered (79.8%)

Branch coverage included in aggregate %.

139 of 304 new or added lines in 18 files covered. (45.72%)

2 existing lines in 1 file now uncovered.

6129 of 6813 relevant lines covered (89.96%)

27562.41 hits per line

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

90.32
/src/brsTypes/index.ts
1
import {
143✔
2
    ValueKind,
3
    BrsInvalid,
4
    BrsBoolean,
5
    BrsString,
6
    Uninitialized,
7
    BrsValue,
8
    Comparable,
9
} from "./BrsType";
10
import { RoArray } from "./components/RoArray";
143✔
11
import { RoList } from "./components/RoList";
12
import { RoByteArray } from "./components/RoByteArray";
13
import { RoAssociativeArray } from "./components/RoAssociativeArray";
143✔
14
import { Int32 } from "./Int32";
143✔
15
import { Int64 } from "./Int64";
143✔
16
import { Float } from "./Float";
143✔
17
import { Double } from "./Double";
143✔
18
import { Callable } from "./Callable";
143✔
19
import { BrsComponent } from "./components/BrsComponent";
143✔
20
import { RoString } from "./components/RoString";
143✔
21
import { BrsInterface } from "./BrsInterface";
22
import { RoPath } from "./components/RoPath";
143✔
23
import { roDouble } from "./components/RoDouble";
143✔
24
import { roFloat } from "./components/RoFloat";
143✔
25
import { roInt } from "./components/RoInt";
143✔
26
import { roLongInteger } from "./components/RoLongInteger";
143✔
27
import { RoDeviceInfoEvent } from "./components/RoDeviceInfoEvent";
143✔
28
import { RoSGNodeEvent } from "./components/RoSGNodeEvent";
143✔
29
import { RoSGScreenEvent } from "./components/RoSGScreenEvent";
143✔
30

31
export * from "./BrsType";
143✔
32
export * from "./Int32";
143✔
33
export * from "./Int64";
143✔
34
export * from "./Float";
143✔
35
export * from "./Double";
143✔
36
export * from "./BrsInterface";
143✔
37
export * from "./Callable";
143✔
38
export * from "./components/BrsComponent";
143✔
39
export * from "./components/RoDeviceInfo";
143✔
40
export * from "./components/RoArray";
143✔
41
export * from "./components/RoList";
143✔
42
export * from "./components/RoByteArray";
143✔
43
export * from "./components/RoDateTime";
143✔
44
export * from "./components/RoAssociativeArray";
143✔
45
export * from "./components/RoTimespan";
143✔
46
export * from "./components/BrsObjects";
143✔
47
export * from "./components/RoRegex";
143✔
48
export * from "./components/RoXMLElement";
143✔
49
export * from "./components/RoString";
143✔
50
export * from "./components/RoBoolean";
143✔
51
export * from "./components/RoDouble";
143✔
52
export * from "./components/RoFloat";
143✔
53
export * from "./components/RoInt";
143✔
54
export * from "./components/RoLongInteger";
143✔
55
export * from "./components/RoInvalid";
143✔
56
export * from "./components/RoSGNodeEvent";
143✔
57
export * from "./components/RoSGNode";
143✔
58
export * from "./components/RoMessagePort";
143✔
59
export * from "./components/RoAppInfo";
143✔
60
export * from "./components/RoPath";
143✔
61
export * from "./nodes/NodeFactory";
143✔
62
export * from "./nodes/Group";
143✔
63
export * from "./nodes/Scene";
143✔
64
export * from "./nodes/MiniKeyboard";
143✔
65
export * from "./nodes/TextEditBox";
143✔
66
export * from "./nodes/LayoutGroup";
143✔
67
export * from "./nodes/Rectangle";
143✔
68
export * from "./nodes/Label";
143✔
69
export * from "./nodes/Font";
143✔
70
export * from "./nodes/Poster";
143✔
71
export * from "./nodes/ArrayGrid";
143✔
72
export * from "./nodes/MarkupGrid";
143✔
73
export * from "./nodes/ContentNode";
143✔
74
export * from "./nodes/Timer";
143✔
75
export * from "./Boxing";
143✔
76
export * from "./Coercion";
143✔
77

78
/**
79
 * Determines whether or not the given value is a number.
80
 * @param value the BrightScript value in question.
81
 * @returns `true` if `value` is a numeric value, otherwise `false`.
82
 */
83
export function isBrsNumber(value: BrsType): value is BrsNumber {
143✔
84
    return NumberKinds.has(value?.kind);
54,934✔
85
}
86

87
export function isNumberKind(kind: ValueKind): boolean {
143✔
88
    return NumberKinds.has(kind);
275✔
89
}
90

91
export const NumberKinds = new Set([
143✔
92
    ValueKind.Int32,
93
    ValueKind.Float,
94
    ValueKind.Double,
95
    ValueKind.Int64,
96
]);
97

98
export const PrimitiveKinds = new Set([
143✔
99
    ValueKind.Uninitialized,
100
    ValueKind.Invalid,
101
    ValueKind.Boolean,
102
    ...NumberKinds,
103
    ValueKind.String,
104
]);
105

106
/**
107
 * Determines whether or not the given value is a string.
108
 * @param value the BrightScript value in question.
109
 * @returns `true` if `value` is a string, otherwise `false`.
110
 */
111
export function isBrsString(value: BrsType): value is BrsString {
143✔
112
    return value?.kind === ValueKind.String || value instanceof RoString;
5,054!
113
}
114

115
/**
116
 * Determines whether or not the given value is a boolean.
117
 * @param value the BrightScript value in question.
118
 * @returns `true` if `value` if a boolean, otherwise `false`.
119
 */
120
export function isBrsBoolean(value: BrsType): value is BrsBoolean {
143✔
121
    return value?.kind === ValueKind.Boolean;
2,099!
122
}
123

124
/**
125
 * Determines whether or not the given value is a BrightScript callable.
126
 * @param value the BrightScript value in question.
127
 * @returns `true` if `value` is a Callable value, otherwise `false`.
128
 */
129
export function isBrsCallable(value: BrsType): value is Callable {
143✔
130
    return value?.kind === ValueKind.Callable;
19,326!
131
}
132

133
/**
134
 * Determines whether or not the provided value is an instance of a iterable BrightScript type.
135
 * @param value the BrightScript value in question.
136
 * @returns `true` if `value` can be iterated across, otherwise `false`.
137
 */
138
export function isIterable(value: BrsType): value is Iterable {
143✔
139
    return "get" in value && "getElements" in value && "set" in value;
18,416✔
140
}
141

142
/**
143
 * Determines whether or not the given value can be compared as a string.
144
 * @param value the BrightScript value in question.
145
 * @returns `true` if `value` can be compared as a string, otherwise `false`.
146
 */
147
export function isStringComp(value: BrsType): value is BrsString & Comparable {
143✔
148
    return isBrsString(value) || value instanceof RoPath;
2,517✔
149
}
150

151
/** Determines whether or not the given value is a BrightScript boxed number.
152
 * @param value the BrightScript value in question.
153
 * @returns `true` if `value` is a boxed number, otherwise `false`.
154
 */
155
export function isBoxedNumber(value: BrsType): value is BoxedNumber {
143✔
156
    return (
37,978✔
157
        value instanceof roInt ||
151,850✔
158
        value instanceof roFloat ||
159
        value instanceof roDouble ||
160
        value instanceof roLongInteger
161
    );
162
}
163

164
/** The set of BrightScript numeric types. */
165
export type BrsNumber = Int32 | Int64 | Float | Double;
166

167
/** The set of BrightScript boxed numeric types. */
168
export type BoxedNumber = roInt | roFloat | roDouble | roLongInteger;
169

170
/**
171
 * Determines whether or not the given value is a BrightScript event component.
172
 * @param value the BrightScript value in question.
173
 * @returns `true` if `value` is a BrightScript event component, otherwise `false`.
174
 */
175
export function isBrsEvent(value: BrsType): value is BrsEvent {
143✔
NEW
176
    return (
×
177
        value instanceof RoDeviceInfoEvent ||
×
178
        value instanceof RoSGNodeEvent ||
179
        value instanceof RoSGScreenEvent
180
    );
181
}
182

183
// The set of BrightScript Event components
184
export type BrsEvent = RoDeviceInfoEvent | RoSGNodeEvent | RoSGScreenEvent;
185

186
/**
187
 * The set of all comparable BrightScript types. Only primitive (i.e. intrinsic * and unboxed)
188
 * BrightScript types are comparable to each other.
189
 */
190
export type BrsPrimitive = BrsInterface | BrsInvalid | BrsBoolean | BrsString | BrsNumber;
191

192
/** The set of BrightScript iterable types. */
193
export type Iterable = RoArray | RoList | RoAssociativeArray | RoByteArray;
194

195
// this is getting weird - we need a lesThan and greaterThan function?!
196
export type AllComponents = { kind: ValueKind.Object } & BrsComponent & BrsValue;
197

198
/** The set of all supported types in BrightScript. */
199
export type BrsType = BrsPrimitive | Iterable | Callable | AllComponents | Uninitialized;
200

201
// Function to check if the value is a BrightScript Type
202
export function isBrsType(value: any): value is BrsType {
143✔
203
    return (
2,008✔
204
        isBrsBoolean(value) ||
11,275✔
205
        isBrsString(value) ||
206
        isBrsNumber(value) ||
207
        value === BrsInvalid.Instance ||
208
        value instanceof BrsComponent ||
209
        value instanceof Callable ||
210
        value instanceof Uninitialized
211
    );
212
}
213

214
/** The valid ISO Date formats for roDateTime and roTimeSpan parsing */
215
export const ValidDateFormats = [
143✔
216
    "YYYY-MM-DDTHH:mm:ss.SSS[Z]",
217
    "YYYY-MM-DDTHH:mm:ss.SSS",
218
    "YYYY-MM-DDTHH:mm:ss[Z]",
219
    "YYYY-MM-DDTHH:mm:ss",
220
    "YYYY-MM-DDTHH:mm[Z]",
221
    "YYYY-MM-DDTHH:mm",
222
    "YYYY-MM-DDTHH[Z]",
223
    "YYYY-MM-DDTHH",
224
    "YYYY-MM-DDT",
225
    "YYYY-MM-DD[Z]",
226
    "YYYY-MM-DD",
227
    "YYYY-MM[Z]",
228
    "YYYY-MM",
229
    "YYYY[Z]",
230
    "YYYY",
231
];
232

233
/**
234
 * Converts a JavaScript object or Map to a RoAssociativeArray, converting each property or entry to the corresponding BrightScript type.
235
 * @param input The JavaScript object or Map to convert.
236
 * @returns A RoAssociativeArray with the converted properties or entries.
237
 */
238
export function toAssociativeArray(input: any): RoAssociativeArray {
143✔
239
    const associativeArray = new RoAssociativeArray([]);
292✔
240
    if (input instanceof Map) {
292✔
241
        input.forEach((value, key) => {
68✔
242
            let brsKey: BrsString;
243
            if (typeof key === "string") {
×
244
                brsKey = new BrsString(key);
×
245
            } else {
246
                throw new Error(`Unsupported key type: ${typeof key}`);
×
247
            }
248
            associativeArray.set(brsKey, brsValueOf(value), true);
×
249
        });
250
    } else if (typeof input === "object" && input !== null) {
224!
251
        for (const key in input) {
224✔
252
            if (input.hasOwnProperty(key)) {
2,130✔
253
                const brsKey = new BrsString(key);
2,130✔
254
                associativeArray.set(brsKey, brsValueOf(input[key]), true);
2,130✔
255
            }
256
        }
257
    } else {
258
        throw new Error(`Unsupported input type: ${typeof input}`);
×
259
    }
260
    return associativeArray;
292✔
261
}
262

263
/**
264
 * Converts a value to its representation as a BrsType. If no such
265
 * representation is possible, throws an Error.
266
 * @param {any} x Some value.
267
 * @return {BrsType} The BrsType representation of `x`.
268
 * @throws {Error} If `x` cannot be represented as a BrsType.
269
 */
270
export function brsValueOf(x: any): BrsType {
143✔
271
    if (x === null || x === undefined || Number.isNaN(x)) {
2,148✔
272
        return BrsInvalid.Instance;
5✔
273
    }
274
    const maxInt = 0x80000000;
2,143✔
275
    const t: string = typeof x;
2,143✔
276
    switch (t) {
2,143!
277
        case "boolean":
278
            return BrsBoolean.from(x);
17✔
279
        case "string":
280
            return new BrsString(x);
73✔
281
        case "number":
282
            if (Number.isInteger(x)) {
45✔
283
                return x >= -maxInt && x < maxInt ? new Int32(x) : new Int64(x);
40✔
284
            }
285
            return x >= -3.4e38 && x <= 3.4e38 ? new Float(x) : new Double(x);
5!
286
        case "object":
287
            if (isBrsType(x)) {
2,008✔
288
                return x;
2,002✔
289
            } else if (Array.isArray(x)) {
6✔
290
                return new RoArray(x.map(brsValueOf));
2✔
291
            }
292
            return toAssociativeArray(x);
4✔
293
        default:
294
            throw new Error(`brsValueOf not implemented for: ${x} <${t}>`);
×
295
    }
296
}
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

© 2025 Coveralls, Inc