jom

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 30, 2021 License: GPL-3.0 Imports: 19 Imported by: 0

Documentation

Overview

Implementation of json_map.JsonMapInt along with some other helper functions which relate to the JOM.

JsonMap should not be used directly, json_map.JsonMapInt should be used instead for variable declaration, then jom.New, Unmarshal, etc. for creating a JsonMap.

Example

How to create a new JSON map which contains a script and how to mark it up with other script types.

jsonMap := New()
err := jsonMap.Unmarshal([]byte(`
	{
		hello: world
		script: 
			'''#//!js
			json.trail['hello'] += '/js';
			'''
	}
	`))
if err != nil {
	panic(err)
}

// We evaluate the JOM to run the JS script in the "script" key.
jsonMap.Run()

// We can use the MustSet/JsonPathSetter function to set a callback within the JOM that will run natively in Go.
// Note: Go callbacks and scripts written as strings directly within the JOM cannot be executed at the same time
//       due to the way the JOM is serialised and passed to the JS VM.
jsonMap.MustSet("$.script", func(json json_map.JsonMapInt) {
	insides := json.GetInsides()
	(*insides)["hello"] = (*insides)["hello"].(string) + "/go"
})

// We evaluate the JOM to run the Go callback in the "script" key.
jsonMap.Run()

// The String implementation of JsonMap will Marshall the JOM to hjson, then convert to a string.
fmt.Println(jsonMap)
Output:

