Nykakin / chompjs

Parsing JavaScript objects into Python data structures
MIT License
197 stars 11 forks source link

Handle JavaScript spread operator #53

Open Nykakin opened 1 year ago

Nykakin commented 1 year ago

Allow parsing objects using JavaScript spread syntaxt:

let entry = { name: "Test", value: "drive"};
let expanded_entry = { ...entry, "new": "data"};

let names = ["John", "Joe", "Jack"];
let expanded_names = [...names, "James"];

Currently it's not possible:

>>> chompjs.parse_js_object('{ ...entry, "new": "data"}')
Traceback (most recent call last):
    ...
json.decoder.JSONDecodeError: Expecting ':' delimiter: line 1 column 12 (char 11)
>>> chompjs.parse_js_object('[...names, "James"]')
Traceback (most recent call last):
    ...
ValueError: Error parsing input near character 4

I guess expected output should be {"new": "data"} and ["James"] and entries marked with triple dots should be ignored.

Nykakin commented 1 year ago

Looks like expanding in place is not trivial to handle:

let expanded_entry = { ...{'a': 12, "new": "data"}};

This is just the same as {'a': 12, 'new': 'data'} but if we ignore stuff after ... operator then using chompjs.parse_js_object(" { ...{'a': 12, "new": "data"}}") will return an empty dictionary, which is not optimal.

I need to think how to properly tackle this input.

Nykakin commented 1 year ago

After some though I've figured out a possible API. There should be a new function, parse_nested_js_object than attempts to expands all JSON objects. If expanded object is a variable then it needs to be passed down as a keyword arguments. Either a string or a list/dict should be accepted. So it should looks like this:

s = '''let expanded_entry = { ...{'a': 12, "new": "data"}};'''
chompjs.parse_nested_js_object(s) # returns {'a': 12, 'new': 'data'}

e = '''let entry = { name: "Test", value: "drive"};'''
s = '''let expanded_entry = { ...entry, "new": "data"};'''
chompjs.parse_nested_js_object(s, entry=e) # returns {"name": "Test", value: "drive", "new", "data"}

e = '''let names = [["John", "Joe", "Jack"], ["Kevin", "Alice", "Bob"], ["Helen", "Mike"]];'''
s = '''let expanded_names = [...names[0], ...names[1], "James"];'''
names = chompjs.parse_js_object(e)
chompjs.parse_nested_js_object(s, {"names[0]": names[0], "names[1]": names[1]}) # returns ["John", "Joe", "Jack", "Kevin", "Alice", "Bob", "James"]