Skip to content
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

Enhance Function component #81

Merged
merged 13 commits into from
Sep 23, 2022
14 changes: 13 additions & 1 deletion examples/basic/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ const avatar = 'https://i.imgur.com/1bX5QH6.jpg'
function aPlusB (a: number, b: number) {
return a + b
}
const aPlusBConst = function (a: number, b: number) {
return a + b
}

const loopObject = {
foo: 1,
Expand Down Expand Up @@ -71,7 +74,16 @@ const example = {
'second-child': false,
'last-child': null
},
fn: aPlusB,
function: aPlusB,
constFunction: aPlusBConst,
anonymousFunction: function (a: number, b: number) {
return a + b
},
shortFunction: (arg1: any, arg2: any) => console.log(arg1, arg2),
shortLongFunction: (arg1: any, arg2: any) => {
console.log(arg1, arg2)
return '123'
},
string_number: '1234',
timer: 0,
avatar,
Expand Down
4 changes: 2 additions & 2 deletions src/components/DataKeyPair.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const DataKeyPair: React.FC<DataKeyPairProps> = (props) => {
}
return propsEditable
}, [path, propsEditable, storeEditable, value])
const [tempValue, setTempValue] = useState(value)
const [tempValue, setTempValue] = useState(typeof value === 'function' ? () => value : value)
const depth = path.length
const key = path[depth - 1]
const hoverPath = useJsonViewerStore(store => store.hoverPath)
Expand Down Expand Up @@ -114,7 +114,7 @@ export const DataKeyPair: React.FC<DataKeyPairProps> = (props) => {
try {
copy(
JSON.stringify(
value,
typeof value === 'function' ? value.toString() : value,
null,
' '
)
Expand Down
59 changes: 40 additions & 19 deletions src/components/DataTypes/Function.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,55 @@ import { DataTypeLabel } from '../DataTypeLabel'
const functionBody = (func: Function) => {
const funcString = func.toString()

return funcString.substring(
funcString.indexOf('{', funcString.indexOf(')')) + 1,
funcString.lastIndexOf('}')
)
let isUsualFunction = true;
let parenthesisPos = funcString.indexOf(')');
let arrowPos = funcString.indexOf('=>');
if (arrowPos !== -1 && arrowPos > parenthesisPos) {
isUsualFunction = false
}
if (isUsualFunction) {
return funcString.substring(
funcString.indexOf('{', parenthesisPos) + 1,
funcString.lastIndexOf('}')
)
}

return funcString.substring(funcString.indexOf('=>') + 2)
}

const functionName = (func: Function) => {
return func.toString()
.slice(9, -1)
.replace(/\{[\s\S]+/, '')
let funcString = func.toString();
const isUsualFunction = funcString.indexOf('function') !== -1
if (isUsualFunction) {
return funcString.substring(8, funcString.indexOf('{')).trim();
}

return funcString.substring(0, funcString.indexOf('=>') + 2).trim()
}

const lb = '{'
const rb = '}'

export const PreFunctionType: React.FC<DataItemProps<Function>> = (props) => {
return (
<Box
component='span' className='data-object-start'
sx={{
letterSpacing: 0.5
}}
>
<>
<DataTypeLabel dataType='function'/>
{functionName(props.value)}
{lb}
</Box>
<Box
component='span' className='data-function-start'
sx={{
letterSpacing: 0.5,
}}
>
{functionName(props.value)}
{' '}{lb}
</Box>
</>
)
}

export const PostFunctionType: React.FC<DataItemProps<Function>> = () => {
return (
<Box component='span' className='data-object-end'>
<Box component='span' className='data-function-end'>
{rb}
</Box>
)
Expand All @@ -60,10 +76,15 @@ export const FunctionType: React.FC<DataItemProps<Function>> = (props) => {
{props.inspect
? functionBody(props.value)
: (
<Box component='span' className='data-object-body'>
<Box component='span' className='data-function-body'
onClick={() => props.setInspect(true)}
sx={{
'&:hover': {cursor: 'pointer'}
}}
>
...
</Box>
)
)
}
</Box>
)
Expand Down
160 changes: 159 additions & 1 deletion tests/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {fireEvent, render, screen} from '@testing-library/react'
import { fireEvent, render, screen } from '@testing-library/react'
import { expectTypeOf } from 'expect-type'
import React from 'react'
import { describe, expect, it } from 'vitest'
Expand Down Expand Up @@ -281,3 +281,161 @@ describe('Expand elements by click on dots', () => {
})
})


describe('test functions', () => {
const func1 = function (...args: any[]) {
console.log(args)
return '111';
}

function func2(...args: any[]) {
console.log(args)
return '222';
}

const dataProvider = [
[
function (...args: any) {
console.log(args)
return '333';
},
`(...args) {`,
`
console.log(args);
return "333";
`
],
[
func1,
`(...args) {`,
`
console.log(args);
return "111";
`
],
[
func2,
`func2(...args) {`,
`
console.log(args);
return "222";
`
],
[
(...args:any) => console.log('555'),
`(...args) => {`,
` console.log("555")`
],
[
(...args:any) => {
console.log(args)
return '666'
},
`(...args) => {`,
` {
console.log(args);
return "666";
}`
],
[
function (a: number, b: number) {
throw Error('Be careful to use the function just as value in useState() hook')
}
,
`(a, b) {`,
`
throw Error("Be careful to use the function just as value in useState() hook");
`
],
[
({prop1, prop2, ...other}:any) => {
console.log(prop1, prop2, other)
return '777'
},
`({
prop1,
prop2,
...other
}) => {`,
` {
console.log(prop1, prop2, other);
return "777";
}`
],
[
{
func: ({prop1, prop2, ...other}:any) => {
console.log(prop1, prop2, other)
return '777'
}
},
`({
prop1,
prop2,
...other
}) => {`,
` {
console.log(prop1, prop2, other);
return "777";
}`
],
[
// @ts-ignore
(function(e,n){return e+n}),
`(e, n) {`,
`
return e + n;
`
],
]
for (let iteration of dataProvider) {
it('render', () => {
const {container} = render(
<JsonViewer
rootName={false}
value={iteration[0]}
/>
)
expect(container.children.length).eq(1)
const functionName = container.getElementsByClassName('data-function-start')
expect(functionName.length).eq(1)
expect(functionName[0].textContent).eq(iteration[1])

const functionBody = container.getElementsByClassName('data-function')
expect(functionBody.length).eq(1)
expect(functionBody[0].textContent).eq(iteration[2])
});
}
})

describe('Expand function by click on dots', () => {
it('render', () => {
const {container, rerender} = render(
<JsonViewer
rootName={false}
value={(e:any) => console.log('it works')}
defaultInspectDepth={0}
/>
)

let elements = container.getElementsByClassName('data-function-body');
expect(elements.length).eq(1)
expect(elements[0].textContent).eq('...')
fireEvent.click(elements[0])

rerender(
<JsonViewer
rootName={false}
value={(e:any) => console.log('it works')}
defaultInspectDepth={0}
/>
)
elements = container.getElementsByClassName('data-function-body');
expect(elements.length).eq(0)

elements = container.getElementsByClassName('data-function');
expect(elements.length).eq(1)
expect(elements[0].children.length).eq(0)
expect(elements[0].textContent).not.eq('...')
})
})