@barefootjs/shared 0.33.2 → 0.33.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
- export { BF_SCOPE, BF_SLOT, BF_HOST, BF_AT, BF_ROOT, BF_PROPS, BF_COND, BF_ITEM, BF_PORTAL_OWNER, BF_PORTAL_ID, BF_PORTAL_PLACEHOLDER, BF_PARENT_OWNED_PREFIX, BF_SCOPE_COMMENT_PREFIX, BF_SCOPE_COMMENT_END_PREFIX, BF_LOOP_START, BF_LOOP_END, BF_LOOP_ITEM, loopItemMarker, loopStartMarker, loopEndMarker, BF_KEY, BF_KEY_PREFIX, BF_PLACEHOLDER, BF_ASYNC, BF_ASYNC_RESOLVE, BF_REGION, BF_PARENT_SCOPE_PLACEHOLDER, BF_SEAM_HYDRATE, BF_SEAM_HYDRATE_WITHIN, BF_SEAM_DISPOSE_WITHIN, BF_SEAM_PUSH_SEARCH, BF_SEAM_NAV_SEARCH, } from './markers.ts';
1
+ export { BF_SCOPE, BF_SLOT, BF_HOST, BF_AT, BF_ROOT, BF_PROPS, BF_COND, BF_ITEM, BF_PORTAL_OWNER, BF_PORTAL_ID, BF_PORTAL_PLACEHOLDER, BF_PARENT_OWNED_PREFIX, BF_SCOPE_COMMENT_PREFIX, BF_SCOPE_COMMENT_END_PREFIX, BF_LOOP_START, BF_LOOP_END, BF_LOOP_ITEM, loopItemMarker, loopStartMarker, loopEndMarker, BF_KEY, BF_KEY_PREFIX, keyAttrName, BF_PLACEHOLDER, BF_ASYNC, BF_ASYNC_RESOLVE, BF_REGION, BF_PARENT_SCOPE_PLACEHOLDER, BF_SEAM_HYDRATE, BF_SEAM_HYDRATE_WITHIN, BF_SEAM_DISPOSE_WITHIN, BF_SEAM_PUSH_SEARCH, BF_SEAM_NAV_SEARCH, } from './markers.ts';
2
2
  export { classifyDOMProp, toHTMLAttrName, toHTMLAttrNameRuntime, isBooleanAttr, isEventProp, BOOLEAN_ATTRS, } from './dom-prop.ts';
3
3
  export type { DOMPropKind, DOMPropClassification } from './dom-prop.ts';
4
4
  export { decodeEntities, escapeHtml } from './html-entities.ts';
5
+ export { resolveJsxChildrenProp } from './jsx-children-prop.ts';
6
+ export type { ChildrenSlotPropLike } from './jsx-children-prop.ts';
5
7
  export type { ProfilerEvent, ProfilerEventType, ProfilerSubscriberKind, } from './profiler-events.ts';
package/dist/index.js CHANGED
@@ -27,6 +27,9 @@ function loopEndMarker(markerId) {
27
27
  }
28
28
  var BF_KEY = "data-key";
29
29
  var BF_KEY_PREFIX = "data-key-";
30
+ function keyAttrName(loopDepth) {
31
+ return loopDepth > 0 ? `${BF_KEY_PREFIX}${loopDepth}` : BF_KEY;
32
+ }
30
33
  var BF_PLACEHOLDER = "data-bf-ph";
31
34
  var BF_ASYNC = "bf-async";
32
35
  var BF_ASYNC_RESOLVE = "bf-async-resolve";
