Skip to content

feat: backport support for props.quotesOnKeys and props.sortKeys #48

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/components/DataKeyPair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const DataKeyPair: React.FC<DataKeyPairProps> = (props) => {
store => store.colorspace.base0C)
const { Component, PreComponent, PostComponent, Editor } = useTypeComponents(
value)
const quotesOnKeys = useJsonViewerStore(store => store.quotesOnKeys)
const rootName = useJsonViewerStore(store => store.rootName)
const isRoot = root === value
const isNumberKey = Number.isInteger(Number(key))
Expand Down Expand Up @@ -164,7 +165,18 @@ export const DataKeyPair: React.FC<DataKeyPairProps> = (props) => {
</>
)
},
[Editor, copied, copy, editable, editing, enableClipboard, onChange, path, tempValue, value])
[
Editor,
copied,
copy,
editable,
editing,
enableClipboard,
onChange,
path,
tempValue,
value
])

const expandable = !!(PreComponent && PostComponent)
const KeyRenderer = useJsonViewerStore(store => store.keyRenderer)
Expand Down Expand Up @@ -220,7 +232,7 @@ export const DataKeyPair: React.FC<DataKeyPairProps> = (props) => {
isNumberKey
? <Box component='span'
style={{ color: numberKeyColor }}>{key}</Box>
: <>&quot;{key}&quot;</>
: quotesOnKeys ? <>&quot;{key}&quot;</> : <>{key}</>
)
}
{
Expand Down
16 changes: 14 additions & 2 deletions src/components/DataTypes/Object.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ export const ObjectType: React.FC<DataItemProps<object>> = (props) => {
const [displayLength, setDisplayLength] = useState(
useJsonViewerStore(store => store.maxDisplayLength)
)
const objectSortKeys = useJsonViewerStore(store => store.objectSortKeys)
const elements = useMemo(() => {
if (!props.inspect) {
return null
Expand Down Expand Up @@ -188,7 +189,16 @@ export const ObjectType: React.FC<DataItemProps<object>> = (props) => {
})
} else {
// object
const entries = Object.entries(value)
let entries: [key: string, value: unknown][] = Object.entries(value)
if (objectSortKeys) {
entries = entries.sort(([a], [b]) => {
if (objectSortKeys === true) {
return a.localeCompare(b)
} else {
return objectSortKeys(a, b)
}
})
}
const elements = entries.slice(0, displayLength).map(([key, value]) => {
const path = [...props.path, key]
return (
Expand Down Expand Up @@ -221,7 +231,9 @@ export const ObjectType: React.FC<DataItemProps<object>> = (props) => {
props.path,
groupArraysAfterLength,
displayLength,
keyColor])
keyColor,
objectSortKeys
])
const marginLeft = props.inspect ? 0.6 : 0
const width = useJsonViewerStore(store => store.indentWidth)
const indentWidth = props.inspect ? width - marginLeft : width
Expand Down
4 changes: 4 additions & 0 deletions src/stores/JsonViewerStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export type JsonViewerState<T = unknown> = {
maxDisplayLength: number
defaultInspectDepth: number
collapseStringsAfterLength: number
objectSortKeys: boolean | ((a: string, b: string) => number)
quotesOnKeys: boolean
colorspace: Colorspace
editable: boolean | (<U>(path: Path, currentValue: U) => boolean)
rootName: false | string
Expand Down Expand Up @@ -50,6 +52,8 @@ export const createJsonViewerStore = <T = unknown>(props: JsonViewerProps<T>) =>
keyRenderer: props.keyRenderer ?? DefaultKeyRenderer,
editable: props.editable ?? true,
defaultInspectDepth: props.defaultInspectDepth ?? 5,
objectSortKeys: props.objectSortKeys ?? false,
quotesOnKeys: props.quotesOnKeys ?? true,
// internal state
inspectCache: {},
hoverPath: null,
Expand Down
17 changes: 17 additions & 0 deletions src/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,23 @@ export type JsonViewerProps<T = unknown> = {
* @default 100
*/
collapseStringsAfterLength?: number

/**
* Whether sort keys through `String.prototype.localeCompare()`
*
* @default false
*/
objectSortKeys?: boolean | ((a: string, b: string) => number)

/**
* set `false` to remove quotes from keys
*
* true for `"name"`, false for `name`
*
* @default true
*/
quotesOnKeys?: boolean

className?: string
style?: React.CSSProperties
/**
Expand Down
75 changes: 75 additions & 0 deletions tests/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,61 @@ import { describe, it } from 'vitest'

import { JsonViewer } from '../src'

function aPlusB (a: number, b: number) {
return a + b
}

const loopObject = {
foo: 1,
goo: 'string'
} as Record<string, any>

loopObject.self = loopObject

const loopArray = [
loopObject
]

loopArray[1] = loopArray

const longArray = Array.from({ length: 1000 }).map((_, i) => i)
const map = new Map<any, any>()
map.set('foo', 1)
map.set('goo', 'hello')
map.set({}, 'world')

const set = new Set([1, 2, 3])

const superLongString = '1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111'

const full = {
loopObject,
loopArray,
longArray,
string: 'this is a string',
integer: 42,
array: [19, 19, 810, 'test', NaN],
nestedArray: [
[1, 2],
[3, 4]
],
map,
set,
float: 114.514,
undefined,
superLongString,
object: {
'first-child': true,
'second-child': false,
'last-child': null
},
fn: aPlusB,
string_number: '1234',
timer: 0,
date: new Date('Tue Sep 13 2022 14:07:44 GMT-0500 (Central Daylight Time)'),
bigint: 110101195306153019n
}

describe('render <JsonViewer/>', () => {
it('render undefined', () => {
render(<JsonViewer value={undefined}/>)
Expand Down Expand Up @@ -71,4 +126,24 @@ describe('render <JsonViewer/>', () => {
}}/>)
render(<JsonViewer value={(a: number, b: number) => a + b}/>)
})

it('render full', () => {
render(<JsonViewer value={full}/>)
})
})

describe('render <JsonViewer/> with props', () => {
it('render with quotesOnKeys', () => {
const selection = [true, false]
selection.forEach(quotesOnKeys => {
render(<JsonViewer value={full} quotesOnKeys={quotesOnKeys}/>)
})
})

it('render with objectSortKeys', () => {
const selection = [true, false, (a: string, b: string) => a.localeCompare(b)]
selection.forEach(objectSortKeys => {
render(<JsonViewer value={full} objectSortKeys={objectSortKeys}/>)
})
})
})