Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 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 | 1x 1x 1x 28x 3x 3x 28x 3x 3x 28x 28x 60x 60x 46x 60x 18x 60x 2x 2x 26x 60x 28x 18x 18x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 18x 11x 18x 2x 5x 3x 3x 16x 18x 28x 28x 28x 1x 7x 7x 11x 11x 7x 2x 2x 7x 5x 5x 5x 5x 7x 7x 1x 7x 7x 9x 9x 7x 2x 2x 7x 5x 5x 5x 5x 7x 7x | import { captureStack, isMutableRef, type MutableRef, untrack } from '@anchorlib/core';
import { type BindingRef, isBinding } from './binding.js';
import type { BindableComponentProps } from './types.js';
/**
* Creates a proxy for props that handles binding references and read-only properties.
*
* This function creates a proxy that:
* - Resolves binding references to their actual values on get operations
* - Prevents assignment to event handler properties (those starting with "on")
* - Properly handles setting values on binding references
*
* @template P - The props type
* @param props - The props object to wrap
* @returns A proxy wrapping the props object
*/
// biome-ignore lint/suspicious/noExplicitAny: library
export function proxyProps<P extends Record<string, any>>(props: P): BindableComponentProps<P> {
const omit = (keys: Array<keyof P>) => {
return omitProps(props, newProps, keys ?? []);
};
const pick = (keys: Array<keyof P>) => {
return pickProps(props, newProps, keys ?? []);
};
const newProps = new Proxy(props as P, {
get(target, key, receiver) {
if (key === '$omit') return omit;
if (key === '$pick') return pick;
const bindingRef = Reflect.get(target, key, receiver);
if (isBinding(bindingRef)) {
return (bindingRef as BindingRef<unknown, unknown>).value;
} else if (isMutableRef(bindingRef)) {
return (bindingRef as MutableRef<unknown>).value;
}
return bindingRef;
},
set(target, key, value, receiver) {
const bindingRef = untrack(() => Reflect.get(target, key, receiver));
if (typeof key === 'string' && key.startsWith('on')) {
const error = new Error(`Property '${key}' is read-only.`);
captureStack.violation.general(
'Read-only property assignment',
`Cannot assign to read-only property '${key}'. Event handlers can only be specified in parent component.`,
error,
[
'Event handler properties (starting with "on") are read-only.',
'- Define event handlers in the parent component.',
'- Only mutate properties meant for two-way data binding.',
]
);
return true;
}
if (isBinding(bindingRef)) {
(bindingRef as BindingRef<unknown, unknown>).value = value;
} else if (isMutableRef(bindingRef)) {
(bindingRef as MutableRef<unknown>).value = value;
} else {
Reflect.set(target, key, value, receiver);
}
return true;
},
});
return newProps as never as BindableComponentProps<P>;
}
/**
* Creates a new object excluding specified properties from the original object.
*
* This function returns a proxy that filters out specified keys when enumerating
* the object's properties. The returned object behaves like the original but
* omits the excluded properties from enumeration and spreading operations.
*
* @template T - The type of the original object
* @template K - The type of keys to exclude
* @param source - The original object to create a proxy for
* @param props - The proxied object to omit properties from
* @param excludes - An array of keys to exclude from the object (default: empty array)
* @returns A new object with specified properties omitted
*/
export function omitProps<T, K extends keyof T>(source: T, props: T, excludes: Array<K> = []): Omit<T, K> {
return new Proxy(source as Record<string, unknown>, {
get(_target, key, receiver) {
return Reflect.get(props as Record<string, unknown>, key, receiver);
},
set(_target, key, value, receiver) {
return Reflect.set(props as Record<string, unknown>, key, value, receiver);
},
ownKeys(target: Record<string, unknown>): ArrayLike<string | symbol> {
return untrack(() => {
return Object.keys(target as Record<string, unknown>).filter((k) => !excludes.includes(k as never));
});
},
}) as never;
}
/**
* Creates a new object including only specified properties from the original object.
*
* This function returns a proxy that includes only specified keys when enumerating
* the object's properties. The returned object behaves like the original but
* only contains the included properties during enumeration and spreading operations.
*
* @template T - The type of the original object
* @template K - The type of keys to include
* @param source - The original object to create a proxy for
* @param props - The original object to pick properties from
* @param includes - An array of keys to include in the object (default: empty array)
* @returns A new object with only specified properties included
*/
export function pickProps<T, K extends keyof T>(source: T, props: T, includes: Array<K> = []): Pick<T, K> {
return new Proxy(source as Record<string, unknown>, {
get(_target, key, receiver) {
return Reflect.get(props as Record<string, unknown>, key, receiver);
},
set(_target, key, value, receiver) {
return Reflect.set(props as Record<string, unknown>, key, value, receiver);
},
ownKeys(target: Record<string, unknown>): ArrayLike<string | symbol> {
return untrack(() => {
return Object.keys(target as Record<string, unknown>).filter((k) => includes.includes(k as never));
});
},
}) as never;
}
|