JavaScript

出てくるもの

.lps 一つにつき ES モジュール一つと、その隣にソースマップが出ます。推論の結果をコード生成が受け取るので、型が分かっている算術は演算子になり、クラスへの送信はメソッド呼び出しになります。

static fact$(n) {
  return ((n <= 1) ? 1 : (n * Calc.fact$((n - 1))));
}

$.Http.get$("orders.json");
$.Json.parse$($.send(r, "body", []));

ただし、組み込み型への操作は今も $.send を通ります。Str は JavaScript の文字列そのもの、Array は JavaScript の配列そのものです。そこには ,collect: にあたるメソッドがありません。プロトタイプに足すこともしません。だから呼び先を静的に決められず、実行時に選びます。実際の画面では、送信の大半がこれです。

速さへの影響は測ってあります。一描画のうち $.send が占めるのは 1% 未満です。この形にしておくと、組み込み型のセレクタが何を意味するかを決める場所が一箇所で済みます。

JavaScript に届く

読むべき .d.ts はありません。使うものを自分で宣言します。OCaml の external や Haskell の FFI と同じやり方です。

Extern subclass: #Session global: 'sessionStorage'.
Session class >> getItem: Str -> Maybe[Str].
Session class >> setItem: Str with: Str -> Unit.

Extern subclass: #Ctx.
Ctx >> fillRect: Int y: Int w: Int h: Int -> Unit.
Ctx >> fillStyle := Str.

書けるのは、グローバル、モジュール(from: 'node:path')、コンストラクタ(new:)、プロパティの読み、プロパティへの代入。これで全部です。localStorageWebSocket も canvas も locationrequestAnimationFrame も、この形で届きます。どれも言語には入っていません。

境界での変換

宣言した型が変換の仕方を決めます。型の内側まで辿って変換します。

JavaScript へJavaScript から
Int Float Str Bool素の値として$.int など
Date'2026-08-12'。暦の日付は時間帯を持たない$.date
Maybe[T]値か null。中身も変換する$.maybe
Dict[Str V]素のオブジェクト。値も変換する$.dict
Array[T]T がそのままなら、そのまま複製して凍らせる
Future[T]そのまま。Future は Promise そのものそのまま

正直な読み方が一つに決まらないものは、半端に変換せずに断ります。

"take:" cannot cross to JavaScript: JavaScript has no decimal, and which way to
lose that is the caller's to choose — send `asString` to keep the digits,
`asFloat` to compute with it

ActorRef も同じ理由で断ります。住所はこのランタイムの外では意味を持ちません。

難読化はできません

出てくる JavaScript に、名前を潰す道具(terser や uglify の mangle)をかけると壊れます。理由は二つです。

送信はセレクタを文字列で運びます。 $.send(o, "at:put:", [...])"at:put:" はランタイム側のメソッド名と一致していなければなりません。プロパティ名を潰すと、この二つがずれます。

Html clone: はデザイナのページと CSS セレクタで突き合わせます。 '#lines tr' のような文字列まで潰すと、ページとの照合が外れます。

除外リストを作れば動きますが、画面を増やすたびに伸びます。難読化を前提にした運用は勧めません。

配るときに気をつけること

lpsc build.mjs の隣に .mjs.map を書きます。このソースマップには .lps が丸ごと入っています。 コメントも含めてです。配布するのは .mjs だけにしてください。

読める JavaScript が残ることについては、そのままで構いません。難読化は読む手間を上げるだけで、守りにはなりません。権限の判断(この人に単価を見せてよいか、この受注を進めてよいか)は、サーバで行ってください。そこで行っていれば client が読めても失うものはなく、行っていなければ難読化しても通信を見れば分かります。