Skip to main content

JavaScript Runtime Limits

Hosanna compiles TypeScript to BrightScript for Roku. Most application code can stay platform-neutral, but Roku is not a browser or a Node.js process: the compiler lowers supported JavaScript features to BrightScript and reports code it cannot preserve safely.

Treat compiler and Hosanna ESLint diagnostics as the contract. Do not assume that an old list of supported methods is authoritative, and do not suppress an HS-* diagnostic until you have checked the generated BrightScript and exercised the path on a device.

Verify With Project Tooling

Run both checks in an application:

npm run lint
npx hst build roku dev device

The application may wrap those commands with package scripts. See Linter and Diagnostics for filtering and suppression guidance.

High-Impact Differences

Browser and Node APIs

Roku code has no DOM, window, browser storage, Node.js filesystem, Buffer, or Node crypto. Use Hosanna abstractions such as views, IHosannaDevice, IDeviceRegistry, HTTP commands, and platform adapters. Keep browser-only code in web-target files and native-only work behind a bridge.

Numbers, Infinity, and NaN

BrightScript has no JavaScript Infinity or native NaN value.

  • Infinity produces HS-1038 and is lowered to 2147483647; do not rely on infinity arithmetic.
  • The NaN keyword is rejected. Conversion helpers use Hosanna's NaN-like representation internally.
  • Validate conversion results with Number.isNaN(value) or a documented fallback before arithmetic.
  • Number.isFinite is non-coercing, matching JavaScript: numeric values can be finite; strings and booleans are not.
  • parseInt supports prefixed hexadecimal, octal, and binary strings as well as an explicit radix.
  • parseFloat supports decimal and exponent notation.
const parsed = Number.parseFloat(input);
if (Number.isNaN(parsed)) {
return 0;
}
return parsed;

For values that require BrightScript's 64-bit integer form, opt in with roLongInteger:

const timestamp = HsDate.now() as roLongInteger;

The compiler cannot infer that requirement from TypeScript's number type.

Dates

The compiler remaps supported Date construction and static calls to Hosanna's HsDate implementation and reports the conversion. Prefer HsDate explicitly in shared code so that the runtime dependency and supported surface are clear.

const now = HsDate.now();
const date = new HsDate(now);

Only the HsDate methods implemented by the framework are portable to Roku.

APIs Are Allowlisted

Using a familiar JavaScript method does not prove it is available on Roku. The compiler checks the current shared allowlists and reports unsupported methods. Notable examples:

  • supported array methods include push, variadic unshift, flat, flatMap, findLast, and findLastIndex;
  • supported string methods do not currently include codePointAt or normalize;
  • supported object statics include assign, defineProperty, defineProperties, entries, getOwnPropertyNames, keys, and values;
  • object prototype and property-descriptor semantics are limited because BrightScript associative arrays do not have JavaScript prototype chains;
  • only the console methods in the shared allowlist are portable.

Avoid copying a method table into application code or suppressing an unsupported-method diagnostic based on older documentation.

Functions and Closures

BrightScript function values do not have all JavaScript closure semantics.

  • A closure cannot mutate a captured local. Hoist mutable state into an object or class field.
  • A closure cannot capture a variable from the expression that initializes that same variable.
  • Nested function declarations, generator functions, and yield are unsupported.
  • IIFEs are diagnosed; extract a named function or assign an arrow function before calling it.
  • Non-arrow closures cannot reliably use this.
  • Function references passed across a SceneGraph Task boundary must be exported module functions. See Async Function Pointers.
const state = { count: 0 };
const increment = () => {
state.count += 1;
};

Classes and Names

  • Classes declared inside functions are unsupported.
  • Private JavaScript class fields and methods are unsupported.
  • Class and module member names must be unique under BrightScript's case-insensitive name rules.
  • Duplicate class names are rejected where a runtime name would be ambiguous.
  • TypeScript namespaces are unsupported; use ES modules.

Modules and Static Data

Use TypeScript modules. JSON imports are not supported in Roku-transpiled source. Put runtime environment settings in the generated build config and load other static data through an application-owned asset or service layer.

pkg:/assets/meta/build-config.json

Do not use hs:no-module for ordinary application files. It exists for entry-point and interop cases, and top-level runtime statements in such a file are invalid.

Regular Expressions

BrightScript's roRegex does not support JavaScript's Unicode (u) or sticky (y) flags. The compiler reports these flags because Roku ignores them at runtime. Rewrite the expression instead of suppressing the diagnostic.

Async/Await

Async/await is experimental and off by default. Its Roku implementation supports a documented subset of named async functions and statement-position awaits. Awaits in loops, switches, finally blocks, compound expressions, async arrows, and several other shapes are rejected.

Read Experimental Async/Await on Roku before enabling it. Legacy direct HsPromise.then() calls remain synchronous for compatibility, and promises must not cross SceneGraph interpreter boundaries.

Portability Checklist

Before shipping a shared feature to Roku:

  1. Run the application linter and Roku compiler without hiding new HS-* diagnostics.
  2. Replace browser or Node APIs with Hosanna services.
  3. Check every unfamiliar built-in method against the installed supported-API package.
  4. Exercise number conversion, equality, dates, regexes, and closure-heavy code on Roku.
  5. Inspect generated BrightScript when a warning describes a lowering or slow path.
  6. Use targeted hs:disable-next-line HS-#### only after documenting why the emitted code is safe.

Keep suppressions narrow. A repository-wide suppression can hide a later use with different runtime behavior.

Talk to us