1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- import isEmpty from 'lodash/isEmpty';
- import isNull from 'lodash/isNull';
- import memoize from 'lodash/memoize';
- import {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 && this.local[key] && 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' || isNull(value)) {
- 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 && 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);
- }
|