diff --git a/apps/demo/src/index.tsx b/apps/demo/src/index.tsx index 6ba3ccb19..4f8616b32 100644 --- a/apps/demo/src/index.tsx +++ b/apps/demo/src/index.tsx @@ -1,11 +1,13 @@ import './styles.css'; // global styles -import { assertNonNull } from '@h5web/app'; +import { assertNonNull, enableBigIntSerialization } from '@h5web/app'; import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import DemoApp from './DemoApp'; +enableBigIntSerialization(); // for `RawVis` and `MetadataViewer` + const rootElem = document.querySelector('#root'); assertNonNull(rootElem); diff --git a/packages/app/README.md b/packages/app/README.md index eae05d487..18097ba89 100644 --- a/packages/app/README.md +++ b/packages/app/README.md @@ -389,6 +389,44 @@ import { getFeedbackMailto } from '@h5web/app'; }} /> ``` +#### `enableBigIntSerialization` + +Invoke this function before rendering your application to allow the _Raw_ +visualization and metadata inspector to serialize and display +[big integers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type): + +```jsx +enableBigIntSerialization(); +createRoot(document.querySelector('#root')).render(); +``` + +This is recommended if you work with a provider that supports 64-bit integers — +i.e. one that may provide dataset and attribute values that include primitive +`bigint` numbers — currently only [`MockProvider`](#mockprovider). + +The _Raw_ visualization and metadata inspector rely on `JSON.stringify()` to +render dataset and attribute values. By default, `JSON.stringify()` does not +know how to serialize `bigint` numbers and throws an error if it encounters one. +`enableBigIntSerialization()` teaches `JSON.stringify()` to convert big integers +to strings: + +```js +> JSON.stringify(123n); +TypeError: Do not know how to serialize a BigInt + +> enableBigIntSerialization(); +> JSON.stringify(123n); +"123n" +``` + +> The `n` suffix (i.e. the same suffix used for `bigint` literals as +> demonstrated above) is added to help distinguish big integer strings from +> other strings. + +> If you're application already implements `bigint` serialization, you don't +> need to call `enableBigIntSerialization()`. Doing so would override the +> existing implementation, which might have unintended effects. + ### Context The viewer component `App` communicates with its wrapping data provider through diff --git a/packages/app/src/index.ts b/packages/app/src/index.ts index 343490d05..d01b0c98f 100644 --- a/packages/app/src/index.ts +++ b/packages/app/src/index.ts @@ -6,6 +6,7 @@ export { default as MockProvider } from './providers/mock/MockProvider'; export { default as HsdsProvider } from './providers/hsds/HsdsProvider'; export { default as H5GroveProvider } from './providers/h5grove/H5GroveProvider'; +export { enableBigIntSerialization } from './utils'; export { getFeedbackMailto } from './breadcrumbs/utils'; export type { FeedbackContext } from './breadcrumbs/models'; export type { ExportFormat, ExportURL } from './providers/models'; diff --git a/packages/app/src/utils.ts b/packages/app/src/utils.ts index 472976fbc..7090cc9c2 100644 --- a/packages/app/src/utils.ts +++ b/packages/app/src/utils.ts @@ -5,3 +5,13 @@ import type { AttrName } from './providers/models'; export function hasAttribute(entity: Entity, attributeName: AttrName) { return entity.attributes.some((attr) => attr.name === attributeName); } + +export function enableBigIntSerialization(): void { + // eslint-disable-next-line no-extend-native + Object.defineProperty(BigInt.prototype, 'toJSON', { + configurable: true, + value: function toJSON(this: bigint) { + return `${this.toString()}n`; + }, + }); +}