mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
95 lines
2.5 KiB
TypeScript
95 lines
2.5 KiB
TypeScript
import isEmpty from 'lodash/isEmpty';
|
|
import memoize from 'lodash/memoize';
|
|
|
|
import type {Meta} from 'sentry/types';
|
|
|
|
const GET_META = Symbol('GET_META');
|
|
const IS_PROXY = Symbol('IS_PROXY');
|
|
|
|
type SymbolProp = typeof GET_META | typeof IS_PROXY;
|
|
|
|
function isAnnotated(meta) {
|
|
if (isEmpty(meta)) {
|
|
return false;
|
|
}
|
|
return !isEmpty(meta.rem) || !isEmpty(meta.err);
|
|
}
|
|
|
|
type Local = Record<string, any> | undefined;
|
|
|
|
export class MetaProxy {
|
|
private local: Local;
|
|
|
|
constructor(local: Local) {
|
|
this.local = local;
|
|
}
|
|
|
|
get<T extends {}>(
|
|
obj: T | Array<T>,
|
|
prop: Extract<keyof T, string> | SymbolProp,
|
|
receiver: T
|
|
) {
|
|
// trap calls to `getMeta` to return meta object
|
|
if (prop === GET_META) {
|
|
return key => {
|
|
if (this.local?.[key]?.['']) {
|
|
// TODO: Error checks
|
|
const meta = this.local[key][''];
|
|
|
|
return isAnnotated(meta) ? meta : undefined;
|
|
}
|
|
return undefined;
|
|
};
|
|
}
|
|
|
|
// this is how we can determine if current `obj` is a proxy
|
|
if (prop === IS_PROXY) {
|
|
return true;
|
|
}
|
|
|
|
const value = Reflect.get(obj, prop, receiver);
|
|
if (!Reflect.has(obj, prop) || typeof value !== 'object' || value === null) {
|
|
return value;
|
|
}
|
|
|
|
// This is so we don't create a new Proxy from an object that is
|
|
// already a proxy. Otherwise we can get into very deep recursive calls
|
|
if (Reflect.get(obj, IS_PROXY, receiver)) {
|
|
return value;
|
|
}
|
|
|
|
// Make sure we apply proxy to all children (objects and arrays)
|
|
// Do we need to check for annotated inside of objects?
|
|
return new Proxy(value, new MetaProxy(this.local?.[prop]));
|
|
}
|
|
}
|
|
|
|
export const withMeta = memoize(function withMeta<T>(event: T): T {
|
|
if (!event) {
|
|
return event;
|
|
}
|
|
|
|
// Return unproxied `event` if browser does not support `Proxy`
|
|
if (typeof window.Proxy === 'undefined' || typeof window.Reflect === 'undefined') {
|
|
return event;
|
|
}
|
|
|
|
// withMeta returns a type that is supposed to be 100% compatible with its
|
|
// input type. Proxy typing on typescript is not really functional enough to
|
|
// make this work without casting.
|
|
//
|
|
// https://github.com/microsoft/TypeScript/issues/20846
|
|
return new Proxy(event, new MetaProxy((event as any)._meta)) as T;
|
|
});
|
|
|
|
export function getMeta<T extends {}>(
|
|
obj: T | undefined,
|
|
prop: Extract<keyof T, string>
|
|
): Meta | undefined {
|
|
if (!obj || typeof obj[GET_META] !== 'function') {
|
|
return undefined;
|
|
}
|
|
|
|
return obj[GET_META](prop);
|
|
}
|