json-dry
json-dry copied to clipboard
string with ~ break Dry.parse
Use case that break parse:
console.log(Dry.parse('{"path": "~/projects"}'));
return {"path": undefined}
for internal ref usage, it should not be string that can easily by used by user. Maybe something like:
{"__dry__": "ref", "value": "projects"}
if the object have prop __dry__
it mean it internal object and not real object provided by user.
True, that would break parsing. But if you stringify that object using Dry.stringify instead of regular JSON.stringify it would be escaped.
Though using an object instead of a string could be a good idea, I'll have to do some tests.
+1 for using an object for references.
@nevcos, @jcubic: Well, it could improve speed a bit (as we could do away with the code that ensures strings don't start with a ~
tilde in it)
Currently the code already uses objects for instances and such, these look like:
{
dry : 'toDry',
value : {...},
drypath : [...]
}
So I could replace it with
{
dry : 'ref',
drypath : ['path', 'to', 'value']
}
That would make everything more consistent.
There's also the option to use arrays
['~', 'path', 'to', 'value']
That would be a bit less verbose, but maybe less readable?
And then about the property name: currently just dry
is used to identify a special object. I'm open to change that to something like _dry
, though currently I don't think it would cause many collisions since you would also need a value
property in the same object.
I'm not sure how json-dry works internally, but thought I'd point out that JSON.stringify
executes the toJSON
method of the objects it encounters. So, in theory, you could map every occurrence of an object in the target to {value: obj, toJSON: '~objName'}
, then run JSON.stringify
on your resulting "map", parse that result, then shove the original into a non-iterable Symbol prop so Dry.parse
can easily retrieve it.
That was a lot of words. I'm not sure it makes sense. If I didn't have my own project I need to work on this weekend, I might try to write some code for it =P
I take that back. Dry.stringify
returns a string (as I now realize the name implies). That string should be unique to Dry. So instead of returning:
{
"reference_one": {
"date": {
"dry": "date",
"value": "2018-01-14T17:45:57.989Z"
},
"regex": {
"dry": "regexp",
"value": "/test/i"
}
},
"reference_two": "~reference_one",
"date": "~reference_one~date"
}
which is regular JSON that can be parsed by JSON.parse
, you should return something like:
{
"reference_one": {
"date": {
"dry": "date",
"value": "2018-01-14T17:45:57.989Z"
},
"regex": {
"dry": "regexp",
"value": "/test/i"
}
},
"reference_two": :reference_one,
"date": :reference_one.date
}
It's un-parsable by JSON.parse
which is a hidden requirement of this project since no code/library outside of Dry should be able to operate on this string since it's a unique view of a circular JSON structure. Granted, this means that you now have to write your own parser, but that's half of the fun =P
An earlier iteration of json-dry actually contained its own json.js based parser, but it was more trouble than it's worth.
Also: the stringifying is an afterthought. Dry.stringify
is actually just a JSON.stringify
wrapper around Dry.toDryObject
.
So json-dry actually first creates an intermediate object and then stringifies that using the built-in JSON parser. And yeah: this is much faster than using a custom stringifier/parser :)
If you're wondering why such an intermediate object would be useful: it's for times when you can use a structured clone (like in IndexedDB or web workers), which is (again) a lot faster.
And backwards compatibility with json is important. If you would first use JSON.parse
ton a json-dry string you would get a valid object. That valid object can then still be given to Dry.parse