Skip to content

Feature request: Add JSON path parameter to JSONVisitor functions #50

Closed
@Marcono1234

Description

@Marcono1234

Rationale

The JSONVisitor is quite useful for validating the content of a JSON document (and getting locations of incorrect data). However, currently it is rather cumbersome to find out at which JSON path in the document the parser is when a visitor function is called.

Suggestion

It would therefore be good if some of the JSONVisitor functions had an extra parameter for the JSONPath of the currently visited element:

  • onObjectBegin, onArrayBegin, onLiteralValue
  • onObjectProperty: Here the property which is visited should probably not be part of the JSON path

For the other functions adding a JSONPath would probably either not add much value (onObjectEnd, onSeparator, onArrayEnd), or its behavior cannot be defined very well (onComment, onError).

However, because JSONPath is a mutable array (and is therefore modified when the parser proceeds), it would be sanest to only hand out copies of it to the visitor functions. A performant way in which this could be implemented is to have a supplier function of JSON path so the copy is only created when the user actually uses the JSON path. For example:

export interface JSONVisitor {
    onObjectBegin?: (
        offset: number,
        length: number,
        startLine: number,
        startCharacter: number,
        pathSupplier: () => JSONPath
    ) => void;

    ...
}

Based on the TypeScript documentation adding an extra function parameter should not be an issue.

What do yo think?

Workaround

Users implementing JSONVisitor can manually maintain a JSON path array, updating it in the respective visitor functions.

Demo implementation (might contain bugs)
const path = []

jsoncParser.visit(jsonContent, {
    onError(error, offset, length, startLine, startCharacter) {
        // ... error handling
    },
    onArrayBegin() {
        path.push(0)
    },
    onArrayEnd() {
        path.pop()
    },
    onSeparator() {
        // Check if inside of array (and therefore path element is array index)
        if (typeof path[path.length - 1] === "number") {
            path[path.length - 1]++
        }
    },
    onObjectBegin() {
        // Push temporary placeholder for object property names
        path.push(undefined)
    },
    onObjectEnd() {
        path.pop()
    },
    onObjectProperty(property, offset, length, startLine, startCharacter) {
        path[path.length - 1] = property
    },
    onLiteralValue(value, offset, length, startLine, startCharacter) {
        // ... process value
    }
})

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature-requestRequest for new features or functionality

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions