json-dry icon indicating copy to clipboard operation
json-dry copied to clipboard

string with ~ break Dry.parse

Open jcubic opened this issue 7 years ago • 6 comments

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.

jcubic avatar Jan 20 '18 15:01 jcubic

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.

skerit avatar Jan 20 '18 16:01 skerit

+1 for using an object for references.

nevcos avatar Jan 22 '18 08:01 nevcos

@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.

skerit avatar Jan 22 '18 11:01 skerit

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

THEtheChad avatar Jan 27 '18 17:01 THEtheChad

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

THEtheChad avatar Jan 27 '18 18:01 THEtheChad

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

skerit avatar Jan 29 '18 13:01 skerit