jhermsmeier/node-vcf

What is get returning?

bitwombat opened this issue · 3 comments

I'm absolutely bumfuzzled by what get returns.

My code looks something like:

    var photo = card.get( 'photo' );

If I console.log( photo ), I get:

{ [String: '<bunch of base64 data>'] encoding: 'BASE64', type: 'jpeg' }

What throws me so severely is that this is supposedly an object (starts with {) but it's made up of an array which doesn't have a property as a key, then no comma between that array's end and the property 'encoding'. Huh?

So I do a JSON.stringify( photo, null, 4 ) and get:

[
    "photo",
    {
        "encoding": "BASE64",
        "type": "jpeg"
    },
    "text",
    "<bunch of base64 data>"
]

Why that's different, I don't know, but it at least looks like a proper JavaScript data structure. It's an array, yet when I console.log( photo[0] ) I get "undefined".

I've stuck debug console.logs in the source and so know it's returning this.data[ key ].clone() (confirmed with typeof), but that's not helping me make sense of this, or get my photo data!

I also know, from test/photo.js, that it's a vCard.Property. Still confused :)

Never seen anything like this! My JS must improve!

Answer: My photo's data is in photo['_data']. The confusion above is probably because of the toString function in lib/property.js, but I'm too unsure, and it's too late, for me to do a PR :)

I understand you completely - I was worried it might be too confusing. Documentation will help a lot, once I get around to writing it, because what's going on behind the scene is rather simple.

TL;DR: card.get( 'propname' ) either returns a vCard.Property instance, or an array of those (or null/undefined if not set).

So, first of all, the weird display of it if you console.log() it, is due to .valueOf() returning a string, whereas the vCard.Property object is not and does not inherit from String, which still makes the log formatter think it's a String object with additional "own" properties on it.
The following illustrates that a bit:

> var s = new String('somevalue')
undefined
> s.someProp = 123
123
> console.log(s)
{ [String: 'somevalue'] someProp: 123 }

Second, the reason why JSON.stringify( prop ) does not yield the actual data structure is that I'm using the .toJSON() method to return the jCard equivalent of the vCard, or vCard property in this case. Reasoning behind that was to easily convert between vCards and jCards (also because turning jCards into hCards is easier):

var card = vCard.parse(data)
var jcard = card.toJSON()
var card = vCard.fromJSON( jcard )

The actual structure and functionality can be inspected in lib/property.js, where you'll see that it's just

Property {
  _field: 'photo',
  _data: 'base64mumblemumble',
  encoding: 'BASE64',
  type: 'jpeg'
}

where .toString() returns the vCard format, .toJSON() the jCard format, and .valueOf() the ._data (the actual value of the property in question).

Makes sense!

I should have known that's what the console.log format meant...

Thanks for the explanation.