Skip to content

Lambé 0.10.0: WASM-clean library, frontmatter-aware Markdown, idiom redirects#8

Merged
hakimjonas merged 2 commits into
mainfrom
feature/lambe-0.10.0
May 26, 2026
Merged

Lambé 0.10.0: WASM-clean library, frontmatter-aware Markdown, idiom redirects#8
hakimjonas merged 2 commits into
mainfrom
feature/lambe-0.10.0

Conversation

@hakimjonas
Copy link
Copy Markdown
Owner

Summary

Polish release built on rumil 0.7.1 / rumil_parsers 0.8.1.

  • Library is now dart:io-free. loadSchemaFromFile / loadSchemaForData move to bin/schema_io.dart; mergeSchemaWithData stays in the public API. This is the breaking change of the release — needed for the lambé playground in arda-web to compile to WASM without bridges.
  • Markdown frontmatter no longer absorbed as prose. parseInput(text, Format.markdown) now uses parseMarkdownWithFrontmatter. Files without frontmatter parse byte-identically to before; files with frontmatter gain a frontmatter key addressable via .frontmatter.title, .frontmatter.tags[0], etc.
  • Foreign-idiom redirects widen to getpath/setpath/tojson/fromjson/regex family/@uri/@html/@sh/@json/$ENV. test/match/sub no longer produce misleading "did you mean text/map/sum?" guesses.
  • Output-shape error messages clarify. Writer's bridge suggestion now reads Append one of these stages to the end of your query (keep your existing flags such as -t hcl): with the format name interpolated.
  • --schema <data-file> migration hint. When the argument has a data extension, the error suggests lam --print-shape <file>.
  • .jsonlines extension auto-implies --ndjson (joining .ndjson and .jsonl).
  • Heterogeneous-list shape descriptions list sampled types: --print-shape on a mixed array now emits sampled: number, string, boolean, null, array (heterogeneous).
  • tonumber and add jq-compatibility aliases now documented. Surface was already implemented in 0.9; 0.10 documents it across doc/jq-to-lambe.md, doc/syntax.md, doc/lam.1.md, and AGENTS.md.

Performance

End-to-end CLI / library benchmark (median of 7 runs, after warm-up), comparing 0.9.0 (rumil 0.7.0 / rumil_parsers 0.8.0) against this release:

Workload AOT 0.9.0 AOT 0.10.0 Δ WASM 0.9.0 WASM 0.10.0 Δ
--print-shape on 50k items 742.2 ms 693.8 ms -6.5% 319.9 ms 290.1 ms -9.3%
.items | filter(.value > 50000) | length 748.5 ms 704.8 ms -5.8% 324.9 ms 285.9 ms -12.0%
group_by(.role) on 1k records 30.7 ms 27.1 ms -11.7% 12.4 ms 11.8 ms -4.8%

The win comes from rumil's hot/cold dispatch split (4–6% on synthetic format benches; compounded through lambé's deeper call chain). WASM is also the relevant runtime for the lambé playground in arda-web; users get faster live-explain feedback in the browser.

Test plan

  • Full test suite passes against published rumil 0.7.1 / rumil_parsers 0.8.1 (1657/1657)
  • dart pub publish --dry-run reports 0 warnings
  • Library compiles WASM-clean (lib/ has no dart:io imports)
  • CHANGELOG documents the breaking removal and migration path

Largest concrete change: the published library now has zero dart:io
imports, so the lambé playground in arda-web (which compiles with
`dart compile wasm`) gets a clean platform compatibility report from
pana and runs without dart:io bridges.

Breaking — library API surface
==============================

Removed from `package:lambe`:
- `loadSchemaFromFile`
- `loadSchemaForData`

Both helpers used `dart:io` (file IO). They moved to `bin/schema_io.dart`
where the CLI consumes them. `mergeSchemaWithData` (pure) stays in
`lib/src/schema/loader.dart` and remains exported.

REPL and readline (CLI-only) moved out of lib/ into bin/:
- `lib/src/repl.dart`         → `bin/repl.dart`
- `lib/src/readline.dart`     → `bin/readline.dart`
- `lib/src/highlight_grammar.dart` → `bin/highlight_grammar.dart`

bin/lam.dart and bin/repl.dart updated to use `package:lambe/...` for
the lib/ imports they still need, plus relative imports for sibling
bin/ files.

Markdown frontmatter
====================

`parseInput(text, Format.markdown)` now uses
`parseMarkdownWithFrontmatter` from rumil_parsers 0.8.1. A leading
`---` YAML frontmatter block becomes a sibling `frontmatter` field on
the document instead of being absorbed into the body as prose.

