@barefootjs/cli 0.26.2 → 0.26.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -52,6 +52,21 @@ return <div>...</div>
52
52
  ))}
53
53
  ```
54
54
 
55
+ `.flatMap()` expands nested collections into a flat run of keyed elements. A pure projection body — the nested `.map()` as the whole body, expression or single-`return` block — compiles on every adapter; a body with statements before the projection (early returns, `const`s) runs as JS on JS-runtime adapters and needs [`/* @client */`](./client-directive.md) on DSL backends:
56
+
57
+ ```tsx
58
+ // ✅ Projection — works on every adapter
59
+ {todos().flatMap(todo => todo.tags.map(tag => (
60
+ <li key={`${todo.id}:${tag}`}>{tag}</li>
61
+ )))}
62
+
63
+ // ✅ Statement body — JS-runtime adapters; /* @client */ on Go/Mojo etc.
64
+ {todos().flatMap(todo => {
65
+ if (todo.hidden) return []
66
+ return todo.tags.map(tag => <li key={`${todo.id}:${tag}`}>{tag}</li>)
67
+ })}
68
+ ```
69
+
55
70
  `.sort()` and `.toSorted()` can be chained with `.map()` and `.filter()`:
56
71
 
57
72
  ```tsx
@@ -105,14 +120,16 @@ Some JavaScript expressions cannot be translated into marked template syntax. Wh
105
120
  |---|---|---|
106
121
  | `.filter()` with destructured param (`({done}) => done`) | works (runs as JS) | **BF101** |
107
122
  | `.filter()` with `function` keyword callback | works | **BF101** |
108
- | `.reduce()`, `.forEach()`, `.flatMap()` | works | **BF101** |
123
+ | `.reduce()`, `.forEach()`, value-returning `.flatMap()` with an off-catalogue projection | works | **BF101** |
124
+ | JSX-returning `.flatMap()` projection (`items.flatMap(it => it.tags.map(tag => <li key={...}/>))`) | works | works |
125
+ | JSX-returning `.flatMap()` with a statement body (early `return`, `const` before the projection) | works (runs as JS) | **BF021** |
109
126
  | Nested `.filter()` / `.map()` in a filter predicate (`x => x.tags.filter(...).length > 0`) | works | works |
110
127
  | Nested `.some()` / `.find()` / `.reduce()` in a filter predicate | works | **BF101** |
111
- | Sort comparator that's a multi-statement block body or `localeCompare(b, locale, opts)` | **BF021** (all adapters) | **BF021** |
112
- | Sort comparator that's a function reference to an imported/prop identifier, or an alias chain (`const c2 = c1`) | **BF021** (all adapters) | **BF021** |
113
- | `typeof` in a filter predicate | **BF021** (all adapters) | **BF021** |
128
+ | Sort comparator that's a multi-statement block body or `localeCompare(b, locale, opts)` | works (runs as JS) | **BF021** |
129
+ | Sort comparator that's a function reference to an imported/prop identifier, or an alias chain (`const c2 = c1`) | works (runs as JS) | **BF021** |
130
+ | `typeof` in a filter predicate | works (runs as JS) | **BF021** |
114
131
 
115
- `BF021` is raised at the IR layer and applies to every adapter. `BF101` is raised by adapters that can't lower the expression to their template language. Either way, add [`/* @client */`](./client-directive.md) to opt into client-only evaluation and suppress the error.
132
+ An off-subset `filter` predicate or `sort` comparator (`typeof`, an imperative block body, an imported/aliased comparator reference, …) is raised as `BF021` only on non-JS template adapters — a JS-runtime adapter (Hono, CSR) executes the callback body verbatim at SSR, so it compiles there. `BF101` is raised by adapters that can't lower the expression to their template language. Either way, add [`/* @client */`](./client-directive.md) on a DSL backend to defer the shape to client-only evaluation and suppress the error.
116
133
 
117
134
  ### Patterns that error on Go / Mojo
118
135
 
@@ -165,9 +182,9 @@ A nested `.some()` / `.find()` / `.reduce()` still has no faithful Go/Mojo lower
165
182
  {items().filter(x => x.done)}
166
183
  ```
167
184
 
168
- ### Patterns that error on all adapters
185
+ ### Sort comparators that error on Go / Mojo
169
186
 
170
- **Unsupported sort comparators** (imperative block bodies, unresolved function references):
187
+ **Unsupported sort comparators** (imperative block bodies, unresolved function references) — a JS-runtime adapter (Hono, CSR) runs any of these verbatim; only non-JS template backends refuse them:
171
188
 
172
189
  A value-producing block body normalizes to an expression — pure `const`
173
190
  bindings inline (let-inline) and a value-producing `if` / early `return`
@@ -181,10 +198,10 @@ becomes a ternary — so it lowers on all adapters just like the expression form
181
198
  ```
182
199
 
183
200
  Only a genuinely imperative comparator — one that re-assigns a local, loops, or
184
- `break`s — has no value-position lowering and errors:
201
+ `break`s — has no value-position lowering and errors on Go / Mojo:
185
202
 
186
203
  ```tsx
187
- // ❌ BF021 (all adapters)
204
+ // ❌ BF021 on Go/Mojo — a JS-runtime target (Hono, CSR) runs the comparator
188
205
  {items().sort((a, b) => { let r = 0; r = a.name > b.name ? 1 : -1; return r }).map(item => (
189
206
  <Item key={item.id} item={item} />
190
207
  ))}
@@ -201,7 +218,7 @@ compiles (see the "Sort comparators" section above); an **imported** or
201
218
  only one binding, so it can't see through a re-export or `const c2 = c1`:
202
219
 
203
220
  ```tsx
204
- // ❌ BF021 — `byPrice` is imported, not declared in this file
221
+ // ❌ BF021 on Go/Mojo — `byPrice` is imported, not declared in this file
205
222
  import { byPrice } from './comparators'
206
223
  function SortedList({ items }: { items: Item[] }) {
207
224
  return <ul>{items.sort(byPrice).map((item) => <li key={item.id}>{item.name}</li>)}</ul>