@@ -335,12 +338,23 @@ function decodeEntities(text) {
335
338
  function escapeHtml(text) {
336
339
  return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
337
340
  }
341
+ // src/jsx-children-prop.ts
342
+ function resolveJsxChildrenProp(props) {
343
+ const prop = props.find((p) => p.name === "children");
344
+ if (!prop)
345
+ return [];
346
+ if (prop.value.kind !== "jsx-children")
347
+ return [];
348
+ return prop.value.children ?? [];
349
+ }
338
350
  export {
339
351
  toHTMLAttrNameRuntime,
340
352
  toHTMLAttrName,
353
+ resolveJsxChildrenProp,
341
354
  loopStartMarker,
342
355
  loopItemMarker,
343
356
  loopEndMarker,
357
+ keyAttrName,
344
358
  isEventProp,
345
359
  isBooleanAttr,
346
360
  escapeHtml,
@@ -0,0 +1,52 @@
1
+ /**
2
+ * BarefootJS — reserved `children` JSX-prop resolver
3
+ *
4
+ * Answers one question for every adapter: "which prop on this component
5
+ * call supplies the reserved `children` slot?" Before this module existed,
6
+ * two independently-maintained answers had drifted apart (issue #2773):
7
+ *
8
+ * - The seven DSL adapters (Blade/ERB/Jinja/Mojolicious/minijinja/Twig/
9
+ * Xslate) each carried a byte-identical private copy of this function in
10
+ * their own `lib/ir-scope.ts`, matching on the prop NAMED `children`.
11
+ * - The Go template adapter's `jsxChildrenPropNodes` answered a different
12
+ * question: the FIRST prop of ANY name carrying a `jsx-children`
13
+ * payload. For a component with an earlier JSX-element prop (e.g.
14
+ * `header={<span/>}`) and no `children` prop at all, that silently
15
+ * backfilled `.Children` with the `header` payload — and when a
16
+ * `children` prop WAS also given, it lost `children`'s payload entirely
17
+ * in favor of the earlier prop's.
18
+ *
19
+ * Hono, the reference adapter, resolves `children` by name — ordinary JSX
20
+ * semantics: `<Card header={<A/>} children={<B/>} />` binds `header` and
21
+ * `children` to two separate props, exactly as `React.createElement`
22
+ * would. The DSL adapters already agreed with Hono; this module makes
23
+ * their shared answer the ONLY implementation, so Go template (and any
24
+ * future adapter) calls it instead of growing its own copy that can
25
+ * re-diverge.
26
+ *
27
+ * Generic and structurally typed rather than importing `IRProp`/`IRNode`
28
+ * from `@barefootjs/jsx`: `@barefootjs/jsx` itself depends on
29
+ * `@barefootjs/shared`, so importing the other direction would be a
30
+ * dependency cycle. Callers pass their real IR prop array and get back a
31
+ * concretely-typed node array — no cast, no parallel type declaration to
32
+ * keep in sync with `@barefootjs/jsx`'s `AttrValue` union.
33
+ */
34
+ /** Structural shape of an `AttrValue`-like prop value, generic over the node type a `jsx-children` payload carries. */
35
+ interface JsxChildrenAttrValueLike<TNode> {
36
+ kind: string;
37
+ children?: TNode[];
38
+ }
39
+ /** Structural shape of one IR prop, generic over the node type. */
40
+ export interface ChildrenSlotPropLike<TNode> {
41
+ name: string;
42
+ value: JsxChildrenAttrValueLike<TNode>;
43
+ }
44
+ /**
45
+ * Find the prop literally named `children` and, if its value carries a
46
+ * `jsx-children` payload, return that payload's nodes. Returns `[]` when
47
+ * no `children` prop exists, or when one exists but is not a resolved
48
+ * JSX-children payload (e.g. an ordinary expression prop that merely
49
+ * happens to be named `children`).
50
+ */
51
+ export declare function resolveJsxChildrenProp<TNode>(props: ReadonlyArray<ChildrenSlotPropLike<TNode>>): TNode[];
52
+ export {};
package/dist/markers.d.ts CHANGED
@@ -118,6 +118,21 @@ export declare function loopEndMarker(markerId: string): string;
118
118
  export declare const BF_KEY = "data-key";
119
119
  /** Nested loop key attribute prefix: `data-key-1`, `data-key-2` */
120
120
  export declare const BF_KEY_PREFIX = "data-key-";
121
+ /**
122
+ * The row-key attribute NAME for a `.map()` nested `loopDepth` levels deep
123
+ * (0 = outermost): `data-key` at depth 0, `data-key-N` at depth N > 0.
124
+ *
125
+ * Single source of truth for a derivation that used to be re-implemented at
126
+ * every emission site — the CSR codegen path (`ir-to-client-js/utils.ts`,
127
+ * pre-existing re-export), IR-build time (`IRElement.keyAttr`,
128
+ * `jsx-to-ir.ts`), and — before that consolidation — independently again by
129
+ * each of the 9 SSR adapters (a mutable stack in Hono, a `currentLoopKeyDepth`
130
+ * field in every DSL adapter) and by the client runtime's `mapArray`, which
131
+ * used to skip depth entirely and always write plain `data-key` (#2753 Shape
132
+ * B). Living here, in the one package every one of those consumers already
133
+ * depends on, is what makes "compute it once" possible instead of aspirational.
134
+ */
135
+ export declare function keyAttrName(loopDepth: number): string;
121
136
  /** Component placeholder in loop templates: `data-bf-ph="s5"` */
122
137
  export declare const BF_PLACEHOLDER = "data-bf-ph";
123
138
  /** Async boundary placeholder: `bf-async="a0"` */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@barefootjs/shared",
3
- "version": "0.33.2",
3
+ "version": "0.33.4",
4
4
  "description": "Shared constants for BarefootJS compiler and runtime",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/index.ts CHANGED
@@ -21,6 +21,7 @@ export {
21
21
  loopEndMarker,
22
22
  BF_KEY,
23
23
  BF_KEY_PREFIX,
24
+ keyAttrName,
24
25
  BF_PLACEHOLDER,
25
26
  BF_ASYNC,
26
27
  BF_ASYNC_RESOLVE,
@@ -43,6 +44,8 @@ export {
43
44
  } from './dom-prop.ts'
44
45
  export type { DOMPropKind, DOMPropClassification } from './dom-prop.ts'
45
46
  export { decodeEntities, escapeHtml } from './html-entities.ts'
47
+ export { resolveJsxChildrenProp } from './jsx-children-prop.ts'
48
+ export type { ChildrenSlotPropLike } from './jsx-children-prop.ts'
46
49
 
47
50
  export type {
48
51
  ProfilerEvent,
@@ -0,0 +1,61 @@
1
+ /**
2
+ * BarefootJS — reserved `children` JSX-prop resolver
3
+ *
4
+ * Answers one question for every adapter: "which prop on this component
5
+ * call supplies the reserved `children` slot?" Before this module existed,
6
+ * two independently-maintained answers had drifted apart (issue #2773):
7
+ *
8
+ * - The seven DSL adapters (Blade/ERB/Jinja/Mojolicious/minijinja/Twig/
9
+ * Xslate) each carried a byte-identical private copy of this function in
10
+ * their own `lib/ir-scope.ts`, matching on the prop NAMED `children`.
11
+ * - The Go template adapter's `jsxChildrenPropNodes` answered a different
12
+ * question: the FIRST prop of ANY name carrying a `jsx-children`
13
+ * payload. For a component with an earlier JSX-element prop (e.g.
14
+ * `header={<span/>}`) and no `children` prop at all, that silently
15
+ * backfilled `.Children` with the `header` payload — and when a
16
+ * `children` prop WAS also given, it lost `children`'s payload entirely
17
+ * in favor of the earlier prop's.
18
+ *
19
+ * Hono, the reference adapter, resolves `children` by name — ordinary JSX
20
+ * semantics: `<Card header={<A/>} children={<B/>} />` binds `header` and
21
+ * `children` to two separate props, exactly as `React.createElement`
22
+ * would. The DSL adapters already agreed with Hono; this module makes
23
+ * their shared answer the ONLY implementation, so Go template (and any
24
+ * future adapter) calls it instead of growing its own copy that can
25
+ * re-diverge.
26
+ *
27
+ * Generic and structurally typed rather than importing `IRProp`/`IRNode`
28
+ * from `@barefootjs/jsx`: `@barefootjs/jsx` itself depends on
29
+ * `@barefootjs/shared`, so importing the other direction would be a
30
+ * dependency cycle. Callers pass their real IR prop array and get back a
31
+ * concretely-typed node array — no cast, no parallel type declaration to
32
+ * keep in sync with `@barefootjs/jsx`'s `AttrValue` union.
33
+ */
34
+
35
+ /** Structural shape of an `AttrValue`-like prop value, generic over the node type a `jsx-children` payload carries. */
36
+ interface JsxChildrenAttrValueLike<TNode> {
37
+ kind: string
38
+ children?: TNode[]
39
+ }
40
+
41
+ /** Structural shape of one IR prop, generic over the node type. */
42
+ export interface ChildrenSlotPropLike<TNode> {
43
+ name: string
44
+ value: JsxChildrenAttrValueLike<TNode>
45
+ }
46
+
47
+ /**
48
+ * Find the prop literally named `children` and, if its value carries a
49
+ * `jsx-children` payload, return that payload's nodes. Returns `[]` when
50
+ * no `children` prop exists, or when one exists but is not a resolved
51
+ * JSX-children payload (e.g. an ordinary expression prop that merely
52
+ * happens to be named `children`).
53
+ */
54
+ export function resolveJsxChildrenProp<TNode>(
55
+ props: ReadonlyArray<ChildrenSlotPropLike<TNode>>,
56
+ ): TNode[] {
57
+ const prop = props.find(p => p.name === 'children')
58
+ if (!prop) return []
59
+ if (prop.value.kind !== 'jsx-children') return []
60
+ return prop.value.children ?? []
61
+ }
package/src/markers.ts CHANGED
@@ -171,6 +171,24 @@ export const BF_KEY = 'data-key'
171
171
  /** Nested loop key attribute prefix: `data-key-1`, `data-key-2` */
172
172
  export const BF_KEY_PREFIX = 'data-key-'
173
173
 
174
+ /**
175
+ * The row-key attribute NAME for a `.map()` nested `loopDepth` levels deep
176
+ * (0 = outermost): `data-key` at depth 0, `data-key-N` at depth N > 0.
177
+ *
178
+ * Single source of truth for a derivation that used to be re-implemented at
179
+ * every emission site — the CSR codegen path (`ir-to-client-js/utils.ts`,
180
+ * pre-existing re-export), IR-build time (`IRElement.keyAttr`,
181
+ * `jsx-to-ir.ts`), and — before that consolidation — independently again by
182
+ * each of the 9 SSR adapters (a mutable stack in Hono, a `currentLoopKeyDepth`
183
+ * field in every DSL adapter) and by the client runtime's `mapArray`, which
184
+ * used to skip depth entirely and always write plain `data-key` (#2753 Shape
185
+ * B). Living here, in the one package every one of those consumers already
186
+ * depends on, is what makes "compute it once" possible instead of aspirational.
187
+ */
188
+ export function keyAttrName(loopDepth: number): string {
189
+ return loopDepth > 0 ? `${BF_KEY_PREFIX}${loopDepth}` : BF_KEY
190
+ }
191
+
174
192
  /** Component placeholder in loop templates: `data-bf-ph="s5"` */
175
193
  export const BF_PLACEHOLDER = 'data-bf-ph'
176
194