Skip to content

Advisory: TypeScript-for-AutoJs6/Rhino gotchas found + a fork-agnostic verification toolkit #563

Description

@djbclark

New community toolkit: TypeScript-for-AutoJs6 gotchas + a fork-agnostic verification suite

First, thank you for AutoJs6 — it's the backbone of a fairly involved fleet-automation project of mine, and it's been a genuinely solid piece of software to build on.

While debugging a production bug this week, I ran into four separate, previously-undocumented (as far as I could find) mismatches between what tsc/Node-based tests accept and what AutoJs6's bundled Rhino engine actually runs — each invisible until the compiled output executed on a real device. I ended up writing a small, fork-agnostic toolkit documenting all four with runnable reproductions, in case it saves someone else the same debugging session:

https://github.com/djbclark/autojs6-typescript

Summary of what it covers (full writeup + runnable broken examples in the repo):

  1. Two files anywhere in the require graph independently require()-ing the same module under the same local binding name (e.g. const log = require("./log.js") in two different files) crash the whole script the moment both load: TypeError: redeclaration of var log. (jvm-npm.js#67). Reproducible with a minimal 2-file example, independent of const/let/var, independent of which file is the entry script.
  2. The entry script (main.js, executed directly by the engine, never require()'d) can't carry TypeScript's CommonJS exports stamp — any .ts file with import/export syntax gets Object.defineProperty(exports, "__esModule", ...) unconditionally, which throws ReferenceError: "exports" is not defined. when it's the entry script rather than a required module.
  3. for...of throws EvaluatorException: syntax error at runtime specifically under "use strict" (which every tsc-compiled file has) — a parse-time error, not a compile-time one, so nothing catches it before deploy.
  4. Some host APIs return a Java/Kotlin object whose contract is "call toString()" rather than a genuine JS string (confirmed case: Engine.getSource()) — calling .indexOf()/.trim()/etc. directly on it throws TypeError: Cannot find function indexOf. even when a .d.ts types it string.

I got stuck trying to reproduce #1 outside a real device — tracing RhinoJavaScriptEngine.init() / ScriptRuntime.rhinoRequireFunction suggests jvm-npm.js should ultimately delegate to Rhino's official, properly-isolating commonjs.module.Require, but I couldn't close the gap between that and what actually happens on-device (or replicate it via raw Java interop from a standalone Rhino shell) with the time I had. Full investigation notes are in the repo's examples/broken/01-redeclaration/README.md — if anyone with more Rhino/AutoJs6 internals context can pin down the exact mechanism, I'd genuinely appreciate it, and I'm happy to fold a fix or better repro back into the toolkit.

Not asking for anything here beyond a heads-up in case it's useful — feel free to close if it's not the right venue. Thanks again for the project.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions