Skip to content

Commit

Permalink
[DJSON-ACTION]: Json dynamic parser
Browse files Browse the repository at this point in the history
  • Loading branch information
amadolid committed Dec 11, 2023
1 parent dcae5fd commit 0fedf37
Show file tree
Hide file tree
Showing 4 changed files with 440 additions and 0 deletions.
1 change: 1 addition & 0 deletions jaseci_core/jaseci/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ def load_standard():
import jaseci.extens.act_lib.stripe # noqa
import jaseci.extens.act_lib.regex # noqa
import jaseci.extens.act_lib.maths # noqa
import jaseci.extens.act_lib.djson # noqa


load_standard()
130 changes: 130 additions & 0 deletions jaseci_core/jaseci/extens/act_lib/djson.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
"""Built in actions for Jaseci"""
from jaseci.jsorc.live_actions import jaseci_action
from json import loads, dumps
from re import compile

internal = compile(r"\(([a-zA-Z0-9_\.\$]*?)\)")
full = compile(r"^\{\{([a-zA-Z0-9_\.\$\(\)]*?)\}\}$")
partial = compile(r"\{\{([a-zA-Z0-9_\.\$\(\)]*?)\}\}")


def convert_dict(value) -> dict:
try:
if isinstance(value, str):
return loads(value)
else:
return dict(value)
except:
return "Error JSON loads!"


def convert_str(value) -> str:
if isinstance(value, (dict, list)):
return dumps(value)
else:
return "" if value == None else str(value)


def get_deep_value(keys: list[str], source, default):
if len(keys) == 0:
return source

key = keys.pop(0)
_type = type(source)
if _type is dict and key in source:
return get_deep_value(keys, source[key], default)
elif _type is list and key.isnumeric():
return get_deep_value(keys, source[int(key)], default)
else:
return default


def get_value(jpath: str, source, default=None):
while internal.search(jpath):
for intern in internal.findall(jpath):
jpath = jpath.replace(
"(" + intern + ")", convert_str(get_value(intern, source, ""))
)

if jpath:
keys = jpath.split(".")
key = keys.pop(0)
if key == "$":
if isinstance(source, (dict, list)):
return get_deep_value(keys, source, default)
elif len(keys) == 0:
return source
elif key == "$s":
if isinstance(source, (dict, list)):
return convert_str(get_deep_value(keys, source, default))
elif len(keys) == 0:
return convert_str(source)
elif key == "$i":
if isinstance(source, (dict, list)):
value = get_deep_value(keys, source, default)
return 0 if value == None else int(value)
elif len(keys) == 0:
return 0 if source == None else int(source)
elif key == "$d":
if isinstance(source, (dict, list)):
return convert_dict(get_deep_value(keys, source, default))
elif len(keys) == 0:
return convert_dict(source)
else:
pass
# for future syntax
return default


def parse_str(key: str, value: str, target, source):
matcher = full.match(value)
if matcher:
value = get_value(matcher.group(1), source)
else:
for jpath in partial.findall(value):
value = value.replace(
"{{" + jpath + "}}", convert_str(get_value(jpath, source, ""))
)

if key:
target[key] = value
else:
return value


def traverse_dict(target: dict, source):
for key in target.keys():
traverse(key, target[key], target, source)


def traverse_list(target: list, source):
for key, value in enumerate(target):
traverse(key, value, target, source)


def traverse(key, value, target, source):
_type = type(value)
if _type is dict:
traverse_dict(value, source)
elif _type is list:
traverse_list(value, source)
elif _type is str:
parse_str(key, value, target, source)


@jaseci_action()
def parse(source, target):
"""
Dynamic parsing of target dict or list
Return - parsed target object
"""
_type = type(target)
if _type is dict:
traverse_dict(target, source)
elif _type is list:
traverse_list(target, source)
elif _type is str:
return parse_str(None, target, None, source)

