• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mac-s-g / react-json-view / #1956

16 Oct 2021 03:44PM UTC coverage: 76.364% (-7.0%) from 83.316%
#1956

push

dutzi
autofocus

290 of 397 branches covered (73.05%)

Branch coverage included in aggregate %.

2 of 5 new or added lines in 1 file covered. (40.0%)

89 existing lines in 5 files now uncovered.

508 of 648 relevant lines covered (78.4%)

41.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.21
/src/js/components/DataTypes/Object.js
1
import React from 'react';
2
import { polyfill } from 'react-lifecycles-compat';
3
import { toType } from './../../helpers/util';
4

5
//data type components
6
import { JsonObject } from './DataTypes';
7

8
import VariableEditor from './../VariableEditor';
9
import VariableMeta from './../VariableMeta';
10
import ArrayGroup from './../ArrayGroup';
11
import ObjectName from './../ObjectName';
12

13
//attribute store
14
import AttributeStore from './../../stores/ObjectAttributes';
15

16
//icons
17
import { CollapsedIcon, ExpandedIcon } from './../ToggleIcons';
18

19
//theme
20
import Theme from './../../themes/getStyle';
21

22
//increment 1 with each nested object & array
23
const DEPTH_INCREMENT = 1;
1✔
24
//single indent is 5px
25
const SINGLE_INDENT = 5;
1✔
26

