Prepare json literal inpsection
This commit is contained in:
77
backend/src/JsonAstParser.ts
Normal file
77
backend/src/JsonAstParser.ts
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
const parse = require('json-to-ast')
|
||||||
|
|
||||||
|
interface JsonPropertyLocation {
|
||||||
|
path: string
|
||||||
|
line: number
|
||||||
|
column: number
|
||||||
|
}
|
||||||
|
|
||||||
|
type JsonAst = JsonAstLiteral | JsonAstObject | JsonAstArray
|
||||||
|
|
||||||
|
interface JsonAstLocation {
|
||||||
|
start: {
|
||||||
|
line: number
|
||||||
|
column: number
|
||||||
|
offset: number
|
||||||
|
}
|
||||||
|
end: {
|
||||||
|
line: number
|
||||||
|
column: number
|
||||||
|
offset: number
|
||||||
|
}
|
||||||
|
source: null | string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JsonAstIdentifier {
|
||||||
|
type: 'Identifier'
|
||||||
|
value: string
|
||||||
|
raw: string
|
||||||
|
loc: JsonAstLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JsonAstObjectProperty {
|
||||||
|
type: 'Property'
|
||||||
|
key: JsonAstIdentifier
|
||||||
|
value: JsonAst
|
||||||
|
loc: JsonAstLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JsonAstLiteral {
|
||||||
|
type: 'Literal'
|
||||||
|
value: string | number | boolean | any
|
||||||
|
raw: string
|
||||||
|
loc: JsonAstLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JsonAstObject {
|
||||||
|
type: 'Object'
|
||||||
|
children: Array<JsonAstObjectProperty>
|
||||||
|
loc: JsonAstLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
interface JsonAstArray {
|
||||||
|
type: 'Array'
|
||||||
|
children: Array<JsonAst>
|
||||||
|
loc: JsonAstLocation
|
||||||
|
}
|
||||||
|
|
||||||
|
function jsonToPropertyPaths(ast: JsonAst, previousPath: Array<string> = []): Array<JsonPropertyLocation> {
|
||||||
|
let children: Array<Array<JsonPropertyLocation>> = []
|
||||||
|
if (ast.type === 'Literal') {
|
||||||
|
return [{
|
||||||
|
path: previousPath.join('.'),
|
||||||
|
line: ast.loc.start.line,
|
||||||
|
column: ast.loc.start.column,
|
||||||
|
}]
|
||||||
|
} else if (ast.type === 'Array') {
|
||||||
|
children = ast.children.map((value, idx) => jsonToPropertyPaths(value, previousPath.slice().concat([String(idx)])))
|
||||||
|
} else if (ast.type === 'Object') {
|
||||||
|
children = ast.children.map(property => jsonToPropertyPaths(property.value, previousPath.slice().concat([property.key.value])))
|
||||||
|
}
|
||||||
|
|
||||||
|
return children.reduce((a, b) => a.concat(b), [])
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseJson(formattedJson: string): Array<JsonPropertyLocation> {
|
||||||
|
return jsonToPropertyPaths((parse(formattedJson) as JsonAst), [])
|
||||||
|
}
|
||||||
48
backend/src/spec/JsonAstParser.spec.ts
Normal file
48
backend/src/spec/JsonAstParser.spec.ts
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
import 'mocha'
|
||||||
|
|
||||||
|
import { expect } from 'chai'
|
||||||
|
import { parseJson } from '../JsonAstParser'
|
||||||
|
const dotProp = require('dot-prop')
|
||||||
|
|
||||||
|
describe('access JSON values via dot property paths', () => {
|
||||||
|
it('object with literal', () => {
|
||||||
|
let data = {
|
||||||
|
foo: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = parseJson(JSON.stringify(data, undefined, 2))
|
||||||
|
expect(result[0].path).to.eq('foo')
|
||||||
|
expect(result[0].line).to.eq(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('nested object', () => {
|
||||||
|
let data = {
|
||||||
|
foo: {
|
||||||
|
bar: 4
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = parseJson(JSON.stringify(data, undefined, 2))
|
||||||
|
expect(result[0].path).to.eq('foo.bar')
|
||||||
|
expect(result[0].line).to.eq(3)
|
||||||
|
expect(dotProp.get(data, result[0].path)).to.eq(4)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
it('array path', () => {
|
||||||
|
let data = {
|
||||||
|
foo: [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = parseJson(JSON.stringify(data, undefined, 2))
|
||||||
|
expect(result.length).to.eq(3)
|
||||||
|
|
||||||
|
expect(result[2].path).to.eq('foo.2')
|
||||||
|
expect(result[2].line).to.eq(5)
|
||||||
|
expect(dotProp.get(data, result[2].path)).to.eq(3)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -95,6 +95,7 @@
|
|||||||
"electron-telemetry": "git+https://github.com/thomasnordquist/electron-telemetry.git#dist",
|
"electron-telemetry": "git+https://github.com/thomasnordquist/electron-telemetry.git#dist",
|
||||||
"electron-updater": "^4.0.6",
|
"electron-updater": "^4.0.6",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
|
"json-to-ast": "^2.1.0",
|
||||||
"lowdb": "^1.0.0",
|
"lowdb": "^1.0.0",
|
||||||
"mqtt": "^2.18.8",
|
"mqtt": "^2.18.8",
|
||||||
"sha1": "^1.1.1",
|
"sha1": "^1.1.1",
|
||||||
|
|||||||
15
yarn.lock
15
yarn.lock
@@ -753,6 +753,11 @@ cliui@^5.0.0:
|
|||||||
strip-ansi "^5.2.0"
|
strip-ansi "^5.2.0"
|
||||||
wrap-ansi "^5.1.0"
|
wrap-ansi "^5.1.0"
|
||||||
|
|
||||||
|
code-error-fragment@0.0.230:
|
||||||
|
version "0.0.230"
|
||||||
|
resolved "https://registry.yarnpkg.com/code-error-fragment/-/code-error-fragment-0.0.230.tgz#d736d75c832445342eca1d1fedbf17d9618b14d7"
|
||||||
|
integrity sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==
|
||||||
|
|
||||||
code-point-at@^1.0.0:
|
code-point-at@^1.0.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
|
||||||
@@ -1721,7 +1726,7 @@ graceful-fs@^4.1.0, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2
|
|||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
|
||||||
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
|
integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
|
||||||
|
|
||||||
grapheme-splitter@^1.0.2:
|
grapheme-splitter@^1.0.2, grapheme-splitter@^1.0.4:
|
||||||
version "1.0.4"
|
version "1.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
|
resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e"
|
||||||
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
|
integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==
|
||||||
@@ -2200,6 +2205,14 @@ json-stringify-safe@~5.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
|
||||||
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
|
||||||
|
|
||||||
|
json-to-ast@^2.1.0:
|
||||||
|
version "2.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/json-to-ast/-/json-to-ast-2.1.0.tgz#041a9fcd03c0845036acb670d29f425cea4faaf9"
|
||||||
|
integrity sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==
|
||||||
|
dependencies:
|
||||||
|
code-error-fragment "0.0.230"
|
||||||
|
grapheme-splitter "^1.0.4"
|
||||||
|
|
||||||
json5@^2.1.0:
|
json5@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850"
|
resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850"
|
||||||
|
|||||||
Reference in New Issue
Block a user