return target
224 changes: 224 additions & 0 deletions jaseci_core/jaseci/extens/act_lib/tests/fixtures/djson.jac
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
walker parser {
can djson.parse;
with entry {

report "[1]: whole source";
report djson.parse(
{"a": 1},
{"b": "{{$}}"}
);

report "[2]: whole source cast to string";
report djson.parse(
{"a": 1},
{"b": "{{$s}}"}
);

report "[3]: int";
report djson.parse(
{"a": 1},
{"b": "{{$.a}}"}
);

report "[4]: int cast to string";
report djson.parse(
{"a": 1},
{"b": "{{$s.a}}"}
);

report "[5]: int partial";
report djson.parse({"a": 1},
{"b": "partial-{{$.a}}"}
);

report "[6]: string";
report djson.parse(
{"a": "1"},
{"b": "{{$.a}}"}
);

report "[7]: string partial";
report djson.parse(
{"a": "1"},
{"b": "partial-{{$.a}}"}
);

report "[8]: int list";
report djson.parse(
{"a": [1]},
{"b": "{{$.a}}"}
);

report "[9]: int list cast to string";
report djson.parse(
{"a": [1]},
{"b": "{{$s.a}}"}
);

report "[10]: int list partial";
report djson.parse(
{"a": [1]},
{"b": "partial-{{$.a}}"}
);

report "[11]: int list index";
report djson.parse(
{"a": [1]},
{"b": "{{$.a.0}}"}
);

report "[12]: string list";
report djson.parse(
{"a": ["1"]},
{"b": "{{$.a}}"}
);

report "[13]: string list cast to string";
report djson.parse(
{"a": ["1"]},
{"b": "{{$s.a}}"}
);

report "[14]: string list partial";
report djson.parse(
{"a": ["1"]},
{"b": "partial-{{$.a}}"}
);

report "[15]: string list index";
report djson.parse(
{"a": ["1"]},
{"b": "{{$.a.0}}"}
);

report "[16]: dict";
report djson.parse(
{"a": {"test": 1}},
{"b": "{{$.a}}"}
);

report "[17]: dict cast to string";
report djson.parse(
{"a": {"test": 1}},
{"b": "{{$s.a}}"}
);

report "[18]: dict partial";
report djson.parse(
{"a": {"test": 1}},
{"b": "partial-{{$.a}}"}
);

report "[19]: nested dict";
report djson.parse(
{"a": {"test": 1}},
{"b": "{{$.a.test}}"}
);

report "[20]: nested dict cast to string";
report djson.parse(
{"a": {"test": 1}},
{"b": "{{$s.a.test}}"}
);

report "[21]: nested dict partial";
report djson.parse(
{"a": {"test": 1}},
{"b": "partial-{{$.a.test}}"}
);

report "[22]: super nested dict that returns the value";
report djson.parse(
{"a": {"test": [{
"a":1,
"b":2,
"c":3
}]}},
"{{$.a.test.0.c}}"
);

report "[23]: string target";
report djson.parse(
{"a": "1"},
"{{$.a}}"
);

report "[24]: string target";
report djson.parse(
{"a": "1"},
"{{$.a}}"
);

report "[25]: string target partial";
report djson.parse(
{"a": "1"},
"partial-{{$.a}}"
);

report "[26]: string source";
report djson.parse(
"testing",
{"b": "{{$}}"}
);

report "[27]: string source partial";
report djson.parse(
"testing",
{"b": "partial-{{$}}"}
);

report "[28]: int source";
report djson.parse(
1,
{"b": "{{$}}"}
);

report "[29]: int source cast";
report djson.parse(
1,
{"b": "{{$s}}"}
);

report "[30]: int source partial";
report djson.parse(
1,
{"b": "partial-{{$}}"}
);

report "[31]: int source string target";
report djson.parse(
1,
"{{$}}"
);

report "[32]: int source string target cast";
report djson.parse(
1,
"{{$s}}"
);

report "[33]: not existing";
report djson.parse(
{"a": {"b": 1}},
{"b": "{{$.a.c}}"}
);

report "[34]: not existing cast to string empty";
report djson.parse(
{"a": {"b": 1}},
{"b": "{{$s.a.c}}"}
);

report "[35]: string source cast to dict";
report djson.parse(
"{}",
"{{$d}}"
);

report "[36]: string source cast to int";
report djson.parse(
"1",
"{{$i}}"
);
}
}
Loading

0 comments on commit 0fedf37

Please sign in to comment.