@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/LICENSE +21 -0
- package/README.md +75 -0
- package/lib/analysis/index.js.html +5406 -0
- package/lib/index.js +142 -0
- package/lib/index.js.map +1 -0
- package/lib/types/index.d.ts +139 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/index2.d.ts +29 -0
- package/lib/types/index2.d.ts.map +1 -0
- package/package.json +49 -0
- package/src/index.ts +279 -0
- package/src/tests/setup.ts +3 -0
- package/src/tests/solid-compat.test.ts +647 -0
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
|
package/lib/index.js.map
ADDED
|
@@ -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":"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"}
|
|
@@ -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 }
|