|
1 | | -/** @import { ProxyMetadata } from '#client' */ |
2 | 1 | /** @typedef {{ file: string, line: number, column: number }} Location */ |
3 | 2 |
|
4 | | -import { STATE_SYMBOL_METADATA } from '../constants.js'; |
5 | | -import { render_effect, user_pre_effect } from '../reactivity/effects.js'; |
6 | | -import { dev_current_component_function } from '../context.js'; |
7 | | -import { get_prototype_of } from '../../shared/utils.js'; |
8 | | -import * as w from '../warnings.js'; |
9 | | -import { FILENAME, UNINITIALIZED } from '../../../constants.js'; |
10 | | - |
11 | 3 | /** @type {Record<string, Array<{ start: Location, end: Location, component: Function }>>} */ |
12 | 4 | const boundaries = {}; |
13 | 5 |
|
@@ -71,8 +63,6 @@ export function get_component() { |
71 | 63 | return null; |
72 | 64 | } |
73 | 65 |
|
74 | | -export const ADD_OWNER = Symbol('ADD_OWNER'); |
75 | | - |
76 | 66 | /** |
77 | 67 | * Together with `mark_module_end`, this function establishes the boundaries of a `.svelte` file, |
78 | 68 | * such that subsequent calls to `get_component` can tell us which component is responsible |
@@ -106,199 +96,3 @@ export function mark_module_end(component) { |
106 | 96 | boundary.component = component; |
107 | 97 | } |
108 | 98 | } |
109 | | - |
110 | | -/** |
111 | | - * @param {any} object |
112 | | - * @param {any | null} owner |
113 | | - * @param {boolean} [global] |
114 | | - * @param {boolean} [skip_warning] |
115 | | - */ |
116 | | -export function add_owner(object, owner, global = false, skip_warning = false) { |
117 | | - if (object && !global) { |
118 | | - const component = dev_current_component_function; |
119 | | - const metadata = object[STATE_SYMBOL_METADATA]; |
120 | | - if (metadata && !has_owner(metadata, component)) { |
121 | | - let original = get_owner(metadata); |
122 | | - |
123 | | - if (owner && owner[FILENAME] !== component[FILENAME] && !skip_warning) { |
124 | | - w.ownership_invalid_binding(component[FILENAME], owner[FILENAME], original[FILENAME]); |
125 | | - } |
126 | | - } |
127 | | - } |
128 | | - |
129 | | - add_owner_to_object(object, owner, new Set()); |
130 | | -} |
131 | | - |
132 | | -/** |
133 | | - * @param {() => unknown} get_object |
134 | | - * @param {any} Component |
135 | | - * @param {boolean} [skip_warning] |
136 | | - */ |
137 | | -export function add_owner_effect(get_object, Component, skip_warning = false) { |
138 | | - user_pre_effect(() => { |
139 | | - add_owner(get_object(), Component, false, skip_warning); |
140 | | - }); |
141 | | -} |
142 | | - |
143 | | -/** |
144 | | - * @param {any} _this |
145 | | - * @param {Function} owner |
146 | | - * @param {Array<() => any>} getters |
147 | | - * @param {boolean} skip_warning |
148 | | - */ |
149 | | -export function add_owner_to_class(_this, owner, getters, skip_warning) { |
150 | | - _this[ADD_OWNER].current ||= getters.map(() => UNINITIALIZED); |
151 | | - |
152 | | - for (let i = 0; i < getters.length; i += 1) { |
153 | | - const current = getters[i](); |
154 | | - // For performance reasons we only re-add the owner if the state has changed |
155 | | - if (current !== _this[ADD_OWNER][i]) { |
156 | | - _this[ADD_OWNER].current[i] = current; |
157 | | - add_owner(current, owner, false, skip_warning); |
158 | | - } |
159 | | - } |
160 | | -} |
161 | | - |
162 | | -/** |
163 | | - * @param {ProxyMetadata | null} from |
164 | | - * @param {ProxyMetadata} to |
165 | | - */ |
166 | | -export function widen_ownership(from, to) { |
167 | | - if (to.owners === null) { |
168 | | - return; |
169 | | - } |
170 | | - |
171 | | - while (from) { |
172 | | - if (from.owners === null) { |
173 | | - to.owners = null; |
174 | | - break; |
175 | | - } |
176 | | - |
177 | | - for (const owner of from.owners) { |
178 | | - to.owners.add(owner); |
179 | | - } |
180 | | - |
181 | | - from = from.parent; |
182 | | - } |
183 | | -} |
184 | | - |
185 | | -/** |
186 | | - * @param {any} object |
187 | | - * @param {Function | null} owner If `null`, then the object is globally owned and will not be checked |
188 | | - * @param {Set<any>} seen |
189 | | - */ |
190 | | -function add_owner_to_object(object, owner, seen) { |
191 | | - const metadata = /** @type {ProxyMetadata} */ (object?.[STATE_SYMBOL_METADATA]); |
192 | | - |
193 | | - if (metadata) { |
194 | | - // this is a state proxy, add owner directly, if not globally shared |
195 | | - if ('owners' in metadata && metadata.owners != null) { |
196 | | - if (owner) { |
197 | | - metadata.owners.add(owner); |
198 | | - } else { |
199 | | - metadata.owners = null; |
200 | | - } |
201 | | - } |
202 | | - } else if (object && typeof object === 'object') { |
203 | | - if (seen.has(object)) return; |
204 | | - seen.add(object); |
205 | | - if (ADD_OWNER in object && object[ADD_OWNER]) { |
206 | | - // this is a class with state fields. we put this in a render effect |
207 | | - // so that if state is replaced (e.g. `instance.name = { first, last }`) |
208 | | - // the new state is also co-owned by the caller of `getContext` |
209 | | - render_effect(() => { |
210 | | - object[ADD_OWNER](owner); |
211 | | - }); |
212 | | - } else { |
213 | | - var proto = get_prototype_of(object); |
214 | | - |
215 | | - if (proto === Object.prototype) { |
216 | | - // recurse until we find a state proxy |
217 | | - for (const key in object) { |
218 | | - if (Object.getOwnPropertyDescriptor(object, key)?.get) { |
219 | | - // Similar to the class case; the getter could update with a new state |
220 | | - let current = UNINITIALIZED; |
221 | | - render_effect(() => { |
222 | | - const next = object[key]; |
223 | | - if (current !== next) { |
224 | | - current = next; |
225 | | - add_owner_to_object(next, owner, seen); |
226 | | - } |
227 | | - }); |
228 | | - } else { |
229 | | - add_owner_to_object(object[key], owner, seen); |
230 | | - } |
231 | | - } |
232 | | - } else if (proto === Array.prototype) { |
233 | | - // recurse until we find a state proxy |
234 | | - for (let i = 0; i < object.length; i += 1) { |
235 | | - add_owner_to_object(object[i], owner, seen); |
236 | | - } |
237 | | - } |
238 | | - } |
239 | | - } |
240 | | -} |
241 | | - |
242 | | -/** |
243 | | - * @param {ProxyMetadata} metadata |
244 | | - * @param {Function} component |
245 | | - * @returns {boolean} |
246 | | - */ |
247 | | -function has_owner(metadata, component) { |
248 | | - if (metadata.owners === null) { |
249 | | - return true; |
250 | | - } |
251 | | - |
252 | | - return ( |
253 | | - metadata.owners.has(component) || |
254 | | - // This helps avoid false positives when using HMR, where the component function is replaced |
255 | | - (FILENAME in component && |
256 | | - [...metadata.owners].some( |
257 | | - (owner) => /** @type {any} */ (owner)[FILENAME] === component[FILENAME] |
258 | | - )) || |
259 | | - (metadata.parent !== null && has_owner(metadata.parent, component)) |
260 | | - ); |
261 | | -} |
262 | | - |
263 | | -/** |
264 | | - * @param {ProxyMetadata} metadata |
265 | | - * @returns {any} |
266 | | - */ |
267 | | -function get_owner(metadata) { |
268 | | - return ( |
269 | | - metadata?.owners?.values().next().value ?? |
270 | | - get_owner(/** @type {ProxyMetadata} */ (metadata.parent)) |
271 | | - ); |
272 | | -} |
273 | | - |
274 | | -let skip = false; |
275 | | - |
276 | | -/** |
277 | | - * @param {() => any} fn |
278 | | - */ |
279 | | -export function skip_ownership_validation(fn) { |
280 | | - skip = true; |
281 | | - fn(); |
282 | | - skip = false; |
283 | | -} |
284 | | - |
285 | | -/** |
286 | | - * @param {ProxyMetadata} metadata |
287 | | - */ |
288 | | -export function check_ownership(metadata) { |
289 | | - if (skip) return; |
290 | | - |
291 | | - const component = get_component(); |
292 | | - |
293 | | - if (component && !has_owner(metadata, component)) { |
294 | | - let original = get_owner(metadata); |
295 | | - |
296 | | - // @ts-expect-error |
297 | | - if (original[FILENAME] !== component[FILENAME]) { |
298 | | - // @ts-expect-error |
299 | | - w.ownership_invalid_mutation(component[FILENAME], original[FILENAME]); |
300 | | - } else { |
301 | | - w.ownership_invalid_mutation(); |
302 | | - } |
303 | | - } |
304 | | -} |
0 commit comments