27
class RjvObject extends React.PureComponent {
28
    constructor(props) {
29
        super(props);
46✔
30
        const state = RjvObject.getState(props);
46✔
31
        this.state = {
46✔
32
            ...state,
33
            prevProps: {}
34
        };
35
    }
36

37
    static getState = props => {
1✔
38
        const size = Object.keys(props.src).length;
100✔
39
        const expanded =
40
            (props.collapsed === false ||
100✔
41
                (props.collapsed !== true && props.collapsed > props.depth)) &&
42
            (!props.shouldCollapse ||
43
                props.shouldCollapse({
44
                    name: props.name,
45
                    src: props.src,
46
                    type: toType(props.src),
47
                    namespace: props.namespace
48
                }) === false) &&
49
            //initialize closed if object has no items
50
            size !== 0;
51
        const state = {
100✔
52
            expanded: AttributeStore.get(
53
                props.rjvId,
54
                props.namespace,
55
                'expanded',
56
                expanded
57
            ),
58
            object_type: props.type === 'array' ? 'array' : 'object',
100✔
59
            parent_type: props.type === 'array' ? 'array' : 'object',
100✔
60
            size,
61
            hovered: false
62
        };
63
        return state;
100✔
64
    };
65

66
    static getDerivedStateFromProps(nextProps, prevState) {
67
        const { prevProps } = prevState;
54✔
68
        if (
54!
69
            nextProps.src !== prevProps.src ||
75!
70
            nextProps.collapsed !== prevProps.collapsed ||
71
            nextProps.name !== prevProps.name ||
72
            nextProps.namespace !== prevProps.namespace ||
73
            nextProps.rjvId !== prevProps.rjvId
74
        ) {
75
            const newState = RjvObject.getState(nextProps);
54✔
76
            return {
54✔
77
                ...newState,
78
                prevProps: nextProps
79
            };
80
        }
81
        return null;
×
82
    }
83

84
    toggleCollapsed = () => {
46✔
85
        this.setState(
×
86
            {
87
                expanded: !this.state.expanded
88
            },
89
            () => {
90
                AttributeStore.set(
×
91
                    this.props.rjvId,
92
                    this.props.namespace,
93
                    'expanded',
94
                    this.state.expanded
95
                );
96
            }
97
        );
98
    };
99

100
    getObjectContent = (depth, src, props) => {
46✔
101
        return (
39✔
102
            <div class="pushed-content object-container">
103
                <div
104
                    class="object-content"
105
                    {...Theme(this.props.theme, 'pushed-content')}
106
                >
107
                    {this.renderObjectContents(src, props)}
108
                </div>
109
            </div>
110
        );
111
    };
112

113
    getEllipsis = () => {
46✔
114
        const { size } = this.state;
15✔
115

116
        if (size === 0) {
15✔
117
            //don't render an ellipsis when an object has no items
118
            return null;
7✔
119
        } else {
120
            return (
8✔
121
                <div
122
                    {...Theme(this.props.theme, 'ellipsis')}
123
                    class="node-ellipsis"
124
                    onClick={this.toggleCollapsed}
125
                >
126
                    ...
127
                </div>
128
            );
129
        }
130
    };
131

132
    getObjectMetaData = src => {
46✔
133
        const { rjvId, theme } = this.props;
54✔
134
        const { size, hovered } = this.state;
54✔
135
        return (
54✔
136
            <VariableMeta rowHovered={hovered} size={size} {...this.props} />
137
        );
138
    };
139

140
    getBraceStart(object_type, expanded) {
141
        const { src, theme, iconStyle, parent_type } = this.props;
54✔
142

143
        if (parent_type === 'array_group') {
54✔
144
            return (
2✔
145
                <span>
146
                    <span {...Theme(theme, 'brace')}>
147
                        {object_type === 'array' ? '[' : '{'}
2!
148
                    </span>
149
                    {expanded ? this.getObjectMetaData(src) : null}
2!
150
                </span>
151
            );
152
        }
153

154
        const IconComponent = expanded ? ExpandedIcon : CollapsedIcon;
52✔
155

156
        return (
52✔
157
            <span>
158
                <span
159
                    onClick={e => {
160
                        this.toggleCollapsed();
×
161
                    }}
162
                    {...Theme(theme, 'brace-row')}
163
                >
164
                    <div
165
                        class="icon-container"
166
                        {...Theme(theme, 'icon-container')}
167
                    >
168
                        <IconComponent {...{ theme, iconStyle }} />
169
                    </div>
170
                    <ObjectName
171
                        {...this.props}
172
                        onToggleCollapsed={this.toggleCollapsed}
173
                        isExpanded={expanded}
174
                    />
175
                    <span {...Theme(theme, 'brace')}>
176
                        {object_type === 'array' ? '[' : '{'}
52✔
177
                    </span>
178
                </span>
179
                {expanded ? this.getObjectMetaData(src) : null}
52✔
180
            </span>
181
        );
182
    }
183

184
    render() {
185
        // `indentWidth` and `collapsed` props will
186
        // perpetuate to children via `...rest`
187
        const {
188
            depth,
189
            src,
190
            namespace,
191
            name,
192
            type,
193
            parent_type,
194
            theme,
195
            jsvRoot,
196
            iconStyle,
197
            ...rest
198
        } = this.props;
54✔
199

200
        const { object_type, expanded } = this.state;
54✔
201

202
        let styles = {};
54✔
203
        if (!jsvRoot && parent_type !== 'array_group') {
54✔
204
            styles.paddingLeft = this.props.indentWidth * SINGLE_INDENT;
43✔
205
        } else if (parent_type === 'array_group') {
11✔
206
            styles.borderLeft = 0;
2✔
207
            styles.display = 'inline';
2✔
208
        }
209

210
        return (
54✔
211
            <div
212
                class="object-key-val"
213
                onMouseEnter={() =>
UNCOV
214
                    this.setState({ ...this.state, hovered: true })
×
215
                }
216
                onMouseLeave={() =>
UNCOV
217
                    this.setState({ ...this.state, hovered: false })
×
218
                }
219
                {...Theme(theme, jsvRoot ? 'jsv-root' : 'objectKeyVal', styles)}
54✔
220
            >
221
                {this.getBraceStart(object_type, expanded)}
222
                {expanded
54✔
223
                    ? this.getObjectContent(depth, src, {
224
                          theme,
225
                          iconStyle,
226
                          ...rest
227
                      })
228
                    : this.getEllipsis()}
229
                <span class="brace-row">
230
                    <span
231
                        style={{
232
                            ...Theme(theme, 'brace').style,
233
                            paddingLeft: expanded ? '3px' : '0px'
54✔
234
                        }}
235
                    >
236
                        {object_type === 'array' ? ']' : '}'}
54✔
237
                    </span>
238
                    {expanded ? null : this.getObjectMetaData(src)}
54✔
239
                </span>
240
            </div>
241
        );
242
    }
243

244
    renderObjectContents = (variables, props) => {
46✔
245
        const {
246
            depth,
247
            parent_type,
248
            index_offset,
249
            groupArraysAfterLength,
250
            namespace
251
        } = this.props;
39✔
252
        const { object_type } = this.state;
39✔
253
        let elements = [],
39✔
254
            variable;
255
        let keys = Object.keys(variables || {});
39!
256
        if (this.props.sortKeys && object_type !== 'array') {
39✔
257
            keys = keys.sort();
1✔
258
        }
259

260
        keys.forEach(name => {
39✔
261
            variable = new JsonVariable(name, variables[name]);
118✔
262

263
            if (parent_type === 'array_group' && index_offset) {
118✔
264
                variable.name = parseInt(variable.name) + index_offset;
2✔
265
            }
266
            if (!variables.hasOwnProperty(name)) {
118!
UNCOV
267
                return;
×
268
            } else if (variable.type === 'object') {
118✔
269
                elements.push(
12✔
270
                    <JsonObject
271
                        key={variable.name}
272
                        depth={depth + DEPTH_INCREMENT}
273
                        name={variable.name}
274
                        src={variable.value}
275
                        namespace={namespace.concat(variable.name)}
276
                        parent_type={object_type}
277
                        {...props}
278
                    />
279
                );
280
            } else if (variable.type === 'array') {
106✔
281
                let ObjectComponent = JsonObject;
13✔
282

283
                if (
13!
284
                    groupArraysAfterLength &&
23✔
285
                    variable.value.length > groupArraysAfterLength
286
                ) {
UNCOV
287
                    ObjectComponent = ArrayGroup;
×
288
                }
289

290
                elements.push(
13✔
291
                    <ObjectComponent
292
                        key={variable.name}
293
                        depth={depth + DEPTH_INCREMENT}
294
                        name={variable.name}
295
                        src={variable.value}
296
                        namespace={namespace.concat(variable.name)}
297
                        type="array"
298
                        parent_type={object_type}
299
                        {...props}
300
                    />
301
                );
302
            } else {
303
                elements.push(
93✔
304
                    <VariableEditor
305
                        key={variable.name + '_' + namespace}
306
                        variable={variable}
307
                        singleIndent={SINGLE_INDENT}
308
                        namespace={namespace}
309
                        type={this.props.type}
310
                        {...props}
311
                    />
312
                );
313
            }
314
        });
315

316
        return elements;
39✔
317
    };
318
}
319

320
//just store name, value and type with a variable
321
class JsonVariable {
322
    constructor(name, value) {
323
        this.name = name;
118✔
324
        this.value = value;
118✔
325
        this.type = toType(value);
118✔
326
    }
327
}
328

329
polyfill(RjvObject);
1✔
330

331
//export component
332
export default RjvObject;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc