wana
Version:
Easy observable state for React
152 lines (143 loc) • 4.52 kB
JavaScript
import { getDebug, getCurrentAuto } from './shared/6ab9b088.mjs';
export { addDebugAction, getCurrentAuto, getDebug, setDebug } from './shared/6ab9b088.mjs';
import { is } from '@alloc/is';
import { isDev } from '@alloc/is-dev';
import { $O, globals } from './shared/815e560c.mjs';
import { useChanges, useAutoDepth } from './shared/79278540.mjs';
import { useEffect } from 'react';
import 'react-layout-effect';
import 'use-memo-one';
function format(message, values, styles = {}) {
const args = [];
const formatted = message.replace(/\$(\w+)/g, (_, key) => {
const value = key in styles && typeof values[key] == "object" ? JSON.stringify(values[key]) : values[key];
const style = key in styles ? styles[key] : is.string(value) ? "color: #5162FF" : null;
if (is.string(style)) {
args.push(style, String(value), "");
return "%c%s%c";
}
args.push(value);
return "%O";
});
return [formatted].concat(args);
}
let prevTime = Date.now();
function logChange(change, targetId) {
let verb;
let meta;
if (change.op == "add") {
verb = "Added";
meta = {value: change.value};
} else if (change.op == "remove") {
verb = "Removed";
meta = {oldValue: change.oldValue};
} else if (change.op == "replace") {
verb = "Replaced";
meta = {value: change.value, oldValue: change.oldValue};
} else if (change.op == "splice") {
verb = "Spliced";
meta = {value: change.value, oldValue: change.oldValue};
} else {
verb = "Cleared";
meta = {oldValue: change.oldValue};
}
console.log(...format("$verb $key of $targetId with", {
verb,
key: is.string(change.key) ? `"${change.key}"` : change.key,
targetId: targetId || (getDebug(change.target) || change.target.constructor).name
}, {
verb: "",
targetId: "color: #7BB347"
}), meta, change.target);
if (isDev && console.groupCollapsed) {
const now = Date.now();
console.groupCollapsed(`Stack trace (+${now - prevTime}ms)`);
console.trace();
console.groupEnd();
prevTime = now;
}
}
function logChanges(target, {name, onChange} = {}) {
const observable = target[$O];
if (!observable) {
throw Error("Expected an observable object");
}
const observers = observable.get($O);
const observer = {
onChange: (change) => {
if (onChange) {
onChange(change);
}
logChange(change, name);
},
dispose: () => {
observers.delete(observer);
}
};
observers.add(observer);
return observer;
}
function useChangeLog(target, {name, onChange} = {}) {
useChanges(target, (change) => {
if (onChange) {
onChange(change);
}
if (process.env.NODE_ENV !== "test") {
logChange(change, name);
}
});
}
function useObserverLog(name) {
const auto = getCurrentAuto();
if (!auto) {
throw Error('Cannot call "useObserverLog" outside a "withAuto" component');
}
useEffect(() => {
const {observer} = auto;
if (observer) {
const {observed} = observer;
let [message, ...args] = format("$count values were observed by $name", {count: observed.size, name: name || getDebug(auto).name}, {name: "color: #7BB347"});
observed.forEach(({key, owner}) => {
const [line, ...vars] = format("\n $key of $target", {
key: key == $O ? "all" : is.string(key) ? `"${key}"` : key,
target: owner.source
}, key == $O ? {key: ""} : void 0);
message += line;
args.push(...vars);
});
console.log(message, ...args);
}
});
}
function logRender(auto, depth, component) {
if (!component.displayName) {
console.warn('Component without "displayName" is harder to debug', component.__render || component);
}
const indent = " ".repeat(depth);
const debug = getDebug(auto);
console.debug(indent + "<" + debug.name + " />", "\u269B\uFE0F" + debug.renders, [
...debug.actions
]);
}
let lastComponent;
if (isDev) {
const {onRender} = globals;
globals.onRender = (auto, depth, component) => {
lastComponent = component;
if (onRender) {
onRender(auto, depth, component);
}
};
}
function useRenderLog() {
const depth = useAutoDepth();
if (isDev) {
const auto = getCurrentAuto();
if (!auto || !lastComponent) {
throw Error('Cannot call "useRenderLog" outside a "withAuto" component');
}
logRender(auto, depth, lastComponent);
}
}
export { logChange, logChanges, useChangeLog, useObserverLog, useRenderLog };
//# sourceMappingURL=debug.mjs.map