-
-
Notifications
You must be signed in to change notification settings - Fork 33
Expand file tree
/
Copy pathutils.ts
More file actions
257 lines (223 loc) · 7.56 KB
/
utils.ts
File metadata and controls
257 lines (223 loc) · 7.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
import {trimString} from '@solid-devtools/shared/utils'
import {type Node, type Solid, NodeType} from './types.ts'
import setup from './setup.ts'
export const isSolidOwner = (o: Solid.SourceMapValue | Solid.Owner | Solid.Store | Solid.Signal): o is Solid.Owner =>
'owned' in o
export const isSolidComputation = (o: Solid.Owner): o is Solid.Computation =>
!!(o as any).fn
export const isSolidRoot = (o: Solid.Owner): o is Solid.Root =>
!('fn' in o)
export const isSolidMemo = (o: Solid.Owner): o is Solid.Memo =>
'fn' in o && 'comparator' in o
export const isSolidComponent = (o: Solid.Owner): o is Solid.Component =>
'component' in o
export const isStoreNode = (o: object): o is Solid.StoreNode =>
setup.store.$NODE in o
export const isSolidStore = (o: Solid.Owner | Solid.SourceMapValue | Solid.Store): o is Solid.Store =>
!('observers' in o) &&
typeof o.value === 'object' &&
o.value != null &&
setup.solid.$PROXY in o.value
export const isSolidSignal = (o: Solid.SourceMapValue): o is Solid.Signal =>
'value' in o &&
'observers' in o &&
'observerSlots' in o &&
'comparator' in o
export function getNodeType(
o: Solid.SourceMapValue | Solid.Signal | Solid.Owner | Solid.Store
): NodeType {
if (isSolidOwner(o)) return getOwnerType(o)
if (isSolidStore(o)) return NodeType.Store
if (isSolidSignal(o)) return NodeType.Signal
else return NodeType.CustomValue
}
const SOLID_REFRESH_PREFIX = '[solid-refresh]'
export const getOwnerType = (o: Solid.Owner): NodeType => {
if (typeof o.sdtType !== 'undefined') return o.sdtType
if (!isSolidComputation(o)) {
if ('sources' in o) return NodeType.CatchError
return NodeType.Root
}
if (isSolidComponent(o)) return NodeType.Component
// memo
if ('comparator' in o) {
if (
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
(o.owner as {component?: Function} | null)?.component?.name.startsWith(
SOLID_REFRESH_PREFIX,
)
) {
return NodeType.Refresh
}
return NodeType.Memo
}
// Effect
if (!o.pure) {
if (o.user === true) return NodeType.Effect
/*
after solid 1.8 context is being copied to children owners
so need to check if the reference is the same
*/
if (o.context !== null && (!o.owner || o.owner.context !== o.context))
return NodeType.Context
return NodeType.Render
}
return NodeType.Computation
}
export function getNode(
o: Solid.SourceMapValue | Solid.Signal | Solid.Owner | Solid.Store,
): Node {
return {
kind: getNodeType(o),
data: o as any,
}
}
export const getNodeName = (o: {
component?: ((..._: any) => any) & {displayName?: string},
name?: string,
}): string | undefined => {
let name: string | undefined
search: {
if (typeof o.component === 'function' &&
typeof o.component.displayName === 'string' &&
o.component.displayName.length > 0
) {
name = o.component.displayName
break search
}
/* solid.devComponent already assigns o.component.name to o.name */
if (o.name != null && o.name.length > 0) {
name = o.name
break search
}
return undefined
}
if (name.startsWith(SOLID_REFRESH_PREFIX)) {
name = name.slice(SOLID_REFRESH_PREFIX.length)
}
name = trimString(name, 36)
return name
}
export function markOwnerType(o: Solid.Owner): NodeType {
if (o.sdtType !== undefined) return o.sdtType
return (o.sdtType = getOwnerType(o))
}
/**
* Checks if the passed owner is disposed.
*/
export function isDisposed(o: Readonly<Solid.Owner>): boolean {
return !!(isSolidComputation(o)
? o.owner && (!o.owner.owned || !o.owner.owned.includes(o))
: (o as Solid.Root).isDisposed)
}
export function onCleanup(fn: () => void) {
let owner = setup.solid.getOwner()
if (owner) {
if (owner.cleanups === null) owner.cleanups = [fn]
else owner.cleanups.push(fn)
}
}
export function getComponentRefreshNode(owner: Readonly<Solid.Component>): Solid.Memo | null {
const {owned} = owner
let refresh: Solid.Owner
if (owned && owned.length === 1 && markOwnerType((refresh = owned[0]!)) === NodeType.Refresh) {
return refresh as Solid.Memo
}
return null
}
export function resolveElements(value: unknown): HTMLElement[] | null {
// do not call a function, unless it's a signal (to prevent creating new nodes)
if (typeof value === 'function' && !value.length && value.name === 'bound readSignal') {
return resolveElements(value())
}
if (Array.isArray(value)) {
const results: HTMLElement[] = []
for (const item of value) {
const result = resolveElements(item)
if (result)
Array.isArray(result) ? results.push.apply(results, result) : results.push(result)
}
return results.length ? results : null
}
return value instanceof HTMLElement ? [value] : null
}
/**
* helper to getting to an owner that you want — walking downwards
*/
export function findOwner(
root: Solid.Owner,
predicate: (owner: Solid.Owner) => boolean,
): Solid.Owner | null {
const queue: Solid.Owner[] = [root]
for (const owner of queue) {
if (predicate(owner)) return owner
if (Array.isArray(owner.owned)) queue.push(...owner.owned)
}
return null
}
export function lookupOwner(
owner: Solid.Owner,
predicate: (owner: Solid.Owner) => boolean,
): Solid.Owner | null {
do {
if (predicate(owner)) return owner
owner = owner.owner!
} while (owner.owner)
return null
}
/**
* Attach onCleanup callback to a reactive owner
* @param prepend add the callback to the front of the stack, instead of pushing, fot it to be called before other cleanup callbacks.
* @returns a function to remove the cleanup callback
*/
export function onOwnerCleanup(
owner: Solid.Owner,
fn: VoidFunction,
prepend = false,
symbol?: symbol,
): VoidFunction {
if (owner.cleanups === null) owner.cleanups = [fn]
else {
if (symbol) {
if (owner.cleanups.some(c => (c as any)[symbol])) {
return () =>
owner.cleanups?.splice(
owner.cleanups.findIndex(c => (c as any)[symbol]),
1,
)
}
;(fn as any)[symbol] = true
}
if (prepend) owner.cleanups.unshift(fn)
else owner.cleanups.push(fn)
}
return () => owner.cleanups?.splice(owner.cleanups.indexOf(fn), 1)
}
/**
* Attach onCleanup callback to the parent of a reactive owner if it has one.
* @param prepend add the callback to the front of the stack, instead of pushing, fot it to be called before other cleanup callbacks.
* @returns a function to remove the cleanup callback
*/
export function onParentCleanup(
owner: Solid.Owner,
fn: VoidFunction,
prepend = false,
symbol?: symbol,
): VoidFunction {
if (owner.owner) return onOwnerCleanup(owner.owner, fn, prepend, symbol)
return () => {
/* noop */
}
}
/**
* Listen to when the owner is disposed. (not on cleanup)
*/
export function onOwnerDispose(
owner: Solid.Owner,
fn: VoidFunction,
prepend = false,
symbol?: symbol,
): VoidFunction {
if (isSolidRoot(owner)) return onOwnerCleanup(owner, fn, prepend, symbol)
return onParentCleanup(owner, fn, prepend, symbol)
}