HS runtime: empty/swap/compound events, host-set! fix — 403→423 (51%)
- Fix host-set → host-set! in emit-inc/emit-dec (increment/decrement properties) - Implement empty/clear command: parser dispatch, compiler, polymorphic runtime - Implement swap command: parser dispatch, compiler (let+do temp swap pattern) - Add parse-compound-event-name: joins dot/colon tokens (example.event, htmx:load) - Add hs-compile to source parser (was only in WASM deploy copy) - Add clear/swap to tokenizer keywords and cmd-kw? list - Generator: fix run() with extra args, String.raw support Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -674,11 +674,12 @@ def extract_hs_expr(raw):
|
||||
def generate_eval_only_test(test, idx):
|
||||
"""Generate SX deftest for no-HTML tests using eval-hs.
|
||||
Handles patterns:
|
||||
- run("expr").toBe(val)
|
||||
- expect(run("expr")).toBe(val)
|
||||
- var result = await run(`expr`); expect(result).toBe(val)
|
||||
- run("expr").toEqual([...])
|
||||
- run("expr").toBe(val) or run("expr", opts).toBe(val)
|
||||
- expect(run("expr")).toBe(val) or expect(run("expr", opts)).toBe(val)
|
||||
- var result = await run(`expr`, opts); expect(result).toBe(val)
|
||||
- run("expr").toEqual([...]) or run("expr").toEqual({...})
|
||||
- run("expr").toThrow()
|
||||
Also handles String.raw`expr` template literals.
|
||||
"""
|
||||
body = test.get('body', '')
|
||||
lines = []
|
||||
@@ -687,28 +688,47 @@ def generate_eval_only_test(test, idx):
|
||||
|
||||
assertions = []
|
||||
|
||||
# Pattern 1: Inline — run("expr").toBe(val) or expect(run("expr")).toBe(val)
|
||||
# Shared sub-pattern for run() call with optional String.raw and extra args:
|
||||
# run(QUOTE expr QUOTE) or run(QUOTE expr QUOTE, opts) or run(String.raw`expr`, opts)
|
||||
# Extra args can contain nested parens/braces, so we allow anything non-greedy up to the
|
||||
# matching close-paren by tracking that the close-paren follows the quote.
|
||||
_Q = r'["\x27`]' # quote character class
|
||||
_RUN_OPEN = r'(?:await\s+)?run\((?:String\.raw)?(' + _Q + r')(.+?)\1' # groups: (quote, expr)
|
||||
_RUN_ARGS = r'(?:\s*,\s*[^)]*(?:\([^)]*\)[^)]*)*)*' # optional extra args with nested parens
|
||||
|
||||
# Pattern 1: Inline — expect(run("expr", opts)).toBe(val) or run("expr", opts).toBe(val)
|
||||
for m in re.finditer(
|
||||
r'(?:expect\()?(?:await\s+)?run\((["\x27`])(.+?)\1\)\)?\.toBe\(([^)]+)\)',
|
||||
r'(?:expect\()?' + _RUN_OPEN + _RUN_ARGS + r'\)\)?\.toBe\(([^)]+)\)',
|
||||
body, re.DOTALL
|
||||
):
|
||||
hs_expr = extract_hs_expr(m.group(2))
|
||||
expected_sx = js_val_to_sx(m.group(3))
|
||||
assertions.append(f' (assert= (eval-hs "{hs_expr}") {expected_sx})')
|
||||
|
||||
# Pattern 1b: Inline — run("expr").toEqual([...])
|
||||
# Pattern 1b: Inline — run("expr", opts).toEqual([...])
|
||||
for m in re.finditer(
|
||||
r'(?:expect\()?(?:await\s+)?run\((["\x27`])(.+?)\1\)\)?\.toEqual\((\[.*?\])\)',
|
||||
r'(?:expect\()?' + _RUN_OPEN + _RUN_ARGS + r'\)\)?\.toEqual\((\[.*?\])\)',
|
||||
body, re.DOTALL
|
||||
):
|
||||
hs_expr = extract_hs_expr(m.group(2))
|
||||
expected_sx = js_val_to_sx(m.group(3))
|
||||
assertions.append(f' (assert= (eval-hs "{hs_expr}") {expected_sx})')
|
||||
|
||||
# Pattern 2: Two-line — var result = await run(`expr`); expect(result).toBe(val)
|
||||
# Pattern 1c: Inline — run("expr", opts).toEqual({...})
|
||||
if not assertions:
|
||||
for m in re.finditer(
|
||||
r'(?:expect\()?' + _RUN_OPEN + _RUN_ARGS + r'\)\)?\.toEqual\((\{.*?\})\)',
|
||||
body, re.DOTALL
|
||||
):
|
||||
hs_expr = extract_hs_expr(m.group(2))
|
||||
# Object toEqual — emit as dict assertion comment (can't fully convert JS objects to SX)
|
||||
obj_str = m.group(3).strip()
|
||||
assertions.append(f' ;; TODO: assert= (eval-hs "{hs_expr}") against {obj_str}')
|
||||
|
||||
# Pattern 2: Two-line — var result = await run(`expr`, opts); expect(result...).toBe/toEqual(val)
|
||||
if not assertions:
|
||||
run_match = re.search(
|
||||
r'(?:var|let|const)\s+\w+\s*=\s*(?:await\s+)?run\((["\x27`])(.+?)\1\)',
|
||||
r'(?:var|let|const)\s+\w+\s*=\s*' + _RUN_OPEN + _RUN_ARGS + r'\)',
|
||||
body, re.DOTALL
|
||||
)
|
||||
if run_match:
|
||||
@@ -722,7 +742,7 @@ def generate_eval_only_test(test, idx):
|
||||
|
||||
# Pattern 3: toThrow — expect(() => run("expr")).toThrow()
|
||||
for m in re.finditer(
|
||||
r'run\((["\x27`])(.+?)\1\).*?\.toThrow\(\)',
|
||||
r'run\((?:String\.raw)?(["\x27`])(.+?)\1\).*?\.toThrow\(\)',
|
||||
body, re.DOTALL
|
||||
):
|
||||
hs_expr = extract_hs_expr(m.group(2))
|
||||
|
||||
Reference in New Issue
Block a user