{
  hello: world/js/go
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Eval

func Eval(jsonBytes []byte, verbose bool) (out []byte, err error)

Evaluates the scripts within a given hjson byte array.

Should really only be called from within CLI main. Returns the evaluated JSON as a byte array and nil if everything is good. Otherwise an empty byte array and an error will be returned if an error occurs.

Example

Eval takes a JOM in the form of hjson byte array, runs all scripts within it and returns the evaluated byte array as JSON (not hjson).

Ideal for evaluating a JOM read from a file and saving to another file.

out, _ := Eval([]byte(`
	{
		eval: ""
		script:
			'''#//!js
			json.trail["eval"] = "does this!";
			'''
	}
	`), false)
fmt.Println(string(out))
Output:

{"eval":"does this!"}

Types

type JsonMap

type JsonMap struct {

	// Whether or not the JSON has an Array at its root
	Array bool
	// contains filtered or unexported fields
}

Wrapper for map[string]interface{} that can be easily extensible with more functionality.

func New

func New() *JsonMap

Construct a new empty JsonMap.

Returns a pointer to a JsonMap.

func NewFromMap

func NewFromMap(jsonMap map[string]interface{}) *JsonMap

Constructs a new JsonMap from the given string->interface{} map.

Returns a pointer to a JsonMap.

func (*JsonMap) Clone

func (jsonMap *JsonMap) Clone(clear bool) json_map.JsonMapInt

Return a clone of the JsonMap. If clear is given then New will be called but "Array" field will be inherited.

Note: This is primarily used when using json_map.JsonMapInt to return a new JsonMap to avoid cyclic imports.

func (*JsonMap) FindScriptFields

func (jsonMap *JsonMap) FindScriptFields() (found bool)

Finds all the script and non-script fields within a JsonMap.

Updates the script and nonScript fields within the JsonMap's traversal object. Scripts will be replaced by a code.Code value which contains the runnable.

func (*JsonMap) GetAbsolutePaths

func (jsonMap *JsonMap) GetAbsolutePaths(absolutePaths *json_map.AbsolutePaths) (values []*json_map.JsonPathNode, errs []error)

Given the list of absolute paths for a JsonMap, will return the list of values that said paths lead to.

An absolute path is an array of json_map.AbsolutePathKey(s), each of which represent a descent down the JsonMap. Will start a goroutine for each absolute path slice in the given json_map.AbsolutePaths struct meaning that lookup is pretty fast.

func (*JsonMap) GetCurrentScopePath

func (jsonMap *JsonMap) GetCurrentScopePath() string

Returns the current scopes JSON Path to itself.

This just uses the string builder within the traversal field.

func (*JsonMap) GetInsides

func (jsonMap *JsonMap) GetInsides() *map[string]interface{}

Getter for insides. Useful when using json_map.JsonMapInt

func (*JsonMap) IsArray

func (jsonMap *JsonMap) IsArray() bool

Checks whether the JsonMap is an array at its root.

func (*JsonMap) JsonPathSelector

func (jsonMap *JsonMap) JsonPathSelector(jsonPath string) (out []*json_map.JsonPathNode, err error)

Given a valid JSON path will return the list of pointers to json_map.JsonPathNode(s) that satisfies the JSON path.

A wrapper for json_map.ParseJsonPath and GetAbsolutePaths. Note: The JSON path syntax is very particular. If a JSON path is not being parsed make sure it looks like the below examples.

This function supports the following JSON path syntax:

Property selection

Selects a property from a map.

.property
// BUT NOT
['property']

Element selection

Selects an element from an array. If a comma separated list is given this will give a new list of the elements at the given indices.

[n]
// OR
[x, y, z]

First descent

"...+" descends down the alphabetically first map/array. Any dots following "..." will indicate another first ascent.

...property

For example:

.....property

Will perform first ascent three times.

Recursive lookup

Takes precedence over First descent. Searches for all the properties of the given name.

..property

Wildcards

Selects all values/elements from a map or an array respectively.

// Key-values
.property.*
// Elements
property[*]

List slicing

Slice a list from start to finish. Supports one missing side and negative indices. Similar to python list slicing.

// From <start> to <end>
[start:end]
// From <start> to the end of the array
[start:]
// From the last <start> elements to the end of the array
[-start:]
// From the start of the array to <end> element
[:end]
// The entire array excluding the last <end> elements
[:-end]
// NOT SUPPORTED
[:]

Filter expressions

A filter expression will be run against every value within a map and every element in an array. The resulting array it will produce will be all the values on which the filter expression evaluated to true. Any JS expression which can be processed by the Otto interpreter can be run as a filter expression. Therefore the expression must be a boolean expression or one which can be cast to boolean using "!!".

[?(expression)]

The current node can be referred to using the '@' character.

$.property[?(@.name)]

Any JSON paths used within an expression will also be evaluated from the current scope.

$.property[?($[0].name == @.name)]

func (*JsonMap) JsonPathSetter

func (jsonMap *JsonMap) JsonPathSetter(jsonPath string, value interface{}) (err error)

Given a valid JSON path: will set the values pointed to by the JSON path to be the value given.

If nil is given as the value then the pointed to elements will be deleted. A wrapper for json_map.ParseJsonPath -> SetAbsolutePaths.

func (*JsonMap) MarkupCode

func (jsonMap *JsonMap) MarkupCode(jsonPath string, shebangName string, script string) (err error)

Adds the given script of the given shebangName (must be a supported language) at the path pointed to by the given jsonPath.

This just validates the given shebangName, constructs the script with the appropriate shebang and runs JsonPathSetter on the given jsonPath with the constructed script as a value.

func (*JsonMap) Marshal

func (jsonMap *JsonMap) Marshal() (out []byte, err error)

Marshal a JsonMap back into JSON.

func (*JsonMap) MustDelete

func (jsonMap *JsonMap) MustDelete(jsonPath string)

A wrapper for MustSet(jsonPath, nil).

Example

Deleting a key from a JSON map using a JSON path.

jsonMap := New()
_ = jsonMap.Unmarshal([]byte(`
	{
		hello: world
		friends: [
			{
				name: Jeff
				age: 20
			}
			{
				name: Bob
				age: 24
			}
			{
				name: Tim
				age: 38
			}
		]
	}
	`))

// Deleting the "hello" key-value pair pointed to by "$.hello"
jsonMap.MustDelete("$.hello")

fmt.Println(jsonMap)
Output:

{
  friends:
  [
    {
      age: 20
      name: Jeff
    }
    {
      age: 24
      name: Bob
    }
    {
      age: 38
      name: Tim
    }
  ]
}

func (*JsonMap) MustGet

func (jsonMap *JsonMap) MustGet(jsonPath string) (out []interface{})

Like JsonPathSelector, only it panics when an error occurs and returns an []interface{} instead of []json_map.JsonPathNode.

The type of out depends on how many results were returned:

• If no == 0 then out == nil.

• If no > 0 then out == []interface{}.

Example

Getting a key from a JSON map using a JSON path.

jsonMap := New()
_ = jsonMap.Unmarshal([]byte(`
	{
		hello: world
		friends: [
			{
				name: Jeff
				age: 20
			}
			{
				name: Bob
				age: 24
			}
			{
				name: Tim
				age: 38
			}
		]
	}
	`))

// Getting the "hello" key-value pair pointed to by "$.hello"
nodes := jsonMap.MustGet("$.hello")

fmt.Println(nodes[0].(string))
Output:

world

func (*JsonMap) MustPop

func (jsonMap *JsonMap) MustPop(jsonPath string, indices ...int) (popped []interface{})

Pops from an []interface{} indicated by the given JSON path at the given indices and panics if any errors occur.

NOTE: this assumes that the JSON path points to an array and will use JsonPathSetter to set the JSON path to be the array selected + the pushed values.

Indices conditions:

• If no indices are given delete value at the start of the array.

• If duplicates occur then they will be ignored/removed.

• Can be unsorted (will be sorted within function).

• Indices that are not within the range of the array will be ignored.

Example

Popping a friend from the "friends" array.

jsonMap := New()
_ = jsonMap.Unmarshal([]byte(`
	{
		hello: world
		friends: [
			{
				name: Jeff
				age: 20
			}
			{
				name: Bob
				age: 24
			}
			{
				name: Tim
				age: 38
			}
		]
	}
	`))

// Popping the head of the "$.friends" array.
popped := jsonMap.MustPop("$.friends")

fmt.Println(popped[0].(map[string]interface{}))
fmt.Println(jsonMap)
Output:

map[age:20 name:Jeff]
{
  friends:
  [
    {
      age: 24
      name: Bob
    }
    {
      age: 38
      name: Tim
    }
  ]
  hello: world
}

func (*JsonMap) MustPush

func (jsonMap *JsonMap) MustPush(jsonPath string, value interface{}, indices ...int)

Pushes to an []interface{} indicated by the given JSON path at the given indices and panics if any errors occur.

Note: This assumes that the JSON path points to an array and will use JsonPathSetter to set the JSON path to be the array selected + the pushed values.

Indices conditions:

• If no indices are given insert value at the end of the array (len(arr)).

• If duplicates occur then they will be ignored/removed.

• Can be unsorted (will be sorted within function).

• If a given index is greater than the length of the array to insert to, all empty spaces will be filled with nil.

Example

Pushing a new friend to "friends" array.

jsonMap := New()
_ = jsonMap.Unmarshal([]byte(`
	{
		hello: world
		friends: [
			{
				name: Jeff
				age: 20
			}
			{
				name: Bob
				age: 24
			}
			{
				name: Tim
				age: 38
			}
		]
	}
	`))

// Pushing a new map[string]interface{} to "$.friends" array
jsonMap.MustPush("$.friends", map[string]interface{}{
	"name": "David",
	"age":  32,
})

fmt.Println(jsonMap)
Output:

{
  friends:
  [
    {
      age: 20
      name: Jeff
    }
    {
      age: 24
      name: Bob
    }
    {
      age: 38
      name: Tim
    }
    {
      age: 32
      name: David
    }
  ]
  hello: world
}

func (*JsonMap) MustSet

func (jsonMap *JsonMap) MustSet(jsonPath string, value interface{})

Like JsonPathSetter, only it panics when an error occurs.

Example

Setting a key from a JSON map using a JSON path.

jsonMap := New()
_ = jsonMap.Unmarshal([]byte(`
	{
		hello: world
		friends: [
			{
				name: Jeff
				age: 20
			}
			{
				name: Bob
				age: 24
			}
			{
				name: Tim
				age: 38
			}
		]
	}
	`))

// Setting the "hello" key-value pair pointed to by "$.hello" to "me"
jsonMap.MustSet("$.hello", "me")

fmt.Println(jsonMap)
Output:

{
  friends:
  [
    {
      age: 20
      name: Jeff
    }
    {
      age: 24
      name: Bob
    }
    {
      age: 38
      name: Tim
    }
  ]
  hello: me
}

func (*JsonMap) Run

func (jsonMap *JsonMap) Run()

Given a JsonMap this will traverse it and execute all scripts. Will update the given JsonMap in place.

• All scripts will be run and removed from the JsonMap.

• In cases where there are more than one script tag on a level: scripts will be evaluated in lexicographical script-key order.

func (*JsonMap) SetAbsolutePaths

func (jsonMap *JsonMap) SetAbsolutePaths(absolutePaths *json_map.AbsolutePaths, value interface{}) (err error)

Given the list of absolute paths for a JsonMap: will set the values pointed to by the given JSON path to be the given value.

If a value of nil is given the structures pointed to by the absolute paths will be deleted. To avoid race conditions this routine runs single threaded which means this operation can be significantly slower than getting values. It's important to bear this in mind.

func (*JsonMap) String

func (jsonMap *JsonMap) String() string

Marshals the JsonMap into hjson and returns the stringified byte array.

func (*JsonMap) Strip

func (jsonMap *JsonMap) Strip()

Strips any script key-value pairs found within the JsonMap and updates it in place.

This is essentially just a wrapper for FindScriptFields which just sets insides to be traversal.nonScript.

func (*JsonMap) Unmarshal

func (jsonMap *JsonMap) Unmarshal(jsonBytes []byte) (err error)

Unmarshal a hjson byte string and package it as a JsonMap.

type Traversal

type Traversal struct {
	// contains filtered or unexported fields
}

Holds some info about the current traversal of the JOM.

Used when evaluating a JsonMap.

Directories

Path Synopsis
Contains the JsonMapInt interface which should be used in signatures as well as constants and types relating to AbsolutePaths and JSON path parsing to AbsolutePaths.
Contains the JsonMapInt interface which should be used in signatures as well as constants and types relating to AbsolutePaths and JSON path parsing to AbsolutePaths.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL