@pyreon/solid-compat 0.1.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/lib/index.js ADDED
@@ -0,0 +1,142 @@
1
+ import { ErrorBoundary, For, Match, Show, Suspense, Switch, createContext as pyreonCreateContext, onMount as pyreonOnMount, onUnmount as pyreonOnUnmount, useContext as pyreonUseContext } from "@pyreon/core";
2
+ import { batch as pyreonBatch, computed, createSelector as pyreonCreateSelector, effect, effectScope, getCurrentScope, runUntracked, setCurrentScope, signal } from "@pyreon/reactivity";
3
+
4
+ //#region src/index.ts
5
+ function createSignal(initialValue) {
6
+ const s = signal(initialValue);
7
+ const getter = () => s();
8
+ const setter = (v) => {
9
+ if (typeof v === "function") s.update(v);
10
+ else s.set(v);
11
+ };
12
+ return [getter, setter];
13
+ }
14
+ function createEffect(fn) {
15
+ effect(fn);
16
+ }
17
+ function createRenderEffect(fn) {
18
+ effect(fn);
19
+ }
20
+ function createMemo(fn) {
21
+ const c = computed(fn);
22
+ return () => c();
23
+ }
24
+ function createRoot(fn) {
25
+ const scope = effectScope();
26
+ const prev = getCurrentScope();
27
+ setCurrentScope(scope);
28
+ try {
29
+ return fn(() => scope.stop());
30
+ } finally {
31
+ setCurrentScope(prev);
32
+ }
33
+ }
34
+ function on(deps, fn) {
35
+ let prevInput;
36
+ let prevValue;
37
+ let initialized = false;
38
+ return () => {
39
+ const input = Array.isArray(deps) ? deps.map((d) => d()) : deps();
40
+ if (!initialized) {
41
+ initialized = true;
42
+ prevValue = fn(input, void 0, void 0);
43
+ prevInput = input;
44
+ return prevValue;
45
+ }
46
+ const result = runUntracked(() => fn(input, prevInput, prevValue));
47
+ prevInput = input;
48
+ prevValue = result;
49
+ return result;
50
+ };
51
+ }
52
+ function mergeProps(...sources) {
53
+ const target = {};
54
+ for (const source of sources) {
55
+ const descriptors = Object.getOwnPropertyDescriptors(source);
56
+ for (const key of Reflect.ownKeys(descriptors)) {
57
+ const desc = descriptors[key];
58
+ if (!desc) continue;
59
+ if (desc.get) Object.defineProperty(target, key, {
60
+ get: desc.get,
61
+ enumerable: true,
62
+ configurable: true
63
+ });
64
+ else Object.defineProperty(target, key, {
65
+ value: desc.value,
66
+ writable: true,
67
+ enumerable: true,
68
+ configurable: true
69
+ });
70
+ }
71
+ }
72
+ return target;
73
+ }
74
+ function splitProps(props, ...keys) {
75
+ const picked = {};
76
+ const rest = {};
77
+ const keySet = new Set(keys.flat());
78
+ const descriptors = Object.getOwnPropertyDescriptors(props);
79
+ for (const key of Reflect.ownKeys(descriptors)) {
80
+ const desc = descriptors[key];
81
+ if (!desc) continue;
82
+ const target = typeof key === "string" && keySet.has(key) ? picked : rest;
83
+ if (desc.get) Object.defineProperty(target, key, {
84
+ get: desc.get,
85
+ enumerable: true,
86
+ configurable: true
87
+ });
88
+ else Object.defineProperty(target, key, {
89
+ value: desc.value,
90
+ writable: true,
91
+ enumerable: true,
92
+ configurable: true
93
+ });
94
+ }
95
+ return [picked, rest];
96
+ }
97
+ function children(fn) {
98
+ return createMemo(() => {
99
+ const result = fn();
100
+ if (typeof result === "function") return result();
101
+ return result;
102
+ });
103
+ }
104
+ function lazy(loader) {
105
+ let resolved = null;
106
+ let error = null;
107
+ let promise = null;
108
+ const load = () => {
109
+ if (!promise) promise = loader().then((mod) => {
110
+ resolved = mod.default;
111
+ return mod;
112
+ }).catch((err) => {
113
+ error = err instanceof Error ? err : new Error(String(err));
114
+ promise = null;
115
+ throw error;
116
+ });
117
+ return promise;
118
+ };
119
+ const LazyComponent = ((props) => {
120
+ if (error) throw error;
121
+ if (!resolved) throw load();
122
+ return resolved(props);
123
+ });
124
+ LazyComponent.preload = load;
125
+ return LazyComponent;
126
+ }
127
+ function getOwner() {
128
+ return getCurrentScope();
129
+ }
130
+ function runWithOwner(owner, fn) {
131
+ const prev = getCurrentScope();
132
+ setCurrentScope(owner);
133
+ try {
134
+ return fn();
135
+ } finally {
136
+ setCurrentScope(prev);
137
+ }
138
+ }
139
+
140
+ //#endregion
141
+ export { ErrorBoundary, For, Match, Show, Suspense, Switch, pyreonBatch as batch, children, createEffect as createComputed, createEffect, pyreonCreateContext as createContext, createMemo, createRenderEffect, createRoot, pyreonCreateSelector as createSelector, createSignal, getOwner, lazy, mergeProps, on, pyreonOnUnmount as onCleanup, pyreonOnMount as onMount, runWithOwner, splitProps, runUntracked as untrack, pyreonUseContext as useContext };
142
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["pyreonSignal","pyreonComputed"],"sources":["../src/index.ts"],"sourcesContent":["// @pyreon/solid-compat — SolidJS-compatible API shims running on Pyreon's reactive engine\n\nimport type { ComponentFn, 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 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 signal as pyreonSignal,\n runUntracked,\n setCurrentScope,\n} from \"@pyreon/reactivity\"\n\n// ─── createSignal ────────────────────────────────────────────────────────────\n\nexport type SignalGetter<T> = () => T\nexport type SignalSetter<T> = (v: T | ((prev: T) => T)) => void\n\nexport function createSignal<T>(initialValue: T): [SignalGetter<T>, SignalSetter<T>] {\n const s = pyreonSignal<T>(initialValue)\n\n const getter: SignalGetter<T> = () => s()\n\n const setter: SignalSetter<T> = (v) => {\n if (typeof v === \"function\") {\n s.update(v as (prev: T) => T)\n } else {\n s.set(v)\n }\n }\n\n return [getter, setter]\n}\n\n// ─── createEffect ────────────────────────────────────────────────────────────\n\nexport function createEffect(fn: () => void): void {\n pyreonEffect(fn)\n}\n\n// ─── createRenderEffect ──────────────────────────────────────────────────────\n\nexport function createRenderEffect(fn: () => void): void {\n pyreonEffect(fn)\n}\n\n// ─── createComputed (legacy Solid API) ───────────────────────────────────────\n\nexport { createEffect as createComputed }\n\n// ─── createMemo ──────────────────────────────────────────────────────────────\n\nexport function createMemo<T>(fn: () => T): () => T {\n const c = pyreonComputed(fn)\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): () => 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 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\nexport { pyreonOnMount as onMount }\nexport { pyreonOnUnmount as onCleanup }\n\n// ─── createSelector ──────────────────────────────────────────────────────────\n\nexport { pyreonCreateSelector as createSelector }\n\n// ─── mergeProps ──────────────────────────────────────────────────────────────\n\nexport function mergeProps<T extends object[]>(...sources: [...T]): T[number] {\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 T[number]\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): ComponentFn<P> & { preload: () => Promise<{ default: ComponentFn<P> }> } {\n let resolved: ComponentFn<P> | null = null\n let error: 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 resolved = mod.default\n return mod\n })\n .catch((err) => {\n error = err instanceof Error ? err : new Error(String(err))\n // Allow retry on next render by resetting the promise\n promise = null\n throw error\n })\n }\n return promise\n }\n\n const LazyComponent = ((props: P) => {\n if (error) throw error\n if (!resolved) {\n // Throw the promise so Suspense can catch it\n throw load()\n }\n return resolved(props)\n }) as ComponentFn<P> & { preload: () => Promise<{ default: ComponentFn<P> }> }\n\n LazyComponent.preload = load\n\n return LazyComponent\n}\n\n// ─── createContext / useContext ───────────────────────────────────────────────\n\nexport { pyreonCreateContext as createContext }\nexport { pyreonUseContext as useContext }\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// ─── Re-exports from @pyreon/core ──────────────────────────────────────────────\n\nexport { Show, Switch, Match, For, Suspense, ErrorBoundary }\n"],"mappings":";;;;AAiCA,SAAgB,aAAgB,cAAqD;CACnF,MAAM,IAAIA,OAAgB,aAAa;CAEvC,MAAM,eAAgC,GAAG;CAEzC,MAAM,UAA2B,MAAM;AACrC,MAAI,OAAO,MAAM,WACf,GAAE,OAAO,EAAoB;MAE7B,GAAE,IAAI,EAAE;;AAIZ,QAAO,CAAC,QAAQ,OAAO;;AAKzB,SAAgB,aAAa,IAAsB;AACjD,QAAa,GAAG;;AAKlB,SAAgB,mBAAmB,IAAsB;AACvD,QAAa,GAAG;;AASlB,SAAgB,WAAc,IAAsB;CAClD,MAAM,IAAIC,SAAe,GAAG;AAC5B,cAAa,GAAG;;AAKlB,SAAgB,WAAc,IAAmC;CAC/D,MAAM,QAAQ,aAAa;CAC3B,MAAM,OAAO,iBAAiB;AAC9B,iBAAgB,MAAM;AACtB,KAAI;AACF,SAAO,SAAS,MAAM,MAAM,CAAC;WACrB;AACR,kBAAgB,KAAK;;;AASzB,SAAgB,GACd,MACA,IAIqB;CAGrB,IAAI;CACJ,IAAI;CACJ,IAAI,cAAc;AAElB,cAAa;EAEX,MAAM,QACJ,MAAM,QAAQ,KAAK,GAAI,KAA2B,KAAK,MAAM,GAAG,CAAC,GAAI,MAAwB;AAG/F,MAAI,CAAC,aAAa;AAChB,iBAAc;AACd,eAAY,GAAG,OAAO,QAAW,OAAU;AAC3C,eAAY;AACZ,UAAO;;EAGT,MAAM,SAAS,mBAAmB,GAAG,OAAO,WAAW,UAAU,CAAC;AAClE,cAAY;AACZ,cAAY;AACZ,SAAO;;;AAuBX,SAAgB,WAA+B,GAAG,SAA4B;CAC5E,MAAM,SAAS,EAAE;AACjB,MAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,cAAc,OAAO,0BAA0B,OAAO;AAC5D,OAAK,MAAM,OAAO,QAAQ,QAAQ,YAAY,EAAE;GAC9C,MAAM,OAAO,YAAY;AACzB,OAAI,CAAC,KAAM;AAEX,OAAI,KAAK,IACP,QAAO,eAAe,QAAQ,KAAK;IACjC,KAAK,KAAK;IACV,YAAY;IACZ,cAAc;IACf,CAAC;OAEF,QAAO,eAAe,QAAQ,KAAK;IACjC,OAAO,KAAK;IACZ,UAAU;IACV,YAAY;IACZ,cAAc;IACf,CAAC;;;AAIR,QAAO;;AAKT,SAAgB,WACd,OACA,GAAG,MACuC;CAC1C,MAAM,SAAS,EAAE;CACjB,MAAM,OAAO,EAAE;CACf,MAAM,SAAS,IAAI,IAAY,KAAK,MAAM,CAAa;CAEvD,MAAM,cAAc,OAAO,0BAA0B,MAAM;AAC3D,MAAK,MAAM,OAAO,QAAQ,QAAQ,YAAY,EAAE;EAC9C,MAAM,OAAO,YAAY;AACzB,MAAI,CAAC,KAAM;EACX,MAAM,SAAS,OAAO,QAAQ,YAAY,OAAO,IAAI,IAAI,GAAG,SAAS;AACrE,MAAI,KAAK,IACP,QAAO,eAAe,QAAQ,KAAK;GACjC,KAAK,KAAK;GACV,YAAY;GACZ,cAAc;GACf,CAAC;MAEF,QAAO,eAAe,QAAQ,KAAK;GACjC,OAAO,KAAK;GACZ,UAAU;GACV,YAAY;GACZ,cAAc;GACf,CAAC;;AAIN,QAAO,CAAC,QAAQ,KAA2B;;AAK7C,SAAgB,SAAS,IAAwC;AAO/D,QANa,iBAAiB;EAC5B,MAAM,SAAS,IAAI;AAEnB,MAAI,OAAO,WAAW,WAAY,QAAQ,QAA6B;AACvE,SAAO;GACP;;AAMJ,SAAgB,KACd,QAC0E;CAC1E,IAAI,WAAkC;CACtC,IAAI,QAAsB;CAC1B,IAAI,UAAuD;CAE3D,MAAM,aAAa;AACjB,MAAI,CAAC,QACH,WAAU,QAAQ,CACf,MAAM,QAAQ;AACb,cAAW,IAAI;AACf,UAAO;IACP,CACD,OAAO,QAAQ;AACd,WAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC;AAE3D,aAAU;AACV,SAAM;IACN;AAEN,SAAO;;CAGT,MAAM,kBAAkB,UAAa;AACnC,MAAI,MAAO,OAAM;AACjB,MAAI,CAAC,SAEH,OAAM,MAAM;AAEd,SAAO,SAAS,MAAM;;AAGxB,eAAc,UAAU;AAExB,QAAO;;AAUT,SAAgB,WAA+B;AAC7C,QAAO,iBAAiB;;AAG1B,SAAgB,aAAgB,OAA2B,IAAgB;CACzE,MAAM,OAAO,iBAAiB;AAC9B,iBAAgB,MAAM;AACtB,KAAI;AACF,SAAO,IAAI;WACH;AACR,kBAAgB,KAAK"}
@@ -0,0 +1,139 @@
1
+ import { ErrorBoundary, For, Match, Show, Suspense, Switch, createContext as pyreonCreateContext, onMount as pyreonOnMount, onUnmount as pyreonOnUnmount, useContext as pyreonUseContext } from "@pyreon/core";
2
+ import { batch as pyreonBatch, computed, createSelector as pyreonCreateSelector, effect, effectScope, getCurrentScope, runUntracked, setCurrentScope, signal } from "@pyreon/reactivity";
3
+
4
+ //#region src/index.ts
5
+ function createSignal(initialValue) {
6
+ const s = signal(initialValue);
7
+ const getter = () => s();
8
+ const setter = v => {
9
+ if (typeof v === "function") s.update(v);else s.set(v);
10
+ };
11
+ return [getter, setter];
12
+ }
13
+ function createEffect(fn) {
14
+ effect(fn);
15
+ }
16
+ function createRenderEffect(fn) {
17
+ effect(fn);
18
+ }
19
+ function createMemo(fn) {
20
+ const c = computed(fn);
21
+ return () => c();
22
+ }
23
+ function createRoot(fn) {
24
+ const scope = effectScope();
25
+ const prev = getCurrentScope();
26
+ setCurrentScope(scope);
27
+ try {
28
+ return fn(() => scope.stop());
29
+ } finally {
30
+ setCurrentScope(prev);
31
+ }
32
+ }
33
+ function on(deps, fn) {
34
+ let prevInput;
35
+ let prevValue;
36
+ let initialized = false;
37
+ return () => {
38
+ const input = Array.isArray(deps) ? deps.map(d => d()) : deps();
39
+ if (!initialized) {
40
+ initialized = true;
41
+ prevValue = fn(input, void 0, void 0);
42
+ prevInput = input;
43
+ return prevValue;
44
+ }
45
+ const result = runUntracked(() => fn(input, prevInput, prevValue));
46
+ prevInput = input;
47
+ prevValue = result;
48
+ return result;
49
+ };
50
+ }
51
+ function mergeProps(...sources) {
52
+ const target = {};
53
+ for (const source of sources) {
54
+ const descriptors = Object.getOwnPropertyDescriptors(source);
55
+ for (const key of Reflect.ownKeys(descriptors)) {
56
+ const desc = descriptors[key];
57
+ if (!desc) continue;
58
+ if (desc.get) Object.defineProperty(target, key, {
59
+ get: desc.get,
60
+ enumerable: true,
61
+ configurable: true
62
+ });else Object.defineProperty(target, key, {
63
+ value: desc.value,
64
+ writable: true,
65
+ enumerable: true,
66
+ configurable: true
67
+ });
68
+ }
69
+ }
70
+ return target;
71
+ }
72
+ function splitProps(props, ...keys) {
73
+ const picked = {};
74
+ const rest = {};
75
+ const keySet = new Set(keys.flat());
76
+ const descriptors = Object.getOwnPropertyDescriptors(props);
77
+ for (const key of Reflect.ownKeys(descriptors)) {
78
+ const desc = descriptors[key];
79
+ if (!desc) continue;
80
+ const target = typeof key === "string" && keySet.has(key) ? picked : rest;
81
+ if (desc.get) Object.defineProperty(target, key, {
82
+ get: desc.get,
83
+ enumerable: true,
84
+ configurable: true
85
+ });else Object.defineProperty(target, key, {
86
+ value: desc.value,
87
+ writable: true,
88
+ enumerable: true,
89
+ configurable: true
90
+ });
91
+ }
92
+ return [picked, rest];
93
+ }
94
+ function children(fn) {
95
+ return createMemo(() => {
96
+ const result = fn();
97
+ if (typeof result === "function") return result();
98
+ return result;
99
+ });
100
+ }
101
+ function lazy(loader) {
102
+ let resolved = null;
103
+ let error = null;
104
+ let promise = null;
105
+ const load = () => {
106
+ if (!promise) promise = loader().then(mod => {
107
+ resolved = mod.default;
108
+ return mod;
109
+ }).catch(err => {
110
+ error = err instanceof Error ? err : new Error(String(err));
111
+ promise = null;
112
+ throw error;
113
+ });
114
+ return promise;
115
+ };
116
+ const LazyComponent = props => {
117
+ if (error) throw error;
118
+ if (!resolved) throw load();
119
+ return resolved(props);
120
+ };
121
+ LazyComponent.preload = load;
122
+ return LazyComponent;
123
+ }
124
+ function getOwner() {
125
+ return getCurrentScope();
126
+ }
127
+ function runWithOwner(owner, fn) {
128
+ const prev = getCurrentScope();
129
+ setCurrentScope(owner);
130
+ try {
131
+ return fn();
132
+ } finally {
133
+ setCurrentScope(prev);
134
+ }
135
+ }
136
+
137
+ //#endregion
138
+ export { ErrorBoundary, For, Match, Show, Suspense, Switch, pyreonBatch as batch, children, createEffect as createComputed, createEffect, pyreonCreateContext as createContext, createMemo, createRenderEffect, createRoot, pyreonCreateSelector as createSelector, createSignal, getOwner, lazy, mergeProps, on, pyreonOnUnmount as onCleanup, pyreonOnMount as onMount, runWithOwner, splitProps, runUntracked as untrack, pyreonUseContext as useContext };
139
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":["pyreonSignal","pyreonComputed"],"sources":["../../src/index.ts"],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { ComponentFn, ErrorBoundary, For, Match, Props, Show, Suspense, Switch, VNodeChild, createContext as pyreonCreateContext, onMount as pyreonOnMount, onUnmount as pyreonOnUnmount, useContext as pyreonUseContext } from "@pyreon/core";
2
+ import { EffectScope, batch as pyreonBatch, createSelector as pyreonCreateSelector, runUntracked } from "@pyreon/reactivity";
3
+
4
+ //#region src/index.d.ts
5
+ type SignalGetter<T> = () => T;
6
+ type SignalSetter<T> = (v: T | ((prev: T) => T)) => void;
7
+ declare function createSignal<T>(initialValue: T): [SignalGetter<T>, SignalSetter<T>];
8
+ declare function createEffect(fn: () => void): void;
9
+ declare function createRenderEffect(fn: () => void): void;
10
+ declare function createMemo<T>(fn: () => T): () => T;
11
+ declare function createRoot<T>(fn: (dispose: () => void) => T): T;
12
+ type AccessorArray = readonly (() => unknown)[];
13
+ type OnEffectFunction<D, V> = (input: D, prevInput: D | undefined, prev: V | undefined) => V;
14
+ declare function on<S extends (() => unknown) | AccessorArray, V>(deps: S, fn: OnEffectFunction<S extends (() => infer R) ? R : S extends readonly (() => infer R)[] ? R[] : never, V>): () => V | undefined;
15
+ declare function mergeProps<T extends object[]>(...sources: [...T]): T[number];
16
+ declare function splitProps<T extends Record<string, unknown>, K extends (keyof T)[]>(props: T, ...keys: K): [Pick<T, K[number]>, Omit<T, K[number]>];
17
+ declare function children(fn: () => VNodeChild): () => VNodeChild;
18
+ declare function lazy<P extends Props>(loader: () => Promise<{
19
+ default: ComponentFn<P>;
20
+ }>): ComponentFn<P> & {
21
+ preload: () => Promise<{
22
+ default: ComponentFn<P>;
23
+ }>;
24
+ };
25
+ declare function getOwner(): EffectScope | null;
26
+ declare function runWithOwner<T>(owner: EffectScope | null, fn: () => T): T;
27
+ //#endregion
28
+ export { ErrorBoundary, For, Match, Show, SignalGetter, SignalSetter, Suspense, Switch, pyreonBatch as batch, children, createEffect as createComputed, createEffect, pyreonCreateContext as createContext, createMemo, createRenderEffect, createRoot, pyreonCreateSelector as createSelector, createSignal, getOwner, lazy, mergeProps, on, pyreonOnUnmount as onCleanup, pyreonOnMount as onMount, runWithOwner, splitProps, runUntracked as untrack, pyreonUseContext as useContext };
29
+ //# sourceMappingURL=index2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index2.d.ts","names":[],"sources":["../../src/index.ts"],"mappings":";;;;KA8BY,YAAA,YAAwB,CAAA;AAAA,KACxB,YAAA,OAAmB,CAAA,EAAG,CAAA,KAAM,IAAA,EAAM,CAAA,KAAM,CAAA;AAAA,iBAEpC,YAAA,GAAA,CAAgB,YAAA,EAAc,CAAA,IAAK,YAAA,CAAa,CAAA,GAAI,YAAA,CAAa,CAAA;AAAA,iBAkBjE,YAAA,CAAa,EAAA;AAAA,iBAMb,kBAAA,CAAmB,EAAA;AAAA,iBAUnB,UAAA,GAAA,CAAc,EAAA,QAAU,CAAA,SAAU,CAAA;AAAA,iBAOlC,UAAA,GAAA,CAAc,EAAA,GAAK,OAAA,iBAAwB,CAAA,GAAI,CAAA;AAAA,KAa1D,aAAA;AAAA,KACA,gBAAA,UAA0B,KAAA,EAAO,CAAA,EAAG,SAAA,EAAW,CAAA,cAAe,IAAA,EAAM,CAAA,iBAAkB,CAAA;AAAA,iBAE3E,EAAA,6BAA+B,aAAA,IAAA,CAC7C,IAAA,EAAM,CAAA,EACN,EAAA,EAAI,gBAAA,CACF,CAAA,2BAA0B,CAAA,GAAI,CAAA,sCAAuC,CAAA,YACrE,CAAA,UAEK,CAAA;AAAA,iBA8CO,UAAA,oBAAA,CAAA,GAAkC,OAAA,MAAa,CAAA,IAAK,CAAA;AAAA,iBA6BpD,UAAA,WAAqB,MAAA,oCAA0C,CAAA,IAAA,CAC7E,KAAA,EAAO,CAAA,KACJ,IAAA,EAAM,CAAA,IACP,IAAA,CAAK,CAAA,EAAG,CAAA,WAAY,IAAA,CAAK,CAAA,EAAG,CAAA;AAAA,iBA+BhB,QAAA,CAAS,EAAA,QAAU,UAAA,SAAmB,UAAA;AAAA,iBAYtC,IAAA,WAAe,KAAA,CAAA,CAC7B,MAAA,QAAc,OAAA;EAAU,OAAA,EAAS,WAAA,CAAY,CAAA;AAAA,KAC5C,WAAA,CAAY,CAAA;EAAO,OAAA,QAAe,OAAA;IAAU,OAAA,EAAS,WAAA,CAAY,CAAA;EAAA;AAAA;AAAA,iBA2CpD,QAAA,CAAA,GAAY,WAAA;AAAA,iBAIZ,YAAA,GAAA,CAAgB,KAAA,EAAO,WAAA,SAAoB,EAAA,QAAU,CAAA,GAAI,CAAA"}
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@pyreon/solid-compat",
3
+ "version": "0.1.0",
4
+ "description": "SolidJS-compatible API shim for Pyreon — write Solid-style code that runs on Pyreon's reactive engine",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/pyreon/pyreon.git",
9
+ "directory": "packages/solid-compat"
10
+ },
11
+ "homepage": "https://github.com/pyreon/pyreon/tree/main/packages/solid-compat#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/pyreon/pyreon/issues"
14
+ },
15
+ "files": [
16
+ "lib",
17
+ "src",
18
+ "README.md",
19
+ "LICENSE"
20
+ ],
21
+ "sideEffects": false,
22
+ "type": "module",
23
+ "main": "./lib/index.js",
24
+ "module": "./lib/index.js",
25
+ "types": "./lib/types/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "bun": "./src/index.ts",
29
+ "import": "./lib/index.js",
30
+ "types": "./lib/types/index.d.ts"
31
+ }
32
+ },
33
+ "scripts": {
34
+ "build": "vl_rolldown_build",
35
+ "dev": "vl_rolldown_build-watch",
36
+ "test": "vitest run",
37
+ "typecheck": "tsc --noEmit",
38
+ "prepublishOnly": "bun run build"
39
+ },
40
+ "dependencies": {
41
+ "@pyreon/core": "workspace:*",
42
+ "@pyreon/reactivity": "workspace:*",
43
+ "@pyreon/runtime-dom": "workspace:*"
44
+ },
45
+ "devDependencies": {
46
+ "@happy-dom/global-registrator": "^20.8.3",
47
+ "happy-dom": "^20.8.3"
48
+ }
49
+ }
package/src/index.ts ADDED
@@ -0,0 +1,279 @@
1
+ // @pyreon/solid-compat — SolidJS-compatible API shims running on Pyreon's reactive engine
2
+
3
+ import type { ComponentFn, Props, VNodeChild } from "@pyreon/core"
4
+ import {
5
+ ErrorBoundary,
6
+ For,
7
+ Match,
8
+ createContext as pyreonCreateContext,
9
+ onMount as pyreonOnMount,
10
+ onUnmount as pyreonOnUnmount,
11
+ useContext as pyreonUseContext,
12
+ Show,
13
+ Suspense,
14
+ Switch,
15
+ } from "@pyreon/core"
16
+ import {
17
+ type EffectScope,
18
+ effectScope,
19
+ getCurrentScope,
20
+ batch as pyreonBatch,
21
+ computed as pyreonComputed,
22
+ createSelector as pyreonCreateSelector,
23
+ effect as pyreonEffect,
24
+ signal as pyreonSignal,
25
+ runUntracked,
26
+ setCurrentScope,
27
+ } from "@pyreon/reactivity"
28
+
29
+ // ─── createSignal ────────────────────────────────────────────────────────────
30
+
31
+ export type SignalGetter<T> = () => T
32
+ export type SignalSetter<T> = (v: T | ((prev: T) => T)) => void
33
+
34
+ export function createSignal<T>(initialValue: T): [SignalGetter<T>, SignalSetter<T>] {
35
+ const s = pyreonSignal<T>(initialValue)
36
+
37
+ const getter: SignalGetter<T> = () => s()
38
+
39
+ const setter: SignalSetter<T> = (v) => {
40
+ if (typeof v === "function") {
41
+ s.update(v as (prev: T) => T)
42
+ } else {
43
+ s.set(v)
44
+ }
45
+ }
46
+
47
+ return [getter, setter]
48
+ }
49
+
50
+ // ─── createEffect ────────────────────────────────────────────────────────────
51
+
52
+ export function createEffect(fn: () => void): void {
53
+ pyreonEffect(fn)
54
+ }
55
+
56
+ // ─── createRenderEffect ──────────────────────────────────────────────────────
57
+
58
+ export function createRenderEffect(fn: () => void): void {
59
+ pyreonEffect(fn)
60
+ }
61
+
62
+ // ─── createComputed (legacy Solid API) ───────────────────────────────────────
63
+
64
+ export { createEffect as createComputed }
65
+
66
+ // ─── createMemo ──────────────────────────────────────────────────────────────
67
+
68
+ export function createMemo<T>(fn: () => T): () => T {
69
+ const c = pyreonComputed(fn)
70
+ return () => c()
71
+ }
72
+
73
+ // ─── createRoot ──────────────────────────────────────────────────────────────
74
+
75
+ export function createRoot<T>(fn: (dispose: () => void) => T): T {
76
+ const scope = effectScope()
77
+ const prev = getCurrentScope()
78
+ setCurrentScope(scope)
79
+ try {
80
+ return fn(() => scope.stop())
81
+ } finally {
82
+ setCurrentScope(prev)
83
+ }
84
+ }
85
+
86
+ // ─── on ──────────────────────────────────────────────────────────────────────
87
+
88
+ type AccessorArray = readonly (() => unknown)[]
89
+ type OnEffectFunction<D, V> = (input: D, prevInput: D | undefined, prev: V | undefined) => V
90
+
91
+ export function on<S extends (() => unknown) | AccessorArray, V>(
92
+ deps: S,
93
+ fn: OnEffectFunction<
94
+ S extends () => infer R ? R : S extends readonly (() => infer R)[] ? R[] : never,
95
+ V
96
+ >,
97
+ ): () => V | undefined {
98
+ type D = S extends () => infer R ? R : S extends readonly (() => infer R)[] ? R[] : never
99
+
100
+ let prevInput: D | undefined
101
+ let prevValue: V | undefined
102
+ let initialized = false
103
+
104
+ return () => {
105
+ // Read dependencies to register tracking
106
+ const input: D = (
107
+ Array.isArray(deps) ? (deps as (() => unknown)[]).map((d) => d()) : (deps as () => unknown)()
108
+ ) as D
109
+
110
+ if (!initialized) {
111
+ initialized = true
112
+ prevValue = fn(input, undefined, undefined)
113
+ prevInput = input
114
+ return prevValue
115
+ }
116
+
117
+ const result = runUntracked(() => fn(input, prevInput, prevValue))
118
+ prevInput = input
119
+ prevValue = result
120
+ return result
121
+ }
122
+ }
123
+
124
+ // ─── batch ───────────────────────────────────────────────────────────────────
125
+
126
+ export { pyreonBatch as batch }
127
+
128
+ // ─── untrack ─────────────────────────────────────────────────────────────────
129
+
130
+ export { runUntracked as untrack }
131
+
132
+ // ─── onMount / onCleanup ─────────────────────────────────────────────────────
133
+
134
+ export { pyreonOnMount as onMount }
135
+ export { pyreonOnUnmount as onCleanup }
136
+
137
+ // ─── createSelector ──────────────────────────────────────────────────────────
138
+
139
+ export { pyreonCreateSelector as createSelector }
140
+
141
+ // ─── mergeProps ──────────────────────────────────────────────────────────────
142
+
143
+ export function mergeProps<T extends object[]>(...sources: [...T]): T[number] {
144
+ const target = {} as Record<PropertyKey, unknown>
145
+ for (const source of sources) {
146
+ const descriptors = Object.getOwnPropertyDescriptors(source)
147
+ for (const key of Reflect.ownKeys(descriptors)) {
148
+ const desc = descriptors[key as string]
149
+ if (!desc) continue
150
+ // Preserve getters for reactivity
151
+ if (desc.get) {
152
+ Object.defineProperty(target, key, {
153
+ get: desc.get,
154
+ enumerable: true,
155
+ configurable: true,
156
+ })
157
+ } else {
158
+ Object.defineProperty(target, key, {
159
+ value: desc.value,
160
+ writable: true,
161
+ enumerable: true,
162
+ configurable: true,
163
+ })
164
+ }
165
+ }
166
+ }
167
+ return target as T[number]
168
+ }
169
+
170
+ // ─── splitProps ──────────────────────────────────────────────────────────────
171
+
172
+ export function splitProps<T extends Record<string, unknown>, K extends (keyof T)[]>(
173
+ props: T,
174
+ ...keys: K
175
+ ): [Pick<T, K[number]>, Omit<T, K[number]>] {
176
+ const picked = {} as Pick<T, K[number]>
177
+ const rest = {} as Record<string, unknown>
178
+ const keySet = new Set<string>(keys.flat() as string[])
179
+
180
+ const descriptors = Object.getOwnPropertyDescriptors(props)
181
+ for (const key of Reflect.ownKeys(descriptors)) {
182
+ const desc = descriptors[key as string]
183
+ if (!desc) continue
184
+ const target = typeof key === "string" && keySet.has(key) ? picked : rest
185
+ if (desc.get) {
186
+ Object.defineProperty(target, key, {
187
+ get: desc.get,
188
+ enumerable: true,
189
+ configurable: true,
190
+ })
191
+ } else {
192
+ Object.defineProperty(target, key, {
193
+ value: desc.value,
194
+ writable: true,
195
+ enumerable: true,
196
+ configurable: true,
197
+ })
198
+ }
199
+ }
200
+
201
+ return [picked, rest as Omit<T, K[number]>]
202
+ }
203
+
204
+ // ─── children ────────────────────────────────────────────────────────────────
205
+
206
+ export function children(fn: () => VNodeChild): () => VNodeChild {
207
+ const memo = createMemo(() => {
208
+ const result = fn()
209
+ // Resolve function children (reactive getters)
210
+ if (typeof result === "function") return (result as () => VNodeChild)()
211
+ return result
212
+ })
213
+ return memo
214
+ }
215
+
216
+ // ─── lazy ────────────────────────────────────────────────────────────────────
217
+
218
+ export function lazy<P extends Props>(
219
+ loader: () => Promise<{ default: ComponentFn<P> }>,
220
+ ): ComponentFn<P> & { preload: () => Promise<{ default: ComponentFn<P> }> } {
221
+ let resolved: ComponentFn<P> | null = null
222
+ let error: Error | null = null
223
+ let promise: Promise<{ default: ComponentFn<P> }> | null = null
224
+
225
+ const load = () => {
226
+ if (!promise) {
227
+ promise = loader()
228
+ .then((mod) => {
229
+ resolved = mod.default
230
+ return mod
231
+ })
232
+ .catch((err) => {
233
+ error = err instanceof Error ? err : new Error(String(err))
234
+ // Allow retry on next render by resetting the promise
235
+ promise = null
236
+ throw error
237
+ })
238
+ }
239
+ return promise
240
+ }
241
+
242
+ const LazyComponent = ((props: P) => {
243
+ if (error) throw error
244
+ if (!resolved) {
245
+ // Throw the promise so Suspense can catch it
246
+ throw load()
247
+ }
248
+ return resolved(props)
249
+ }) as ComponentFn<P> & { preload: () => Promise<{ default: ComponentFn<P> }> }
250
+
251
+ LazyComponent.preload = load
252
+
253
+ return LazyComponent
254
+ }
255
+
256
+ // ─── createContext / useContext ───────────────────────────────────────────────
257
+
258
+ export { pyreonCreateContext as createContext }
259
+ export { pyreonUseContext as useContext }
260
+
261
+ // ─── getOwner / runWithOwner ─────────────────────────────────────────────────
262
+
263
+ export function getOwner(): EffectScope | null {
264
+ return getCurrentScope()
265
+ }
266
+
267
+ export function runWithOwner<T>(owner: EffectScope | null, fn: () => T): T {
268
+ const prev = getCurrentScope()
269
+ setCurrentScope(owner)
270
+ try {
271
+ return fn()
272
+ } finally {
273
+ setCurrentScope(prev)
274
+ }
275
+ }
276
+
277
+ // ─── Re-exports from @pyreon/core ──────────────────────────────────────────────
278
+
279
+ export { Show, Switch, Match, For, Suspense, ErrorBoundary }