@zenithbuild/runtime 0.7.5 → 0.7.7

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.
@@ -0,0 +1,11 @@
1
+ export function isZenithRuntimeError(error: any): boolean;
2
+ export function createZenithRuntimeError(details: any, cause: any): Error;
3
+ export function throwZenithRuntimeError(details: any, cause: any): void;
4
+ export function rethrowZenithRuntimeError(error: any, fallback?: {}): void;
5
+ export const DOCS_LINKS: Readonly<{
6
+ eventBinding: "/docs/documentation/contracts/runtime-contract.md#event-bindings";
7
+ expressionScope: "/docs/documentation/reference/reactive-binding-model.md#expression-resolution";
8
+ markerTable: "/docs/documentation/reference/markers.md";
9
+ componentBootstrap: "/docs/documentation/contracts/runtime-contract.md#component-bootstrap";
10
+ refs: "/docs/documentation/reference/reactive-binding-model.md#refs-and-mount";
11
+ }>;
@@ -0,0 +1,279 @@
1
+ const MAX_MESSAGE_LENGTH = 120;
2
+ const MAX_HINT_LENGTH = 140;
3
+ const MAX_PATH_LENGTH = 120;
4
+ const MAX_DOCS_LINK_LENGTH = 180;
5
+ const MAX_SNIPPET_LENGTH = 220;
6
+ const MAX_STACK_LENGTH = 420;
7
+ const VALID_PHASES = Object.freeze(Object.assign(Object.create(null), {
8
+ hydrate: 1,
9
+ bind: 1,
10
+ render: 1,
11
+ event: 1
12
+ }));
13
+ const VALID_CODES = Object.freeze(Object.assign(Object.create(null), {
14
+ UNRESOLVED_EXPRESSION: 1,
15
+ NON_RENDERABLE_VALUE: 1,
16
+ MARKER_MISSING: 1,
17
+ FRAGMENT_MOUNT_FAILED: 1,
18
+ BINDING_APPLY_FAILED: 1,
19
+ EVENT_HANDLER_FAILED: 1,
20
+ COMPONENT_BOOTSTRAP_FAILED: 1,
21
+ UNSAFE_MEMBER_ACCESS: 1
22
+ }));
23
+ const DOCS_EXPRESSION_SCOPE = '/docs/documentation/reference/reactive-binding-model.md#expression-resolution';
24
+ const DOCS_RENDERABLE_VALUES = '/docs/documentation/reference/reactive-binding-model.md#renderable-values';
25
+ const DOCS_MARKERS = '/docs/documentation/reference/markers.md';
26
+ const DOCS_FRAGMENT_CONTRACT = '/docs/documentation/contracts/runtime-contract.md#fragment-contract';
27
+ const DOCS_BINDING_APPLICATION = '/docs/documentation/contracts/runtime-contract.md#binding-application';
28
+ const DOCS_EVENT_BINDINGS = '/docs/documentation/contracts/runtime-contract.md#event-bindings';
29
+ const DOCS_COMPONENT_BOOTSTRAP = '/docs/documentation/contracts/runtime-contract.md#component-bootstrap';
30
+ const DOCS_LINK_BY_CODE = Object.freeze({
31
+ UNRESOLVED_EXPRESSION: DOCS_EXPRESSION_SCOPE,
32
+ NON_RENDERABLE_VALUE: DOCS_RENDERABLE_VALUES,
33
+ MARKER_MISSING: DOCS_MARKERS,
34
+ FRAGMENT_MOUNT_FAILED: DOCS_FRAGMENT_CONTRACT,
35
+ BINDING_APPLY_FAILED: DOCS_BINDING_APPLICATION,
36
+ EVENT_HANDLER_FAILED: DOCS_EVENT_BINDINGS,
37
+ COMPONENT_BOOTSTRAP_FAILED: DOCS_COMPONENT_BOOTSTRAP,
38
+ UNSAFE_MEMBER_ACCESS: DOCS_EXPRESSION_SCOPE
39
+ });
40
+ const ABSOLUTE_PATH_RE = /(?:[A-Za-z]:\\[^\s"'`]+|\/(?:Users|home|private|tmp|var\/folders)\/[^\s"'`]+)/g;
41
+ function _truncate(input, maxLength) {
42
+ const text = String(input ?? '');
43
+ if (text.length <= maxLength)
44
+ return text;
45
+ return `${text.slice(0, maxLength - 3)}...`;
46
+ }
47
+ function _sanitizeAbsolutePaths(value) {
48
+ return String(value ?? '').replace(ABSOLUTE_PATH_RE, '<path>');
49
+ }
50
+ function _compact(value, sanitizePaths = true) {
51
+ const text = sanitizePaths ? _sanitizeAbsolutePaths(value) : String(value ?? '');
52
+ return text.replace(/\s+/g, ' ').trim();
53
+ }
54
+ function _sanitizeOptionalText(value, maxLength, sanitizePaths = true) {
55
+ if (value === null || value === undefined || value === false) {
56
+ return undefined;
57
+ }
58
+ const compact = _compact(value, sanitizePaths);
59
+ if (!compact)
60
+ return undefined;
61
+ return _truncate(compact, maxLength);
62
+ }
63
+ function _sanitizeMessage(value) {
64
+ return _sanitizeOptionalText(value, MAX_MESSAGE_LENGTH) || 'Runtime failure';
65
+ }
66
+ const _sanitizeHint = (value) => _sanitizeOptionalText(value, MAX_HINT_LENGTH);
67
+ const _sanitizePath = (value) => _sanitizeOptionalText(value, MAX_PATH_LENGTH);
68
+ const _sanitizeDocsLink = (value) => _sanitizeOptionalText(value, MAX_DOCS_LINK_LENGTH, false);
69
+ function _sanitizeSourceLocation(value) {
70
+ if (!value || typeof value !== 'object')
71
+ return undefined;
72
+ const line = Number(value.line);
73
+ const column = Number(value.column);
74
+ if (!Number.isInteger(line) || !Number.isInteger(column)) {
75
+ return undefined;
76
+ }
77
+ if (line < 1 || column < 1) {
78
+ return undefined;
79
+ }
80
+ return { line, column };
81
+ }
82
+ function _sanitizeSource(value) {
83
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
84
+ return undefined;
85
+ }
86
+ const file = typeof value.file === 'string' ? _truncate(value.file.trim(), 240) : '';
87
+ if (!file) {
88
+ return undefined;
89
+ }
90
+ const start = _sanitizeSourceLocation(value.start);
91
+ const end = _sanitizeSourceLocation(value.end);
92
+ const snippet = typeof value.snippet === 'string'
93
+ ? _truncate(_compact(value.snippet, false), MAX_SNIPPET_LENGTH)
94
+ : undefined;
95
+ return {
96
+ file,
97
+ ...(start ? { start } : null),
98
+ ...(end ? { end } : null),
99
+ ...(snippet ? { snippet } : null)
100
+ };
101
+ }
102
+ function _normalizeMarker(marker) {
103
+ if (!marker || typeof marker !== 'object')
104
+ return undefined;
105
+ const markerType = _truncate(_compact(marker.type || 'data-zx'), 48);
106
+ const markerId = marker.id;
107
+ if (markerId === null || markerId === undefined || markerId === '')
108
+ return undefined;
109
+ if (typeof markerId === 'number') {
110
+ return { type: markerType, id: markerId };
111
+ }
112
+ return { type: markerType, id: _truncate(_sanitizeAbsolutePaths(markerId), 48) };
113
+ }
114
+ function _extractErrorMessage(error) {
115
+ if (!error)
116
+ return '';
117
+ if (typeof error === 'string')
118
+ return error;
119
+ if (error instanceof Error && typeof error.message === 'string')
120
+ return error.message;
121
+ if (typeof error.message === 'string')
122
+ return error.message;
123
+ return String(error);
124
+ }
125
+ function _readProcessEnv(name) {
126
+ const runtimeProcess = typeof process !== 'undefined' ? process : globalThis?.process;
127
+ const value = runtimeProcess?.env?.[name];
128
+ return typeof value === 'string' ? value : undefined;
129
+ }
130
+ function _shouldLogRuntimeError() {
131
+ if (_readProcessEnv('ZENITH_LOG_RUNTIME_ERRORS') === '1') {
132
+ return true;
133
+ }
134
+ const isTestMode = _readProcessEnv('NODE_ENV') === 'test'
135
+ || _readProcessEnv('ZENITH_TEST_MODE') === '1';
136
+ return !isTestMode;
137
+ }
138
+ const _renderOverlay = () => { };
139
+ function _mapLegacyError(error, fallback) {
140
+ const rawMessage = _extractErrorMessage(error);
141
+ const safeMessage = _sanitizeMessage(rawMessage);
142
+ const details = {
143
+ phase: VALID_PHASES[fallback.phase] ? fallback.phase : 'hydrate',
144
+ code: VALID_CODES[fallback.code] ? fallback.code : 'BINDING_APPLY_FAILED',
145
+ message: _sanitizeMessage(fallback.message || safeMessage),
146
+ marker: _normalizeMarker(fallback.marker),
147
+ path: _sanitizePath(fallback.path),
148
+ hint: _sanitizeHint(fallback.hint),
149
+ source: _sanitizeSource(fallback.source),
150
+ docsLink: _sanitizeDocsLink(fallback.docsLink)
151
+ };
152
+ if (/failed to resolve expression literal/i.test(rawMessage)) {
153
+ details.phase = 'bind';
154
+ details.code = 'UNRESOLVED_EXPRESSION';
155
+ details.hint = details.hint || 'Verify expression scope keys and signal aliases.';
156
+ }
157
+ else if (/non-renderable (object|function)/i.test(rawMessage)) {
158
+ details.phase = 'render';
159
+ details.code = 'NON_RENDERABLE_VALUE';
160
+ const match = rawMessage.match(/at\s+([A-Za-z0-9_\[\].-]+)/);
161
+ if (match && !details.path) {
162
+ details.path = _sanitizePath(match[1]);
163
+ }
164
+ details.hint = details.hint || 'Use map() to render object fields into nodes.';
165
+ }
166
+ else if (/unresolved .* marker index/i.test(rawMessage)) {
167
+ details.phase = 'bind';
168
+ details.code = 'MARKER_MISSING';
169
+ const markerMatch = rawMessage.match(/unresolved\s+(\w+)\s+marker index\s+(\d+)/i);
170
+ if (markerMatch && !details.marker) {
171
+ details.marker = {
172
+ type: `data-zx-${markerMatch[1]}`,
173
+ id: Number(markerMatch[2])
174
+ };
175
+ }
176
+ details.hint = details.hint || 'Confirm SSR markers and client selector tables match.';
177
+ }
178
+ if (!details.docsLink) {
179
+ details.docsLink = DOCS_LINK_BY_CODE[details.code];
180
+ }
181
+ return details;
182
+ }
183
+ export function isZenithRuntimeError(error) {
184
+ return !!(error &&
185
+ typeof error === 'object' &&
186
+ error.zenithRuntimeError &&
187
+ error.zenithRuntimeError.kind === 'ZENITH_RUNTIME_ERROR');
188
+ }
189
+ export function createZenithRuntimeError(details, cause) {
190
+ const phase = VALID_PHASES[details?.phase] ? details.phase : 'hydrate';
191
+ const code = VALID_CODES[details?.code] ? details.code : 'BINDING_APPLY_FAILED';
192
+ const message = _sanitizeMessage(details?.message || 'Runtime failure');
193
+ const docsLink = _sanitizeDocsLink(details?.docsLink || DOCS_LINK_BY_CODE[code]);
194
+ const payload = {
195
+ kind: 'ZENITH_RUNTIME_ERROR',
196
+ phase,
197
+ code,
198
+ message,
199
+ ...(docsLink ? { docsLink } : null)
200
+ };
201
+ const marker = _normalizeMarker(details?.marker);
202
+ if (marker)
203
+ payload.marker = marker;
204
+ const path = _sanitizePath(details?.path);
205
+ if (path)
206
+ payload.path = path;
207
+ const hint = _sanitizeHint(details?.hint);
208
+ if (hint)
209
+ payload.hint = hint;
210
+ const source = _sanitizeSource(details?.source);
211
+ if (source)
212
+ payload.source = source;
213
+ const stack = _sanitizeHint(details?.stack);
214
+ if (stack) {
215
+ payload.stack = _truncate(stack, MAX_STACK_LENGTH);
216
+ }
217
+ const error = new Error(`[Zenith Runtime] ${code}: ${message}`);
218
+ error.name = 'ZenithRuntimeError';
219
+ error.zenithRuntimeError = payload;
220
+ if (cause !== undefined) {
221
+ error.cause = cause;
222
+ }
223
+ error.toJSON = () => payload;
224
+ return error;
225
+ }
226
+ function _reportRuntimeError(error) {
227
+ if (!error || error.__zenithRuntimeErrorReported === true)
228
+ return;
229
+ error.__zenithRuntimeErrorReported = true;
230
+ const payload = error.zenithRuntimeError;
231
+ if (payload
232
+ && _shouldLogRuntimeError()
233
+ && typeof console !== 'undefined'
234
+ && typeof console.error === 'function') {
235
+ console.error('[Zenith Runtime]', payload);
236
+ }
237
+ _renderOverlay(payload);
238
+ }
239
+ export function throwZenithRuntimeError(details, cause) {
240
+ const error = createZenithRuntimeError(details, cause);
241
+ _reportRuntimeError(error);
242
+ throw error;
243
+ }
244
+ export function rethrowZenithRuntimeError(error, fallback = {}) {
245
+ if (isZenithRuntimeError(error)) {
246
+ const payload = error.zenithRuntimeError || {};
247
+ let updatedPayload = payload;
248
+ const marker = payload.marker || _normalizeMarker(fallback.marker);
249
+ const path = payload.path || _sanitizePath(fallback.path);
250
+ const hint = payload.hint || _sanitizeHint(fallback.hint);
251
+ const source = payload.source || _sanitizeSource(fallback.source);
252
+ const docsLink = payload.docsLink || _sanitizeDocsLink(fallback.docsLink || DOCS_LINK_BY_CODE[payload.code]);
253
+ if (marker || path || hint || source || docsLink) {
254
+ updatedPayload = {
255
+ ...payload,
256
+ ...(marker ? { marker } : null),
257
+ ...(path ? { path } : null),
258
+ ...(hint ? { hint } : null),
259
+ ...(source ? { source } : null),
260
+ ...(docsLink ? { docsLink } : null)
261
+ };
262
+ error.zenithRuntimeError = updatedPayload;
263
+ error.toJSON = () => updatedPayload;
264
+ }
265
+ _reportRuntimeError(error);
266
+ throw error;
267
+ }
268
+ const mapped = _mapLegacyError(error, fallback || {});
269
+ const wrapped = createZenithRuntimeError(mapped, error);
270
+ _reportRuntimeError(wrapped);
271
+ throw wrapped;
272
+ }
273
+ export const DOCS_LINKS = Object.freeze({
274
+ eventBinding: DOCS_EVENT_BINDINGS,
275
+ expressionScope: DOCS_EXPRESSION_SCOPE,
276
+ markerTable: DOCS_MARKERS,
277
+ componentBootstrap: DOCS_COMPONENT_BOOTSTRAP,
278
+ refs: '/docs/documentation/reference/reactive-binding-model.md#refs-and-mount'
279
+ });
package/dist/events.js CHANGED
@@ -40,7 +40,7 @@ function _resolveEventHandler(context, expressionBinding, marker, eventBinding)
40
40
  message: `Event binding at index ${eventBinding.index} expected a function reference. You passed: ${_describeBindingExpression(expressionBinding)}`,
41
41
  marker: { type: `data-zx-on-${eventBinding.event}`, id: eventBinding.index },
42
42
  path: `event[${eventBinding.index}].${eventBinding.event}`,
43
- hint: 'Use on:*={handler} or ensure the forwarded prop is a function.',
43
+ hint: 'Use on:*={handler}; forwarded props must be functions.',
44
44
  docsLink: DOCS_LINKS.eventBinding,
45
45
  source: _resolveBindingSource(expressionBinding, marker, eventBinding)
46
46
  });
@@ -57,7 +57,7 @@ function _createWrappedEventHandler(handler, expressionBinding, marker, eventBin
57
57
  message: `Event handler failed for "${eventBinding.event}"`,
58
58
  marker: { type: `data-zx-on-${eventBinding.event}`, id: eventBinding.index },
59
59
  path: `event[${eventBinding.index}].${eventBinding.event}`,
60
- hint: 'Inspect the handler body and referenced state.',
60
+ hint: 'Inspect handler body and referenced state.',
61
61
  docsLink: DOCS_LINKS.eventBinding,
62
62
  source: _resolveBindingSource(expressionBinding, marker, eventBinding)
63
63
  });
@@ -3,7 +3,6 @@ export function _evaluateExpression(binding: any, stateValues: any, stateKeys: a
3
3
  export function _throwUnresolvedMemberChainError(literal: any, markerIndex: any, mode: any, pathSuffix: any, hint: any, source: any): void;
4
4
  export function _resolveStrictMemberChainLiteral(literal: any, stateValues: any, stateKeys: any, params: any, ssrData: any, mode: any, props: any, markerIndex: any, source: any): any;
5
5
  export function _resolvePrimitiveLiteral(literal: any): any;
6
- export function _buildLiteralScope(stateValues: any, stateKeys: any, params: any, ssrData: any, mode: any, props: any): any;
7
6
  export function _resolveBindingSource(binding: any, markerBinding: any, eventBinding: any): any;
8
7
  export function _describeBindingExpression(binding: any): string;
9
8
  export function _markerTypeForError(kind: any): any;
@@ -1,6 +1,7 @@
1
1
  import { throwZenithRuntimeError, DOCS_LINKS } from './diagnostics.js';
2
2
  import { _fragment } from './markup.js';
3
3
  export const UNRESOLVED_LITERAL = Symbol('unresolved_literal');
4
+ const OWN = Object.prototype.hasOwnProperty;
4
5
  export const STRICT_MEMBER_CHAIN_LITERAL_RE = /^(?:true|false|null|undefined|[A-Za-z_$][A-Za-z0-9_$]*(\.[A-Za-z_$][A-Za-z0-9_$]*)*)$/;
5
6
  export const CANONICAL_MEMBER_CHAIN_BASES = new Set(['props', 'params', 'data', 'ssr']);
6
7
  export const UNSAFE_MEMBER_KEYS = new Set(['__proto__', 'prototype', 'constructor']);
@@ -17,109 +18,60 @@ export function _resolveExpressionSignalIndices(binding) {
17
18
  return [];
18
19
  }
19
20
  export function _evaluateExpression(binding, stateValues, stateKeys, signalMap, componentBindings, params, ssrData, mode, props, exprFns, markerBinding = null, eventBinding = null) {
20
- if (binding.fn_index != null && binding.fn_index !== undefined) {
21
- const fns = Array.isArray(exprFns) ? exprFns : [];
22
- const fn = fns[binding.fn_index];
21
+ const runtimeProps = props || {};
22
+ if (binding.fn_index != null) {
23
+ const fn = Array.isArray(exprFns) ? exprFns[binding.fn_index] : undefined;
23
24
  if (typeof fn === 'function') {
24
- try {
25
- return fn({
26
- signalMap,
27
- params,
28
- ssrData,
29
- props: props || {},
30
- componentBindings,
31
- fragment: _fragment
32
- });
33
- }
34
- catch (fnErr) {
35
- throw fnErr;
36
- }
25
+ return fn({
26
+ signalMap,
27
+ params,
28
+ ssrData,
29
+ props: runtimeProps,
30
+ componentBindings,
31
+ fragment: _fragment
32
+ });
37
33
  }
38
34
  }
39
- if (binding.signal_index !== null && binding.signal_index !== undefined) {
35
+ if (binding.signal_index != null) {
40
36
  const signalValue = signalMap.get(binding.signal_index);
41
37
  if (!signalValue || typeof signalValue.get !== 'function') {
42
38
  throw new Error('[Zenith Runtime] expression.signal_index did not resolve to a signal');
43
39
  }
44
- return mode === 'event' ? signalValue : signalValue.get();
40
+ return _rvm(signalValue, mode);
45
41
  }
46
- if (binding.state_index !== null && binding.state_index !== undefined) {
47
- const resolved = stateValues[binding.state_index];
48
- if (mode !== 'event' &&
49
- resolved &&
50
- typeof resolved === 'object' &&
51
- typeof resolved.get === 'function') {
52
- return resolved.get();
53
- }
54
- if (mode !== 'event' && typeof resolved === 'function') {
55
- return resolved();
56
- }
57
- return resolved;
42
+ if (binding.state_index != null) {
43
+ return _rvm(stateValues[binding.state_index], mode);
58
44
  }
59
45
  if (typeof binding.component_instance === 'string' && typeof binding.component_binding === 'string') {
60
- const instanceBindings = componentBindings[binding.component_instance];
61
- const resolved = instanceBindings && Object.prototype.hasOwnProperty.call(instanceBindings, binding.component_binding)
62
- ? instanceBindings[binding.component_binding]
63
- : undefined;
64
- if (mode !== 'event' &&
65
- resolved &&
66
- typeof resolved === 'object' &&
67
- typeof resolved.get === 'function') {
68
- return resolved.get();
69
- }
70
- if (mode !== 'event' && typeof resolved === 'function') {
71
- return resolved();
72
- }
73
- return resolved;
46
+ return _rvm(_rcb(binding, componentBindings), mode);
74
47
  }
75
- if (binding.literal !== null && binding.literal !== undefined) {
76
- if (typeof binding.literal === 'string') {
77
- const trimmedLiteral = binding.literal.trim();
78
- // 1. Static primitives (true, false, null, undefined, numbers, quoted strings)
79
- const primitiveValue = _resolvePrimitiveLiteral(trimmedLiteral);
80
- if (primitiveValue !== UNRESOLVED_LITERAL) {
81
- return primitiveValue;
82
- }
83
- // 2. Canonical payload roots
84
- if (trimmedLiteral === 'data' || trimmedLiteral === 'ssr') {
85
- return ssrData;
86
- }
87
- if (trimmedLiteral === 'params') {
88
- return params;
89
- }
90
- if (trimmedLiteral === 'props') {
91
- return props || {};
92
- }
93
- // 3. Bounded canonical member chains (props.*, params.*, data.*, ssr.*, exact stateKeys)
94
- const strictMemberValue = _resolveStrictMemberChainLiteral(trimmedLiteral, stateValues, stateKeys, params, ssrData, mode, props, binding.marker_index, _resolveBindingSource(binding, markerBinding, eventBinding));
95
- if (strictMemberValue !== UNRESOLVED_LITERAL) {
96
- return strictMemberValue;
97
- }
98
- // 4. Anything else is a literal that was not lowered by the compiler.
99
- // No heuristic guessing, no identifier extraction, no alias recovery.
100
- throwZenithRuntimeError({
101
- phase: 'bind',
102
- code: 'EXPRESSION_NOT_LOWERED',
103
- message: `Expression literal was not lowered by the compiler: ${_truncateLiteralForError(trimmedLiteral)}`,
104
- marker: {
105
- type: _markerTypeForError(mode),
106
- id: binding.marker_index
107
- },
108
- path: `expression[${binding.marker_index}]`,
109
- hint: 'This expression must be lowered to fn_index, signal_index, or state_index by the compiler. Literal string interpretation is restricted to static primitives and canonical member chains (props.*, params.*, data.*, ssr.*).',
110
- docsLink: DOCS_LINKS.expressionScope,
111
- source: _resolveBindingSource(binding, markerBinding, eventBinding)
112
- });
113
- }
48
+ if (binding.literal == null) {
49
+ return '';
50
+ }
51
+ if (typeof binding.literal !== 'string') {
114
52
  return binding.literal;
115
53
  }
116
- return '';
54
+ const trimmedLiteral = binding.literal.trim();
55
+ const primitiveValue = _resolvePrimitiveLiteral(trimmedLiteral);
56
+ if (primitiveValue !== UNRESOLVED_LITERAL) {
57
+ return primitiveValue;
58
+ }
59
+ const canonicalRootValue = _rcr(trimmedLiteral, params, ssrData, runtimeProps);
60
+ if (canonicalRootValue !== UNRESOLVED_LITERAL) {
61
+ return canonicalRootValue;
62
+ }
63
+ const source = _resolveBindingSource(binding, markerBinding, eventBinding);
64
+ const strictMemberValue = _resolveStrictMemberChainLiteral(trimmedLiteral, stateValues, stateKeys, params, ssrData, mode, runtimeProps, binding.marker_index, source);
65
+ if (strictMemberValue !== UNRESOLVED_LITERAL) {
66
+ return strictMemberValue;
67
+ }
68
+ _tenl(trimmedLiteral, binding.marker_index, mode, source);
117
69
  }
118
70
  export function _throwUnresolvedMemberChainError(literal, markerIndex, mode, pathSuffix, hint, source) {
119
71
  throwZenithRuntimeError({
120
72
  phase: 'bind',
121
73
  code: 'UNRESOLVED_EXPRESSION',
122
- message: `Failed to resolve expression literal: ${_truncateLiteralForError(literal)}`,
74
+ message: `Failed to resolve literal: ${_truncateLiteralForError(literal)}`,
123
75
  marker: {
124
76
  type: _markerTypeForError(mode),
125
77
  id: markerIndex
@@ -134,53 +86,53 @@ export function _resolveStrictMemberChainLiteral(literal, stateValues, stateKeys
134
86
  if (typeof literal !== 'string' || !STRICT_MEMBER_CHAIN_LITERAL_RE.test(literal)) {
135
87
  return UNRESOLVED_LITERAL;
136
88
  }
137
- // Primitives are handled by _resolvePrimitiveLiteral before this function
138
89
  if (literal === 'true' || literal === 'false' || literal === 'null' || literal === 'undefined') {
139
90
  return UNRESOLVED_LITERAL;
140
91
  }
141
92
  const segments = literal.split('.');
142
93
  const baseIdentifier = segments[0];
143
- // Bounded resolution: only canonical payload prefixes and exact state keys
144
- const isCanonicalBase = CANONICAL_MEMBER_CHAIN_BASES.has(baseIdentifier);
145
- const isExactStateKey = !isCanonicalBase && Array.isArray(stateKeys) && stateKeys.includes(baseIdentifier);
146
- if (!isCanonicalBase && !isExactStateKey) {
147
- // Not a canonical base and not an exact state key — this literal was not lowered
94
+ const baseValue = _resolveStrictBase(baseIdentifier, stateValues, stateKeys, params, ssrData, props);
95
+ if (baseValue === UNRESOLVED_LITERAL) {
148
96
  return UNRESOLVED_LITERAL;
149
97
  }
150
- const scope = _buildLiteralScope(stateValues, stateKeys, params, ssrData, mode, props);
151
- if (!Object.prototype.hasOwnProperty.call(scope, baseIdentifier)) {
152
- _throwUnresolvedMemberChainError(literal, markerIndex, mode, `expression.${baseIdentifier}`, `Base identifier "${baseIdentifier}" is not bound. Check props/data/params and declared state keys.`, source);
153
- }
154
- let cursor = scope[baseIdentifier];
98
+ const failResolve = (suffix, hint) => _throwUnresolvedMemberChainError(literal, markerIndex, mode, `expression.${suffix}`, hint, source);
99
+ let cursor = baseValue;
155
100
  let traversedPath = baseIdentifier;
156
101
  for (let i = 1; i < segments.length; i++) {
157
102
  const segment = segments[i];
158
103
  if (UNSAFE_MEMBER_KEYS.has(segment)) {
159
- throwZenithRuntimeError({
160
- phase: 'bind',
161
- code: 'UNSAFE_MEMBER_ACCESS',
162
- message: `Blocked unsafe member access: ${segment} in path "${literal}"`,
163
- path: `marker[${markerIndex}].expression.${literal}`,
164
- hint: 'Property access to __proto__, prototype, and constructor is forbidden.',
165
- docsLink: DOCS_LINKS.expressionScope,
166
- source
167
- });
104
+ _tuma(literal, markerIndex, segment, source);
168
105
  }
169
106
  if (cursor === null || cursor === undefined) {
170
- _throwUnresolvedMemberChainError(literal, markerIndex, mode, `expression.${traversedPath}.${segment}`, `Cannot read "${segment}" from ${traversedPath} because it is null or undefined.`, source);
107
+ failResolve(`${traversedPath}.${segment}`, `Cannot read "${segment}" from ${traversedPath}; value is null/undefined.`);
171
108
  }
172
109
  const cursorType = typeof cursor;
173
110
  if (cursorType !== 'object' && cursorType !== 'function') {
174
- _throwUnresolvedMemberChainError(literal, markerIndex, mode, `expression.${traversedPath}.${segment}`, `Cannot read "${segment}" from ${traversedPath} because it resolved to a ${cursorType}.`, source);
111
+ failResolve(`${traversedPath}.${segment}`, `Cannot read "${segment}" from ${traversedPath}; value is ${cursorType}.`);
175
112
  }
176
- if (!Object.prototype.hasOwnProperty.call(cursor, segment)) {
177
- _throwUnresolvedMemberChainError(literal, markerIndex, mode, `expression.${traversedPath}.${segment}`, `Missing member "${segment}" on ${traversedPath}. Check your bindings.`, source);
113
+ if (!OWN.call(cursor, segment)) {
114
+ failResolve(`${traversedPath}.${segment}`, `Missing member "${segment}" on ${traversedPath}.`);
178
115
  }
179
116
  cursor = cursor[segment];
180
117
  traversedPath = `${traversedPath}.${segment}`;
181
118
  }
182
119
  return cursor;
183
120
  }
121
+ function _resolveStrictBase(baseIdentifier, stateValues, stateKeys, params, ssrData, props) {
122
+ if (baseIdentifier === '__zenith_fragment')
123
+ return _fragment;
124
+ if (CANONICAL_MEMBER_CHAIN_BASES.has(baseIdentifier)) {
125
+ if (baseIdentifier === 'props')
126
+ return props || {};
127
+ if (baseIdentifier === 'params')
128
+ return params;
129
+ return ssrData;
130
+ }
131
+ if (!Array.isArray(stateKeys))
132
+ return UNRESOLVED_LITERAL;
133
+ const stateIndex = stateKeys.indexOf(baseIdentifier);
134
+ return stateIndex === -1 ? UNRESOLVED_LITERAL : stateValues[stateIndex];
135
+ }
184
136
  export function _resolvePrimitiveLiteral(literal) {
185
137
  if (typeof literal !== 'string') {
186
138
  return UNRESOLVED_LITERAL;
@@ -215,45 +167,21 @@ export function _resolvePrimitiveLiteral(literal) {
215
167
  }
216
168
  return UNRESOLVED_LITERAL;
217
169
  }
218
- export function _buildLiteralScope(stateValues, stateKeys, params, ssrData, mode, props) {
219
- const scope = Object.create(null);
220
- scope.params = params;
221
- scope.data = ssrData;
222
- scope.ssr = ssrData;
223
- scope.props = props || {};
224
- scope.__zenith_fragment = _fragment;
225
- // Exact state keys only — no alias derivation, no mangled-name recovery
226
- if (Array.isArray(stateKeys)) {
227
- for (let i = 0; i < stateKeys.length; i++) {
228
- const key = stateKeys[i];
229
- if (typeof key !== 'string' || key.length === 0) {
230
- continue;
231
- }
232
- if (Object.prototype.hasOwnProperty.call(scope, key)) {
233
- continue;
234
- }
235
- scope[key] = stateValues[i];
236
- }
237
- }
238
- return scope;
239
- }
240
- // _isLikelyExpressionLiteral and _extractMissingIdentifier removed:
241
- // Runtime no longer performs heuristic identifier extraction or expression
242
- // shape guessing. Unresolved literals throw EXPRESSION_NOT_LOWERED directly.
243
170
  export function _resolveBindingSource(binding, markerBinding, eventBinding) {
244
- const candidates = [
245
- binding?.source,
246
- eventBinding?.source,
247
- markerBinding?.source
248
- ];
249
- for (let i = 0; i < candidates.length; i++) {
250
- const candidate = candidates[i];
251
- if (candidate && typeof candidate === 'object' && typeof candidate.file === 'string') {
252
- return candidate;
253
- }
254
- }
171
+ const source = binding?.source;
172
+ if (_isSourceSpan(source))
173
+ return source;
174
+ const eventSource = eventBinding?.source;
175
+ if (_isSourceSpan(eventSource))
176
+ return eventSource;
177
+ const markerSource = markerBinding?.source;
178
+ if (_isSourceSpan(markerSource))
179
+ return markerSource;
255
180
  return undefined;
256
181
  }
182
+ function _isSourceSpan(value) {
183
+ return Boolean(value) && typeof value === 'object' && typeof value.file === 'string';
184
+ }
257
185
  export function _describeBindingExpression(binding) {
258
186
  if (!binding || typeof binding !== 'object') {
259
187
  return '<unknown>';
@@ -286,10 +214,60 @@ export function _truncateLiteralForError(str) {
286
214
  return String(str);
287
215
  const sanitized = str
288
216
  .replace(/[A-Za-z]:\\[^\s"'`]+/g, '<path>')
289
- .replace(/\/Users\/[^\s"'`]+/g, '<path>')
290
- .replace(/\/home\/[^\s"'`]+/g, '<path>')
291
- .replace(/\/private\/[^\s"'`]+/g, '<path>')
292
- .replace(/\/tmp\/[^\s"'`]+/g, '<path>')
293
- .replace(/\/var\/folders\/[^\s"'`]+/g, '<path>');
217
+ .replace(/\/(?:Users|home|private|tmp|var\/folders)\/[^\s"'`]+/g, '<path>');
294
218
  return sanitized.length > 100 ? `${sanitized.substring(0, 97)}...` : sanitized;
295
219
  }
220
+ function _rvm(value, mode) {
221
+ if (mode === 'event') {
222
+ return value;
223
+ }
224
+ if (value && typeof value === 'object' && typeof value.get === 'function') {
225
+ return value.get();
226
+ }
227
+ if (typeof value === 'function') {
228
+ return value();
229
+ }
230
+ return value;
231
+ }
232
+ function _rcb(binding, componentBindings) {
233
+ const instanceBindings = componentBindings[binding.component_instance];
234
+ if (!instanceBindings || !OWN.call(instanceBindings, binding.component_binding)) {
235
+ return undefined;
236
+ }
237
+ return instanceBindings[binding.component_binding];
238
+ }
239
+ function _rcr(literal, params, ssrData, props) {
240
+ if (literal === 'data' || literal === 'ssr')
241
+ return ssrData;
242
+ if (literal === 'params')
243
+ return params;
244
+ if (literal === 'props')
245
+ return props;
246
+ return UNRESOLVED_LITERAL;
247
+ }
248
+ function _tenl(literal, markerIndex, mode, source) {
249
+ throwZenithRuntimeError({
250
+ phase: 'bind',
251
+ code: 'EXPRESSION_NOT_LOWERED',
252
+ message: `Expression literal was not lowered by the compiler: ${_truncateLiteralForError(literal)}`,
253
+ marker: {
254
+ type: _markerTypeForError(mode),
255
+ id: markerIndex
256
+ },
257
+ path: `expression[${markerIndex}]`,
258
+ hint: 'Lower expression to fn_index/signal_index/state_index.',
259
+ docsLink: DOCS_LINKS.expressionScope,
260
+ source
261
+ });
262
+ }
263
+ function _tuma(literal, markerIndex, member, source) {
264
+ throwZenithRuntimeError({
265
+ phase: 'bind',
266
+ code: 'UNSAFE_MEMBER_ACCESS',
267
+ message: `Blocked unsafe member access: ${member} in path "${literal}"`,
268
+ path: `marker[${markerIndex}].expression.${literal}`,
269
+ hint: 'Property access to __proto__/prototype/constructor is forbidden.',
270
+ docsLink: DOCS_LINKS.expressionScope,
271
+ source
272
+ });
273
+ }