Skip to content

Commit 5a8343b

Browse files
committed
add null and undefined as primitives + fix some styles
1 parent dfad48a commit 5a8343b

5 files changed

Lines changed: 37 additions & 25 deletions

File tree

src/components/Json/Json.module.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
.string {
5353
color: #eaa;
5454
}
55+
.other {
56+
color: #d6d6d6;
57+
}
5558
.comment {
5659
color: #ccd8;
5760
}

src/components/Json/Json.stories.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ export const Default: Story = {
2323
b: 'hello',
2424
c: [1, 2, 3],
2525
d: { e: 4, f: 5 },
26+
e: null,
27+
f: undefined,
28+
g: true,
29+
// h: 123456n, // commented because it breaks storybook...
2630
},
2731
label: 'json',
2832
},
@@ -41,6 +45,7 @@ export const Arrays: Story = {
4145
strings100: Array.from({ length: 100 }, (_, i) => `hello ${i}`),
4246
misc: Array.from({ length: 8 }, (_, i) => i % 2 ? `hello ${i}` : i),
4347
misc2: Array.from({ length: 8 }, (_, i) => i % 3 === 0 ? i : i % 3 === 1 ? `hello ${i}` : [i, i + 1, i + 2]),
48+
misc3: [1, 'hello', null, undefined],
4449
arrays100: Array.from({ length: 100 }, (_, i) => [i, i + 1, i + 2]),
4550
},
4651
label: 'json',
@@ -59,6 +64,7 @@ export const Objects: Story = {
5964
strings100: Object.fromEntries(Array.from({ length: 100 }, (_, i) => [`k${i}`, `hello ${i}`])),
6065
misc: Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`k${i}`, i % 2 ? `hello ${i}` : i])),
6166
misc2: Object.fromEntries(Array.from({ length: 8 }, (_, i) => [`k${i}`, i % 3 === 0 ? i : i % 3 === 1 ? `hello ${i}` : [i, i + 1, i + 2]])),
67+
misc3: { k0: 1, k1: 'a', k2: null, k3: undefined },
6268
arrays100: Object.fromEntries(Array.from({ length: 100 }, (_, i) => [`k${i}`, [i, i + 1, i + 2]])),
6369
},
6470
label: 'json',

src/components/Json/Json.test.tsx

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ describe('Json Component', () => {
3636
['foo', 'bar'],
3737
[],
3838
[1, 2, 3],
39+
[1, 'foo', null, undefined],
3940
])('shows short arrays of primitive items, without trailing comment about length', (array) => {
4041
const { queryByText } = render(<Json json={array} />)
4142
expect(queryByText('...')).toBeNull()
4243
expect(queryByText('length')).toBeNull()
4344
})
4445

4546
it.for([
46-
[1, 'foo', null],
47+
[1, 'foo', [1, 2, 3]],
4748
Array.from({ length: 101 }, (_, i) => i),
4849
])('hides long arrays, and non-primitive items, with trailing comment about length', (array) => {
4950
const { queryByText } = render(<Json json={array} />)
@@ -66,8 +67,6 @@ describe('Json Component', () => {
6667
})
6768

6869
it.for([
69-
{ obj: undefined },
70-
{ obj: null },
7170
{ obj: [314, null] },
7271
{ obj: { nested: true } },
7372
])('expands short objects with non-primitive values', (obj) => {
@@ -76,8 +75,6 @@ describe('Json Component', () => {
7675
})
7776

7877
it.for([
79-
{ obj: undefined },
80-
{ obj: null },
8178
{ obj: [314, null] },
8279
{ obj: { nested: true } },
8380
])('hides the content and append number of entries when objects with non-primitive values are collapsed', (obj) => {
@@ -90,7 +87,7 @@ describe('Json Component', () => {
9087
it.for([
9188
{},
9289
{ a: 1, b: 2 },
93-
{ a: 1, b: true },
90+
{ a: 1, b: true, c: null, d: undefined },
9491
Object.fromEntries(Array.from({ length: 101 }, (_, i) => [`key${i}`, { nested: true }])),
9592
])('collapses long objects, or objects with only primitive values (included empty object)', (obj) => {
9693
const { queryByText } = render(<Json json={obj} />)
@@ -107,25 +104,23 @@ describe('Json Component', () => {
107104
})
108105

109106
it('toggles array collapse state', () => {
110-
const { getByText, queryByText } = render(<Json json={['foo', null]} />)
111-
expect(getByText('"foo"')).toBeDefined()
112-
expect(queryByText('null')).toBeNull()
107+
const longArray = Array.from({ length: 101 }, (_, i) => i)
108+
const { getByText, queryByText } = render(<Json json={longArray} />)
109+
expect(getByText('...')).toBeDefined()
113110
fireEvent.click(getByText('▶'))
114-
expect(getByText('null')).toBeDefined()
111+
expect(queryByText('...')).toBeNull()
115112
fireEvent.click(getByText('▼'))
116-
expect(getByText('"foo"')).toBeDefined()
117-
expect(queryByText('null')).toBeNull()
113+
expect(getByText('...')).toBeDefined()
118114
})
119115

120116
it('toggles object collapse state', () => {
121-
const { getByText, queryByText } = render(<Json json={{ key: 'value' }} />)
122-
expect(getByText('key:')).toBeDefined()
123-
expect(getByText('"value"')).toBeDefined()
117+
const longObject = Object.fromEntries(Array.from({ length: 101 }, (_, i) => [`key${i}`, { nested: true }]))
118+
const { getByText, queryByText } = render(<Json json={longObject} />)
119+
expect(getByText('...')).toBeDefined()
124120
fireEvent.click(getByText('▶'))
125-
expect(queryByText('key: "value"')).toBeNull()
121+
expect(queryByText('...')).toBeNull()
126122
fireEvent.click(getByText('▼'))
127-
expect(getByText('key:')).toBeDefined()
128-
expect(getByText('"value"')).toBeDefined()
123+
expect(getByText('...')).toBeDefined()
129124
})
130125
})
131126

@@ -135,8 +130,8 @@ describe('isPrimitive', () => {
135130
expect(isPrimitive(42)).toBe(true)
136131
expect(isPrimitive(true)).toBe(true)
137132
expect(isPrimitive(1n)).toBe(true)
138-
expect(isPrimitive(null)).toBe(false)
139-
expect(isPrimitive(undefined)).toBe(false)
133+
expect(isPrimitive(null)).toBe(true)
134+
expect(isPrimitive(undefined)).toBe(true)
140135
expect(isPrimitive({})).toBe(false)
141136
expect(isPrimitive([])).toBe(false)
142137
})

src/components/Json/Json.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@ function JsonContent({ json, label }: JsonProps): ReactNode {
2929
div = <>{key}<span className={styles.number}>{JSON.stringify(json)}</span></>
3030
} else if (typeof json === 'bigint') {
3131
// it's not really json, but show it anyway
32-
div = <>{key}<span>{json.toString()}</span></>
32+
div = <>{key}<span className={styles.number}>{json.toString()}</span></>
33+
} else if (json === undefined) {
34+
// it's not json
35+
div = <>{key}<span className={styles.other}>undefined</span></>
3336
} else {
34-
div = <>{key}<span>{JSON.stringify(json)}</span></>
37+
div = <>{key}<span className={styles.other}>{JSON.stringify(json)}</span></>
3538
}
3639
}
3740
return div
@@ -54,7 +57,9 @@ function CollapsedArray({ array }: {array: unknown[]}): ReactNode {
5457
}
5558
// should we continue?
5659
if (isPrimitive(value)) {
57-
const asString = typeof value === 'bigint' ? value.toString() : JSON.stringify(value)
60+
const asString = typeof value === 'bigint' ? value.toString() :
61+
value === undefined ? 'undefined' /* see JsonContent - even if JSON.stringify([undefined]) === '[null]' */:
62+
JSON.stringify(value)
5863
characterCount += asString.length
5964
if (characterCount < maxCharacterCount) {
6065
children.push(<JsonContent json={value} key={`value-${index}`} />)
@@ -118,7 +123,9 @@ function CollapsedObject({ obj }: {obj: object}): ReactNode {
118123
}
119124
// should we continue?
120125
if (isPrimitive(value)) {
121-
const asString = typeof value === 'bigint' ? value.toString() : JSON.stringify(value)
126+
const asString = typeof value === 'bigint' ? value.toString() :
127+
value === undefined ? 'undefined' /* see JsonContent - even if JSON.stringify([undefined]) === '[null]' */:
128+
JSON.stringify(value)
122129
characterCount += key.length + kvSeparator.length + asString.length
123130
if (characterCount < maxCharacterCount) {
124131
children.push(<JsonContent json={value as unknown} label={key} key={`value-${index}`} />)

src/components/Json/helpers.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export function isPrimitive(value: unknown): boolean {
22
return (
3-
value !== undefined &&
3+
value === undefined ||
4+
value === null ||
45
!Array.isArray(value) &&
56
typeof value !== 'object' &&
67
typeof value !== 'function'

0 commit comments

Comments
 (0)