2026-05-28 09:26:39 +02:00
2026-05-28 09:26:39 +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-27 17:54:01 +02:00
2026-05-28 09:26:39 +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 version-locked buildmap.

Important:
- Always create a new subdirectory for the release, for example
  /mnt/data/<project>-build-NNN/<collection-name>.
- Do not work directly in /mnt/data with individual files of the same name;
  avoid version confusion by copying/patching everything into that buildmap.
- Keep the package structure consistent:
  - 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 match 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 is required, use a separate executor/test-framework module.
  Tests must not fail simply because node/deno/bun/qjs is missing; they must
  skip with clear warnings unless a REQUIRE environment variable has been set.
- Do not use shell-based internet access for dependencies. If packages are needed, retrieve
  them via the rktsndbx bootstrap/package-index flow.
- After completion, provide a zip file containing exactly the tested buildmap.
- Briefly report which commands were executed, what the test results were,
  and which zip file 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 for with-handlers, so a side-effecting catch handler does not prematurely return from the surrounding JavaScript wrapper. Use js/expression when the value of a with-handlers form itself 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%