feat: add DataAccessor abstraction for custom value introspection#211
Open
TooTallNate wants to merge 3 commits intostorybookjs:mainfrom
Open
feat: add DataAccessor abstraction for custom value introspection#211TooTallNate wants to merge 3 commits intostorybookjs:mainfrom
TooTallNate wants to merge 3 commits intostorybookjs:mainfrom
Conversation
Abstract all native JavaScript introspection operations (typeof, instanceof, Object.getOwnPropertyNames, Object.keys, property access, etc.) behind a DataAccessor interface. This allows react-inspector to inspect proxy objects, remote values, or values in a different runtime (e.g. QuickJS JSValue handles) that don't support native JS reflection. The new `dataAccessor` prop is accepted by Inspector, ObjectInspector, and TableInspector. When not provided, it defaults to `defaultDataAccessor` which uses native JS operations, making this a fully backward-compatible change. Exports: `DataAccessor` (type) and `defaultDataAccessor` (implementation).
There was a problem hiding this comment.
Pull request overview
This PR introduces a DataAccessor abstraction and React context plumbing so react-inspector can introspect “non-native” values (proxies, remote handles, alternate runtimes) without relying on direct JavaScript reflection APIs.
Changes:
- Added
DataAccessorinterface plusdefaultDataAccessorimplementation and aDataAccessorContext/useDataAccessor()hook. - Wired
dataAccessorthrough Tree/Object/Table inspector rendering paths (previews, property access, key enumeration, path expansion). - Exported the new public API surface (
DataAccessortype +defaultDataAccessor) from the package entrypoint.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/DataAccessor.ts | Defines the accessor contract and the native default implementation. |
| src/DataAccessorContext.ts | Adds context + hook to access the current accessor throughout the component tree. |
| src/index.tsx | Exposes DataAccessor and defaultDataAccessor as new public exports. |
| src/tree-view/TreeView.tsx | Accepts dataAccessor prop and provides it via context; passes accessor into path expansion. |
| src/tree-view/pathUtils.ts | Uses accessor-based property reads during automatic expansion (getExpandedPaths). |
| src/object-inspector/ObjectInspector.tsx | Creates iterators using accessor operations and forwards dataAccessor to TreeView. |
| src/object-inspector/ObjectPreview.tsx | Uses accessor to preview arrays/objects without native reflection. |
| src/object/ObjectValue.tsx | Uses accessor for type checks and display formatting. |
| src/table-inspector/TableInspector.tsx | Accepts dataAccessor, uses it for header discovery and cell reads, and provides it via context. |
| src/table-inspector/getHeaders.ts | Uses accessor for array/object detection and key enumeration. |
| src/table-inspector/DataContainer.tsx | Uses accessor from context for property existence checks and value retrieval. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Remove unused DataAccessor type imports from TreeView.tsx and TableInspector.tsx - Fix getter binding in defaultDataAccessor.getProperty to call with receiver - Handle sparse arrays in ObjectPreview by checking hasOwnProperty per index - Use accessor.typeof instead of native typeof in TableInspector sort comparator - Add unit tests for getExpandedPaths with a custom accessor
Author
|
In case you're curious, you can see this functionality being utilized in this commit: vercel-labs/quickjs-wasi@308cbe1 Already available live at: https://quickjs-wasi.labs.vercel.dev/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
DataAccessorinterface that abstracts all native JavaScript introspection operations (typeof,instanceof,Object.getOwnPropertyNames,Object.keys, property access, etc.) used when inspecting valuesJSValuehandles) that don't support native JS reflectiondataAccessorprop is provided, the default implementation uses native JS operationsMotivation
When inspecting values that are not regular JavaScript objects — such as proxy handles to values in a WebAssembly-embedded QuickJS runtime — native operations like
Object.getOwnPropertyNames(),typeof,instanceof, and bracket property access don't work. These values have their own APIs for introspection (e.g.handle.getProp(name),vm.typeof(handle)).This PR abstracts every introspection operation behind a
DataAccessorinterface so consumers can provide custom implementations for non-native value types.API
New exports from
react-inspector:DataAccessor(TypeScript interface) — 18 methods covering all introspection operations:typeof(),isNull(),isArray(),isDate(),isRegExp(),isIterable(),isBuffer(),hasChildren(),isObjectPrototype()getProperty(),getOwnPropertyNames(),keys(),hasOwnProperty(),propertyIsEnumerable()getPrototypeOf(),getConstructorName(),getFunctionName()toString(),iterate(),length()defaultDataAccessor— the default implementation using native JS operationsNew prop on
Inspector,ObjectInspector, andTableInspector:dataAccessor?: DataAccessor— optional custom accessor for inspecting non-native valuesExample usage with QuickJS
Changes
src/DataAccessor.tsDataAccessorinterface +defaultDataAccessorimplementationsrc/DataAccessorContext.tsuseDataAccessor()hooksrc/index.tsxDataAccessortype anddefaultDataAccessorsrc/object-inspector/ObjectInspector.tsxcreateIterator; acceptsdataAccessorpropsrc/object/ObjectValue.tsxsrc/object-inspector/ObjectPreview.tsxsrc/tree-view/TreeView.tsxDataAccessorContext.Provider; passes togetExpandedPathssrc/tree-view/pathUtils.tsgetPropertyin path expansionsrc/table-inspector/TableInspector.tsxsrc/table-inspector/getHeaders.tssrc/table-inspector/DataContainer.tsxTesting
All 30 existing tests pass. Build succeeds with clean type output.
npm install-able URL