Skip to content

Commit

Permalink
Update lib/vcard: Fix trim empty lines in .parse()
Browse files Browse the repository at this point in the history
  • Loading branch information
jhermsmeier committed Jun 25, 2016
1 parent 55607da commit 7c8dd84
Showing 1 changed file with 74 additions and 74 deletions.
148 changes: 74 additions & 74 deletions lib/vcard.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
* @return {vCard}
*/
function vCard( data ) {

if( !(this instanceof vCard) )
return new vCard( data )

this.version = '4.0'

if( data != null ) {
this.parse( data )
}

}

// Exports
Expand All @@ -36,34 +36,34 @@ vCard.parse = function parse( data ) {
/**
* Folds a long line according to the RFC 5322.
* <http://tools.ietf.org/html/rfc5322#section-2.1.1>
*
* @param {String} input
* @param {Number} maxLength
* @param {Boolean} hardWrap
* @return {String}
*
* @param {String} input
* @param {Number} maxLength
* @param {Boolean} hardWrap
* @return {String}
*/
vCard.foldLine = function foldLine( input, maxLength, hardWrap ) {

// Remove any newlines
input = input.replace( /\r?\n/g, '' )

// RFC compliant default line length
maxLength = maxLength && maxLength > 5
? maxLength : 78

// We really don't need to fold this
if( input.length <= maxLength )
return input

// Substract 3 because CRLF<space> is the line delimiter
// (3 bytes + 1 <space> extra because of soft folding)
maxLength = maxLength - 4

const CRLF = '\r\n'

var lines = [], len = input.length
var lastIndex = 0, index = 0

if( !hardWrap ) {
while( ~(lastIndex = input.lastIndexOf( ' ', maxLength + index )) ) {
if( lastIndex <= index ) { break }
Expand All @@ -76,43 +76,43 @@ vCard.foldLine = function foldLine( input, maxLength, hardWrap ) {
}
}
}

// We remove the one <space> extra here again,
// since we're going into hard folding mode
maxLength++

while( index < len ) {
lines.push( input.slice( index, index += maxLength ) )
}

return lines.join( CRLF + ' ' )

}

/**
* vCard prototype
* @type {Object}
*/
vCard.prototype = {

constructor: vCard,

/**
* [set description]
* @param {String} key
* @param {Mixed} value
* @param {Object} params
*/
set: function( key, value, params ) {

// Enable omitting the value argument
if( arguments.length === 2 ) {
params = value
value = null
} else {
params.data = value
}

// Handle multiple entries with the same key
if( this[ key ] ) {
Array.isArray( this[ key ] ) ?
Expand All @@ -121,33 +121,33 @@ vCard.prototype = {
} else {
this[ key ] = params
}

return this

},

/**
* [parse description]
* @param {String} data
* @return {vCard}
*/
parse: function( data ) {

// Normalize and split into lines
var lines = ( data + '' )
// Trim whitespace
.replace( /^\s+|\s+$/g, '' )
// Trim blank lines
.replace( /\r?\n(\s+|$)/g, '' )
.replace( /(\r?\n)\s*(\r?\n)|$/g, '$1' )
// Unfold folded lines
.replace( /\r?\n[\x20\x09]+/g, '' )
// Split into lines
.split( /\r?\n/g )

// Bail out, if we got nothing to parse
if( !lines.length )
return

// Keep begin, version and end markers
// for eventual error messages
var begin = lines[0]
Expand All @@ -160,158 +160,158 @@ vCard.prototype = {
'Invalid format: expected "BEGIN:VCARD" but found "'+ begin +'"'
)
}

// Check for the end marker
if( !/END:VCARD/i.test( end ) ) {
throw new SyntaxError(
'Invalid format: expected "END:VCARD" but found "'+ end +'"'
)
}

// Check for version number
if( !/VERSION:\d\.\d/i.test( version ) ) {
throw new SyntaxError(
'Invalid format: expected "VERSION:\\d.\\d" but found "'+ version +'"'
)
}

// Process each line
for( var i = 1; i < lines.length - 1; i++ ) {
this.parseLine( lines[i] )
}

return this

},

/**
* [parseLine description]
* @param {String} line
* @return {vCard}
*/
parseLine: function( line ) {

var match = line
// Trim whitespace
.replace( /^\s+|\s+$/g, '' )
// Match key / value
.match( /^([^:;]+)[;:](.*)$/i )

if( match == null ) {
throw new SyntaxError(
'Invalid format: "'+ line + '"'
)
}

// Normalize key & value
var key = match[1].toLowerCase().replace( /-/g, '_' )
var value = match[2].replace( /^\s+|\s+$/g, '' )

// Field data object
var field = {}

// Extract PARAM="VAL,VAL;VAL" (escaped value)
// and PARAM=VAL,VAL (multi value)
value = value.replace(
/(?:(?:([a-z0-9-]+)=(")([^"]+)")|(?:([a-z0-9-]+)=([^";:]+)))(?:[;:])/ig,
function setParam( match ) {

var escaped = arguments[2] === '"'
var value = arguments[3] || arguments[5]
var key = ( arguments[1] || arguments[4] )
.toLowerCase().replace( /-/g, '_' )

var values = value.split( /\s*,\s*/g )

values.length < 2 || escaped ?
field[ key ] = value :
field[ key ] = values

return ''

}
)

// Set the actual literal value
if( value.length ) {
field.data = value
}

// ...
this.set( key, field )

return this

},

/**
* [toString description]
* @param {Number} version
* @return {String}
* @return {String}
*/
toString: function( version ) {

// version = version || this.version
if( version ) {
console.warn(
'WARNING: String serialization is currently '+
'only supported for vCard version 4.0'
)
}

var lines = []
var keys = Object.keys( this )

lines.push( 'BEGIN:VCARD' )
lines.push( 'VERSION:4.0' )

for( var i = 0; i < keys.length; i++ ) {

var key = keys[i]
var values = this[ key ] != null ?
[].concat( this[ key ] ) : []

for( var k = 0; k < values.length; k++ ) {

var value = values[k]
var line = key.toUpperCase()

if( key === 'version' )
continue

if( typeof value !== 'object' ) {
lines.push( line + ':' + value )
continue
}

for( var param in value ) {

if( param === 'data' )
continue

line = line + ';' + param.toUpperCase() + '=' +
[].concat( value[ param ] )
.map( function( value ) {
return /[;:,]/.test( value ) ?
'"' + value + '"' : value
}).join()

}

if( value.data != null ) {
line = line + ':' + value.data
}

lines.push( vCard.foldLine( line, 75 ) )

}

}

lines.push( 'END:VCARD' )

return lines.join( '\r\n' )

}

}

0 comments on commit 7c8dd84

Please sign in to comment.