@almadar/core 10.41.0 → 10.43.0

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.
@@ -1,5 +1,6 @@
1
- import { a as EntityField, E as EntityPersistence, R as RelationConfig, J as JsonValue } from './entity-DfD-iXkn.js';
2
- import { T as TraitEventListener, a as TraitReference } from './trait-2E6TQw19.js';
1
+ import { E as EntityField, a as EntityPersistence, R as RelationConfig } from './effect-NbTgX2yB.js';
2
+ import { T as TraitEventListener, a as TraitReference } from './trait-DdBiEffx.js';
3
+ import { J as JsonValue } from './expression-Yf7qvvOs.js';
3
4
 
4
5
  /**
5
6
  * Cross-cutting presentation knobs that don't live per orbital
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@almadar/core",
3
- "version": "10.41.0",
3
+ "version": "10.43.0",
4
4
  "description": "Core schema types and definitions for Almadar",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -27,6 +27,8 @@ export {
27
27
  type CoreBinding,
28
28
  type ParsedBinding,
29
29
  } from './expression.js';
30
+ import type { SExpr } from './expression.js';
31
+ import type { RuntimeValue } from './json.js';
30
32
 
31
33
  // ============================================================================
32
34
  // Binding Schema
@@ -128,6 +130,83 @@ export const BINDING_CONTEXT_RULES = {
128
130
 
129
131
  export type BindingContext = keyof typeof BINDING_CONTEXT_RULES;
130
132
 
133
+ // ============================================================================
134
+ // Render-Time Binding Markers
135
+ // ============================================================================
136
+
137
+ /**
138
+ * Tag property of a `RenderBindingMarker`. `$`-prefixed so it can never
139
+ * collide with a pattern prop key (prop keys are camelCase identifiers).
140
+ */
141
+ export const RENDER_BINDING_MARKER = '$renderBinding' as const;
142
+
143
+ /**
144
+ * A render-ui prop leaf that is evaluated at RENDER time, not at flush time.
145
+ *
146
+ * The interpreted path's executor carries `@entity`-dependent leaves into
147
+ * slot content as these markers instead of resolving them eagerly; the
148
+ * renderer (`@almadar/ui`'s SlotContentRenderer) resolves each marker
149
+ * against the live entity store on every render — the same model the
150
+ * compiled shell uses (state-based JSX reading `fields?.X` per React
151
+ * render). Payload-dependent leaves are never deferred: `@payload` is
152
+ * event-scoped and does not exist at render time.
153
+ *
154
+ * A `type` (not `interface`) so it carries an implicit index signature and
155
+ * stays assignable to the `SExpr` record branch at guard call sites.
156
+ */
157
+ export type RenderBindingMarker = {
158
+ readonly [RENDER_BINDING_MARKER]: true;
159
+ /** The raw prop expression: a binding string (`'@entity.hp'`, embedded
160
+ * form `'HP: @entity.hp'`) or an S-expression tree. */
161
+ readonly expression: SExpr;
162
+ };
163
+
164
+ /** Narrow an arbitrary prop value to a `RenderBindingMarker`. */
165
+ export function isRenderBindingMarker(value: RuntimeValue): value is RenderBindingMarker {
166
+ return (
167
+ typeof value === 'object' &&
168
+ value !== null &&
169
+ !Array.isArray(value) &&
170
+ RENDER_BINDING_MARKER in value &&
171
+ value[RENDER_BINDING_MARKER] === true
172
+ );
173
+ }
174
+
175
+ /** Matches a whole `@entity` token (path or bracket suffix allowed). */
176
+ const ENTITY_BINDING_RE = /@entity(?=[.\[\]]|$)/;
177
+
178
+ /** Matches a whole `@payload` / `@callsitePayload` token. */
179
+ const PAYLOAD_BINDING_RE = /@(?:callsitePayload|payload)(?=[.\[\]]|$)/;
180
+
181
+ /**
182
+ * Does this raw prop expression reference `@entity` anywhere (pure binding,
183
+ * embedded-binding string, nested S-expression, or object tree)? Marker
184
+ * objects count as entity-referencing by construction.
185
+ */
186
+ export function containsEntityBinding(value: SExpr): boolean {
187
+ if (typeof value === 'string') return ENTITY_BINDING_RE.test(value);
188
+ if (Array.isArray(value)) return value.some(containsEntityBinding);
189
+ if (value !== null && typeof value === 'object') {
190
+ if (isRenderBindingMarker(value)) return true;
191
+ return Object.values(value as Record<string, SExpr>).some(containsEntityBinding);
192
+ }
193
+ return false;
194
+ }
195
+
196
+ /**
197
+ * Does this raw prop expression reference the event payload (`@payload` /
198
+ * `@callsitePayload`) anywhere? Such leaves stay flush-time evaluated —
199
+ * the payload does not exist at render time.
200
+ */
201
+ export function containsPayloadBinding(value: SExpr): boolean {
202
+ if (typeof value === 'string') return PAYLOAD_BINDING_RE.test(value);
203
+ if (Array.isArray(value)) return value.some(containsPayloadBinding);
204
+ if (value !== null && typeof value === 'object') {
205
+ return Object.values(value as Record<string, SExpr>).some(containsPayloadBinding);
206
+ }
207
+ return false;
208
+ }
209
+
131
210
  // ============================================================================
132
211
  // Binding Validation Helpers
133
212
  // ============================================================================