Skip to content

Commit

Permalink
Merge pull request #36 from iammatis/issue-33
Browse files Browse the repository at this point in the history
Fix #33 newlines and escape chars formatting and parsing
  • Loading branch information
iammatis committed May 7, 2020
2 parents ea65a7d + 0edb74a commit 9bf50bd
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 6 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

### Fixed

- Fixed newlines and escape chars formatting and parsing
- Fixed event start to support ComplexDate

## [0.3.2] - 2020-04-21
Expand All @@ -30,7 +31,7 @@

### Fixed

- Return RRule when parsin iCal data
- Return RRule when parsing iCal data

## [0.1.0] - 2020-02-04

Expand Down
2 changes: 1 addition & 1 deletion src/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export class Builder implements IBuilder {
this.add(fmt.formatDate('DTSTART', event.start))
this.add(fmt.formatString('CLASS', event.class))
this.add(fmt.formatDate('CREATED', event.created))
this.add(fmt.formatString('SUMMARY', event.summary))
this.add(fmt.formatString('DESCRIPTION', event.description))
this.add(fmt.formatGeo(event.geo))
this.add(fmt.formatDate('LAST-MODIFIED', event.lastModified))
Expand All @@ -62,7 +63,6 @@ export class Builder implements IBuilder {
this.add(fmt.formatString('PRIORITY', event.priority))
this.add(fmt.formatString('SEQUENCE', event.sequnce))
this.add(fmt.formatString('STATUS', event.status))
this.add(fmt.formatString('SUMMARY', event.summary))
this.add(fmt.formatString('TRANSP', event.transp))
this.add(fmt.formatString('URL', event.url))
this.add(fmt.formatString('RECURRENCE-ID', event.recurrenceId))
Expand Down
15 changes: 14 additions & 1 deletion src/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import RRule from 'rrule'
class Formatter implements IFormatter {
public formatString(attrName: string, value?: string | number): string {
return value !== undefined && value !== '' && value !== null
? this.foldLine(`${attrName}:${value}`)
? this.foldLine(`${attrName}:${this.escapeChars(value)}`)
: ''
}

Expand Down Expand Up @@ -200,6 +200,7 @@ class Formatter implements IFormatter {
private foldLine(line: string): string {
const MAX_LENGTH = 75
const lines = []

while (line.length > MAX_LENGTH) {
lines.push(line.slice(0, MAX_LENGTH))
line = line.slice(MAX_LENGTH)
Expand Down Expand Up @@ -228,6 +229,18 @@ class Formatter implements IFormatter {
}
}
}

private escapeChars(value: string | number): string | number {
if (typeof value === 'number') {
return value;
}

return value
.replace(/\\/g, '\\\\')
.replace(/;/g, '\\;')
.replace(/,/g, '\\,')
.replace(/r?\n/g, '\\n')
}
}

export default Formatter
4 changes: 1 addition & 3 deletions src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,8 @@ export class Parser implements IParser {

private splitLines(iCal: string): string[] {
return iCal
.replace(/\r?\n\s|\r/g, '')
.replace(/\\n/g, ' ')
.replace(/\r?\n( |\t)/g, '')
.replace(/ +/g, ' ')
.replace(/\\/g, '')
.split('\n')
}

Expand Down
4 changes: 4 additions & 0 deletions src/parser/properties/string.parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ class StringParser extends BaseParser<string> {
throw new ParsingError(`Invalid iCalendar string value: ${iCalValue}`)
}
return iCalValue
.replace(/\\n/g, '\n')
.replace(/\\;/g, ';')
.replace(/\\,/g, ',')
.replace(/\\\\/g, '\\');
}
}

Expand Down
21 changes: 21 additions & 0 deletions tests/builder.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,27 @@ describe('Test Builder Class', () => {
expect(data).toEqual(file)
})

it('Test event with newlines', () => {

const file = loadFile('events/newlines.ics')

const builder = new Builder({
version: '2.0',
prodId: '-//Example Corp.//CalDAV Client//EN',
events: [
{
dtStamp: '20041210T183904Z',
uid: 'uid1@example.com',
summary: 'Summary with \n\n multiple \n newlines',
description: 'Description with \n newlines'
}
]
})
const data = builder.build()

expect(data).toEqual(file)
})

it('Fails with end and duration at the same time', () => {
const builder = new Builder({
version: '2.0',
Expand Down
10 changes: 10 additions & 0 deletions tests/fixtures/events/newlines.ics
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VEVENT
DTSTAMP:20041210T183904Z
UID:uid1@example.com
SUMMARY:Summary with \n\n multiple \n newlines
DESCRIPTION:Description with \n newlines
END:VEVENT
END:VCALENDAR
11 changes: 11 additions & 0 deletions tests/formatter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ describe('Test Formatter Class', () => {
const data = fmt.formatString('ATTRNAME', 'string')
expect(data).toEqual('ATTRNAME:string')
})

it('Format string with newlines', () => {
const data = fmt.formatString('ATTRNAME', 'string \n with \n\n newlines')
expect(data).toEqual('ATTRNAME:string \\n with \\n\\n newlines')
})


it('Format string with semicolon', () => {
const data = fmt.formatString('ATTRNAME', 'string ; with semicolon')
expect(data).toEqual('ATTRNAME:string \\; with semicolon')
})

it('Test format multiple empty strings', () => {
const data = fmt.formatStrings('ATTRNAME', [])
Expand Down
18 changes: 18 additions & 0 deletions tests/parser/parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ describe('Test Parser', () => {
})
})

it('Parse iCal file with newlines', () => {
const iCal = loadFile('events/newlines.ics')
const calendar = parser.parse(iCal)

expect(calendar).toEqual({
version: '2.0',
prodId: '-//Example Corp.//CalDAV Client//EN',
events: [
{
dtStamp: '20041210T183904Z',
uid: 'uid1@example.com',
summary: 'Summary with \n\n multiple \n newlines',
description: 'Description with \n newlines'
}
]
})
})

it('Parse iCal file from expanded query', () => {
const iCal = loadFile('events/expanded_event.ics')
const calendar = parser.parse(iCal)
Expand Down
6 changes: 6 additions & 0 deletions tests/parser/string.parser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,10 @@ describe('Test String Parser', () => {
expect(str).toEqual('Event\'s summary')
})

it('String with semicolon', () => {
const str = parser.parse('Event \\; summary')

expect(str).toEqual('Event ; summary')
})

})

0 comments on commit 9bf50bd

Please sign in to comment.