In this update
Welcome to the March 2024 edition of “What’s New in RokuCommunity.” Please consider subscribing to stay up to date with what’s happening in RokuCommunity.
The RokuCommunity projects are maintained by a relatively small group of developers (mostly volunteers), and we have a growing list of unresolved issues. We need your help! There are many different ways you can contribute. Whether it’s addressing bugs, improving documentation, introducing new features, or simply helping us manage our expanding list of GitHub issues, your involvement would be greatly appreciated. We are more than happy to guide you in finding the most suitable contribution method that aligns with your interests. To learn more about how you can contribute, feel free to reach out to us on Slack, or explore the existing GitHub issues:
This month we added a new panel called “Roku File System”. This panel will be avaiable anytime the app is running with RDB enabled, and will show all the files in your app as they exist on-device.
Another new panel we’ve added is called “Roku App Overlays”. This panel enables you to register images that will be overlayed onto your running application. This is incredibly useful when trying to build out UI elements against an existing mockup image. This panel will be active anytime the app is running with RTA enabled. Here’s a quick demo showing how it works. You can show and hide the image, change its transparency, rename the image, add multiple images, etc.
We’ve improved the document symbols included within vscode. Several symbol types were missing, such as constants, enums, and certain classes.
We also removed the leading namespace values from relevat symbols since they’re shown in grey next to the symbols anyway. This improves searchability for these symbols as vscode would get confused when typing the symbols without leading namespaces in some situations.
Before:
After:
We’ve been having issues with some of the panels from the BrightScript Language vscode extension randomly disconnecting from the Roku device during debug sessions. We’ve fixed several bugs causing this issue. There’s not much to show here, but hopefully you will see more stability when using these features in the future.
The Roku Device View panel in vscode works by capturing screenshots as fast as the device can generate them. We noticed this was causing issues when sideloading new app builds to the device, as we must be putting too much stress on the device during that time which causes the device to time out. To mitigate this, we now pause the device view screenshot capturing during the sideloading process. This has significantly reduced the failure rate during the sideloading process. Once the device successfully sideloads the app, we resume the screenshot behavior, so you shouldn’t notice any difference in experience.
As of vscode v2.46.0, you can now further customize your launch process. Many developers have custom build processes such as makefile or shell scripts. Historically, the vscode extension hasn’t supported this process because the extension needs to be in control over the entire process. However, we felt it was important for dev teams to be able to use as much of their existing build process as possible.
We’ve added the ability to register a custom packageTask
that will bulid the .zip
instead of having vscode build it. VSCode still needs to be the one moving files into the staging directory, but if you have a custom zipping process, this will now allow you to leverage that feature. Here’s an example launch.json with these new features:
{
//this is a vscode "task" which should be registered in ./vscode/tasks.json
"packageTask": "name-of-task-that-zips-your-app",
//where should vscode put the files that are ready to be staged?
"stagingDir": "./dist",
//where did you put your zip?
"packagePath": "./out/custom.zip"
}
We’ve also added a few missing launch.json settings such as stagingDir
(not sure how that one went undocumented for so long…).
If you’ve ever used the “Roku Devices” panel, you may have noticed that you couldn’t copy numeric values to the clipboard. That has now been fixed as of vscode extension v2.46.1!
Before:
After:
We’ve fixed some issues with syntax highlighting for conditional compile items with spaces between #
and the next keyword (we didn’t even know BrightScript supported spaces there!).
Before:
After:
We fixed a bug when evaluating optional chaining expressions in the vscode REPL or watch panel that would crash instead of properly evaluating the expression. Here are some examples of expressions that should now properly evaluate:
print m.top.gridState?.leftEdgeTime
print m.top.gridState?["leftEdgeTime"]
print m.top.gridState?.["leftEdgeTime"]
If you haven’t been using diagnosticFilters
in brighterscript yet, you should definitely take a look at the docs. These filters support ignoring a list of diagnostics for a specific file or groups of files. Developers commonly use these to ignore errors in vendor libraries that they don’t have direct control over modifying (or don’t want to modify).
This month we added support for negated patterns in the src patters, which is makes the feature even more powerful. You can now do things like this:
"diagnosticFilters": [
{ "src": "vendor/**/*" }, //ignore all errors from vendor libraries
{ "src": "!*/**/*", "codes": [1000] } //except DO show this particular code everywhere
]
What’s great about this is you can even stack multiple patterns together to curate a very specific list of diagnostics, by combining negative and positive patterns, codes, etc.
We’ve had a longstanding bug that when using enums in a ternary expression, the transpiled could would incorrectly inject those enum values into the bslib_ternary()
call. This wouldn’t cause runtime errors since they were never referenced, but it did produce unused variable
errors on-device.
Here’s an example of the issue. This ternary operation:
buttonBaseWidth = (nodeId = "closedCaptions") ? ClosedCaptionsButtonSize.Width : ThumbButtonSize.Width
Would transpile to:
buttonBaseWidth = (function(__bsCondition, ClosedCaptionsButtonSize, ThumbButtonSize)
if __bsCondition then
return 38
else
return 40
end if
end function)((nodeId = "closedCaptions"), ClosedCaptionsButtonSize, ThumbButtonSize)
Notice the ClosedCaptionsButtonSize
being passed as a variable? That causes an unused variable
device warning in the console when the app is sideloaded.
BrighterScript v0.65.26
includes a fix for this issue, and now the names of these enums are omitted from the transpiled output (which is fine since the enums were injected into the inner function body already anyway.
buttonBaseWidth = (function(__bsCondition)
if __bsCondition then
return 38
else
return 40
end if
end function)((nodeId = "closedCaptions"))
You can check out the pull request for how we solved this, or the original issue if you’re curious what the
Starting in BrighterScript v0.65.27, plugin authors can contribute their own document and workspace symbols by using thes enew plugin hooks:
beforeProvideDocumentSymbols
provideDocumentSymbols
afterProvideDocumentSymbols
beforeProvideWorkspaceSymbols
provideWorkspaceSymbols
afterProvideWorkspaceSymbols
We’ve moved the brighterscript logic into the internal brighterscript plugin, so plugin authors can review DocumentSymbolProcessor and WorkspaceSymbolProcessor for examples of how to contribute these symbols. It’s also worth looking at how we’ve implemented our AST walking to discover symbols, which can be found in this PR.
Many brighterscript plugins use Parser.parse()
to generate AST used to replace existing code. This causes the generated sourcemaps to be very incorrect. To mitigate this, we added support for generating AST without any range information at all.
Now most expressions and statements can transpile to proper code without needing location information. There was a lot of internal brighterscript typescript code that didn’t like when AST nodes had null ranges and there may be some edge cases, but we believe we’ve fixed most of those issues.
Here’s how you can leverage this new functionality:
const tokens = Parser.parse('print hello', { trackLocations: false });
The tokens array will have all the same tokens, but none of them will have location information, making them much safer to inject into AST without messing with sourcemaps.
We’ve updated the broadcast safe color for white to now be #EBEBEB
instead of #DBDBDB
. In the future, we’d love to make this list configurable, so if you have any interest in contributing to this, let us know.
The brs project is a BrightScript interpreter that runs off-device, and is implemented in javascript.
roString
methods startsWith()
and endsWith()
We’ve added runtime support for the startsWith()
and endsWith()
methods on the roString
object. Here’s the new methods in action in the brs repl:
We discovered that the MOD operator in BrightScript always truncates the result value, even for float and double values. We’ve aligned the brs runtime to match this behavior.
Before:
After:
We fixed several Windows-specific crashes where brs was not correctly handling Windows path separators. We’ve fixed these bugs which should now allow brs to run more consistently in Windows environments.
roList
We’ve added support for roList
, and both File
and String
now use it.
insertSpaceAfterConditionalCompileSymbol
, fix conditional compile formattingRokuCommunity’s brightscript and brighterscript formatter has gotten a a new formatting option called insertSpaceAfterConditionalCompileSymbol
. This option manages spacing between the #
and the following keyword. When true
, the formatter will add a single space character, and when false
it will remove all whitespace between them.
We’ve also fixed indentation issues with conditional compile tokens that have spaces after the #
(like # if
, # else if
, etc…).
As we create new v1 alpha releases of brighterscript, we’re also keeping the v1 belint alphas in sync. So for example, if you install brighterscript v1.0.0-alpha.28
, you should also install bslint v1.0.0-alpha.28
. There are breaking changes happening between each alpha release of brighterscript v1, which means bslint also needs to target that same bsc version.
We’ve got another great month full of improvements to the brighterscript v1 alpha releases. Here are some of the highlights:
CommentStatement
and all comment tokens from Lexer outputComments in BrighterScript AST have always felt like a hack. Many parsers from other languages (such as TypeScript, eslint, the roslyn compiler, etc…) store comments as trivia rather than actual nodes in the abstract syntax tree. As of brighterscript v1.0.0-alpha.28
, we have now done the same. Here are the changes:
CommentStatement
and CommentExpression
. Comments now reside SOLELY in a new AstNode and token property called leadingTrivia
.TranspileState.transpileToken()
will automatically transpile comments (if they exist) ahead of the token}
, end sub
, etc), use TranspileState.transpileEndBlockToken()
This is probably one of the impactful breaking changes in the BrighterScript v1 releases. We’ll have more information in the coming months, but you can always look through the brighterscript source code for how leading/trailing trivia is handled.
We’ve added const types and for-each loop vars to the hover in VSCode.
Variable shadowing in brighterscript has always been a bit challenging. Previously, you couldn’t have a local variable share the same name as a global function. The same issue was present for classes, namespaces, interfaces, enums, consts, etc. This forced developers to find alternative local variable or parameter names, which could be quite frustrating.
Starting in brighterscript v1.0.0-alpha.28
, we’ve improved this situation significantly. You can now declare a local variable that has the same name as a parent item, and the parent item is “shadowed”/hidden, meaning your local variable wins. You can read the docs to learn more about how all of this new logic works.
here’s some example code:
function alpha()
print "global alpha()"
end function
function test()
alpha() ' prints "global alpha()"
end function
namespace beta
function alpha()
print "beta.alpha()"
end function
function test()
alpha() ' prints "beta.alpha()"
end function
namespace charlie
function alpha()
print "beta.charlie.alpha()"
end function
function test()
alpha() ' prints "beta.charlie.alpha()"
end function
end namespace
end namespace
m
type is now AssociativeArray
We fixed a bug where the m
variable inside an anonymous function inside a class method was incorrectly thinking it was the m
from the class itself. Here’s a screenshot of the error:
As of brighterscript v1.0.0-alpha.28
, that m
will now just be a plain AssociativeArray
Starting in v1.0.0-alpha.28
, when a Class constructor function is used outside of new
it is now treated as a function type, allowing code completion and validation based on that.
We’ve fixed a bug when a parameter has an unresolved type that causing the variable to be marked as “unknown”.
Here’s the issue:
And now we show better errors, like this:
We’ve made the following fixes to mitigate the issue:
typeExpression
in an assignment statementThe BrighterScript transpiler tries its best to produce valid brightscript code, even if sometimes the original code was not valid. One such example is the throw
statement. If you forget to include an error message, brighterscript would auto-include a generic "An error has occurred"
message. However, that message didn’t align with the default message found on device. So we’ve aligned with that, and that message is now "User-specified exception"
. We recommend always writing your own messages so you can more clearly understand them throughout your code, but at least now the messages are aligned with what the device will produce.
Example. This:
sub main()
try
throw 'bs:disable-line
catch e
end try
end sub
Will now transpile to this:
sub main()
try
throw "User-specified exception"
catch e
end try
end sub
For contributors to BrighterScript, we’ve moved all of the logic from scope.validate()
into the BscPlugin
class, further aligning our internal plugin system with the exact same rules and restrictions that third party plugins follow. There’s not much to show here, you can check out the brighterscript#1105 to see the changes we made.
AssociativeArray
types now follow the same pattern as Class
types, where the built in members are from a different symbol provider, so if they are overriden, the overriden type info is used.
Here’s a screenshot of the original issue:
We fixed a bug with bitwise and
and or
operators showing incorrect types in the type system.
Prior to v1.0.0-alpha.28
, here’s what the type system would see:
And now we correctly show:
Historically the BrightScript runtime would only support functions having a maximum of 32 parameters. However, sometime around Roku OS 11.5, they increased this limit to 64. We’ve updated this limit in brighterscript as well, so you can now utilize all of those extra function parameters.
Before:
After:
We’ve added significant validation performance improvements starting in v1.0.0-alpha.29
. The first fix added some caching for local variable validations, checking only un-changed AstSegment
s for function shadowing if those segments make an assignment to a symbol that changed.
Before:
validate@local ---------- 51.368 ops/sec
validate@0.65.26 --------- 101.435 ops/sec
After:
validate@local --------- 286.331 ops/sec
validate@0.65.26 --------- 102.877 ops/sec
We’ve improved overall validation times for most scope validations. Here are some of the changes we made:
Overall, this should cut initial validation time down to about 40%, and should make validation changes in editor much faster…
BEFORE:
% npm run validate
> jellyfin-roku@2.0.5 validate
> npx bsc --copy-to-staging=false --create-package=false
[10:21:34:1920 PM] Using config file: "/roku/jellyfin-roku_2/bsconfig.json"
[10:21:34:1940 PM] Loading 0 plugins for cwd "/roku/jellyfin-roku_2"
[10:21:34:2060 PM] load files
[10:21:34:8270 PM] load files finished. (620.515ms)
[10:21:34:8270 PM] Validating project
[10:21:44:6830 PM] Validating project finished. (9s855.268ms)
AFTER (this is log-level “info”):
% npm run validate
> jellyfin-roku@2.0.5 validate
> npx bsc --copy-to-staging=false --create-package=false --log-level=info
[11:44:09:6900 AM] Using config file: "/roku/jellyfin-roku_2/bsconfig.json"
[11:44:09:6920 AM] Loading 0 plugins for cwd "/roku/jellyfin-roku_2"
[11:44:09:7010 AM] load files
[11:44:10:2920 AM] load files finished. (590.650ms)
[11:44:10:2920 AM] Validating project
[11:44:10:6730 AM] Build component types
[11:44:10:7000 AM] Build component types finished. (27.114ms)
[11:44:10:7010 AM] Validate all scopes
[11:44:14:3260 AM] Validate all scopes finished. (3s624.666ms)
[11:44:14:3260 AM] Validation Metrics: filesValidated=305, fileValidationTime=276.499ms, fileInfoGenerationTime=103.664ms,
programValidationTime=0.308ms, scopesValidated=139, totalLinkTime=600.8ms,
totalScopeValidationTime=2s944.775ms, componentValidationTime=0.567ms
[11:44:14:3290 AM] Validating project finished. (4s37.58ms)
[11:44:14:3300 AM] Program.getDiagnostics()
[11:44:14:3380 AM] diagnostic counts: total=54, after filter=50
[11:44:14:3380 AM] Program.getDiagnostics() finished. (8.233ms)
[11:44:14:3400 AM] Program.getDiagnostics()
[11:44:14:3430 AM] diagnostic counts: total=54, after filter=50
[11:44:14:3430 AM] Program.getDiagnostics() finished. (3.603ms)
We’ve null safety issues in Statement
and Expression
. There isn’t much else to say here other than when we eventually address all of the null safety issues in the brighterscript codebase, we’ll be enabling it by default. This should help us catch a whole category of additional bugs at development time. You can review brighterscript#1033 for more information.
Last but certainly not least, a big Thank You to the following people who contributed this month:
Contributions to vscode-brightscript-language:
Contributions to brighterscript:
CommentStatement
and all comment tokens from Lexer output (PR #1083)create-test-package
command for easier tgz testing (PR #1088)Contributions to roku-deploy:
Contributions to roku-debug:
Contributions to brighterscript-formatter:
insertSpaceAfterConditionalCompileSymbol
, fix conditional compile formatting (PR #87)Contributions to bslint:
Contributions to ropm:
Contributions to brs:
Legal notice
The views and opinions expressed in this website and all of its pages are those from within our open source community and do not represent the views or positions of Roku, Inc. or any entities they represent.
Designed with @arturocuya, powered by Astro
by