Handle invalid json

- fix style
This commit is contained in:
Thomas Nordquist
2019-06-04 14:36:28 +02:00
parent e66f6d098a
commit 09151d14a9
4 changed files with 58 additions and 25 deletions

View File

@@ -1,7 +1,7 @@
import * as diff from 'diff' import * as diff from 'diff'
import * as React from 'react' import * as React from 'react'
import ShowChart from '@material-ui/icons/ShowChart' import ShowChart from '@material-ui/icons/ShowChart'
import { JsonPropertyLocation, literalsMappedByLines } from '../../../../../backend/src/JsonAstParser' import { JsonPropertyLocation } from '../../../../../backend/src/JsonAstParser'
import { lineChangeStyle, trimNewlineRight } from './util' import { lineChangeStyle, trimNewlineRight } from './util'
import { Theme } from '@material-ui/core' import { Theme } from '@material-ui/core'
import { withStyles } from '@material-ui/styles' import { withStyles } from '@material-ui/styles'
@@ -15,21 +15,39 @@ interface Props {
const style = (theme: Theme) => { const style = (theme: Theme) => {
return { return {
gutterLine: { gutterLine: {
display: 'flex' as 'flex',
textAlign: 'right' as 'right', textAlign: 'right' as 'right',
paddingRight: theme.spacing(0.5), paddingRight: theme.spacing(0.5),
height: '16px',
}, },
} }
} }
function tokensForLine(change: diff.Change, line: number, literalPositions: Array<JsonPropertyLocation>) {
let diagram = literalPositions[line] ? <ShowChart style={{ height: '16px' }} /> : ''
if (change.added) {
return [diagram, '+']
} else if (change.removed) {
return '-'
} else {
return [diagram, ' ']
}
}
function Gutters(props: Props) { function Gutters(props: Props) {
let currentLine = -1
const gutters = props.changes.map((change, key) => { const gutters = props.changes.map((change, key) => {
return trimNewlineRight(change.value) return trimNewlineRight(change.value)
.split('\n') .split('\n')
.map((_, idx) => ( .map((_, idx) => {
<div key={`${key}-${idx}`} style={lineChangeStyle(change)} className={props.classes.gutterLine}> currentLine = !change.removed ? currentLine + 1 : currentLine
{change.added ? '+' : null}{change.removed ? '-' : null}{!change.added && !change.removed ? ' ' : null} return (
</div> <div key={`${key}-${idx}`} style={lineChangeStyle(change)} className={props.classes.gutterLine}>
)) {tokensForLine(change, currentLine, props.literalPositions)}
</div>
)
})
}).reduce((a, b) => a.concat(b), []) }).reduce((a, b) => a.concat(b), [])
return <div>{gutters}</div> return <div>{gutters}</div>

View File

@@ -3,7 +3,7 @@ import * as Prism from 'prismjs'
import * as React from 'react' import * as React from 'react'
import DiffCount from './DiffCount' import DiffCount from './DiffCount'
import { CodeBlockColors, CodeBlockColorsBraceMonokai } from '../CodeBlockColors' import { CodeBlockColors, CodeBlockColorsBraceMonokai } from '../CodeBlockColors'
import { literalsMappedByLines, parseJson } from '../../../../../backend/src/JsonAstParser' import { literalsMappedByLines } from '../../../../../backend/src/JsonAstParser'
import { selectTextWithCtrlA } from '../../../utils/handleTextSelectWithCtrlA' import { selectTextWithCtrlA } from '../../../utils/handleTextSelectWithCtrlA'
import { Theme, withStyles } from '@material-ui/core' import { Theme, withStyles } from '@material-ui/core'
import 'prismjs/components/prism-json' import 'prismjs/components/prism-json'
@@ -28,7 +28,7 @@ class CodeDiff extends React.Component<Props, {}> {
public render() { public render() {
const changes = diff.diffLines(this.props.previous, this.props.current) const changes = diff.diffLines(this.props.previous, this.props.current)
const styledLines = Prism.highlight(this.props.current, Prism.languages.json, 'json').split('\n') const styledLines = Prism.highlight(this.props.current, Prism.languages.json, 'json').split('\n')
const literalPositions = literalsMappedByLines(this.props.current) const literalPositions = literalsMappedByLines(this.props.current) || []
let lineNumber = 0 let lineNumber = 0
const code = changes.map((change, key) => { const code = changes.map((change, key) => {
@@ -78,6 +78,7 @@ const style = (theme: Theme) => {
lineHeight: 'normal' as 'normal', lineHeight: 'normal' as 'normal',
paddingLeft: '4px', paddingLeft: '4px',
width: '100%', width: '100%',
height: '16px',
}, },
codeWrapper: { codeWrapper: {
maxHeight: '15em', maxHeight: '15em',

View File

@@ -74,16 +74,24 @@ function jsonToPropertyPaths(ast: JsonAst, previousPath: Array<string> = []): Ar
return children.reduce((a, b) => a.concat(b), []) return children.reduce((a, b) => a.concat(b), [])
} }
// Used for testing only
export function parseJson(formattedJson: string): Array<JsonPropertyLocation> { export function parseJson(formattedJson: string): Array<JsonPropertyLocation> {
return jsonToPropertyPaths((parse(formattedJson) as JsonAst), []) const parsedJson = parse(formattedJson) as JsonAst
return jsonToPropertyPaths(parsedJson, [])
} }
export function literalsMappedByLines(formattedJson: string): Array<JsonPropertyLocation> { export function literalsMappedByLines(formattedJson: string): Array<JsonPropertyLocation> | undefined {
const literals = jsonToPropertyPaths((parse(formattedJson) as JsonAst), []) try {
const lines = [] const parsedJson = parse(formattedJson) as JsonAst
for (const literal of literals) { const literals = jsonToPropertyPaths(parsedJson, [])
lines[literal.line - 1] = literal const lines = []
for (const literal of literals) {
lines[literal.line - 1] = literal
}
return lines
} catch (error) {
return undefined
} }
return lines
} }

View File

@@ -1,28 +1,28 @@
import 'mocha'
import { expect } from 'chai' import { expect } from 'chai'
import { parseJson } from '../JsonAstParser' import { parseJson } from '../JsonAstParser'
import 'mocha'
const dotProp = require('dot-prop') const dotProp = require('dot-prop')
describe('access JSON values via dot property paths', () => { describe('access JSON values via dot property paths', () => {
it('object with literal', () => { it('object with literal', () => {
let data = { const data = {
foo: 4, foo: 4,
} }
let result = parseJson(JSON.stringify(data, undefined, 2)) const result = parseJson(JSON.stringify(data, undefined, 2))
expect(result[0].path).to.eq('foo') expect(result[0].path).to.eq('foo')
expect(result[0].line).to.eq(2) expect(result[0].line).to.eq(2)
}) })
it('nested object', () => { it('nested object', () => {
let data = { const data = {
foo: { foo: {
bar: 4 bar: 4,
}, },
} }
let result = parseJson(JSON.stringify(data, undefined, 2)) const result = parseJson(JSON.stringify(data, undefined, 2))
expect(result[0].path).to.eq('foo.bar') expect(result[0].path).to.eq('foo.bar')
expect(result[0].line).to.eq(3) expect(result[0].line).to.eq(3)
expect(dotProp.get(data, result[0].path)).to.eq(4) expect(dotProp.get(data, result[0].path)).to.eq(4)
@@ -30,7 +30,7 @@ describe('access JSON values via dot property paths', () => {
}) })
it('array path', () => { it('array path', () => {
let data = { const data = {
foo: [ foo: [
1, 1,
2, 2,
@@ -38,11 +38,17 @@ describe('access JSON values via dot property paths', () => {
], ],
} }
let result = parseJson(JSON.stringify(data, undefined, 2)) const result = parseJson(JSON.stringify(data, undefined, 2))
expect(result.length).to.eq(3) expect(result.length).to.eq(3)
expect(result[2].path).to.eq('foo.2') expect(result[2].path).to.eq('foo.2')
expect(result[2].line).to.eq(5) expect(result[2].line).to.eq(5)
expect(dotProp.get(data, result[2].path)).to.eq(3) expect(dotProp.get(data, result[2].path)).to.eq(3)
}) })
it('should fail parsing invalid json', () => {
expect(() => {
const result = parseJson("BLE2MQTT-8C48")
}).to.throw()
})
}) })