2026-05-28 21:34:11 +02:00
2026-05-28 17:44:53 +02:00
2026-05-28 21:34:11 +02:00
2026-05-25 01:45:05 +02:00
2026-05-27 17:54:01 +02:00
2026-05-25 01:45:05 +02:00
2026-05-28 17:44:53 +02:00
2026-05-27 17:54:01 +02:00
2026-05-28 17:44:53 +02:00

js-maker

A syntax-driven Racket-to-JavaScript macro module.

This js-maker module was started as part of racket-webview, and has since evolved under supervision of the author using ChatGPT as AI agent.

Layout

js-maker/
  main.rkt                         public macro module
  info.rkt                         package metadata and package test entry
  scrbl/
    js-maker.scrbl                 Scribble documentation
  testing/
    jsmaker-executors.rkt          JavaScript engine discovery/execution
    jsmaker-test-framework.rkt     JS regression framework
    jsmaker-test-runner.rkt        old-name compatibility wrapper
    jsmaker-regression.rkt         core expression tests
    jsmaker-regexp-regression.rkt  regexp tests
    jsmaker-program-regression.rkt larger program tests
    jsmaker-regressions.rkt        aggregate test entry
  demo/
    show-jsmaker-output.rkt
    show-optimized.rkt

Added language support

This package includes conservative support for:

  • (with-handlers ([exn? handler]) body ...), translated to JavaScript try/catch. Only generic exn? predicates are accepted.
  • Gregor-style local names such as date, time, moment, parse-date, parse-time, parse-moment, date->string, time->string, ->year, ->month, ->day, ->hours, ->minutes, ->seconds, ->js-date, and js-date->datetime. Import prefixes are deliberately not hardcoded; the compiler matches on the local identifier name after any prefix: part.

Run tests

From the directory above jsmaker:

raco make jsmaker/main.rkt jsmaker/testing/jsmaker-regressions.rkt \
  jsmaker/scrbl/jsmaker.scrbl
racket jsmaker/testing/jsmaker-regressions.rkt
raco test -p jsmaker

The test framework looks for JavaScript engines such as node, deno, bun, qjs, d8, jsc, js. Chromium is only used when explicitly selected or when JSMAKER_BROWSER_FALLBACK=1 is set.

When no JavaScript engine is available, the tests generate the JavaScript test files and use an explicit non-failing-javascript-stub. The stub prints notes to stdout, does not execute the generated JavaScript, and succeeds unless JSMAKER_REQUIRE_ENGINE or JSMAKER_REQUIRE_NODE is set. This avoids package server failures caused solely by a missing JavaScript runtime.

Useful environment variables:

JSMAKER_ENGINE=auto|node|deno|bun|qjs|d8|jsc|js|chromium
JSMAKER_ENGINE_PATH=/path/to/executable
JSMAKER_NODE=/path/to/node
JSMAKER_REQUIRE_ENGINE=1
JSMAKER_ENGINE_TIMEOUT_SECONDS=15
JSMAKER_BROWSER_FALLBACK=1

Suggested start prompt for future work

Use this prompt when asking ChatGPT to make a new Racket module or extend this one:

Work on a Racket module/package in a versioned build directory.

Important:
- Always create a new subdirectory for the deliverable, for example
  /mnt/data/<project>-build-NNN/<collection-name>.
- Do not work directly in /mnt/data with loose files that have the same names;
  avoid version confusion by copying and patching everything inside that build
  directory.
- Keep the package structure stable:
  - main.rkt for the public module;
  - testing/ for test infrastructure and regression tests;
  - demo/ for demonstration files;
  - info.rkt for package metadata and test entry points.
- Adjust require paths to that structure before testing.
- Test with Racket itself, for example:
  /tmp/racket/bin/raco make <collection>/main.rkt <collection>/testing/<tests>.rkt
  /tmp/racket/bin/racket <collection>/testing/<tests>.rkt
- If JavaScript execution is needed, use a separate executor/test-framework
  module. Tests must not fail solely because node/deno/bun/qjs is missing; in
  that case they should use an explicit non-failing JavaScript stub that reports
  this to stdout, unless a REQUIRE environment variable is set.
- Do not use shell-based internet access for dependencies. If packages are
  needed, fetch them through the rktsndbx bootstrap/package-index flow.
- Deliver a zip file containing exactly the tested build directory.
- Briefly report which commands were run, what the test results were, and which
  zip contains the tested result.

Latest tested fix

This build includes the with-handlers callee-position fix for inline lambda handlers, including rest-argument handlers such as (lambda args ...). It also fixes top-level js statement-context handling in general: js now emits program/statement text and does not invent an implicit top-level return. This keeps snippets valid when they are passed directly to WebView runJavaScript/evaluateJavaScript, where a top-level JavaScript return is a syntax error. Use js/expression when a generated JavaScript value is needed. The build also adds a Racket-like division-by-zero runtime check for /, so the generic exn? handler subset can catch (/ 10 0).

JavaScript use case demos

The package includes a larger set of JavaScript use case snippets in demo/js-usecases.rkt. They are written in the Racket surface syntax accepted by js and compiled to JavaScript by the macro. The generated JavaScript is also written to demo/js-usecases.generated.js.

The corresponding regression tests live in testing/jsmaker-usecases.rkt and are included by testing/jsmaker-regressions.rkt. The test framework now awaits Promise-valued tests, so asynchronous examples such as the Fetch API can be checked with Node as well.

Covered use cases include random numbers, Set, JavaScript falsey values, currying, object destructuring, setInterval/clearInterval, object property get/set/delete, string concatenation order, Object.freeze/Object.seal, switch/case, classes with constructor defaults, sorting objects, array deletion techniques, Bubble Sort, recursive Binary Search, Map counting, DOM HTML access, anagram checks, pair-sum checks, and Fetch API result/error handling.

Use-case documentation

The file scrbl/usecases.scrbl documents the JavaScript use cases from demo/js-usecases.rkt. Each use case is shown as Racket/js-maker source next to representative generated JavaScript, followed by the behavior covered by the regression test.

The use-case tests in testing/jsmaker-usecases.rkt intentionally use js/expression for the test calls wherever possible. Raw JavaScript is kept only for small test-harness preambles such as fake timers, fake DOM objects, and fake fetch.

Hash regression tests

This build adds testing/jsmaker-hash-regression.rkt, covering common hash operations such as hash, make-hash, hash-ref, hash-set, hash-set!, hash-remove, hash-remove!, hash-update, hash-update!, hash-clear, hash-clear!, hash-copy, hash-keys, hash-values, hash->list, hash-map, and hash-for-each. The current JavaScript backend represents hashes as plain JavaScript objects, so this is a practical string/symbol-key subset rather than a full Racket hash-table implementation for arbitrary keys.

S
Description
Converts simple scheme expressions to javascript for use as javascript code.
Readme MIT 366 KiB
Languages
Racket 99.7%
Makefile 0.3%