Skip to content

Commit 7410a5d

Browse files
authored
Merge pull request #1706 from silx-kit/mock-bigint
Expose utility function to enable bigint serialization in consumer apps
2 parents 457fb59 + 393d351 commit 7410a5d

20 files changed

+74
-1
lines changed

apps/demo/src/index.tsx

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import './styles.css'; // global styles
22

3-
import { assertNonNull } from '@h5web/app';
3+
import { assertNonNull, enableBigIntSerialization } from '@h5web/app';
44
import { StrictMode } from 'react';
55
import { createRoot } from 'react-dom/client';
66

77
import DemoApp from './DemoApp';
88

9+
enableBigIntSerialization(); // for `RawVis` and `MetadataViewer`
10+
911
const rootElem = document.querySelector('#root');
1012
assertNonNull(rootElem);
1113

895 Bytes
Loading
933 Bytes
Loading
776 Bytes
Loading
Loading
Loading
Loading
Loading
Loading
Loading
598 Bytes
Loading
179 Bytes
Loading
Loading
-246 Bytes
Loading
969 Bytes
Loading

packages/app/README.md

+38
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,44 @@ import { getFeedbackMailto } from '@h5web/app';
389389
}} />
390390
```
391391

392+
#### `enableBigIntSerialization`
393+
394+
Invoke this function before rendering your application to allow the _Raw_
395+
visualization and metadata inspector to serialize and display
396+
[big integers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#bigint_type):
397+
398+
```jsx
399+
enableBigIntSerialization();
400+
createRoot(document.querySelector('#root')).render(<MyApp />);
401+
```
402+
403+
This is recommended if you work with a provider that supports 64-bit integers —
404+
i.e. one that may provide dataset and attribute values that include primitive
405+
`bigint` numbers — currently only [`MockProvider`](#mockprovider).
406+
407+
The _Raw_ visualization and metadata inspector rely on `JSON.stringify()` to
408+
render dataset and attribute values. By default, `JSON.stringify()` does not
409+
know how to serialize `bigint` numbers and throws an error if it encounters one.
410+
`enableBigIntSerialization()` teaches `JSON.stringify()` to convert big integers
411+
to strings:
412+
413+
```js
414+
> JSON.stringify(123n);
415+
TypeError: Do not know how to serialize a BigInt
416+
417+
> enableBigIntSerialization();
418+
> JSON.stringify(123n);
419+
"123n"
420+
```
421+
422+
> The `n` suffix (i.e. the same suffix used for `bigint` literals as
423+
> demonstrated above) is added to help distinguish big integer strings from
424+
> other strings.
425+
426+
> If you're application already implements `bigint` serialization, you don't
427+
> need to call `enableBigIntSerialization()`. Doing so would override the
428+
> existing implementation, which might have unintended effects.
429+
392430
### Context
393431

394432
The viewer component `App` communicates with its wrapping data provider through

packages/app/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export { default as MockProvider } from './providers/mock/MockProvider';
66
export { default as HsdsProvider } from './providers/hsds/HsdsProvider';
77
export { default as H5GroveProvider } from './providers/h5grove/H5GroveProvider';
88

9+
export { enableBigIntSerialization } from './utils';
910
export { getFeedbackMailto } from './breadcrumbs/utils';
1011
export type { FeedbackContext } from './breadcrumbs/models';
1112
export type { ExportFormat, ExportURL } from './providers/models';

packages/app/src/providers/mock/mock-file.ts

+7
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ export function makeMockFile(): GroupWithChildren {
5555
scalar('raw_large', undefined), // generated dynamically by `MockProvider`
5656
dataset('raw_png', opaqueType(), [], PNG_RED_DOT),
5757
scalar('scalar_num', 0, { attributes: [scalarAttr('attr', 0)] }),
58+
scalar('scalar_bigint', BigInt(Number.MAX_SAFE_INTEGER) + 1n, {
59+
attributes: [
60+
scalarAttr('attr', BigInt(Number.MAX_SAFE_INTEGER) + 1n),
61+
],
62+
}),
5863
scalar('scalar_str', 'foo', {
5964
attributes: [scalarAttr('attr', 'foo')],
6065
}),
@@ -108,6 +113,7 @@ export function makeMockFile(): GroupWithChildren {
108113
group('nD_datasets', [
109114
array('oneD_linear'),
110115
array('oneD'),
116+
array('oneD_bigint'),
111117
array('oneD_cplx'),
112118
array('oneD_compound', {
113119
type: printableCompoundType({
@@ -121,6 +127,7 @@ export function makeMockFile(): GroupWithChildren {
121127
array('oneD_bool'),
122128
array('oneD_enum', { type: enumType(uintType(8), ENUM_MAPPING) }),
123129
array('twoD'),
130+
array('twoD_bigint'),
124131
array('twoD_cplx'),
125132
array('twoD_compound', {
126133
type: printableCompoundType({

packages/app/src/utils.ts

+10
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,13 @@ import type { AttrName } from './providers/models';
55
export function hasAttribute(entity: Entity, attributeName: AttrName) {
66
return entity.attributes.some((attr) => attr.name === attributeName);
77
}
8+
9+
export function enableBigIntSerialization(): void {
10+
// eslint-disable-next-line no-extend-native
11+
Object.defineProperty(BigInt.prototype, 'toJSON', {
12+
configurable: true,
13+
value: function toJSON(this: bigint) {
14+
return `${this.toString()}n`;
15+
},
16+
});
17+
}

packages/shared/src/mock-values.ts

+15
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ const range9 = () => range(1, 11);
1717

1818
const oneD = () => ndarray(range1().map((val) => val ** 2));
1919

20+
const oneD_bigint = () =>
21+
ndarray(
22+
range8().map((_, i) => BigInt(Number.MAX_SAFE_INTEGER) + BigInt(i - 5)),
23+
);
24+
2025
const oneD_bool = () =>
2126
ndarray([true, false, false, true, true, true, false, true, false, false]);
2227

@@ -89,6 +94,7 @@ const threeD_rgb = () =>
8994
export const mockValues = {
9095
oneD,
9196
oneD_linear: () => ndarray(range1()),
97+
oneD_bigint,
9298
oneD_cplx,
9399
oneD_compound,
94100
oneD_bool,
@@ -103,6 +109,15 @@ export const mockValues = {
103109
shapeTwoD,
104110
);
105111
},
112+
twoD_bigint: () => {
113+
const { data: dataOneDBigInt } = oneD_bigint();
114+
return ndarray(
115+
range5().flatMap((_, i) =>
116+
dataOneDBigInt.map((val) => val + 1n + BigInt(i) * 10n),
117+
),
118+
[3, 5],
119+
);
120+
},
106121
twoD_cplx: () =>
107122
ndarray(
108123
[

0 commit comments

Comments
 (0)