@pyreon/core 0.11.5 → 0.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/analysis/index.js.html +1 -1
- package/lib/index.js +33 -5
- package/lib/index.js.map +1 -1
- package/lib/jsx-dev-runtime.js.map +1 -1
- package/lib/jsx-runtime.js.map +1 -1
- package/lib/types/index.d.ts +145 -98
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/jsx-dev-runtime.d.ts +94 -94
- package/lib/types/jsx-runtime.d.ts +94 -94
- package/package.json +11 -11
- package/src/component.ts +2 -2
- package/src/context.ts +75 -4
- package/src/dynamic.ts +4 -4
- package/src/error-boundary.ts +10 -10
- package/src/for.ts +8 -2
- package/src/h.ts +4 -4
- package/src/index.ts +30 -27
- package/src/jsx-dev-runtime.ts +1 -1
- package/src/jsx-runtime.ts +108 -108
- package/src/lazy.ts +4 -4
- package/src/lifecycle.ts +6 -6
- package/src/portal.ts +2 -2
- package/src/show.ts +4 -4
- package/src/style.ts +51 -51
- package/src/suspense.ts +8 -8
- package/src/telemetry.ts +1 -1
- package/src/tests/component.test.ts +60 -60
- package/src/tests/context.test.ts +102 -102
- package/src/tests/core.test.ts +376 -376
- package/src/tests/cx.test.ts +34 -34
- package/src/tests/dynamic.test.ts +28 -28
- package/src/tests/error-boundary.test.ts +51 -51
- package/src/tests/for.test.ts +26 -26
- package/src/tests/h.test.ts +100 -100
- package/src/tests/jsx-compat.test.tsx +41 -41
- package/src/tests/lazy.test.ts +28 -28
- package/src/tests/lifecycle.test.ts +35 -35
- package/src/tests/map-array.test.ts +36 -36
- package/src/tests/portal.test.ts +21 -21
- package/src/tests/props-extended.test.ts +51 -51
- package/src/tests/props.test.ts +62 -62
- package/src/tests/ref.test.ts +20 -20
- package/src/tests/show.test.ts +94 -94
- package/src/tests/style.test.ts +101 -101
- package/src/tests/suspense.test.ts +44 -44
- package/src/tests/telemetry.test.ts +35 -35
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { runWithHooks } from
|
|
1
|
+
import { runWithHooks } from '../component'
|
|
2
2
|
import {
|
|
3
3
|
createContext,
|
|
4
4
|
popContext,
|
|
@@ -7,96 +7,96 @@ import {
|
|
|
7
7
|
setContextStackProvider,
|
|
8
8
|
useContext,
|
|
9
9
|
withContext,
|
|
10
|
-
} from
|
|
11
|
-
import type { ComponentFn, Props } from
|
|
10
|
+
} from '../context'
|
|
11
|
+
import type { ComponentFn, Props } from '../types'
|
|
12
12
|
|
|
13
|
-
describe(
|
|
14
|
-
test(
|
|
15
|
-
const ctx = createContext(
|
|
16
|
-
expect(typeof ctx.id).toBe(
|
|
17
|
-
expect(ctx.defaultValue).toBe(
|
|
13
|
+
describe('createContext', () => {
|
|
14
|
+
test('returns context with unique symbol id', () => {
|
|
15
|
+
const ctx = createContext('default')
|
|
16
|
+
expect(typeof ctx.id).toBe('symbol')
|
|
17
|
+
expect(ctx.defaultValue).toBe('default')
|
|
18
18
|
})
|
|
19
19
|
|
|
20
|
-
test(
|
|
20
|
+
test('each context has a unique id', () => {
|
|
21
21
|
const a = createContext(1)
|
|
22
22
|
const b = createContext(2)
|
|
23
23
|
expect(a.id).not.toBe(b.id)
|
|
24
24
|
})
|
|
25
25
|
|
|
26
|
-
test(
|
|
26
|
+
test('undefined default value', () => {
|
|
27
27
|
const ctx = createContext<string | undefined>(undefined)
|
|
28
28
|
expect(ctx.defaultValue).toBeUndefined()
|
|
29
29
|
})
|
|
30
30
|
|
|
31
|
-
test(
|
|
31
|
+
test('null default value', () => {
|
|
32
32
|
const ctx = createContext<null>(null)
|
|
33
33
|
expect(ctx.defaultValue).toBeNull()
|
|
34
34
|
})
|
|
35
35
|
|
|
36
|
-
test(
|
|
37
|
-
const obj = { theme:
|
|
36
|
+
test('object default value', () => {
|
|
37
|
+
const obj = { theme: 'dark', lang: 'en' }
|
|
38
38
|
const ctx = createContext(obj)
|
|
39
39
|
expect(ctx.defaultValue).toBe(obj)
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
test(
|
|
42
|
+
test('function default value', () => {
|
|
43
43
|
const fn = () => 42
|
|
44
44
|
const ctx = createContext(fn)
|
|
45
45
|
expect(ctx.defaultValue).toBe(fn)
|
|
46
46
|
})
|
|
47
47
|
})
|
|
48
48
|
|
|
49
|
-
describe(
|
|
50
|
-
test(
|
|
51
|
-
const ctx = createContext(
|
|
52
|
-
expect(useContext(ctx)).toBe(
|
|
49
|
+
describe('useContext', () => {
|
|
50
|
+
test('returns default when no provider exists', () => {
|
|
51
|
+
const ctx = createContext('fallback')
|
|
52
|
+
expect(useContext(ctx)).toBe('fallback')
|
|
53
53
|
})
|
|
54
54
|
|
|
55
|
-
test(
|
|
56
|
-
const ctx = createContext(
|
|
57
|
-
pushContext(new Map([[ctx.id,
|
|
58
|
-
expect(useContext(ctx)).toBe(
|
|
55
|
+
test('returns provided value from pushContext', () => {
|
|
56
|
+
const ctx = createContext('default')
|
|
57
|
+
pushContext(new Map([[ctx.id, 'provided']]))
|
|
58
|
+
expect(useContext(ctx)).toBe('provided')
|
|
59
59
|
popContext()
|
|
60
60
|
})
|
|
61
61
|
|
|
62
|
-
test(
|
|
63
|
-
const ctx = createContext(
|
|
64
|
-
pushContext(new Map([[ctx.id,
|
|
65
|
-
pushContext(new Map([[ctx.id,
|
|
66
|
-
expect(useContext(ctx)).toBe(
|
|
62
|
+
test('returns innermost value with nested pushContext', () => {
|
|
63
|
+
const ctx = createContext('default')
|
|
64
|
+
pushContext(new Map([[ctx.id, 'outer']]))
|
|
65
|
+
pushContext(new Map([[ctx.id, 'inner']]))
|
|
66
|
+
expect(useContext(ctx)).toBe('inner')
|
|
67
67
|
popContext()
|
|
68
|
-
expect(useContext(ctx)).toBe(
|
|
68
|
+
expect(useContext(ctx)).toBe('outer')
|
|
69
69
|
popContext()
|
|
70
70
|
})
|
|
71
71
|
|
|
72
|
-
test(
|
|
73
|
-
const ctxA = createContext(
|
|
74
|
-
const ctxB = createContext(
|
|
72
|
+
test('different contexts in same frame are independent', () => {
|
|
73
|
+
const ctxA = createContext('a-default')
|
|
74
|
+
const ctxB = createContext('b-default')
|
|
75
75
|
const frame = new Map<symbol, unknown>([
|
|
76
|
-
[ctxA.id,
|
|
77
|
-
[ctxB.id,
|
|
76
|
+
[ctxA.id, 'a-value'],
|
|
77
|
+
[ctxB.id, 'b-value'],
|
|
78
78
|
])
|
|
79
79
|
pushContext(frame)
|
|
80
|
-
expect(useContext(ctxA)).toBe(
|
|
81
|
-
expect(useContext(ctxB)).toBe(
|
|
80
|
+
expect(useContext(ctxA)).toBe('a-value')
|
|
81
|
+
expect(useContext(ctxB)).toBe('b-value')
|
|
82
82
|
popContext()
|
|
83
83
|
})
|
|
84
84
|
|
|
85
|
-
test(
|
|
86
|
-
const ctxA = createContext(
|
|
87
|
-
const ctxB = createContext(
|
|
88
|
-
pushContext(new Map([[ctxA.id,
|
|
89
|
-
pushContext(new Map([[ctxB.id,
|
|
85
|
+
test('context not in frame falls through to previous frame', () => {
|
|
86
|
+
const ctxA = createContext('a-default')
|
|
87
|
+
const ctxB = createContext('b-default')
|
|
88
|
+
pushContext(new Map([[ctxA.id, 'a-outer']]))
|
|
89
|
+
pushContext(new Map([[ctxB.id, 'b-inner']]))
|
|
90
90
|
// ctxA is not in the inner frame, should fall through to outer
|
|
91
|
-
expect(useContext(ctxA)).toBe(
|
|
92
|
-
expect(useContext(ctxB)).toBe(
|
|
91
|
+
expect(useContext(ctxA)).toBe('a-outer')
|
|
92
|
+
expect(useContext(ctxB)).toBe('b-inner')
|
|
93
93
|
popContext()
|
|
94
94
|
popContext()
|
|
95
95
|
})
|
|
96
96
|
})
|
|
97
97
|
|
|
98
|
-
describe(
|
|
99
|
-
test(
|
|
98
|
+
describe('pushContext / popContext', () => {
|
|
99
|
+
test('push and pop maintain correct stack order', () => {
|
|
100
100
|
const ctx = createContext(0)
|
|
101
101
|
pushContext(new Map([[ctx.id, 1]]))
|
|
102
102
|
pushContext(new Map([[ctx.id, 2]]))
|
|
@@ -110,50 +110,50 @@ describe("pushContext / popContext", () => {
|
|
|
110
110
|
expect(useContext(ctx)).toBe(0) // default
|
|
111
111
|
})
|
|
112
112
|
|
|
113
|
-
test(
|
|
114
|
-
const warnSpy = vi.spyOn(console,
|
|
113
|
+
test('popContext on empty stack warns in dev mode', () => {
|
|
114
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
|
115
115
|
popContext()
|
|
116
116
|
expect(warnSpy).toHaveBeenCalledWith(
|
|
117
|
-
expect.stringContaining(
|
|
117
|
+
expect.stringContaining('popContext() called on an empty context stack'),
|
|
118
118
|
)
|
|
119
119
|
warnSpy.mockRestore()
|
|
120
120
|
})
|
|
121
121
|
})
|
|
122
122
|
|
|
123
|
-
describe(
|
|
124
|
-
test(
|
|
125
|
-
const ctx = createContext(
|
|
126
|
-
let captured =
|
|
127
|
-
withContext(ctx,
|
|
123
|
+
describe('withContext', () => {
|
|
124
|
+
test('provides value during callback execution', () => {
|
|
125
|
+
const ctx = createContext('default')
|
|
126
|
+
let captured = ''
|
|
127
|
+
withContext(ctx, 'inside', () => {
|
|
128
128
|
captured = useContext(ctx)
|
|
129
129
|
})
|
|
130
|
-
expect(captured).toBe(
|
|
130
|
+
expect(captured).toBe('inside')
|
|
131
131
|
// After withContext, should be back to default
|
|
132
|
-
expect(useContext(ctx)).toBe(
|
|
132
|
+
expect(useContext(ctx)).toBe('default')
|
|
133
133
|
})
|
|
134
134
|
|
|
135
|
-
test(
|
|
136
|
-
const ctx = createContext(
|
|
137
|
-
withContext(ctx,
|
|
138
|
-
expect(useContext(ctx)).toBe(
|
|
135
|
+
test('restores stack on normal completion', () => {
|
|
136
|
+
const ctx = createContext('default')
|
|
137
|
+
withContext(ctx, 'temp', () => {
|
|
138
|
+
expect(useContext(ctx)).toBe('temp')
|
|
139
139
|
})
|
|
140
|
-
expect(useContext(ctx)).toBe(
|
|
140
|
+
expect(useContext(ctx)).toBe('default')
|
|
141
141
|
})
|
|
142
142
|
|
|
143
|
-
test(
|
|
144
|
-
const ctx = createContext(
|
|
143
|
+
test('restores stack even when callback throws', () => {
|
|
144
|
+
const ctx = createContext('safe')
|
|
145
145
|
try {
|
|
146
|
-
withContext(ctx,
|
|
147
|
-
expect(useContext(ctx)).toBe(
|
|
148
|
-
throw new Error(
|
|
146
|
+
withContext(ctx, 'dangerous', () => {
|
|
147
|
+
expect(useContext(ctx)).toBe('dangerous')
|
|
148
|
+
throw new Error('boom')
|
|
149
149
|
})
|
|
150
150
|
} catch {
|
|
151
151
|
// expected
|
|
152
152
|
}
|
|
153
|
-
expect(useContext(ctx)).toBe(
|
|
153
|
+
expect(useContext(ctx)).toBe('safe')
|
|
154
154
|
})
|
|
155
155
|
|
|
156
|
-
test(
|
|
156
|
+
test('nested withContext calls', () => {
|
|
157
157
|
const ctx = createContext(0)
|
|
158
158
|
withContext(ctx, 1, () => {
|
|
159
159
|
expect(useContext(ctx)).toBe(1)
|
|
@@ -169,90 +169,90 @@ describe("withContext", () => {
|
|
|
169
169
|
expect(useContext(ctx)).toBe(0)
|
|
170
170
|
})
|
|
171
171
|
|
|
172
|
-
test(
|
|
173
|
-
const theme = createContext(
|
|
174
|
-
const lang = createContext(
|
|
172
|
+
test('multiple contexts in nested withContext', () => {
|
|
173
|
+
const theme = createContext('light')
|
|
174
|
+
const lang = createContext('en')
|
|
175
175
|
|
|
176
|
-
withContext(theme,
|
|
177
|
-
withContext(lang,
|
|
178
|
-
expect(useContext(theme)).toBe(
|
|
179
|
-
expect(useContext(lang)).toBe(
|
|
176
|
+
withContext(theme, 'dark', () => {
|
|
177
|
+
withContext(lang, 'fr', () => {
|
|
178
|
+
expect(useContext(theme)).toBe('dark')
|
|
179
|
+
expect(useContext(lang)).toBe('fr')
|
|
180
180
|
})
|
|
181
|
-
expect(useContext(lang)).toBe(
|
|
181
|
+
expect(useContext(lang)).toBe('en')
|
|
182
182
|
})
|
|
183
|
-
expect(useContext(theme)).toBe(
|
|
183
|
+
expect(useContext(theme)).toBe('light')
|
|
184
184
|
})
|
|
185
185
|
})
|
|
186
186
|
|
|
187
|
-
describe(
|
|
188
|
-
test(
|
|
189
|
-
const ctx = createContext(
|
|
187
|
+
describe('provide', () => {
|
|
188
|
+
test('pushes context and registers unmount cleanup', () => {
|
|
189
|
+
const ctx = createContext('default')
|
|
190
190
|
const { hooks } = runWithHooks(
|
|
191
191
|
(() => {
|
|
192
|
-
provide(ctx,
|
|
193
|
-
expect(useContext(ctx)).toBe(
|
|
192
|
+
provide(ctx, 'provided-value')
|
|
193
|
+
expect(useContext(ctx)).toBe('provided-value')
|
|
194
194
|
return null
|
|
195
195
|
}) as ComponentFn,
|
|
196
196
|
{} as Props,
|
|
197
197
|
)
|
|
198
198
|
// Context should still be available after runWithHooks
|
|
199
|
-
expect(useContext(ctx)).toBe(
|
|
199
|
+
expect(useContext(ctx)).toBe('provided-value')
|
|
200
200
|
// unmount hooks should include the popContext cleanup
|
|
201
201
|
expect(hooks.unmount.length).toBeGreaterThanOrEqual(1)
|
|
202
202
|
// Running unmount cleans up
|
|
203
203
|
for (const fn of hooks.unmount) fn()
|
|
204
|
-
expect(useContext(ctx)).toBe(
|
|
204
|
+
expect(useContext(ctx)).toBe('default')
|
|
205
205
|
})
|
|
206
206
|
|
|
207
|
-
test(
|
|
208
|
-
const ctxA = createContext(
|
|
209
|
-
const ctxB = createContext(
|
|
207
|
+
test('multiple provides in same component', () => {
|
|
208
|
+
const ctxA = createContext('a')
|
|
209
|
+
const ctxB = createContext('b')
|
|
210
210
|
const { hooks } = runWithHooks(
|
|
211
211
|
(() => {
|
|
212
|
-
provide(ctxA,
|
|
213
|
-
provide(ctxB,
|
|
212
|
+
provide(ctxA, 'A-value')
|
|
213
|
+
provide(ctxB, 'B-value')
|
|
214
214
|
return null
|
|
215
215
|
}) as ComponentFn,
|
|
216
216
|
{} as Props,
|
|
217
217
|
)
|
|
218
|
-
expect(useContext(ctxA)).toBe(
|
|
219
|
-
expect(useContext(ctxB)).toBe(
|
|
218
|
+
expect(useContext(ctxA)).toBe('A-value')
|
|
219
|
+
expect(useContext(ctxB)).toBe('B-value')
|
|
220
220
|
// Clean up
|
|
221
221
|
for (const fn of hooks.unmount) fn()
|
|
222
|
-
expect(useContext(ctxA)).toBe(
|
|
223
|
-
expect(useContext(ctxB)).toBe(
|
|
222
|
+
expect(useContext(ctxA)).toBe('a')
|
|
223
|
+
expect(useContext(ctxB)).toBe('b')
|
|
224
224
|
})
|
|
225
225
|
})
|
|
226
226
|
|
|
227
|
-
describe(
|
|
228
|
-
test(
|
|
227
|
+
describe('setContextStackProvider', () => {
|
|
228
|
+
test('overrides the stack provider', () => {
|
|
229
229
|
const customStack: Map<symbol, unknown>[] = []
|
|
230
|
-
const ctx = createContext(
|
|
230
|
+
const ctx = createContext('default')
|
|
231
231
|
|
|
232
232
|
setContextStackProvider(() => customStack)
|
|
233
233
|
|
|
234
|
-
customStack.push(new Map([[ctx.id,
|
|
235
|
-
expect(useContext(ctx)).toBe(
|
|
234
|
+
customStack.push(new Map([[ctx.id, 'custom']]))
|
|
235
|
+
expect(useContext(ctx)).toBe('custom')
|
|
236
236
|
customStack.pop()
|
|
237
|
-
expect(useContext(ctx)).toBe(
|
|
237
|
+
expect(useContext(ctx)).toBe('default')
|
|
238
238
|
|
|
239
239
|
// Restore default provider
|
|
240
240
|
const freshStack: Map<symbol, unknown>[] = []
|
|
241
241
|
setContextStackProvider(() => freshStack)
|
|
242
242
|
})
|
|
243
243
|
|
|
244
|
-
test(
|
|
245
|
-
const ctx = createContext(
|
|
244
|
+
test('different providers see different stacks', () => {
|
|
245
|
+
const ctx = createContext('default')
|
|
246
246
|
const stack1: Map<symbol, unknown>[] = []
|
|
247
247
|
const stack2: Map<symbol, unknown>[] = []
|
|
248
248
|
|
|
249
249
|
setContextStackProvider(() => stack1)
|
|
250
|
-
pushContext(new Map([[ctx.id,
|
|
251
|
-
expect(useContext(ctx)).toBe(
|
|
250
|
+
pushContext(new Map([[ctx.id, 'stack1-value']]))
|
|
251
|
+
expect(useContext(ctx)).toBe('stack1-value')
|
|
252
252
|
|
|
253
253
|
// Switch to stack2 — should not see stack1's value
|
|
254
254
|
setContextStackProvider(() => stack2)
|
|
255
|
-
expect(useContext(ctx)).toBe(
|
|
255
|
+
expect(useContext(ctx)).toBe('default')
|
|
256
256
|
|
|
257
257
|
// Clean up
|
|
258
258
|
setContextStackProvider(() => stack1)
|