Files without frontmatter parse byte-identically to before. The
frontmatter conversion goes through rumil_parsers' yamlToNative so
anchors and aliases resolve correctly without lambé reimplementing
the walk.

Foreign-idiom redirects (jq compatibility)
==========================================

Adds redirect hints for the rest of the common jq habits a model
might draft. Pipe-op redirects (fire on `... | name(...)`):
`getpath`, `setpath`, `env`, `gsub`, `sub`, `test`, `match`, `scan`,
`splits`, `tojson`, `fromjson`. Inline-idiom redirects: `@uri`,
`@html`, `@sh`, `@json`, `$ENV` and other variable-binding forms.

The regex family (`test`, `match`, `sub`) previously hit the
closest-match suggestion ("did you mean text/map/sum?"). Now they
get the regex-family explanation directly.

Heterogeneous-list shape descriptions
=====================================

`SList` gains an optional `sampledKinds: List<Shape>?` field, populated
when widening to `SAny` because of observed heterogeneity. Empty
lists keep `sampledKinds: null` (no observations to report).

`renderJsonSchema` reads it and emits, for example,
`"sampled: number, string, boolean, null, array (heterogeneous)"`
instead of the generic `"sampled, may be heterogeneous"`.

CLI / error message polish
==========================

- Output-shape error messages clarified: `Append one of these stages
  to the end of your query (keep your existing flags such as -t hcl):`
  instead of the ambiguous `Try appending one of:`. The format name
  interpolates dynamically so HCL / TOML / CSV all read correctly.
- `--schema <data-file>` migration hint when the argument has a data
  extension (`.json`, `.yaml`, etc.) rather than `*.schema.json`,
  pointing at the new `--print-shape` flag instead of dumping usage.
- `.jsonlines` extension joins `.ndjson` and `.jsonl` in
  auto-detecting --ndjson mode.

Tests
=====

- 4 new tests in `test/markdown_text_test.dart` for the frontmatter
  contract (text op no longer scoops frontmatter; frontmatter
  addressable; absent case unchanged; child shape preserved).
- 2 tests in `test/shape_test.dart` updated to assert the new
  `sampledKinds` contract on heterogeneous lists.
- `test/schema_loader_test.dart` imports the moved file-loaders via
  relative path `../bin/schema_io.dart`.

1657 tests pass, format clean, analyze clean.

Performance
===========

Bench (lambé library bench, median of 7, after warm-up) versus
lambé 0.9.0 with rumil 0.7.0 / rumil_parsers 0.8.0:

  Workload                           AOT 0.9.0  0.10.0   Δ      WASM 0.9.0  0.10.0   Δ
  --print-shape on 50k items         742.2 ms   693.8 ms -6.5%  319.9 ms   290.1 ms -9.3%
  filter+length on 50k items         748.5 ms   704.8 ms -5.8%  324.9 ms   285.9 ms -12.0%
  group_by(.role) on 1k records       30.7 ms    27.1 ms -11.7%  12.4 ms    11.8 ms -4.8%

Comes from rumil's hot/cold dispatch split (4-6% on synthetic
format benches), compounded through lambé's deeper call chain.
CHANGELOG entry for 0.10.0 covering the breaking library API removal,
the frontmatter parser adoption, foreign-idiom redirect coverage,
heterogeneous-list description upgrade, error message polish,
performance numbers (5-12% AOT, 5-12% WASM on representative
workloads), and the rumil_parsers ^0.8.0 → ^0.8.1 dependency bump.

jq-compatibility aliases now documented across the canonical surfaces:
- `tonumber` (jq alias for `to_number`) — was implemented in 0.9 but
  undocumented; now appears in jq-to-lambe.md, syntax.md, lam.1.md,
  AGENTS.md.
- `add` (jq alias for `sum`) — same story; same surfaces.

`//` documentation tightened in jq-to-lambe.md: it's the null-fallback
operator (returns the right-hand side when the left evaluates to
null), not an error-handler. The doc previously said "not yet
supported" — that was stale; 0.9 implemented it.

Skill file (.claude/skills/lambe/SKILL.md) gains a sandbox note:
when an agent harness reports `lam: command not found`, the
fall-back is the absolute path `~/.pub-cache/bin/lam`. This is a
shell-PATH issue, not a lambé issue. Documented so future readers
of the skill don't bounce off it.

doc/lam.1 regenerated from doc/lam.1.md via tool/manpage.dart so the
committed mandoc round-trips cleanly with the source.

pubspec bumped to 0.10.0; rumil_parsers constraint bumped to ^0.8.1.
@hakimjonas hakimjonas merged commit af0345a into main May 26, 2026
4 checks passed
@hakimjonas hakimjonas deleted the feature/lambe-0.10.0 branch June 1, 2026 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant