@pyreon/solid-compat 0.14.0 → 0.16.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.
package/README.md CHANGED
@@ -151,3 +151,23 @@ function Display() {
151
151
  - **`lazy(loader)`** -- dynamic import wrapper, throws promises for `<Suspense>`.
152
152
  - **`Show`**, **`Switch`**, **`Match`**, **`For`** -- control flow components.
153
153
  - **`Suspense`**, **`ErrorBoundary`** -- boundary components.
154
+
155
+ ## Composing Pyreon framework components inside solid-compat
156
+
157
+ Pyreon's framework components (`RouterView`, `PyreonUI`, `FormProvider`, `QueryClientProvider`, …) ship marked with `nativeCompat()` from `@pyreon/core` — solid-compat's JSX runtime detects the marker and routes them through Pyreon's setup frame instead of the compat wrapper. **You don't need to do anything** for the 24 components shipped marked.
158
+
159
+ If you write your **own** Pyreon-flavored helper that uses `provide()` / `onMount()` / `onUnmount()` / `effect()` at component-body scope and use it in a solid-compat app, mark it explicitly:
160
+
161
+ ```tsx
162
+ import { nativeCompat, provide, createContext } from '@pyreon/core'
163
+
164
+ const MyCtx = createContext<string>('default')
165
+
166
+ function MyProvider(props: { value: string; children?: unknown }) {
167
+ provide(MyCtx, props.value)
168
+ return props.children as never
169
+ }
170
+ nativeCompat(MyProvider) // ← required for compat-mode apps
171
+ ```
172
+
173
+ Without the marker, the wrapper relocates the body's render context and `provide()` lands in a torn-down context stack — descendants read the default. See [`packages/core/core/src/compat-marker.ts`](../../core/core/src/compat-marker.ts) for details.
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
5386
5386
  </script>
5387
5387
  <script>
5388
5388
  /*<!--*/
5389
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"7b35df5d-1","name":"jsx-runtime.ts"},{"uid":"7b35df5d-3","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"7b35df5d-1":{"renderedLength":186,"gzipLength":138,"brotliLength":0,"metaUid":"7b35df5d-0"},"7b35df5d-3":{"renderedLength":19175,"gzipLength":5477,"brotliLength":0,"metaUid":"7b35df5d-2"}},"nodeMetas":{"7b35df5d-0":{"id":"/src/jsx-runtime.ts","moduleParts":{"index.js":"7b35df5d-1"},"imported":[{"uid":"7b35df5d-4"},{"uid":"7b35df5d-5"}],"importedBy":[{"uid":"7b35df5d-2"}]},"7b35df5d-2":{"id":"/src/index.ts","moduleParts":{"index.js":"7b35df5d-3"},"imported":[{"uid":"7b35df5d-4"},{"uid":"7b35df5d-5"},{"uid":"7b35df5d-0"}],"importedBy":[],"isEntry":true},"7b35df5d-4":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"7b35df5d-2"},{"uid":"7b35df5d-0"}]},"7b35df5d-5":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"7b35df5d-2"},{"uid":"7b35df5d-0"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5389
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"index.js","children":[{"name":"src","children":[{"uid":"ba834b47-1","name":"jsx-runtime.ts"},{"uid":"ba834b47-3","name":"index.ts"}]}]}],"isRoot":true},"nodeParts":{"ba834b47-1":{"renderedLength":186,"gzipLength":138,"brotliLength":0,"metaUid":"ba834b47-0"},"ba834b47-3":{"renderedLength":19113,"gzipLength":5456,"brotliLength":0,"metaUid":"ba834b47-2"}},"nodeMetas":{"ba834b47-0":{"id":"/src/jsx-runtime.ts","moduleParts":{"index.js":"ba834b47-1"},"imported":[{"uid":"ba834b47-4"},{"uid":"ba834b47-5"}],"importedBy":[{"uid":"ba834b47-2"}]},"ba834b47-2":{"id":"/src/index.ts","moduleParts":{"index.js":"ba834b47-3"},"imported":[{"uid":"ba834b47-4"},{"uid":"ba834b47-5"},{"uid":"ba834b47-0"}],"importedBy":[],"isEntry":true},"ba834b47-4":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"ba834b47-2"},{"uid":"ba834b47-0"}]},"ba834b47-5":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"ba834b47-2"},{"uid":"ba834b47-0"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5390
5390
 
5391
5391
  const run = () => {
5392
5392
  const width = window.innerWidth;
@@ -5386,7 +5386,7 @@ var drawChart = (function (exports) {
5386
5386
  </script>
5387
5387
  <script>
5388
5388
  /*<!--*/
5389
- const data = {"version":2,"tree":{"name":"root","children":[{"name":"jsx-runtime.js","children":[{"name":"src","children":[{"uid":"e600c1ac-1","name":"jsx-runtime.ts"},{"uid":"e600c1ac-3","name":"jsx-dev-runtime.ts"}]}]}],"isRoot":true},"nodeParts":{"e600c1ac-1":{"renderedLength":4138,"gzipLength":1377,"brotliLength":0,"metaUid":"e600c1ac-0"},"e600c1ac-3":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"e600c1ac-2"}},"nodeMetas":{"e600c1ac-0":{"id":"/src/jsx-runtime.ts","moduleParts":{"jsx-runtime.js":"e600c1ac-1"},"imported":[{"uid":"e600c1ac-4"},{"uid":"e600c1ac-5"}],"importedBy":[{"uid":"e600c1ac-2"}]},"e600c1ac-2":{"id":"/src/jsx-dev-runtime.ts","moduleParts":{"jsx-runtime.js":"e600c1ac-3"},"imported":[{"uid":"e600c1ac-0"}],"importedBy":[],"isEntry":true},"e600c1ac-4":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"e600c1ac-0"}]},"e600c1ac-5":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"e600c1ac-0"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5389
+ const data = {"version":2,"tree":{"name":"root","children":[{"name":"jsx-runtime.js","children":[{"name":"src","children":[{"uid":"ada46576-1","name":"jsx-runtime.ts"},{"uid":"ada46576-3","name":"jsx-dev-runtime.ts"}]}]}],"isRoot":true},"nodeParts":{"ada46576-1":{"renderedLength":4079,"gzipLength":1347,"brotliLength":0,"metaUid":"ada46576-0"},"ada46576-3":{"renderedLength":0,"gzipLength":0,"brotliLength":0,"metaUid":"ada46576-2"}},"nodeMetas":{"ada46576-0":{"id":"/src/jsx-runtime.ts","moduleParts":{"jsx-runtime.js":"ada46576-1"},"imported":[{"uid":"ada46576-4"},{"uid":"ada46576-5"}],"importedBy":[{"uid":"ada46576-2"}]},"ada46576-2":{"id":"/src/jsx-dev-runtime.ts","moduleParts":{"jsx-runtime.js":"ada46576-3"},"imported":[{"uid":"ada46576-0"}],"importedBy":[],"isEntry":true},"ada46576-4":{"id":"@pyreon/core","moduleParts":{},"imported":[],"importedBy":[{"uid":"ada46576-0"}]},"ada46576-5":{"id":"@pyreon/reactivity","moduleParts":{},"imported":[],"importedBy":[{"uid":"ada46576-0"}]}},"env":{"rollup":"4.23.0"},"options":{"gzip":true,"brotli":false,"sourcemap":false}};
5390
5390
 
5391
5391
  const run = () => {
5392
5392
  const width = window.innerWidth;
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ErrorBoundary, For, Match, Show, Suspense, Switch, createContext as createContext$1, onMount as onMount$1, onUnmount, provide, useContext as useContext$1 } from "@pyreon/core";
1
+ import { ErrorBoundary, For, Match, Show, Suspense, Switch, createContext as createContext$1, nativeCompat, onMount as onMount$1, onUnmount, provide, useContext as useContext$1 } from "@pyreon/core";
2
2
  import { batch as pyreonBatch, computed, createSelector as createSelector$1, effect, effectScope, getCurrentScope, onCleanup as onCleanup$1, runUntracked, setCurrentScope, signal } from "@pyreon/reactivity";
3
3
 
4
4
  //#region src/jsx-runtime.ts
@@ -314,7 +314,6 @@ function lazy(loader) {
314
314
  }
315
315
  const SOLID_CTX = Symbol.for("pyreon:solid-ctx");
316
316
  const SOLID_CTX_BRAND = SOLID_CTX;
317
- const NATIVE_COMPONENT = Symbol.for("pyreon:native-compat");
318
317
  /**
319
318
  * Solid-compatible `createContext` — creates a context with a `.Provider`
320
319
  * component. Uses Pyreon's native context stack for tree-scoped nesting.
@@ -322,11 +321,11 @@ const NATIVE_COMPONENT = Symbol.for("pyreon:native-compat");
322
321
  function createContext(defaultValue) {
323
322
  const pyreonCtx = createContext$1(defaultValue);
324
323
  const Provider = (props) => {
325
- const { value, children } = props;
324
+ const { value, children: kids } = props;
326
325
  provide(pyreonCtx, value);
327
- return children ?? null;
326
+ return kids ?? null;
328
327
  };
329
- Provider[NATIVE_COMPONENT] = true;
328
+ nativeCompat(Provider);
330
329
  return {
331
330
  [SOLID_CTX_BRAND]: true,
332
331
  id: pyreonCtx.id,
@@ -658,7 +657,7 @@ function createUniqueId() {
658
657
  * Solid-compatible `DEV` — an object in dev mode, `undefined` in production.
659
658
  * Used for conditional dev-only code: `if (DEV) { ... }`
660
659
  */
661
- const DEV = import.meta.env?.DEV === true ? {} : void 0;
660
+ const DEV = process.env.NODE_ENV !== "production" ? {} : void 0;
662
661
  /**
663
662
  * Solid-compatible `catchError` — wraps a function and catches synchronous errors.
664
663
  */
@@ -1,4 +1,4 @@
1
- import { ErrorBoundary, For, Fragment, Match, Show, Suspense, Switch, h, onUnmount } from "@pyreon/core";
1
+ import { ErrorBoundary, For, Fragment, Match, Show, Suspense, Switch, h, isNativeCompat, onUnmount } from "@pyreon/core";
2
2
  import { runUntracked, signal } from "@pyreon/reactivity";
3
3
 
4
4
  //#region src/jsx-runtime.ts
@@ -119,7 +119,6 @@ function resolveChildInstance() {
119
119
  parentCtx.hooks[idx] = instance;
120
120
  return instance;
121
121
  }
122
- const _NATIVE_COMPAT = Symbol.for("pyreon:native-compat");
123
122
  function jsx(type, props, key) {
124
123
  const { children, ...rest } = props;
125
124
  const propsWithKey = key != null ? {
@@ -131,7 +130,7 @@ function jsx(type, props, key) {
131
130
  ...propsWithKey,
132
131
  children
133
132
  } : propsWithKey);
134
- if (type[_NATIVE_COMPAT]) return h(type, children !== void 0 ? {
133
+ if (isNativeCompat(type)) return h(type, children !== void 0 ? {
135
134
  ...propsWithKey,
136
135
  children
137
136
  } : propsWithKey);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pyreon/solid-compat",
3
- "version": "0.14.0",
3
+ "version": "0.16.0",
4
4
  "description": "SolidJS-compatible API shim for Pyreon — write Solid-style code that runs on Pyreon's reactive engine",
5
5
  "homepage": "https://github.com/pyreon/pyreon/tree/main/packages/solid-compat#readme",
6
6
  "bugs": {
@@ -14,6 +14,7 @@
14
14
  },
15
15
  "files": [
16
16
  "lib",
17
+ "!lib/**/*.map",
17
18
  "src",
18
19
  "README.md",
19
20
  "LICENSE"
@@ -47,17 +48,20 @@
47
48
  "build": "vl_rolldown_build",
48
49
  "dev": "vl_rolldown_build-watch",
49
50
  "test": "vitest run",
51
+ "test:browser": "vitest run --config ./vitest.browser.config.ts",
50
52
  "typecheck": "tsc --noEmit",
51
53
  "lint": "oxlint .",
52
54
  "prepublishOnly": "bun run build"
53
55
  },
54
56
  "dependencies": {
55
- "@pyreon/core": "^0.14.0",
56
- "@pyreon/reactivity": "^0.14.0",
57
- "@pyreon/runtime-dom": "^0.14.0"
57
+ "@pyreon/core": "^0.16.0",
58
+ "@pyreon/reactivity": "^0.16.0",
59
+ "@pyreon/runtime-dom": "^0.16.0"
58
60
  },
59
61
  "devDependencies": {
60
62
  "@happy-dom/global-registrator": "^20.8.9",
63
+ "@pyreon/test-utils": "^0.13.3",
64
+ "@vitest/browser-playwright": "^4.1.4",
61
65
  "happy-dom": "^20.8.3"
62
66
  }
63
67
  }
package/src/env.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Minimal process type — just enough for `process.env.NODE_ENV` checks.
3
+ * Avoids requiring @types/node in consumers that import pyreon source
4
+ * via the `"bun"` export condition.
5
+ */
6
+ declare var process: { env: { NODE_ENV?: string } }
package/src/index.ts CHANGED
@@ -18,6 +18,7 @@ import {
18
18
  ErrorBoundary,
19
19
  For,
20
20
  Match,
21
+ nativeCompat,
21
22
  createContext as pyreonCreateContext,
22
23
  onMount as pyreonOnMount,
23
24
  onUnmount as pyreonOnUnmount,
@@ -535,9 +536,6 @@ export interface SolidContext<T> {
535
536
 
536
537
  const SOLID_CTX_BRAND: typeof SOLID_CTX = SOLID_CTX
537
538
 
538
- // Tag the Provider so wrapCompatComponent in jsx-runtime skips it
539
- const NATIVE_COMPONENT = Symbol.for('pyreon:native-compat')
540
-
541
539
  /**
542
540
  * Solid-compatible `createContext` — creates a context with a `.Provider`
543
541
  * component. Uses Pyreon's native context stack for tree-scoped nesting.
@@ -548,11 +546,11 @@ export function createContext<T>(defaultValue?: T): SolidContext<T> {
548
546
  // Provider is a NATIVE Pyreon component — not compat-wrapped.
549
547
  // It calls provide() once during setup to push onto the context stack.
550
548
  const Provider = (props: Record<string, unknown>) => {
551
- const { value, children } = props as { value: T; children?: VNodeChild }
549
+ const { value, children: kids } = props as { value: T; children?: VNodeChild }
552
550
  pyreonProvide(pyreonCtx, value)
553
- return children ?? null
551
+ return kids ?? null
554
552
  }
555
- ;(Provider as unknown as Record<symbol, boolean>)[NATIVE_COMPONENT] = true
553
+ nativeCompat(Provider)
556
554
 
557
555
  const ctx: SolidContext<T> = {
558
556
  [SOLID_CTX_BRAND]: true as const,
@@ -1089,8 +1087,7 @@ export function createUniqueId(): string {
1089
1087
  * Solid-compatible `DEV` — an object in dev mode, `undefined` in production.
1090
1088
  * Used for conditional dev-only code: `if (DEV) { ... }`
1091
1089
  */
1092
- export const DEV =
1093
- (import.meta as { env?: { DEV?: boolean } }).env?.DEV === true ? {} : undefined
1090
+ export const DEV = process.env.NODE_ENV !== 'production' ? {} : undefined
1094
1091
 
1095
1092
  // ─── catchError ─────────────────────────────────────────────────────────────
1096
1093
 
@@ -32,6 +32,7 @@ import {
32
32
  For,
33
33
  Fragment,
34
34
  h,
35
+ isNativeCompat,
35
36
  Match,
36
37
  onUnmount,
37
38
  Show,
@@ -260,9 +261,6 @@ function resolveChildInstance(): ChildInstance | undefined {
260
261
 
261
262
  // ─── JSX functions ───────────────────────────────────────────────────────────
262
263
 
263
- // Tag used by compat context Providers to skip compat wrapping
264
- const _NATIVE_COMPAT = Symbol.for('pyreon:native-compat')
265
-
266
264
  export function jsx(
267
265
  type: string | ComponentFn | symbol,
268
266
  props: Props & { children?: VNodeChild | VNodeChild[] },
@@ -272,13 +270,20 @@ export function jsx(
272
270
  const propsWithKey = (key != null ? { ...rest, key } : rest) as Props
273
271
 
274
272
  if (typeof type === 'function') {
273
+ // Defense-in-depth: hardcoded set of Pyreon core control-flow primitives
274
+ // that are always native (kept even after the marker convergence — these
275
+ // are imported into solid-compat directly, so guarding their identity
276
+ // doesn't cost a property lookup and ensures the marker is never lost
277
+ // through any tree-shaking edge case).
275
278
  if (_nativeComponents.has(type)) {
276
279
  const componentProps = children !== undefined ? { ...propsWithKey, children } : propsWithKey
277
280
  return h(type as ComponentFn, componentProps)
278
281
  }
279
282
 
280
- // Native compat components (e.g. context Providers) skip compat wrapping
281
- if ((type as unknown as Record<symbol, boolean>)[_NATIVE_COMPAT]) {
283
+ // Native Pyreon framework components (context Providers, RouterView, etc.)
284
+ // skip compat wrapping see `@pyreon/core`'s `nativeCompat()` for the
285
+ // full contract.
286
+ if (isNativeCompat(type)) {
282
287
  const componentProps = children !== undefined ? { ...propsWithKey, children } : propsWithKey
283
288
  return h(type as ComponentFn, componentProps)
284
289
  }
@@ -0,0 +1,32 @@
1
+ import { h } from '@pyreon/core'
2
+ import { describe, expect, it } from 'vitest'
3
+ import { mountInBrowser } from '@pyreon/test-utils/browser'
4
+ import { createSignal } from './index'
5
+
6
+ /**
7
+ * Real-browser smoke test for `@pyreon/solid-compat`.
8
+ *
9
+ * Per the test-environment-parity rule (`pyreon/require-browser-smoke-test`),
10
+ * every browser-categorized package must ship at least one
11
+ * `*.browser.test.*` file. This catches regressions that happy-dom unit
12
+ * tests can hide: importing the public API and exercising the SolidJS
13
+ * `createSignal` shim end-to-end in real Chromium.
14
+ */
15
+ describe('@pyreon/solid-compat — browser smoke', () => {
16
+ it('createSignal returns [getter, setter] that round-trip', () => {
17
+ const [count, setCount] = createSignal(0)
18
+ expect(count()).toBe(0)
19
+ setCount(7)
20
+ expect(count()).toBe(7)
21
+ })
22
+
23
+ it('mounts a static element in real browser', () => {
24
+ const [name] = createSignal('solid-compat')
25
+ const vnode = h('div', { id: 'solid-compat' }, name())
26
+ const { container, unmount } = mountInBrowser(vnode)
27
+ const el = container.querySelector('#solid-compat')!
28
+ expect(el.textContent).toBe('solid-compat')
29
+ unmount()
30
+ expect(document.getElementById('solid-compat')).toBeNull()
31
+ })
32
+ })
@@ -0,0 +1,70 @@
1
+ import type { ComponentFn } from '@pyreon/core'
2
+ import { createContext, h, nativeCompat, provide, useContext } from '@pyreon/core'
3
+ import { mount } from '@pyreon/runtime-dom'
4
+ import { describe, expect, it } from 'vitest'
5
+ import { jsx } from '../jsx-runtime'
6
+
7
+ // Per-compat unit-level regression test for the marker-bypass contract.
8
+ // See `react-compat/src/tests/native-marker-bypass.test.tsx` for the full
9
+ // rationale + bisect-verification notes.
10
+ //
11
+ // Solid-compat note: solid-compat's jsx() has TWO native-routing paths in
12
+ // sequence — first the hardcoded `_nativeComponents` Set as defense-in-depth
13
+ // (Show, For, Switch, Match, Suspense, ErrorBoundary), then the marker
14
+ // check. These tests use USER-defined NativeProvider/Consumer (NOT in the
15
+ // hardcoded set), so the bypass MUST come from the marker path
16
+ // (`isNativeCompat(type)`), proving the marker check fires correctly.
17
+ //
18
+ // Bisect-verified per file: removing the `if (isNativeCompat(type))` branch
19
+ // from solid-compat's jsx-runtime (while keeping the `_nativeComponents`
20
+ // set check) causes test #1 to fail with
21
+ // `expected [Function wrapped] to be [Function Native]`.
22
+
23
+ function container(): HTMLElement {
24
+ const el = document.createElement('div')
25
+ document.body.appendChild(el)
26
+ return el
27
+ }
28
+
29
+ describe('solid-compat — nativeCompat() marker bypass', () => {
30
+ it('jsx() routes marked components through h() directly (no wrapper)', () => {
31
+ const Native = (props: { children?: unknown }) => h('div', null, props.children as never)
32
+ nativeCompat(Native)
33
+
34
+ const vnode = jsx(Native, {})
35
+
36
+ expect(vnode.type).toBe(Native)
37
+ })
38
+
39
+ it('jsx() wraps UNMARKED components (control — bypass is selective)', () => {
40
+ const Unmarked = (props: { children?: unknown }) => h('div', null, props.children as never)
41
+
42
+ const vnode = jsx(Unmarked, {})
43
+
44
+ expect(vnode.type).not.toBe(Unmarked)
45
+ expect(typeof vnode.type).toBe('function')
46
+ })
47
+
48
+ it('marked Provider mounts inside Pyreon setup frame — provide() reaches descendants', () => {
49
+ const Ctx = createContext<string>('default')
50
+
51
+ const Provider: ComponentFn = (props) => {
52
+ provide(Ctx, props.value as string)
53
+ return props.children as never
54
+ }
55
+ nativeCompat(Provider)
56
+
57
+ const Consumer: ComponentFn = () => {
58
+ const value = useContext(Ctx)
59
+ return h('span', { 'data-value': value }, value)
60
+ }
61
+ nativeCompat(Consumer)
62
+
63
+ const el = container()
64
+ mount(jsx(Provider, { value: 'native', children: jsx(Consumer, {}) }), el)
65
+
66
+ const span = el.querySelector('span')
67
+ expect(span?.getAttribute('data-value')).toBe('native')
68
+ expect(span?.textContent).toBe('native')
69
+ })
70
+ })
package/lib/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["pyreonSignal","pyreonEffect","pyreonComputed","pyreonCreateSelector","pyreonCreateContext","pyreonUseContext"],"sources":["../src/jsx-runtime.ts","../src/index.ts"],"sourcesContent":["/**\n * Compat JSX runtime for SolidJS compatibility mode.\n *\n * When `jsxImportSource` is redirected to `@pyreon/solid-compat` (via the vite\n * plugin's `compat: \"solid\"` option), OXC rewrites JSX to import from this file.\n *\n * For component VNodes, we wrap the component function so it returns a reactive\n * accessor — enabling Solid-style re-renders on state change while Pyreon's\n * existing renderer handles all DOM work.\n *\n * The component body runs inside `runUntracked` to prevent signal reads (from\n * createSignal getters) from being tracked by the reactive accessor. Only the\n * version signal triggers re-renders.\n *\n * ## Child instance preservation\n *\n * When a parent component re-renders, mountReactive does a full teardown+rebuild\n * of the DOM tree. Without preservation, child components get brand new\n * RenderContexts with empty hooks arrays — causing `onMount` and `onCleanup`\n * to fire again, which can trigger infinite re-render loops.\n *\n * To fix this, we store child RenderContexts in the parent's hooks array (indexed\n * by the parent's hook counter). When the child wrapper is called again after a\n * parent re-render, it reuses the existing ctx (preserving hooks state), so\n * hook-indexed guards like `if (idx >= ctx.hooks.length) return` work correctly\n * and lifecycle hooks don't re-fire.\n */\n\nimport type { ComponentFn, Props, VNode, VNodeChild } from '@pyreon/core'\nimport {\n ErrorBoundary,\n For,\n Fragment,\n h,\n Match,\n onUnmount,\n Show,\n Suspense,\n Switch,\n} from '@pyreon/core'\nimport { runUntracked, signal } from '@pyreon/reactivity'\n\nexport { Fragment }\n\n// ─── Render context (used by hooks) ──────────────────────────────────────────\n\nexport interface RenderContext {\n hooks: unknown[]\n scheduleRerender: () => void\n /** Effect entries pending execution after render */\n pendingEffects: EffectEntry[]\n /** Layout effect entries pending execution after render */\n pendingLayoutEffects: EffectEntry[]\n /** Set to true when the component is unmounted */\n unmounted: boolean\n /** Callbacks to run on unmount (lifecycle + effect cleanups) */\n unmountCallbacks: (() => void)[]\n}\n\nexport interface EffectEntry {\n fn: () => (() => void) | void\n deps: unknown[] | undefined\n cleanup: (() => void) | undefined\n}\n\nlet _currentCtx: RenderContext | null = null\nlet _hookIndex = 0\n\nexport function getCurrentCtx(): RenderContext | null {\n return _currentCtx\n}\n\nexport function getHookIndex(): number {\n return _hookIndex++\n}\n\nexport function beginRender(ctx: RenderContext): void {\n _currentCtx = ctx\n _hookIndex = 0\n ctx.pendingEffects = []\n ctx.pendingLayoutEffects = []\n}\n\nexport function endRender(): void {\n _currentCtx = null\n _hookIndex = 0\n}\n\n// ─── Effect runners ──────────────────────────────────────────────────────────\n\nfunction runLayoutEffects(entries: EffectEntry[]): void {\n for (const entry of entries) {\n if (entry.cleanup) entry.cleanup()\n const cleanup = entry.fn()\n entry.cleanup = typeof cleanup === 'function' ? cleanup : undefined\n }\n}\n\nfunction scheduleEffects(ctx: RenderContext, entries: EffectEntry[]): void {\n if (entries.length === 0) return\n queueMicrotask(() => {\n for (const entry of entries) {\n if (ctx.unmounted) return\n if (entry.cleanup) entry.cleanup()\n const cleanup = entry.fn()\n entry.cleanup = typeof cleanup === 'function' ? cleanup : undefined\n }\n })\n}\n\n// ─── Child instance preservation ─────────────────────────────────────────────\n\n/** Stored in the parent's hooks array to preserve child state across re-renders */\ninterface ChildInstance {\n ctx: RenderContext\n version: ReturnType<typeof signal<number>>\n updateScheduled: boolean\n}\n\n// Internal prop keys for passing parent context info to child wrappers\nconst _CHILD_INSTANCE = Symbol.for('pyreon.childInstance')\nconst noop = () => {\n /* noop */\n}\n\n// ─── Component wrapping ──────────────────────────────────────────────────────\n\nconst _wrapperCache = new WeakMap<Function, ComponentFn>()\n\n// Pyreon core components that must NOT be wrapped — they rely on internal reactivity\nconst _nativeComponents: Set<Function> = new Set([\n Show,\n For,\n Switch,\n Match,\n Suspense,\n ErrorBoundary,\n])\n\nfunction wrapCompatComponent(solidComponent: Function): ComponentFn {\n if (_nativeComponents.has(solidComponent)) return solidComponent as ComponentFn\n\n let wrapped = _wrapperCache.get(solidComponent)\n if (wrapped) return wrapped\n\n // The wrapper returns a reactive accessor (() => VNodeChild) which Pyreon's\n // mountChild treats as a reactive expression via mountReactive.\n wrapped = ((props: Props) => {\n // Check for a preserved child instance from the parent's hooks\n const existing = (props as Record<symbol, unknown>)[_CHILD_INSTANCE] as\n | ChildInstance\n | undefined\n\n const ctx: RenderContext = existing?.ctx ?? {\n hooks: [],\n scheduleRerender: () => {\n // Will be replaced below after version signal is created\n },\n pendingEffects: [],\n pendingLayoutEffects: [],\n unmounted: false,\n unmountCallbacks: [],\n }\n\n // When reusing an existing ctx after parent re-render, reset unmounted flag\n // and clear stale unmount callbacks (they belong to the previous mount cycle)\n if (existing) {\n ctx.unmounted = false\n ctx.unmountCallbacks = []\n }\n\n const version = existing?.version ?? signal(0)\n\n // Use a shared updateScheduled flag (preserved across parent re-renders)\n let updateScheduled = existing?.updateScheduled ?? false\n\n ctx.scheduleRerender = () => {\n if (ctx.unmounted || updateScheduled) return\n updateScheduled = true\n queueMicrotask(() => {\n updateScheduled = false\n if (!ctx.unmounted) version.set(version.peek() + 1)\n })\n }\n\n // Register cleanup when component unmounts\n onUnmount(() => {\n ctx.unmounted = true\n for (const cb of ctx.unmountCallbacks) cb()\n })\n\n // Strip the internal prop before passing to the component\n const { [_CHILD_INSTANCE]: _stripped, ...cleanProps } = props as Record<\n string | symbol,\n unknown\n >\n\n // Return reactive accessor — Pyreon's mountChild calls mountReactive\n return () => {\n version() // tracked read — triggers re-execution when state changes\n beginRender(ctx)\n // runUntracked prevents signal reads (from createSignal getters) from\n // being tracked by this accessor — only the version signal should trigger re-renders\n const result = runUntracked(() => (solidComponent as ComponentFn)(cleanProps as Props))\n const layoutEffects = ctx.pendingLayoutEffects\n const effects = ctx.pendingEffects\n endRender()\n\n runLayoutEffects(layoutEffects)\n scheduleEffects(ctx, effects)\n\n return result\n }\n }) as unknown as ComponentFn\n\n // Forward __loading from lazy components so Pyreon's Suspense can detect them\n if ('__loading' in solidComponent) {\n ;(wrapped as unknown as Record<string, unknown>).__loading = (\n solidComponent as unknown as Record<string, unknown>\n ).__loading\n }\n\n _wrapperCache.set(solidComponent, wrapped)\n return wrapped\n}\n\n// ─── Child instance lookup ───────────────────────────────────────────────────\n\nfunction createChildInstance(): ChildInstance {\n return {\n ctx: {\n hooks: [],\n scheduleRerender: noop,\n pendingEffects: [],\n pendingLayoutEffects: [],\n unmounted: false,\n unmountCallbacks: [],\n },\n version: signal(0),\n updateScheduled: false,\n }\n}\n\n/**\n * During a parent component render, get or create the child instance at the\n * current hook index. Returns undefined when called outside a component render.\n */\nfunction resolveChildInstance(): ChildInstance | undefined {\n const parentCtx = _currentCtx\n if (!parentCtx) return undefined\n\n const idx = _hookIndex++\n if (idx < parentCtx.hooks.length) {\n return parentCtx.hooks[idx] as ChildInstance\n }\n const instance = createChildInstance()\n parentCtx.hooks[idx] = instance\n return instance\n}\n\n// ─── JSX functions ───────────────────────────────────────────────────────────\n\n// Tag used by compat context Providers to skip compat wrapping\nconst _NATIVE_COMPAT = Symbol.for('pyreon:native-compat')\n\nexport function jsx(\n type: string | ComponentFn | symbol,\n props: Props & { children?: VNodeChild | VNodeChild[] },\n key?: string | number | null,\n): VNode {\n const { children, ...rest } = props\n const propsWithKey = (key != null ? { ...rest, key } : rest) as Props\n\n if (typeof type === 'function') {\n if (_nativeComponents.has(type)) {\n const componentProps = children !== undefined ? { ...propsWithKey, children } : propsWithKey\n return h(type as ComponentFn, componentProps)\n }\n\n // Native compat components (e.g. context Providers) skip compat wrapping\n if ((type as unknown as Record<symbol, boolean>)[_NATIVE_COMPAT]) {\n const componentProps = children !== undefined ? { ...propsWithKey, children } : propsWithKey\n return h(type as ComponentFn, componentProps)\n }\n\n const wrapped = wrapCompatComponent(type)\n const componentProps =\n children !== undefined ? { ...propsWithKey, children } : { ...propsWithKey }\n\n const childInstance = resolveChildInstance()\n if (childInstance) {\n ;(componentProps as Record<symbol, unknown>)[_CHILD_INSTANCE] = childInstance\n }\n\n return h(wrapped, componentProps)\n }\n\n // DOM element or symbol (Fragment): children go in vnode.children\n const childArray = children === undefined ? [] : Array.isArray(children) ? children : [children]\n\n return h(type, propsWithKey, ...(childArray as VNodeChild[]))\n}\n\nexport const jsxs = jsx\nexport const jsxDEV = jsx\n","/**\n * @pyreon/solid-compat\n *\n * Fully SolidJS-compatible API powered by Pyreon's reactive engine.\n *\n * Components re-render on state change via the compat JSX runtime wrapper.\n * Signals use Pyreon's native signal system internally (enabling auto-tracking\n * for createEffect/createMemo), while the component body runs inside\n * `runUntracked` to prevent signal reads from being tracked by the reactive\n * accessor. Only the version signal triggers re-renders.\n *\n * USAGE:\n * import { createSignal, createEffect } from \"solid-js\" // aliased by vite plugin\n */\n\nimport type { ComponentFn, Context, LazyComponent, Props, VNodeChild } from '@pyreon/core'\nimport {\n ErrorBoundary,\n For,\n Match,\n createContext as pyreonCreateContext,\n onMount as pyreonOnMount,\n onUnmount as pyreonOnUnmount,\n provide as pyreonProvide,\n useContext as pyreonUseContext,\n Show,\n Suspense,\n Switch,\n} from '@pyreon/core'\nimport {\n type EffectScope,\n effectScope,\n getCurrentScope,\n batch as pyreonBatch,\n computed as pyreonComputed,\n createSelector as pyreonCreateSelector,\n effect as pyreonEffect,\n onCleanup as pyreonOnCleanup,\n signal as pyreonSignal,\n runUntracked,\n setCurrentScope,\n} from '@pyreon/reactivity'\nimport { getCurrentCtx, getHookIndex } from './jsx-runtime'\n\n// ─── Type exports (Solid API surface) ───────────────────────────────────────\n\n/** Solid-compatible read accessor type */\nexport type Accessor<T> = () => T\n\n/** Solid-compatible setter type */\nexport type Setter<T> = (v: T | ((prev: T) => T)) => void\n\n/** Solid-compatible signal tuple type */\nexport type Signal<T> = [Accessor<T>, Setter<T>]\n\n/** Solid-compatible owner type */\nexport type Owner = EffectScope\n\n/** Solid-compatible component type */\nexport type Component<P = object> = (props: P) => VNodeChild\n\n/** Solid-compatible parent component type (includes children) */\nexport type ParentComponent<P = object> = (props: P & { children?: VNodeChild }) => VNodeChild\n\n/** Solid-compatible flow component type */\nexport type FlowComponent<P = object> = Component<P>\n\n/** Solid-compatible void component type (no children) */\nexport type VoidComponent<P = object> = Component<P>\n\n// ─── createSignal ────────────────────────────────────────────────────────────\n\nexport type SignalGetter<T> = () => T\nexport type SignalSetter<T> = (v: T | ((prev: T) => T)) => void\n\nexport interface CreateSignalOptions<T> {\n equals?: false | ((prev: T, next: T) => boolean)\n}\n\n/** Hook entry for createSignal — stores signal + stable getter/setter references */\ninterface SignalHookEntry<T> {\n signal: ReturnType<typeof pyreonSignal<T>>\n getter: SignalGetter<T>\n setter: SignalSetter<T>\n}\n\n/**\n * When `equals: false`, Pyreon's internal `Object.is` dedup must be bypassed.\n * We wrap values in a `{ v: T }` box so every `.set()` creates a new reference\n * that passes the internal `Object.is` check. The getter unwraps transparently.\n */\ninterface Boxed<T> {\n v: T\n}\n\nexport function createSignal<T>(\n initialValue: T,\n options?: CreateSignalOptions<T>,\n): [SignalGetter<T>, SignalSetter<T>] {\n const neverEqual = options?.equals === false\n const ctx = getCurrentCtx()\n if (ctx) {\n const idx = getHookIndex()\n if (idx >= ctx.hooks.length) {\n const { scheduleRerender } = ctx\n\n let getter: SignalGetter<T>\n let setter: SignalSetter<T>\n\n if (neverEqual) {\n // Boxed mode — bypass Pyreon's Object.is dedup\n const s = pyreonSignal<Boxed<T>>({ v: initialValue })\n getter = () => s().v\n setter = (v) => {\n const prev = s.peek().v\n const next = typeof v === 'function' ? (v as (prev: T) => T)(prev) : v\n s.set({ v: next }) // new object always passes Object.is\n scheduleRerender()\n }\n } else {\n const s = pyreonSignal<T>(initialValue)\n getter = () => s()\n setter = (v) => {\n const prev = s.peek()\n const next = typeof v === 'function' ? (v as (prev: T) => T)(prev) : v\n if (shouldSkipUpdate(prev, next, options)) return\n s.set(next)\n scheduleRerender()\n }\n }\n\n ctx.hooks[idx] = { signal: null, getter, setter } as unknown as SignalHookEntry<T>\n }\n const entry = ctx.hooks[idx] as SignalHookEntry<T>\n return [entry.getter, entry.setter]\n }\n\n // Outside component — plain Pyreon signal\n if (neverEqual) {\n const s = pyreonSignal<Boxed<T>>({ v: initialValue })\n const getter: SignalGetter<T> = () => s().v\n const setter: SignalSetter<T> = (v) => {\n const prev = s.peek().v\n const next = typeof v === 'function' ? (v as (prev: T) => T)(prev) : v\n s.set({ v: next })\n }\n return [getter, setter]\n }\n\n const s = pyreonSignal<T>(initialValue)\n const getter: SignalGetter<T> = () => s()\n const setter: SignalSetter<T> = (v) => {\n const prev = s.peek()\n const next = typeof v === 'function' ? (v as (prev: T) => T)(prev) : v\n if (shouldSkipUpdate(prev, next, options)) return\n s.set(next)\n }\n return [getter, setter]\n}\n\n/** Solid default: skip update when prev === next. Custom `equals` fn for user-defined comparison. */\nfunction shouldSkipUpdate<T>(prev: T, next: T, options?: CreateSignalOptions<T>): boolean {\n if (typeof options?.equals === 'function') return options.equals(prev, next)\n return prev === next\n}\n\n// ─── createEffect ────────────────────────────────────────────────────────────\n\n/**\n * Solid-compatible `createEffect` — creates a reactive side effect.\n *\n * Supports the `(prev) => next` signature with an optional initial value,\n * matching Solid's `createEffect<T>(fn: (prev: T) => T, initialValue: T)`.\n *\n * In component context: hook-indexed, only created on first render. The effect\n * uses Pyreon's native tracking so signal reads are automatically tracked.\n * A re-entrance guard prevents infinite loops from signal writes inside\n * the effect.\n */\nexport function createEffect<T>(fn: ((prev?: T) => T) | (() => void), initialValue?: T): void {\n const ctx = getCurrentCtx()\n if (ctx) {\n const idx = getHookIndex()\n if (idx < ctx.hooks.length) return // Already registered on first render\n\n let prevValue: T | undefined = initialValue\n let running = false\n const e = pyreonEffect(() => {\n if (running) return\n running = true\n try {\n const result = (fn as (prev?: T) => T)(prevValue)\n if (result !== undefined) prevValue = result\n } finally {\n running = false\n }\n })\n const stop = () => e.dispose()\n ctx.hooks[idx] = stop\n ctx.unmountCallbacks.push(stop)\n return\n }\n\n // Outside component\n let prevValue: T | undefined = initialValue\n pyreonEffect(() => {\n const result = (fn as (prev?: T) => T)(prevValue)\n if (result !== undefined) prevValue = result\n })\n}\n\n// ─── createRenderEffect ──────────────────────────────────────────────────────\n\n/**\n * Solid-compatible `createRenderEffect` — same as createEffect.\n * In Solid, this runs during the render phase; here it runs as a Pyreon effect.\n */\nexport function createRenderEffect(fn: () => void): void {\n createEffect(fn)\n}\n\n// ─── createComputed (legacy Solid API) ───────────────────────────────────────\n\nexport { createEffect as createComputed }\n\n// ─── createMemo ──────────────────────────────────────────────────────────────\n\n/**\n * Solid-compatible `createMemo` — derives a value from reactive sources.\n *\n * Supports the `(prev) => next` signature with an optional initial value,\n * matching Solid's `createMemo<T>(fn: (prev: T) => T, initialValue: T)`.\n *\n * In component context: hook-indexed, only created on first render.\n * Uses Pyreon's native computed for auto-tracking.\n */\nexport function createMemo<T>(fn: ((prev?: T) => T) | (() => T), initialValue?: T): () => T {\n const ctx = getCurrentCtx()\n if (ctx) {\n const idx = getHookIndex()\n if (idx >= ctx.hooks.length) {\n let prevValue: T | undefined = initialValue\n const c = pyreonComputed(() => {\n const result = (fn as (prev?: T) => T)(prevValue)\n prevValue = result\n return result\n })\n ctx.hooks[idx] = c\n }\n const c = ctx.hooks[idx] as ReturnType<typeof pyreonComputed<T>>\n return () => c()\n }\n\n // Outside component\n let prevValue: T | undefined = initialValue\n const c = pyreonComputed(() => {\n const result = (fn as (prev?: T) => T)(prevValue)\n prevValue = result\n return result\n })\n return () => c()\n}\n\n// ─── createRoot ──────────────────────────────────────────────────────────────\n\nexport function createRoot<T>(fn: (dispose: () => void) => T): T {\n const scope = effectScope()\n const prev = getCurrentScope()\n setCurrentScope(scope)\n try {\n return fn(() => scope.stop())\n } finally {\n setCurrentScope(prev)\n }\n}\n\n// ─── on ──────────────────────────────────────────────────────────────────────\n\ntype AccessorArray = readonly (() => unknown)[]\ntype OnEffectFunction<D, V> = (input: D, prevInput: D | undefined, prev: V | undefined) => V\n\nexport function on<S extends (() => unknown) | AccessorArray, V>(\n deps: S,\n fn: OnEffectFunction<\n S extends () => infer R ? R : S extends readonly (() => infer R)[] ? R[] : never,\n V\n >,\n options?: { defer?: boolean },\n): () => V | undefined {\n type D = S extends () => infer R ? R : S extends readonly (() => infer R)[] ? R[] : never\n\n let prevInput: D | undefined\n let prevValue: V | undefined\n let initialized = false\n\n return () => {\n // Read dependencies to register tracking\n const input: D = (\n Array.isArray(deps) ? (deps as (() => unknown)[]).map((d) => d()) : (deps as () => unknown)()\n ) as D\n\n if (!initialized) {\n initialized = true\n if (options?.defer) {\n // When defer=true, skip the first execution — just capture deps\n prevInput = input\n return prevValue\n }\n prevValue = fn(input, undefined, undefined)\n prevInput = input\n return prevValue\n }\n\n const result = runUntracked(() => fn(input, prevInput, prevValue))\n prevInput = input\n prevValue = result\n return result\n }\n}\n\n// ─── batch ───────────────────────────────────────────────────────────────────\n\nexport { pyreonBatch as batch }\n\n// ─── untrack ─────────────────────────────────────────────────────────────────\n\nexport { runUntracked as untrack }\n\n// ─── onMount / onCleanup ─────────────────────────────────────────────────────\n\n/**\n * Solid-compatible `onMount` — runs once after the component's first render.\n */\ntype CleanupFn = () => void\nexport function onMount(fn: () => CleanupFn | void | undefined): void {\n const ctx = getCurrentCtx()\n if (ctx) {\n const idx = getHookIndex()\n if (idx >= ctx.hooks.length) {\n ctx.hooks[idx] = true\n ctx.pendingEffects.push({\n fn: () => {\n fn()\n return undefined\n },\n deps: undefined,\n cleanup: undefined,\n })\n }\n return\n }\n\n // Outside component\n pyreonOnMount(fn)\n}\n\n/**\n * Solid-compatible `onCleanup` — registers a callback to run when the component unmounts.\n */\nexport function onCleanup(fn: () => void): void {\n const ctx = getCurrentCtx()\n if (ctx) {\n const idx = getHookIndex()\n if (idx >= ctx.hooks.length) {\n ctx.hooks[idx] = true\n ctx.unmountCallbacks.push(fn)\n }\n return\n }\n\n // Outside component\n pyreonOnUnmount(fn)\n}\n\n// ─── createSelector ──────────────────────────────────────────────────────────\n\nexport function createSelector<T>(source: () => T): (key: T) => boolean {\n const ctx = getCurrentCtx()\n if (ctx) {\n const idx = getHookIndex()\n if (idx >= ctx.hooks.length) {\n ctx.hooks[idx] = pyreonCreateSelector(source)\n }\n return ctx.hooks[idx] as (key: T) => boolean\n }\n\n return pyreonCreateSelector(source)\n}\n\n// ─── mergeProps ──────────────────────────────────────────────────────────────\n\ntype UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (\n k: infer I,\n) => void\n ? I\n : never\n\ntype MergeProps<T extends object[]> = UnionToIntersection<T[number]>\n\nexport function mergeProps<T extends object[]>(...sources: [...T]): MergeProps<T> {\n const target = {} as Record<PropertyKey, unknown>\n for (const source of sources) {\n const descriptors = Object.getOwnPropertyDescriptors(source)\n for (const key of Reflect.ownKeys(descriptors)) {\n const desc = descriptors[key as string]\n if (!desc) continue\n // Preserve getters for reactivity\n if (desc.get) {\n Object.defineProperty(target, key, {\n get: desc.get,\n enumerable: true,\n configurable: true,\n })\n } else {\n Object.defineProperty(target, key, {\n value: desc.value,\n writable: true,\n enumerable: true,\n configurable: true,\n })\n }\n }\n }\n return target as MergeProps<T>\n}\n\n// ─── splitProps ──────────────────────────────────────────────────────────────\n\nexport function splitProps<T extends Record<string, unknown>, K extends (keyof T)[]>(\n props: T,\n ...keys: K\n): [Pick<T, K[number]>, Omit<T, K[number]>] {\n const picked = {} as Pick<T, K[number]>\n const rest = {} as Record<string, unknown>\n const keySet = new Set<string>(keys.flat() as string[])\n\n const descriptors = Object.getOwnPropertyDescriptors(props)\n for (const key of Reflect.ownKeys(descriptors)) {\n const desc = descriptors[key as string]\n if (!desc) continue\n const target = typeof key === 'string' && keySet.has(key) ? picked : rest\n if (desc.get) {\n Object.defineProperty(target, key, {\n get: desc.get,\n enumerable: true,\n configurable: true,\n })\n } else {\n Object.defineProperty(target, key, {\n value: desc.value,\n writable: true,\n enumerable: true,\n configurable: true,\n })\n }\n }\n\n return [picked, rest as Omit<T, K[number]>]\n}\n\n// ─── children ────────────────────────────────────────────────────────────────\n\nexport function children(fn: () => VNodeChild): () => VNodeChild {\n const memo = createMemo(() => {\n const result = fn()\n // Resolve function children (reactive getters)\n if (typeof result === 'function') return (result as () => VNodeChild)()\n return result\n })\n return memo\n}\n\n// ─── lazy ────────────────────────────────────────────────────────────────────\n\nexport function lazy<P extends Props>(\n loader: () => Promise<{ default: ComponentFn<P> }>,\n): LazyComponent<P> & { preload: () => Promise<{ default: ComponentFn<P> }> } {\n const loaded = pyreonSignal<ComponentFn<P> | null>(null)\n const error = pyreonSignal<Error | null>(null)\n let promise: Promise<{ default: ComponentFn<P> }> | null = null\n\n const load = () => {\n if (!promise) {\n promise = loader()\n .then((mod) => {\n loaded.set(mod.default)\n return mod\n })\n .catch((err) => {\n const e = err instanceof Error ? err : new Error(String(err))\n error.set(e)\n promise = null\n throw e\n })\n }\n return promise\n }\n\n // Uses Pyreon's __loading protocol — Suspense checks this to show fallback.\n // __loading() triggers load() on first call so loading starts when Suspense\n // first encounters the component (not at module load time, not on first render).\n const LazyComp = ((props: P) => {\n const err = error()\n if (err) throw err\n const comp = loaded()\n if (!comp) return null\n return comp(props)\n }) as LazyComponent<P> & { preload: () => Promise<{ default: ComponentFn<P> }> }\n\n LazyComp.__loading = () => {\n const isLoading = loaded() === null && error() === null\n if (isLoading) load()\n return isLoading\n }\n LazyComp.preload = load\n\n return LazyComp\n}\n\n// ─── createContext / useContext ───────────────────────────────────────────────\n\nconst SOLID_CTX = Symbol.for('pyreon:solid-ctx')\n\n/**\n * Solid-compatible context with a Provider component that uses Pyreon's\n * native tree-scoped context stack for proper nesting (inner Provider\n * overrides outer for its subtree).\n */\nexport interface SolidContext<T> {\n readonly [SOLID_CTX_BRAND]: true\n readonly id: symbol\n readonly defaultValue: T | undefined\n Provider: (props: Record<string, unknown>) => unknown\n}\n\nconst SOLID_CTX_BRAND: typeof SOLID_CTX = SOLID_CTX\n\n// Tag the Provider so wrapCompatComponent in jsx-runtime skips it\nconst NATIVE_COMPONENT = Symbol.for('pyreon:native-compat')\n\n/**\n * Solid-compatible `createContext` — creates a context with a `.Provider`\n * component. Uses Pyreon's native context stack for tree-scoped nesting.\n */\nexport function createContext<T>(defaultValue?: T): SolidContext<T> {\n const pyreonCtx = pyreonCreateContext<T>(defaultValue as T)\n\n // Provider is a NATIVE Pyreon component — not compat-wrapped.\n // It calls provide() once during setup to push onto the context stack.\n const Provider = (props: Record<string, unknown>) => {\n const { value, children } = props as { value: T; children?: VNodeChild }\n pyreonProvide(pyreonCtx, value)\n return children ?? null\n }\n ;(Provider as unknown as Record<symbol, boolean>)[NATIVE_COMPONENT] = true\n\n const ctx: SolidContext<T> = {\n [SOLID_CTX_BRAND]: true as const,\n id: pyreonCtx.id,\n defaultValue,\n Provider,\n }\n return ctx\n}\n\n/**\n * Solid-compatible `useContext` — reads the nearest provided value for a context.\n * Works with both compat contexts (from this module's `createContext`) and\n * Pyreon native contexts (from `@pyreon/core`).\n */\nexport function useContext<T>(context: SolidContext<T> | Context<T>): T {\n if (SOLID_CTX in context) {\n const solidCtx = context as SolidContext<T>\n // Reconstruct a Pyreon context with the same id to read from the stack\n const pyreonCtx = { id: solidCtx.id, defaultValue: solidCtx.defaultValue as T } as Context<T>\n return pyreonUseContext(pyreonCtx)\n }\n return pyreonUseContext(context as Context<T>)\n}\n\n// ─── getOwner / runWithOwner ─────────────────────────────────────────────────\n\nexport function getOwner(): EffectScope | null {\n return getCurrentScope()\n}\n\nexport function runWithOwner<T>(owner: EffectScope | null, fn: () => T): T {\n const prev = getCurrentScope()\n setCurrentScope(owner)\n try {\n return fn()\n } finally {\n setCurrentScope(prev)\n }\n}\n\n// ─── createResource ─────────────────────────────────────────────────────────\n\n/**\n * Solid-compatible resource — async data fetching with reactive source tracking.\n * Returns `[resource, { mutate, refetch }]` where `resource()` is the data accessor\n * with `.loading`, `.error`, and `.latest` reactive properties.\n *\n * When the resource is loading and read inside a Suspense boundary, the accessor\n * throws the fetch promise so Suspense can catch it. It also integrates with\n * Pyreon's `__loading` protocol so `<Suspense>` can detect it.\n */\nexport interface Resource<T> {\n (): T | undefined\n loading: boolean\n error: Error | undefined\n latest: T | undefined\n}\n\nexport type ResourceReturn<T> = [\n Resource<T>,\n { mutate: (v: T | ((prev: T | undefined) => T)) => void; refetch: () => void },\n]\n\nexport function createResource<T>(\n fetcher: (info: { value: T | undefined }) => Promise<T> | T,\n options?: { initialValue?: T },\n): ResourceReturn<T>\nexport function createResource<T, S = true>(\n source: (() => S) | true,\n fetcher: (source: S, info: { value: T | undefined }) => Promise<T> | T,\n options?: { initialValue?: T },\n): ResourceReturn<T>\nexport function createResource<T, S = true>(\n sourceOrFetcher:\n | (() => S)\n | true\n | ((info: { value: T | undefined }) => Promise<T> | T),\n maybeFetcherOrOptions?:\n | ((source: S, info: { value: T | undefined }) => Promise<T> | T)\n | { initialValue?: T },\n maybeOptions?: { initialValue?: T },\n): ResourceReturn<T> {\n const hasSource = typeof maybeFetcherOrOptions === 'function'\n const source = hasSource ? (sourceOrFetcher as (() => S) | true) : (() => true as S)\n const fetcher = (\n hasSource ? maybeFetcherOrOptions : sourceOrFetcher\n ) as (source: S, info: { value: T | undefined }) => Promise<T> | T\n const opts = hasSource\n ? maybeOptions\n : (typeof maybeFetcherOrOptions === 'object' ? maybeFetcherOrOptions as { initialValue?: T } : undefined)\n const initialValue = opts?.initialValue\n\n const [data, setData] = createSignal<T | undefined>(initialValue)\n const [loading, setLoading] = createSignal(false)\n const [error, setError] = createSignal<Error | undefined>(undefined)\n\n let latestValue: T | undefined = initialValue\n let fetchPromise: Promise<T> | null = null\n\n const doFetch = () => {\n const src = typeof source === 'function' ? (source as () => S)() : source\n if (src === false || src === null || src === undefined) return\n setLoading(true)\n setError(undefined)\n try {\n const result = fetcher(src as S, { value: latestValue })\n if (result instanceof Promise) {\n fetchPromise = result\n result.then(\n (val) => {\n latestValue = val\n fetchPromise = null\n setData(() => val)\n setLoading(false)\n },\n (err) => {\n fetchPromise = null\n setError(() => (err instanceof Error ? err : new Error(String(err))))\n setLoading(false)\n },\n )\n } else {\n latestValue = result\n fetchPromise = null\n setData(() => result)\n setLoading(false)\n }\n } catch (err) {\n setError(() => (err instanceof Error ? err : new Error(String(err))))\n setLoading(false)\n }\n }\n\n // Auto-fetch on source change\n if (hasSource && typeof source === 'function') {\n createEffect(() => {\n ;(source as () => S)() // track source\n doFetch()\n })\n } else {\n doFetch() // fetch immediately\n }\n\n // Build the resource accessor — throws for Suspense when loading\n const resource = (() => {\n const err = error()\n if (err) throw err // ErrorBoundary catches this\n const current = data()\n if (loading() && fetchPromise && current === undefined) throw fetchPromise // Suspense catches this\n return current\n }) as Resource<T>\n\n Object.defineProperty(resource, 'loading', {\n get: () => loading(),\n enumerable: true,\n })\n Object.defineProperty(resource, 'error', {\n get: () => error(),\n enumerable: true,\n })\n Object.defineProperty(resource, 'latest', {\n get: () => latestValue,\n enumerable: true,\n })\n\n const mutate = (v: T | ((prev: T | undefined) => T)) => {\n if (typeof v === 'function') {\n const next = (v as (prev: T | undefined) => T)(data())\n latestValue = next\n setData(() => next)\n } else {\n latestValue = v\n setData(() => v)\n }\n }\n\n const refetch = () => doFetch()\n\n return [resource, { mutate, refetch }]\n}\n\n// ─── Deep clone (structuredClone replacement) ──────────────────────────────\n\n/**\n * Deep clones plain objects and arrays. Functions, DOM nodes, class instances,\n * and other non-plain values are kept by reference — `structuredClone` would\n * throw on them.\n */\nfunction deepClone<T>(obj: T): T {\n if (obj === null || typeof obj !== 'object') return obj\n if (Array.isArray(obj)) return obj.map((item) => deepClone(item)) as unknown as T\n // Don't clone DOM nodes, class instances, etc. — copy by reference\n if (obj.constructor !== Object && obj.constructor !== Array) return obj\n const result = {} as Record<string, unknown>\n for (const key of Object.keys(obj as object)) {\n result[key] = deepClone((obj as Record<string, unknown>)[key])\n }\n return result as T\n}\n\n// ─── createStore / produce ──────────────────────────────────────────────────\n\n/**\n * Solid-compatible `createStore` — creates a deeply reactive proxy-based store.\n *\n * Returns `[store, setStore]` where:\n * - `store` is a recursive proxy that lazily creates per-path signals for fine-grained tracking\n * - `setStore` supports Solid's path-based setter API:\n * - `setStore('key', value)` — set a top-level key\n * - `setStore('nested', 'key', value)` — set a nested path\n * - `setStore('key', prev => next)` — functional update at a path\n * - `setStore('todos', 0, 'done', true)` — numeric index into arrays\n * - `setStore('todos', t => t.done, 'text', 'x')` — filter predicate on arrays\n * - `setStore(fn)` — mutator function (receives a draft clone)\n */\nexport type SetStoreFunction<_T> = {\n (...args: unknown[]): void\n}\n\nexport function createStore<T extends object>(\n initialValue: T,\n): [T, SetStoreFunction<T>] {\n const signals = new Map<string, ReturnType<typeof pyreonSignal>>()\n let raw: T = deepClone(initialValue)\n\n function getByPath(obj: unknown, path: string): unknown {\n if (!path) return obj\n return path.split('.').reduce((o, k) => (o as Record<string, unknown>)?.[k], obj)\n }\n\n function getSignal(path: string): ReturnType<typeof pyreonSignal> {\n let sig = signals.get(path)\n if (!sig) {\n const value = getByPath(raw, path)\n sig = pyreonSignal(value)\n signals.set(path, sig)\n }\n return sig\n }\n\n function resolveValue(basePath: string): unknown {\n return basePath ? getByPath(raw, basePath) : raw\n }\n\n function makeProxy(basePath: string): unknown {\n // Use a dummy target — all reads go through `raw` via `resolveValue`\n return new Proxy({} as object, {\n get(_target, prop) {\n if (typeof prop === 'symbol') return (resolveValue(basePath) as Record<symbol, unknown>)?.[prop]\n const path = basePath ? `${basePath}.${String(prop)}` : String(prop)\n const sig = getSignal(path)\n sig() // track read\n const value = getByPath(raw, path)\n if (value !== null && typeof value === 'object') {\n return makeProxy(path)\n }\n return value\n },\n has(_target, prop) {\n const current = resolveValue(basePath)\n return current !== null && typeof current === 'object' && prop in (current as object)\n },\n ownKeys(_target) {\n // Track the base path so effects re-run when keys change\n if (basePath) getSignal(basePath)()\n else getSignal('__keys__')()\n const current = resolveValue(basePath)\n return current !== null && typeof current === 'object'\n ? Reflect.ownKeys(current as object)\n : []\n },\n getOwnPropertyDescriptor(_target, prop) {\n const current = resolveValue(basePath)\n if (current !== null && typeof current === 'object') {\n return Object.getOwnPropertyDescriptor(current, prop)\n }\n return undefined\n },\n set() {\n // oxlint-disable-next-line no-console\n console.warn('[Pyreon] Direct mutation on store is not supported. Use the setter function.')\n return true\n },\n })\n }\n\n const proxy = makeProxy('') as T\n\n function updateRaw(newRaw: T) {\n const oldRaw = raw\n raw = newRaw\n\n // Update all tracked signals whose values changed\n for (const [path, sig] of signals) {\n const oldVal = getByPath(oldRaw, path)\n const newVal = getByPath(newRaw, path)\n if (!Object.is(oldVal, newVal)) {\n sig.set(newVal)\n }\n }\n }\n\n /**\n * Applies a value at a path, supporting numeric indices (array access)\n * and filter predicates (functions that select matching array items).\n */\n function applyAtPath(obj: unknown, path: unknown[], value: unknown): void {\n if (path.length === 0) {\n // Apply value to obj itself (top-level update)\n if (typeof value === 'function') {\n const result = (value as (prev: unknown) => unknown)(obj)\n Object.assign(obj as object, result)\n } else {\n Object.assign(obj as object, value)\n }\n return\n }\n\n const [head, ...rest] = path\n\n if (typeof head === 'function') {\n // Filter predicate: apply to all matching items in an array\n if (Array.isArray(obj)) {\n for (let i = 0; i < obj.length; i++) {\n if ((head as (item: unknown, index: number) => boolean)(obj[i], i)) {\n if (rest.length === 0) {\n obj[i] = typeof value === 'function' ? (value as (prev: unknown) => unknown)(obj[i]) : value\n } else {\n applyAtPath(obj[i], rest, value)\n }\n }\n }\n }\n return\n }\n\n const key = head as string | number\n if (rest.length === 0) {\n // Last path segment — set the value\n ;(obj as Record<string | number, unknown>)[key] =\n typeof value === 'function'\n ? (value as (prev: unknown) => unknown)((obj as Record<string | number, unknown>)[key])\n : value\n } else {\n // Recurse into nested object\n applyAtPath((obj as Record<string | number, unknown>)[key], rest, value)\n }\n }\n\n const setStore: SetStoreFunction<T> = (...args: unknown[]) => {\n if (args.length === 1 && typeof args[0] === 'function') {\n // Function form: setStore(state => { state.x = 1 })\n const draft = deepClone(raw)\n ;(args[0] as (state: T) => void)(draft)\n updateRaw(draft)\n } else if (args.length >= 2) {\n // Path form with support for numeric indices and filter predicates\n const value = args[args.length - 1]\n const pathArgs = args.slice(0, -1)\n const draft = deepClone(raw)\n applyAtPath(draft, pathArgs, value)\n updateRaw(draft)\n }\n }\n\n return [proxy, setStore]\n}\n\n/**\n * Solid-compatible `reconcile` — replaces the entire store state with the given value.\n * Used with setStore: `setStore(reconcile(newData))`\n */\nexport function reconcile<T extends object>(value: T): (state: T) => T {\n return () => value\n}\n\n/**\n * Solid-compatible `unwrap` — returns a deep clone of the store's raw data,\n * stripping the reactive proxy.\n */\nexport function unwrap<T>(value: T): T {\n return deepClone(value)\n}\n\n/**\n * Solid-compatible `produce` — creates an Immer-like updater function for stores.\n * Returns a function that clones the state, applies mutations, and returns the result.\n */\nexport function produce<T extends object>(fn: (state: T) => void): (state: T) => T {\n return (state: T) => {\n const draft = deepClone(state)\n fn(draft)\n return draft\n }\n}\n\n// ─── startTransition / useTransition ────────────────────────────────────────\n\n/**\n * Solid-compatible `startTransition` — runs a function as a transition.\n * In Pyreon, this is a no-op wrapper that calls the function synchronously.\n */\nexport function startTransition(fn: () => void): void {\n fn()\n}\n\n/**\n * Solid-compatible `useTransition` — returns `[isPending, startTransition]`.\n * In Pyreon, transitions are not deferred — isPending is always false.\n */\nexport function useTransition(): [() => boolean, (fn: () => void) => void] {\n return [() => false, (fn) => fn()]\n}\n\n// ─── observable / from (interop) ────────────────────────────────────────────\n\ninterface Observer<T> {\n next: (v: T) => void\n}\n\ninterface Subscription {\n unsubscribe: () => void\n}\n\ninterface Observable<T> {\n subscribe: (observer: Observer<T>) => Subscription\n}\n\n/**\n * Solid-compatible `observable` — converts a signal accessor to an observable.\n * Returns an object with a `subscribe` method that tracks signal changes.\n */\nexport function observable<T>(input: () => T): Observable<T> {\n return {\n subscribe(observer: Observer<T>) {\n const e = pyreonEffect(() => {\n observer.next(input())\n })\n return { unsubscribe: () => e.dispose() }\n },\n }\n}\n\n/**\n * Solid-compatible `from` — converts an observable or producer into a signal accessor.\n * Accepts either a producer function `(setter) => cleanup` or an observable with `.subscribe()`.\n */\nexport function from<T>(\n producer:\n | ((setter: (v: T) => void) => () => void)\n | Observable<T>,\n): () => T | undefined {\n const [value, setValue] = createSignal<T | undefined>(undefined)\n\n if (typeof producer === 'function') {\n const cleanup = producer((v) => setValue(() => v))\n pyreonOnCleanup(cleanup)\n } else {\n const sub = producer.subscribe({ next: (v) => setValue(() => v) })\n pyreonOnCleanup(() => sub.unsubscribe())\n }\n\n return value\n}\n\n// ─── mapArray / indexArray ───────────────────────────────────────────────────\n\n/**\n * Solid-compatible `mapArray` — maps a reactive list by item identity.\n * Each item is a static value, while the index is a reactive accessor.\n */\nexport function mapArray<T, U>(\n list: () => readonly T[],\n mapFn: (item: T, index: () => number) => U,\n): () => U[] {\n return createMemo(() => {\n const items = list()\n return items.map((item, i) => mapFn(item, () => i))\n })\n}\n\n/**\n * Solid-compatible `indexArray` — maps a reactive list by index position.\n * Each item is a reactive accessor, while the index is a static number.\n */\nexport function indexArray<T, U>(\n list: () => readonly T[],\n mapFn: (item: () => T, index: number) => U,\n): () => U[] {\n return createMemo(() => {\n const items = list()\n return items.map((item, i) => mapFn(() => item, i))\n })\n}\n\n// ─── Index ──────────────────────────────────────────────────────────────────\n\n/**\n * Solid-compatible `Index` — like `For` but keyed by index.\n * Items are reactive accessors, indices are static numbers.\n *\n * In Solid, `<Index>` keeps DOM nodes stable per index position.\n * Here we use a computed that maps items to `(item: () => T, index: number)`.\n */\nexport function Index<T>(props: {\n each: readonly T[] | (() => readonly T[])\n children: (item: () => T, index: number) => VNodeChild\n}): VNodeChild {\n const list = typeof props.each === 'function'\n ? (props.each as () => readonly T[])\n : () => props.each as readonly T[]\n const mapped = createMemo(() => {\n const items = list()\n return items.map((item, i) => props.children(() => item, i))\n })\n return (() => mapped()) as unknown as VNodeChild\n}\n\n// ─── createUniqueId ─────────────────────────────────────────────────────────\n\nlet _uniqueIdCounter = 0\n\n/**\n * Solid-compatible `createUniqueId` — returns a unique string identifier.\n */\nexport function createUniqueId(): string {\n return `solid-${(_uniqueIdCounter++).toString(36)}`\n}\n\n// ─── DEV ────────────────────────────────────────────────────────────────────\n\n/**\n * Solid-compatible `DEV` — an object in dev mode, `undefined` in production.\n * Used for conditional dev-only code: `if (DEV) { ... }`\n */\nexport const DEV =\n (import.meta as { env?: { DEV?: boolean } }).env?.DEV === true ? {} : undefined\n\n// ─── catchError ─────────────────────────────────────────────────────────────\n\n/**\n * Solid-compatible `catchError` — wraps a function and catches synchronous errors.\n */\nexport function catchError<T>(\n tryFn: () => T,\n onError: (err: Error) => void,\n): T | undefined {\n try {\n return tryFn()\n } catch (e) {\n onError(e instanceof Error ? e : new Error(String(e)))\n return undefined\n }\n}\n\n// ─── createDeferred ─────────────────────────────────────────────────────────\n\n/**\n * Solid-compatible `createDeferred` — creates a memo that updates on next idle frame.\n * In Pyreon there is no concurrent scheduling, so this behaves the same as `createMemo`.\n */\nexport function createDeferred<T>(fn: () => T): () => T {\n return createMemo(fn)\n}\n\n// ─── createReaction ─────────────────────────────────────────────────────────\n\n/**\n * Solid-compatible `createReaction` — manual tracking primitive.\n * Returns a function that accepts a tracking function. When any tracked\n * dependency changes, `onInvalidate` fires (but only after the first run).\n */\nexport function createReaction(onInvalidate: () => void): (tracking: () => void) => void {\n return (trackingFn: () => void) => {\n let first = true\n pyreonEffect(() => {\n trackingFn() // track dependencies\n if (first) {\n first = false\n return\n }\n onInvalidate()\n })\n }\n}\n\n// ─── Re-exports from @pyreon/core ──────────────────────────────────────────────\n\nexport { ErrorBoundary, For, Match, Show, Suspense, Switch }\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsx-runtime.js","names":[],"sources":["../src/jsx-runtime.ts"],"sourcesContent":["/**\n * Compat JSX runtime for SolidJS compatibility mode.\n *\n * When `jsxImportSource` is redirected to `@pyreon/solid-compat` (via the vite\n * plugin's `compat: \"solid\"` option), OXC rewrites JSX to import from this file.\n *\n * For component VNodes, we wrap the component function so it returns a reactive\n * accessor — enabling Solid-style re-renders on state change while Pyreon's\n * existing renderer handles all DOM work.\n *\n * The component body runs inside `runUntracked` to prevent signal reads (from\n * createSignal getters) from being tracked by the reactive accessor. Only the\n * version signal triggers re-renders.\n *\n * ## Child instance preservation\n *\n * When a parent component re-renders, mountReactive does a full teardown+rebuild\n * of the DOM tree. Without preservation, child components get brand new\n * RenderContexts with empty hooks arrays — causing `onMount` and `onCleanup`\n * to fire again, which can trigger infinite re-render loops.\n *\n * To fix this, we store child RenderContexts in the parent's hooks array (indexed\n * by the parent's hook counter). When the child wrapper is called again after a\n * parent re-render, it reuses the existing ctx (preserving hooks state), so\n * hook-indexed guards like `if (idx >= ctx.hooks.length) return` work correctly\n * and lifecycle hooks don't re-fire.\n */\n\nimport type { ComponentFn, Props, VNode, VNodeChild } from '@pyreon/core'\nimport {\n ErrorBoundary,\n For,\n Fragment,\n h,\n Match,\n onUnmount,\n Show,\n Suspense,\n Switch,\n} from '@pyreon/core'\nimport { runUntracked, signal } from '@pyreon/reactivity'\n\nexport { Fragment }\n\n// ─── Render context (used by hooks) ──────────────────────────────────────────\n\nexport interface RenderContext {\n hooks: unknown[]\n scheduleRerender: () => void\n /** Effect entries pending execution after render */\n pendingEffects: EffectEntry[]\n /** Layout effect entries pending execution after render */\n pendingLayoutEffects: EffectEntry[]\n /** Set to true when the component is unmounted */\n unmounted: boolean\n /** Callbacks to run on unmount (lifecycle + effect cleanups) */\n unmountCallbacks: (() => void)[]\n}\n\nexport interface EffectEntry {\n fn: () => (() => void) | void\n deps: unknown[] | undefined\n cleanup: (() => void) | undefined\n}\n\nlet _currentCtx: RenderContext | null = null\nlet _hookIndex = 0\n\nexport function getCurrentCtx(): RenderContext | null {\n return _currentCtx\n}\n\nexport function getHookIndex(): number {\n return _hookIndex++\n}\n\nexport function beginRender(ctx: RenderContext): void {\n _currentCtx = ctx\n _hookIndex = 0\n ctx.pendingEffects = []\n ctx.pendingLayoutEffects = []\n}\n\nexport function endRender(): void {\n _currentCtx = null\n _hookIndex = 0\n}\n\n// ─── Effect runners ──────────────────────────────────────────────────────────\n\nfunction runLayoutEffects(entries: EffectEntry[]): void {\n for (const entry of entries) {\n if (entry.cleanup) entry.cleanup()\n const cleanup = entry.fn()\n entry.cleanup = typeof cleanup === 'function' ? cleanup : undefined\n }\n}\n\nfunction scheduleEffects(ctx: RenderContext, entries: EffectEntry[]): void {\n if (entries.length === 0) return\n queueMicrotask(() => {\n for (const entry of entries) {\n if (ctx.unmounted) return\n if (entry.cleanup) entry.cleanup()\n const cleanup = entry.fn()\n entry.cleanup = typeof cleanup === 'function' ? cleanup : undefined\n }\n })\n}\n\n// ─── Child instance preservation ─────────────────────────────────────────────\n\n/** Stored in the parent's hooks array to preserve child state across re-renders */\ninterface ChildInstance {\n ctx: RenderContext\n version: ReturnType<typeof signal<number>>\n updateScheduled: boolean\n}\n\n// Internal prop keys for passing parent context info to child wrappers\nconst _CHILD_INSTANCE = Symbol.for('pyreon.childInstance')\nconst noop = () => {\n /* noop */\n}\n\n// ─── Component wrapping ──────────────────────────────────────────────────────\n\nconst _wrapperCache = new WeakMap<Function, ComponentFn>()\n\n// Pyreon core components that must NOT be wrapped — they rely on internal reactivity\nconst _nativeComponents: Set<Function> = new Set([\n Show,\n For,\n Switch,\n Match,\n Suspense,\n ErrorBoundary,\n])\n\nfunction wrapCompatComponent(solidComponent: Function): ComponentFn {\n if (_nativeComponents.has(solidComponent)) return solidComponent as ComponentFn\n\n let wrapped = _wrapperCache.get(solidComponent)\n if (wrapped) return wrapped\n\n // The wrapper returns a reactive accessor (() => VNodeChild) which Pyreon's\n // mountChild treats as a reactive expression via mountReactive.\n wrapped = ((props: Props) => {\n // Check for a preserved child instance from the parent's hooks\n const existing = (props as Record<symbol, unknown>)[_CHILD_INSTANCE] as\n | ChildInstance\n | undefined\n\n const ctx: RenderContext = existing?.ctx ?? {\n hooks: [],\n scheduleRerender: () => {\n // Will be replaced below after version signal is created\n },\n pendingEffects: [],\n pendingLayoutEffects: [],\n unmounted: false,\n unmountCallbacks: [],\n }\n\n // When reusing an existing ctx after parent re-render, reset unmounted flag\n // and clear stale unmount callbacks (they belong to the previous mount cycle)\n if (existing) {\n ctx.unmounted = false\n ctx.unmountCallbacks = []\n }\n\n const version = existing?.version ?? signal(0)\n\n // Use a shared updateScheduled flag (preserved across parent re-renders)\n let updateScheduled = existing?.updateScheduled ?? false\n\n ctx.scheduleRerender = () => {\n if (ctx.unmounted || updateScheduled) return\n updateScheduled = true\n queueMicrotask(() => {\n updateScheduled = false\n if (!ctx.unmounted) version.set(version.peek() + 1)\n })\n }\n\n // Register cleanup when component unmounts\n onUnmount(() => {\n ctx.unmounted = true\n for (const cb of ctx.unmountCallbacks) cb()\n })\n\n // Strip the internal prop before passing to the component\n const { [_CHILD_INSTANCE]: _stripped, ...cleanProps } = props as Record<\n string | symbol,\n unknown\n >\n\n // Return reactive accessor — Pyreon's mountChild calls mountReactive\n return () => {\n version() // tracked read — triggers re-execution when state changes\n beginRender(ctx)\n // runUntracked prevents signal reads (from createSignal getters) from\n // being tracked by this accessor — only the version signal should trigger re-renders\n const result = runUntracked(() => (solidComponent as ComponentFn)(cleanProps as Props))\n const layoutEffects = ctx.pendingLayoutEffects\n const effects = ctx.pendingEffects\n endRender()\n\n runLayoutEffects(layoutEffects)\n scheduleEffects(ctx, effects)\n\n return result\n }\n }) as unknown as ComponentFn\n\n // Forward __loading from lazy components so Pyreon's Suspense can detect them\n if ('__loading' in solidComponent) {\n ;(wrapped as unknown as Record<string, unknown>).__loading = (\n solidComponent as unknown as Record<string, unknown>\n ).__loading\n }\n\n _wrapperCache.set(solidComponent, wrapped)\n return wrapped\n}\n\n// ─── Child instance lookup ───────────────────────────────────────────────────\n\nfunction createChildInstance(): ChildInstance {\n return {\n ctx: {\n hooks: [],\n scheduleRerender: noop,\n pendingEffects: [],\n pendingLayoutEffects: [],\n unmounted: false,\n unmountCallbacks: [],\n },\n version: signal(0),\n updateScheduled: false,\n }\n}\n\n/**\n * During a parent component render, get or create the child instance at the\n * current hook index. Returns undefined when called outside a component render.\n */\nfunction resolveChildInstance(): ChildInstance | undefined {\n const parentCtx = _currentCtx\n if (!parentCtx) return undefined\n\n const idx = _hookIndex++\n if (idx < parentCtx.hooks.length) {\n return parentCtx.hooks[idx] as ChildInstance\n }\n const instance = createChildInstance()\n parentCtx.hooks[idx] = instance\n return instance\n}\n\n// ─── JSX functions ───────────────────────────────────────────────────────────\n\n// Tag used by compat context Providers to skip compat wrapping\nconst _NATIVE_COMPAT = Symbol.for('pyreon:native-compat')\n\nexport function jsx(\n type: string | ComponentFn | symbol,\n props: Props & { children?: VNodeChild | VNodeChild[] },\n key?: string | number | null,\n): VNode {\n const { children, ...rest } = props\n const propsWithKey = (key != null ? { ...rest, key } : rest) as Props\n\n if (typeof type === 'function') {\n if (_nativeComponents.has(type)) {\n const componentProps = children !== undefined ? { ...propsWithKey, children } : propsWithKey\n return h(type as ComponentFn, componentProps)\n }\n\n // Native compat components (e.g. context Providers) skip compat wrapping\n if ((type as unknown as Record<symbol, boolean>)[_NATIVE_COMPAT]) {\n const componentProps = children !== undefined ? { ...propsWithKey, children } : propsWithKey\n return h(type as ComponentFn, componentProps)\n }\n\n const wrapped = wrapCompatComponent(type)\n const componentProps =\n children !== undefined ? { ...propsWithKey, children } : { ...propsWithKey }\n\n const childInstance = resolveChildInstance()\n if (childInstance) {\n ;(componentProps as Record<symbol, unknown>)[_CHILD_INSTANCE] = childInstance\n }\n\n return h(wrapped, componentProps)\n }\n\n // DOM element or symbol (Fragment): children go in vnode.children\n const childArray = children === undefined ? [] : Array.isArray(children) ? children : [children]\n\n return h(type, propsWithKey, ...(childArray as VNodeChild[]))\n}\n\nexport const jsxs = jsx\nexport const jsxDEV = jsx\n"],"mappings":";;;;AAiEA,IAAI,cAAoC;AACxC,IAAI,aAAa;AAUjB,SAAgB,YAAY,KAA0B;AACpD,eAAc;AACd,cAAa;AACb,KAAI,iBAAiB,EAAE;AACvB,KAAI,uBAAuB,EAAE;;AAG/B,SAAgB,YAAkB;AAChC,eAAc;AACd,cAAa;;AAKf,SAAS,iBAAiB,SAA8B;AACtD,MAAK,MAAM,SAAS,SAAS;AAC3B,MAAI,MAAM,QAAS,OAAM,SAAS;EAClC,MAAM,UAAU,MAAM,IAAI;AAC1B,QAAM,UAAU,OAAO,YAAY,aAAa,UAAU;;;AAI9D,SAAS,gBAAgB,KAAoB,SAA8B;AACzE,KAAI,QAAQ,WAAW,EAAG;AAC1B,sBAAqB;AACnB,OAAK,MAAM,SAAS,SAAS;AAC3B,OAAI,IAAI,UAAW;AACnB,OAAI,MAAM,QAAS,OAAM,SAAS;GAClC,MAAM,UAAU,MAAM,IAAI;AAC1B,SAAM,UAAU,OAAO,YAAY,aAAa,UAAU;;GAE5D;;AAaJ,MAAM,kBAAkB,OAAO,IAAI,uBAAuB;AAC1D,MAAM,aAAa;AAMnB,MAAM,gCAAgB,IAAI,SAAgC;AAG1D,MAAM,oBAAmC,IAAI,IAAI;CAC/C;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,oBAAoB,gBAAuC;AAClE,KAAI,kBAAkB,IAAI,eAAe,CAAE,QAAO;CAElD,IAAI,UAAU,cAAc,IAAI,eAAe;AAC/C,KAAI,QAAS,QAAO;AAIpB,aAAY,UAAiB;EAE3B,MAAM,WAAY,MAAkC;EAIpD,MAAM,MAAqB,UAAU,OAAO;GAC1C,OAAO,EAAE;GACT,wBAAwB;GAGxB,gBAAgB,EAAE;GAClB,sBAAsB,EAAE;GACxB,WAAW;GACX,kBAAkB,EAAE;GACrB;AAID,MAAI,UAAU;AACZ,OAAI,YAAY;AAChB,OAAI,mBAAmB,EAAE;;EAG3B,MAAM,UAAU,UAAU,WAAW,OAAO,EAAE;EAG9C,IAAI,kBAAkB,UAAU,mBAAmB;AAEnD,MAAI,yBAAyB;AAC3B,OAAI,IAAI,aAAa,gBAAiB;AACtC,qBAAkB;AAClB,wBAAqB;AACnB,sBAAkB;AAClB,QAAI,CAAC,IAAI,UAAW,SAAQ,IAAI,QAAQ,MAAM,GAAG,EAAE;KACnD;;AAIJ,kBAAgB;AACd,OAAI,YAAY;AAChB,QAAK,MAAM,MAAM,IAAI,iBAAkB,KAAI;IAC3C;EAGF,MAAM,GAAG,kBAAkB,WAAW,GAAG,eAAe;AAMxD,eAAa;AACX,YAAS;AACT,eAAY,IAAI;GAGhB,MAAM,SAAS,mBAAoB,eAA+B,WAAoB,CAAC;GACvF,MAAM,gBAAgB,IAAI;GAC1B,MAAM,UAAU,IAAI;AACpB,cAAW;AAEX,oBAAiB,cAAc;AAC/B,mBAAgB,KAAK,QAAQ;AAE7B,UAAO;;;AAKX,KAAI,eAAe,eAChB,CAAC,QAA+C,YAC/C,eACA;AAGJ,eAAc,IAAI,gBAAgB,QAAQ;AAC1C,QAAO;;AAKT,SAAS,sBAAqC;AAC5C,QAAO;EACL,KAAK;GACH,OAAO,EAAE;GACT,kBAAkB;GAClB,gBAAgB,EAAE;GAClB,sBAAsB,EAAE;GACxB,WAAW;GACX,kBAAkB,EAAE;GACrB;EACD,SAAS,OAAO,EAAE;EAClB,iBAAiB;EAClB;;;;;;AAOH,SAAS,uBAAkD;CACzD,MAAM,YAAY;AAClB,KAAI,CAAC,UAAW,QAAO;CAEvB,MAAM,MAAM;AACZ,KAAI,MAAM,UAAU,MAAM,OACxB,QAAO,UAAU,MAAM;CAEzB,MAAM,WAAW,qBAAqB;AACtC,WAAU,MAAM,OAAO;AACvB,QAAO;;AAMT,MAAM,iBAAiB,OAAO,IAAI,uBAAuB;AAEzD,SAAgB,IACd,MACA,OACA,KACO;CACP,MAAM,EAAE,UAAU,GAAG,SAAS;CAC9B,MAAM,eAAgB,OAAO,OAAO;EAAE,GAAG;EAAM;EAAK,GAAG;AAEvD,KAAI,OAAO,SAAS,YAAY;AAC9B,MAAI,kBAAkB,IAAI,KAAK,CAE7B,QAAO,EAAE,MADc,aAAa,SAAY;GAAE,GAAG;GAAc;GAAU,GAAG,aACnC;AAI/C,MAAK,KAA4C,gBAE/C,QAAO,EAAE,MADc,aAAa,SAAY;GAAE,GAAG;GAAc;GAAU,GAAG,aACnC;EAG/C,MAAM,UAAU,oBAAoB,KAAK;EACzC,MAAM,iBACJ,aAAa,SAAY;GAAE,GAAG;GAAc;GAAU,GAAG,EAAE,GAAG,cAAc;EAE9E,MAAM,gBAAgB,sBAAsB;AAC5C,MAAI,cACD,CAAC,eAA2C,mBAAmB;AAGlE,SAAO,EAAE,SAAS,eAAe;;AAMnC,QAAO,EAAE,MAAM,cAAc,GAFV,aAAa,SAAY,EAAE,GAAG,MAAM,QAAQ,SAAS,GAAG,WAAW,CAAC,SAAS,CAEnC;;AAG/D,MAAa,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index2.d.ts","names":[],"sources":["../../../src/index.ts"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"jsx-runtime2.d.ts","names":[],"sources":["../../../src/jsx-runtime.ts"],"mappings":";;;iBAyQgB,GAAA,CACd,IAAA,WAAe,WAAA,WACf,KAAA,EAAO,KAAA;EAAU,QAAA,GAAW,UAAA,GAAa,UAAA;AAAA,GACzC,GAAA,4BACC,KAAA;AAAA,cAkCU,IAAA,SAAI,GAAA"}