round-core 0.0.6 → 0.0.8
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 +21 -0
- package/dist/index.d.ts +341 -326
- package/dist/vite-plugin.js +52 -3
- package/package.json +7 -3
- package/.github/workflows/benchmarks.yml +0 -44
- package/Round.png +0 -0
- package/benchmarks/apps/react/index.html +0 -9
- package/benchmarks/apps/react/main.jsx +0 -25
- package/benchmarks/apps/react/vite.config.js +0 -12
- package/benchmarks/apps/round/index.html +0 -11
- package/benchmarks/apps/round/main.jsx +0 -22
- package/benchmarks/apps/round/vite.config.js +0 -15
- package/benchmarks/bun.lock +0 -497
- package/benchmarks/dist-bench/react/assets/index-9KGqIPOU.js +0 -8
- package/benchmarks/dist-bench/react/index.html +0 -10
- package/benchmarks/dist-bench/round/assets/index-CBBIRhox.js +0 -52
- package/benchmarks/dist-bench/round/index.html +0 -8
- package/benchmarks/package.json +0 -22
- package/benchmarks/scripts/measure-build.js +0 -64
- package/benchmarks/tests/runtime.bench.js +0 -51
- package/benchmarks/vitest.config.js +0 -8
- package/bun.lock +0 -425
- package/cli.js +0 -2
- package/index.js +0 -2
- package/logo.svg +0 -10
- package/src/cli.js +0 -608
- package/src/compiler/index.js +0 -2
- package/src/compiler/transformer.js +0 -443
- package/src/compiler/vite-plugin.js +0 -472
- package/src/index.d.ts +0 -326
- package/src/index.js +0 -45
- package/src/runtime/context.js +0 -101
- package/src/runtime/dom.js +0 -403
- package/src/runtime/error-boundary.js +0 -48
- package/src/runtime/error-reporter.js +0 -13
- package/src/runtime/error-store.js +0 -85
- package/src/runtime/errors.js +0 -152
- package/src/runtime/lifecycle.js +0 -142
- package/src/runtime/markdown.js +0 -72
- package/src/runtime/router.js +0 -468
- package/src/runtime/signals.js +0 -548
- package/src/runtime/store.js +0 -215
- package/src/runtime/suspense.js +0 -128
- package/vite.config.build.js +0 -48
- package/vite.config.js +0 -10
- package/vitest.config.js +0 -8
package/src/runtime/store.js
DELETED
|
@@ -1,215 +0,0 @@
|
|
|
1
|
-
import { bindable, effect } from './signals.js';
|
|
2
|
-
import { reportErrorSafe } from './error-reporter.js';
|
|
3
|
-
|
|
4
|
-
function hasWindow() {
|
|
5
|
-
return typeof window !== 'undefined' && typeof document !== 'undefined';
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Create a shared global state store with actions and optional persistence.
|
|
10
|
-
* @template T
|
|
11
|
-
* @param {T} [initialState={}] Initial state object.
|
|
12
|
-
* @param {Record<string, (state: T, ...args: any[]) => any>} [actions] Action reducers.
|
|
13
|
-
* @returns {RoundStore<T>} The store object.
|
|
14
|
-
*/
|
|
15
|
-
export function createStore(initialState = {}, actions = null) {
|
|
16
|
-
const state = (initialState && typeof initialState === 'object') ? initialState : {};
|
|
17
|
-
const signals = Object.create(null);
|
|
18
|
-
const persistState = {
|
|
19
|
-
enabled: false,
|
|
20
|
-
key: null,
|
|
21
|
-
storage: null,
|
|
22
|
-
persisting: false,
|
|
23
|
-
persistNow: null,
|
|
24
|
-
watchers: new Set()
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
for (const k of Object.keys(state)) {
|
|
28
|
-
signals[k] = bindable(state[k]);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function setKey(k, v) {
|
|
32
|
-
const key = String(k);
|
|
33
|
-
if (!Object.prototype.hasOwnProperty.call(signals, key)) {
|
|
34
|
-
signals[key] = bindable(state[key]);
|
|
35
|
-
}
|
|
36
|
-
state[key] = v;
|
|
37
|
-
signals[key](v);
|
|
38
|
-
if (persistState.enabled && typeof persistState.persistNow === 'function') {
|
|
39
|
-
persistState.persistNow();
|
|
40
|
-
}
|
|
41
|
-
return v;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function patch(obj) {
|
|
45
|
-
if (!obj || typeof obj !== 'object') return;
|
|
46
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
47
|
-
setKey(k, v);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function getSnapshot(reactive = false) {
|
|
52
|
-
const out = {};
|
|
53
|
-
for (const k of Object.keys(signals)) {
|
|
54
|
-
out[k] = reactive ? signals[k]() : signals[k].peek();
|
|
55
|
-
}
|
|
56
|
-
return out;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const store = {
|
|
60
|
-
use(key) {
|
|
61
|
-
const k = String(key);
|
|
62
|
-
if (!Object.prototype.hasOwnProperty.call(signals, k)) {
|
|
63
|
-
signals[k] = bindable(state[k]);
|
|
64
|
-
if (!Object.prototype.hasOwnProperty.call(state, k)) {
|
|
65
|
-
try {
|
|
66
|
-
reportErrorSafe(new Error(`Store key not found: ${k}`), { phase: 'store.use', component: 'createStore' });
|
|
67
|
-
} catch {
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
if (persistState.enabled) {
|
|
73
|
-
const sig = signals[k];
|
|
74
|
-
if (sig && typeof sig === 'function' && !persistState.watchers.has(k)) {
|
|
75
|
-
persistState.watchers.add(k);
|
|
76
|
-
effect(() => {
|
|
77
|
-
sig();
|
|
78
|
-
if (persistState.persisting) return;
|
|
79
|
-
if (typeof persistState.persistNow === 'function') persistState.persistNow();
|
|
80
|
-
}, { onLoad: false });
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return signals[k];
|
|
85
|
-
},
|
|
86
|
-
set(key, value) {
|
|
87
|
-
return setKey(key, value);
|
|
88
|
-
},
|
|
89
|
-
patch,
|
|
90
|
-
snapshot(options = {}) {
|
|
91
|
-
const reactive = options && typeof options === 'object' && options.reactive === true;
|
|
92
|
-
return getSnapshot(reactive);
|
|
93
|
-
},
|
|
94
|
-
actions: {}
|
|
95
|
-
};
|
|
96
|
-
|
|
97
|
-
if (actions && typeof actions === 'object') {
|
|
98
|
-
Object.entries(actions).forEach(([name, reducer]) => {
|
|
99
|
-
if (typeof reducer !== 'function') return;
|
|
100
|
-
const fn = (...args) => {
|
|
101
|
-
try {
|
|
102
|
-
const next = reducer(getSnapshot(false), ...args);
|
|
103
|
-
if (next && typeof next === 'object') {
|
|
104
|
-
patch(next);
|
|
105
|
-
}
|
|
106
|
-
return next;
|
|
107
|
-
} catch (e) {
|
|
108
|
-
reportErrorSafe(e, { phase: 'store.action', component: String(name) });
|
|
109
|
-
}
|
|
110
|
-
};
|
|
111
|
-
store.actions[name] = fn;
|
|
112
|
-
store[name] = fn;
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
store.persist = (storageKey, optionsOrStorage) => {
|
|
117
|
-
if (typeof storageKey !== 'string' || !storageKey.length) return store;
|
|
118
|
-
|
|
119
|
-
const isStorageLike = optionsOrStorage
|
|
120
|
-
&& (typeof optionsOrStorage.getItem === 'function')
|
|
121
|
-
&& (typeof optionsOrStorage.setItem === 'function');
|
|
122
|
-
|
|
123
|
-
const opts = (!isStorageLike && optionsOrStorage && typeof optionsOrStorage === 'object')
|
|
124
|
-
? optionsOrStorage
|
|
125
|
-
: {};
|
|
126
|
-
|
|
127
|
-
const st = isStorageLike
|
|
128
|
-
? optionsOrStorage
|
|
129
|
-
: (opts.storage ?? (hasWindow() ? window.localStorage : null));
|
|
130
|
-
|
|
131
|
-
if (!st || typeof st.getItem !== 'function' || typeof st.setItem !== 'function') return store;
|
|
132
|
-
|
|
133
|
-
const debounceMs = Number.isFinite(Number(opts.debounce)) ? Number(opts.debounce) : 0;
|
|
134
|
-
const exclude = Array.isArray(opts.exclude) ? opts.exclude.map(String) : [];
|
|
135
|
-
|
|
136
|
-
try {
|
|
137
|
-
const raw = st.getItem(storageKey);
|
|
138
|
-
if (raw) {
|
|
139
|
-
const parsed = JSON.parse(raw);
|
|
140
|
-
if (parsed && typeof parsed === 'object') {
|
|
141
|
-
const filtered = exclude.length
|
|
142
|
-
? Object.fromEntries(Object.entries(parsed).filter(([k]) => !exclude.includes(String(k))))
|
|
143
|
-
: parsed;
|
|
144
|
-
patch(filtered);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
} catch {
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
const persistNow = () => {
|
|
151
|
-
try {
|
|
152
|
-
persistState.persisting = true;
|
|
153
|
-
const snap = getSnapshot(false);
|
|
154
|
-
const out = exclude.length
|
|
155
|
-
? Object.fromEntries(Object.entries(snap).filter(([k]) => !exclude.includes(String(k))))
|
|
156
|
-
: snap;
|
|
157
|
-
st.setItem(storageKey, JSON.stringify(out));
|
|
158
|
-
} catch {
|
|
159
|
-
} finally {
|
|
160
|
-
persistState.persisting = false;
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
let debounceId = null;
|
|
165
|
-
const schedulePersist = () => {
|
|
166
|
-
if (debounceMs <= 0) return persistNow();
|
|
167
|
-
try {
|
|
168
|
-
if (debounceId != null) clearTimeout(debounceId);
|
|
169
|
-
} catch {
|
|
170
|
-
}
|
|
171
|
-
debounceId = setTimeout(() => {
|
|
172
|
-
debounceId = null;
|
|
173
|
-
persistNow();
|
|
174
|
-
}, debounceMs);
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
persistState.enabled = true;
|
|
178
|
-
persistState.key = storageKey;
|
|
179
|
-
persistState.storage = st;
|
|
180
|
-
persistState.persistNow = schedulePersist;
|
|
181
|
-
|
|
182
|
-
const origSet = store.set;
|
|
183
|
-
store.set = (k, v) => {
|
|
184
|
-
const res = origSet(k, v);
|
|
185
|
-
schedulePersist();
|
|
186
|
-
return res;
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
const origPatch = store.patch;
|
|
190
|
-
store.patch = (obj) => {
|
|
191
|
-
origPatch(obj);
|
|
192
|
-
schedulePersist();
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
Object.keys(store.actions).forEach((name) => {
|
|
196
|
-
const orig = store.actions[name];
|
|
197
|
-
if (typeof orig !== 'function') return;
|
|
198
|
-
store.actions[name] = (...args) => {
|
|
199
|
-
const res = orig(...args);
|
|
200
|
-
schedulePersist();
|
|
201
|
-
return res;
|
|
202
|
-
};
|
|
203
|
-
store[name] = store.actions[name];
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
Object.keys(signals).forEach((k) => {
|
|
207
|
-
try { store.use(k); } catch { }
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
schedulePersist();
|
|
211
|
-
return store;
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
return store;
|
|
215
|
-
}
|
package/src/runtime/suspense.js
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { signal } from './signals.js';
|
|
2
|
-
import { createElement, Fragment } from './dom.js';
|
|
3
|
-
import { createContext } from './context.js';
|
|
4
|
-
|
|
5
|
-
function isPromiseLike(v) {
|
|
6
|
-
return v && (typeof v === 'object' || typeof v === 'function') && typeof v.then === 'function';
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const SuspenseContext = createContext(null);
|
|
10
|
-
export { SuspenseContext };
|
|
11
|
-
|
|
12
|
-
export function lazy(loader) {
|
|
13
|
-
if (typeof loader !== 'function') {
|
|
14
|
-
throw new Error('lazy(loader) expects a function that returns a Promise');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
let status = 'uninitialized';
|
|
18
|
-
let promise = null;
|
|
19
|
-
let component = null;
|
|
20
|
-
let error = null;
|
|
21
|
-
|
|
22
|
-
function pickComponent(mod) {
|
|
23
|
-
if (!mod) return null;
|
|
24
|
-
if (typeof mod === 'function') return mod;
|
|
25
|
-
if (typeof mod.default === 'function') return mod.default;
|
|
26
|
-
if (typeof mod.Counter === 'function') return mod.Counter;
|
|
27
|
-
|
|
28
|
-
const fns = [];
|
|
29
|
-
for (const k of Object.keys(mod)) {
|
|
30
|
-
if (typeof mod[k] === 'function') fns.push(mod[k]);
|
|
31
|
-
}
|
|
32
|
-
if (fns.length === 1) return fns[0];
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return function LazyComponent(props = {}) {
|
|
37
|
-
if (status === 'resolved') {
|
|
38
|
-
return createElement(component, props);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (status === 'rejected') {
|
|
42
|
-
throw error;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (!promise) {
|
|
46
|
-
status = 'pending';
|
|
47
|
-
try {
|
|
48
|
-
promise = Promise.resolve(loader())
|
|
49
|
-
.then((mod) => {
|
|
50
|
-
const resolved = pickComponent(mod);
|
|
51
|
-
if (typeof resolved !== 'function') {
|
|
52
|
-
throw new Error('lazy() loaded module does not export a component');
|
|
53
|
-
}
|
|
54
|
-
component = resolved;
|
|
55
|
-
status = 'resolved';
|
|
56
|
-
})
|
|
57
|
-
.catch((e) => {
|
|
58
|
-
error = e instanceof Error ? e : new Error(String(e));
|
|
59
|
-
status = 'rejected';
|
|
60
|
-
});
|
|
61
|
-
} catch (e) {
|
|
62
|
-
error = e instanceof Error ? e : new Error(String(e));
|
|
63
|
-
status = 'rejected';
|
|
64
|
-
throw error;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
throw promise;
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function Suspense(props = {}) {
|
|
73
|
-
const tick = signal(0);
|
|
74
|
-
const pending = new Set();
|
|
75
|
-
|
|
76
|
-
// Track promises we are currently waiting for to avoid re-adding them or flickering
|
|
77
|
-
const waiting = new Set();
|
|
78
|
-
|
|
79
|
-
const child = Array.isArray(props.children) ? props.children[0] : props.children;
|
|
80
|
-
const childFn = typeof child === 'function' ? child : () => child;
|
|
81
|
-
|
|
82
|
-
const register = (promise) => {
|
|
83
|
-
if (!waiting.has(promise)) {
|
|
84
|
-
waiting.add(promise);
|
|
85
|
-
pending.add(promise);
|
|
86
|
-
promise.then(
|
|
87
|
-
() => {
|
|
88
|
-
waiting.delete(promise);
|
|
89
|
-
pending.delete(promise);
|
|
90
|
-
tick(tick.peek() + 1);
|
|
91
|
-
},
|
|
92
|
-
() => {
|
|
93
|
-
waiting.delete(promise);
|
|
94
|
-
pending.delete(promise);
|
|
95
|
-
tick(tick.peek() + 1);
|
|
96
|
-
}
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
return createElement(SuspenseContext.Provider, {
|
|
102
|
-
value: { register }
|
|
103
|
-
}, () => {
|
|
104
|
-
// Read tick to re-render when promises resolve
|
|
105
|
-
tick();
|
|
106
|
-
|
|
107
|
-
// If pending promises, show fallback depending on strategy.
|
|
108
|
-
|
|
109
|
-
if (pending.size > 0) {
|
|
110
|
-
return props.fallback ?? null;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
try {
|
|
114
|
-
const res = childFn();
|
|
115
|
-
if (isPromiseLike(res)) {
|
|
116
|
-
register(res);
|
|
117
|
-
return props.fallback ?? null;
|
|
118
|
-
}
|
|
119
|
-
return res ?? null;
|
|
120
|
-
} catch (e) {
|
|
121
|
-
if (isPromiseLike(e)) {
|
|
122
|
-
register(e);
|
|
123
|
-
return props.fallback ?? null;
|
|
124
|
-
}
|
|
125
|
-
throw e;
|
|
126
|
-
}
|
|
127
|
-
});
|
|
128
|
-
}
|
package/vite.config.build.js
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
|
|
5
|
-
export default defineConfig({
|
|
6
|
-
build: {
|
|
7
|
-
target: 'es2022',
|
|
8
|
-
outDir: 'dist',
|
|
9
|
-
emptyOutDir: true,
|
|
10
|
-
minify: false,
|
|
11
|
-
lib: {
|
|
12
|
-
entry: {
|
|
13
|
-
index: path.resolve(__dirname, 'src/index.js'),
|
|
14
|
-
cli: path.resolve(__dirname, 'src/cli.js'),
|
|
15
|
-
'vite-plugin': path.resolve(__dirname, 'src/compiler/vite-plugin.js')
|
|
16
|
-
},
|
|
17
|
-
formats: ['es']
|
|
18
|
-
},
|
|
19
|
-
rollupOptions: {
|
|
20
|
-
external: [
|
|
21
|
-
'vite',
|
|
22
|
-
'marked',
|
|
23
|
-
'node:fs', 'node:path', 'node:process', 'node:url', 'node:vm', 'node:util',
|
|
24
|
-
'fs', 'path', 'process', 'url', 'vm', 'util'
|
|
25
|
-
],
|
|
26
|
-
output: {
|
|
27
|
-
banner: (chunk) => {
|
|
28
|
-
if (chunk.name === 'cli' || chunk.fileName === 'cli.js') {
|
|
29
|
-
return '#!/usr/bin/env node';
|
|
30
|
-
}
|
|
31
|
-
return '';
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
plugins: [
|
|
37
|
-
{
|
|
38
|
-
name: 'copy-dts',
|
|
39
|
-
closeBundle() {
|
|
40
|
-
const src = path.resolve(__dirname, 'src/index.d.ts');
|
|
41
|
-
const dest = path.resolve(__dirname, 'dist/index.d.ts');
|
|
42
|
-
if (fs.existsSync(src)) {
|
|
43
|
-
fs.copyFileSync(src, dest);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
]
|
|
48
|
-
});
|
package/vite.config.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'vite';
|
|
2
|
-
import RoundPlugin from './src/compiler/vite-plugin.js';
|
|
3
|
-
|
|
4
|
-
export default defineConfig({
|
|
5
|
-
plugins: [RoundPlugin({ configPath: './start_exmpl/round.config.json' })],
|
|
6
|
-
root: './', // Serve from root
|
|
7
|
-
server: {
|
|
8
|
-
port: 3000
|
|
9
|
-
}
|
|
10
|
-
});
|