js-maker simpeler
This commit is contained in:
@@ -1,153 +1,12 @@
|
||||
# js-maker
|
||||
|
||||
A syntax-driven Racket-to-JavaScript macro module.
|
||||
A compact Racket-to-JavaScript string maker macro.
|
||||
|
||||
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.
|
||||
This js-maker 3 package is a clean restart from `js-transform.rkt`. It exports
|
||||
only:
|
||||
|
||||
## Layout
|
||||
- `js`
|
||||
- `js1`
|
||||
|
||||
```text
|
||||
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`:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```text
|
||||
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.
|
||||
There is deliberately no `js/expression` compatibility macro in this branch.
|
||||
Use `js1` when the expression-level generator is needed directly.
|
||||
|
||||
Reference in New Issue
Block a user