UNPKG

@gensx/react

Version:

React hooks and components for GenSX AI workflows.

145 lines (140 loc) 5.68 kB
'use strict'; /** * Check out the docs at https://www.gensx.com/docs * Find us on Github https://github.com/gensx-inc/gensx * Find us on Discord https://discord.gg/F5BSU8Kc */ require('../node_modules/.pnpm/fast-json-patch@3.1.1/node_modules/fast-json-patch/index.cjs'); var react = require('react'); var helpers = require('../node_modules/.pnpm/fast-json-patch@3.1.1/node_modules/fast-json-patch/module/helpers.cjs'); var core = require('../node_modules/.pnpm/fast-json-patch@3.1.1/node_modules/fast-json-patch/module/core.cjs'); // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters function useObject(events, label) { const [result, setResult] = react.useState(undefined); // Store the reconstructed object and last processed event index const reconstructedRef = react.useRef({}); const lastIndexRef = react.useRef(-1); const lastEventsRef = react.useRef([]); react.useEffect(() => { // Find all relevant object events const objectEvents = events.filter((event) => event.type === "object" && event.label === label); // Detect reset: events array replaced or truncated const isReset = events !== lastEventsRef.current || objectEvents.length < lastIndexRef.current + 1; if (isReset) { reconstructedRef.current = {}; lastIndexRef.current = -1; } // Apply only new patches for (let i = lastIndexRef.current + 1; i < objectEvents.length; i++) { const event = objectEvents[i]; if (event.isInitial) { reconstructedRef.current = {}; } try { reconstructedRef.current = applyObjectPatches(event.patches, reconstructedRef.current); } catch (error) { console.warn(`Failed to apply patches for object "${label}":`, error); } } lastIndexRef.current = objectEvents.length - 1; lastEventsRef.current = events; setResult(objectEvents.length > 0 ? reconstructedRef.current : undefined); }, [events, label]); return result; } /** * Apply a JSON patch to reconstruct object state. This is useful for consumers who want to reconstruct the full object state from patches. * * @param patches - The JSON patch operations to apply. * @param currentState - The current state of the object (defaults to empty object). * @returns The new state after applying the patches. */ function applyObjectPatches(patches, currentState = {}) { let document = helpers._deepClone(currentState); let standardPatches = []; for (const operation of patches) { if (operation.op === "string-append") { // Handle string append operation if (operation.path === "") { // Root-level string append if (typeof document === "string") { document = document + operation.value; } else { // Warn and skip instead of throwing or replacing console.warn(`Cannot apply string-append: root value is not a string. Skipping operation.`); // Do nothing } continue; } const pathParts = operation.path.split("/").slice(1); // Remove empty first element const target = getValueByPath(document, pathParts.slice(0, -1)); const property = pathParts[pathParts.length - 1]; if (typeof target === "object" && target !== null) { const currentValue = target[property]; if (typeof currentValue === "string") { target[property] = currentValue + operation.value; } else { // Warn and skip instead of replacing console.warn(`Cannot apply string-append: target path '${operation.path}' is not a string. Skipping operation.`); // Do nothing } } else { // Warn and skip instead of throwing console.warn(`Cannot apply string-append: target path '${operation.path}' does not exist or is not an object. Skipping operation.`); // Do nothing } } else { // Handle standard JSON Patch operations standardPatches.push(operation); } } if (standardPatches.length > 0) { const result = core.applyPatch(document, helpers._deepClone(standardPatches)); return result.newDocument; } return document; } /** * Helper function to get a value by path in an object or array (RFC 6901 compliant) */ function getValueByPath(obj, path) { let current = obj; for (const segment of path) { if (Array.isArray(current)) { const idx = Number(segment); if (!Number.isNaN(idx) && idx >= 0 && idx < current.length) { current = current[idx]; } else { return undefined; } } else if (isPlainObject(current)) { if (segment in current) { current = current[segment]; } else { return undefined; } } else { return undefined; } } return current; } /** * Utility to check if a value is a non-null, non-array object */ function isPlainObject(val) { return typeof val === "object" && val !== null && !Array.isArray(val); } exports.useObject = useObject; //# sourceMappingURL=use-object.cjs.map