Skip to content

Commit dbeb75a

Browse files
hyperpolymathclaude
andcommitted
refactor(tests): transpile TS test suite to ReScript
Converts all six TypeScript test files under tests/ to ReScript per the hyperpolymath language policy ("No new TypeScript files — Convert existing TS to ReScript"). The extension runtime is untouched: TS was only in tests/ and never shipped in the XPI (verified by unzipping fireflag-0.1.0.zip before the change). Files: tests/Bindings.res — Deno.test / std/assert bindings tests/unit/TypesTest.res — 23 tests (was types_test.ts) tests/unit/FlagEvaluationTest.res — 19 tests tests/property/FlagPropertiesTest.res — 18 tests tests/aspect/SecurityTest.res — 21 tests tests/e2e/ExtensionLifecycleTest.res — 13 tests tests/bench/FlagBench.res — 26 benchmarks Wire-up: rescript.json — tests/ added as a "dev" source subdir deno.json — added @rescript/runtime esm.sh mapping; test tasks now point at the compiled *.res.js outputs; --no-check bypasses the ReScript runtime's TS-from-d.ts resolution (which Deno's type-checker doesn't understand) .gitignore — ignore *.cmj / *.ast, and the lib/ocaml/*.res mirror the rescript compiler maintains as a cache (the four historically-tracked files are explicitly kept) Verification: deno task test → 94 passed | 0 failed (611ms) deno task test:bench → all 26 benchmarks run Semantic parity with the original TS suite was the only acceptance criterion. Heterogeneous flag values (TS `unknown`) are modelled as an abstract type with identity coercions (toU / fromU) — zero runtime cost. TS classes (FireflagExtension) become mutable records + top-level functions. The `effects`/`caps`/`loc` exclusions we applied in the typed-wasm ECHIDNA erasure test (sibling repo) are not relevant here; fireflag tests exercise behaviour, not proof erasure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 86ee226 commit dbeb75a

23 files changed

Lines changed: 5773 additions & 3036 deletions

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ ai-cli-crash-capture/
8585
*.cmt
8686
*.cmti
8787
*.cmi
88+
*.cmj
89+
*.ast
90+
# The rescript build mirrors each compiled source into `lib/ocaml/<Module>.res`
91+
# as a stable backup copy. The canonical sources live in `extension/lib/rescript/`
92+
# and `tests/` (see rescript.json). Ignore the mirror to keep git history clean.
93+
/lib/ocaml/*.res
94+
# Preserve the handful of files that ARE intentionally tracked there today
95+
# (historic BucklScript layout). `git add -f` can be used for new ones.
96+
!/lib/ocaml/BrowserAPI.res
97+
!/lib/ocaml/DatabaseUpdater.res
98+
!/lib/ocaml/DevTools.res
99+
!/lib/ocaml/Types.res
88100
target/
89101
node_modules/
90102
_build/

deno.json

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
"imports": {
33
"std/": "https://deno.land/std@0.220.0/",
44
"std/assert": "https://deno.land/std@0.220.0/assert/mod.ts",
5-
"std/testing/": "https://deno.land/std@0.220.0/testing/"
5+
"std/testing/": "https://deno.land/std@0.220.0/testing/",
6+
"@rescript/runtime/": "https://esm.sh/@rescript/runtime@12.1.0/"
67
},
78
"tasks": {
8-
"test": "deno test --allow-read tests/",
9-
"test:unit": "deno test --allow-read tests/unit/",
10-
"test:property": "deno test --allow-read tests/property/",
11-
"test:e2e": "deno test --allow-read tests/e2e/",
12-
"test:aspect": "deno test --allow-read tests/aspect/",
13-
"test:bench": "deno bench tests/bench/",
14-
"test:all": "deno test --allow-read tests/ && deno bench tests/bench/"
9+
"test": "deno test --allow-read --no-check 'tests/**/*Test.res.js'",
10+
"test:unit": "deno test --allow-read --no-check 'tests/unit/*Test.res.js'",
11+
"test:property": "deno test --allow-read --no-check 'tests/property/*Test.res.js'",
12+
"test:e2e": "deno test --allow-read --no-check 'tests/e2e/*Test.res.js'",
13+
"test:aspect": "deno test --allow-read --no-check 'tests/aspect/*Test.res.js'",
14+
"test:bench": "deno bench --no-check 'tests/bench/*Bench.res.js'",
15+
"test:all": "deno test --allow-read --no-check 'tests/**/*Test.res.js' && deno bench --no-check 'tests/bench/*Bench.res.js'"
1516
}
1617
}

rescript.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@
44
{
55
"dir": "extension/lib/rescript",
66
"subdirs": true
7+
},
8+
{
9+
"dir": "tests",
10+
"subdirs": true,
11+
"type": "dev"
712
}
813
],
914
"package-specs": [

tests/Bindings.res

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
// Copyright (c) 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
3+
//
4+
// Bindings for the Deno test runtime and the `std/assert` module used by
5+
// the fireflag test suites. The paths `"std/assert"` and `"std/testing/..."`
6+
// are resolved via the import map in `deno.json`.
7+
//
8+
// Kept terse — each binding is the minimum surface the test suites use.
9+
10+
// ── Deno.test ────────────────────────────────────────────────────────────
11+
12+
@scope("Deno") @val
13+
external test: (string, unit => unit) => unit = "test"
14+
15+
@scope("Deno") @val
16+
external testAsync: (string, unit => promise<unit>) => unit = "test"
17+
18+
// ── Deno.bench ───────────────────────────────────────────────────────────
19+
20+
@scope("Deno") @val
21+
external bench: (string, unit => unit) => unit = "bench"
22+
23+
// ── std/assert ───────────────────────────────────────────────────────────
24+
25+
@module("std/assert")
26+
external assertEquals: ('a, 'a) => unit = "assertEquals"
27+
28+
@module("std/assert")
29+
external assertEqualsMsg: ('a, 'a, string) => unit = "assertEquals"
30+
31+
@module("std/assert")
32+
external assertStrictEquals: ('a, 'a) => unit = "assertStrictEquals"
33+
34+
@module("std/assert")
35+
external assertExists: 'a => unit = "assertExists"
36+
37+
@module("std/assert")
38+
external assertNotEquals: ('a, 'a) => unit = "assertNotEquals"
39+
40+
@module("std/assert")
41+
external assertThrows: (unit => 'a) => unit = "assertThrows"
42+
43+
@module("std/assert")
44+
external assertThrowsMsg: (unit => 'a, string) => unit = "assertThrows"
45+
46+
@module("std/assert")
47+
external assertMatch: (string, Js.Re.t) => unit = "assertMatch"
48+
49+
@module("std/assert")
50+
external assertStringIncludes: (string, string) => unit = "assertStringIncludes"
51+
52+
@module("std/assert")
53+
external assertRejects: (unit => promise<'a>) => promise<unit> = "assertRejects"
54+
55+
@module("std/assert")
56+
external assert_: bool => unit = "assert"
57+
58+
@module("std/assert")
59+
external assertMsg: (bool, string) => unit = "assert"
60+
61+
// ── std/testing/bdd (optional) ───────────────────────────────────────────
62+
63+
@module("std/testing/bdd.ts")
64+
external describe: (string, unit => unit) => unit = "describe"
65+
66+
@module("std/testing/bdd.ts")
67+
external it: (string, unit => unit) => unit = "it"

tests/Bindings.res.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)