iamcal 3.0.3 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/component.d.ts +2 -1
- package/lib/component.d.ts.map +1 -1
- package/lib/component.js +14 -16
- package/lib/components/CalendarEvent.d.ts +34 -8
- package/lib/components/CalendarEvent.d.ts.map +1 -1
- package/lib/components/CalendarEvent.js +67 -8
- package/lib/date.d.ts +41 -3
- package/lib/date.d.ts.map +1 -1
- package/lib/date.js +75 -7
- package/lib/duration.d.ts +106 -0
- package/lib/duration.d.ts.map +1 -0
- package/lib/duration.js +277 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -1
- package/lib/io.d.ts +20 -0
- package/lib/io.d.ts.map +1 -1
- package/lib/io.js +30 -1
- package/lib/parse.d.ts +11 -3
- package/lib/parse.d.ts.map +1 -1
- package/lib/parse.js +42 -22
- package/lib/property/Property.d.ts +24 -2
- package/lib/property/Property.d.ts.map +1 -1
- package/lib/property/Property.js +71 -4
- package/lib/property/validate.js +2 -2
- package/package.json +1 -1
- package/src/component.ts +15 -23
- package/src/components/CalendarEvent.ts +73 -9
- package/src/date.ts +96 -13
- package/src/duration.ts +329 -0
- package/src/index.ts +1 -0
- package/src/io.ts +42 -1
- package/src/parse.ts +43 -19
- package/src/property/Property.ts +80 -5
- package/src/property/validate.ts +1 -1
package/src/parse.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import readline from 'readline'
|
|
2
|
-
import { Readable } from 'stream'
|
|
3
2
|
import { Component } from './component'
|
|
4
3
|
import { Calendar, CalendarEvent } from './components'
|
|
5
4
|
import {
|
|
@@ -23,10 +22,22 @@ export class DeserializationError extends Error {
|
|
|
23
22
|
* @param lines The serialized component as a **readline** interface.
|
|
24
23
|
* @returns The deserialized calendar component object.
|
|
25
24
|
* @throws {DeserializationError} If the component is invalid.
|
|
25
|
+
* @deprecated Use the synchronous `deserializeComponentLines` instead.
|
|
26
26
|
*/
|
|
27
27
|
export async function deserializeComponent(
|
|
28
28
|
lines: readline.Interface
|
|
29
29
|
): Promise<Component> {
|
|
30
|
+
const realLines = await readLines(lines)
|
|
31
|
+
return deserializeComponentLines(realLines)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Deserialize a calendar component from a list of lines.
|
|
36
|
+
* @param lines The serialized component as a list of lines.
|
|
37
|
+
* @returns The deserialized calendar component object.
|
|
38
|
+
* @throws {DeserializationError} If the component is invalid.
|
|
39
|
+
*/
|
|
40
|
+
export function deserializeComponentLines(lines: string[]): Component {
|
|
30
41
|
const component = new Component('')
|
|
31
42
|
let done = false
|
|
32
43
|
|
|
@@ -35,7 +46,7 @@ export async function deserializeComponent(
|
|
|
35
46
|
|
|
36
47
|
const subcomponentLines = new Array<string>()
|
|
37
48
|
|
|
38
|
-
const processLine =
|
|
49
|
+
const processLine = (line: string) => {
|
|
39
50
|
if (line.trim() === '') return
|
|
40
51
|
|
|
41
52
|
if (done) {
|
|
@@ -71,7 +82,7 @@ export async function deserializeComponent(
|
|
|
71
82
|
// Check the length of the stack after being popped
|
|
72
83
|
if (stack.length == 1) {
|
|
73
84
|
subcomponentLines.push(line)
|
|
74
|
-
const subcomponent =
|
|
85
|
+
const subcomponent = deserializeComponentString(
|
|
75
86
|
subcomponentLines.join('\r\n')
|
|
76
87
|
)
|
|
77
88
|
subcomponentLines.length = 0
|
|
@@ -117,14 +128,14 @@ export async function deserializeComponent(
|
|
|
117
128
|
that exists on a long line.
|
|
118
129
|
*/
|
|
119
130
|
let unfoldedLine = ''
|
|
120
|
-
for
|
|
131
|
+
for (const line of lines) {
|
|
121
132
|
if (line.startsWith(' ') || line.startsWith('\t')) {
|
|
122
133
|
// Unfold continuation line (remove leading whitespace and append)
|
|
123
134
|
unfoldedLine += line.replace(/[\r\n]/, '').slice(1)
|
|
124
135
|
} else {
|
|
125
136
|
if (unfoldedLine) {
|
|
126
137
|
// Process the previous unfolded line
|
|
127
|
-
|
|
138
|
+
processLine(unfoldedLine)
|
|
128
139
|
}
|
|
129
140
|
// Start a new unfolded line
|
|
130
141
|
unfoldedLine = line
|
|
@@ -132,7 +143,7 @@ export async function deserializeComponent(
|
|
|
132
143
|
}
|
|
133
144
|
|
|
134
145
|
// Process the last unfolded line
|
|
135
|
-
|
|
146
|
+
processLine(unfoldedLine)
|
|
136
147
|
|
|
137
148
|
// Check that component has been closed
|
|
138
149
|
if (!done) {
|
|
@@ -142,21 +153,34 @@ export async function deserializeComponent(
|
|
|
142
153
|
return component
|
|
143
154
|
}
|
|
144
155
|
|
|
156
|
+
/**
|
|
157
|
+
* Convert a **readline** interface to a list of lines.
|
|
158
|
+
* @param rl The interface.
|
|
159
|
+
* @returns The list of lines read from the interface.
|
|
160
|
+
* @throws {DeserializationError} If the component is invalid.
|
|
161
|
+
*/
|
|
162
|
+
async function readLines(rl: readline.Interface): Promise<string[]> {
|
|
163
|
+
return new Promise(resolve => {
|
|
164
|
+
const lines: string[] = []
|
|
165
|
+
|
|
166
|
+
rl.on('line', line => {
|
|
167
|
+
lines.push(line)
|
|
168
|
+
})
|
|
169
|
+
rl.on('close', () => {
|
|
170
|
+
resolve(lines)
|
|
171
|
+
})
|
|
172
|
+
})
|
|
173
|
+
}
|
|
174
|
+
|
|
145
175
|
/**
|
|
146
176
|
* Deserialize a calendar component string.
|
|
147
177
|
* @param text The serialized component.
|
|
148
178
|
* @returns The deserialized component object.
|
|
149
179
|
* @throws {DeserializationError} If the component is invalid.
|
|
150
180
|
*/
|
|
151
|
-
export
|
|
152
|
-
text
|
|
153
|
-
)
|
|
154
|
-
const stream = Readable.from(text)
|
|
155
|
-
const lines = readline.createInterface({
|
|
156
|
-
input: stream,
|
|
157
|
-
crlfDelay: Infinity,
|
|
158
|
-
})
|
|
159
|
-
return deserializeComponent(lines)
|
|
181
|
+
export function deserializeComponentString(text: string): Component {
|
|
182
|
+
const lines = text.split(/\r?\n/g)
|
|
183
|
+
return deserializeComponentLines(lines)
|
|
160
184
|
}
|
|
161
185
|
|
|
162
186
|
/**
|
|
@@ -164,8 +188,8 @@ export async function deserializeComponentString(
|
|
|
164
188
|
* @param text A serialized calendar as you would see in an iCalendar file.
|
|
165
189
|
* @returns The parsed calendar object.
|
|
166
190
|
*/
|
|
167
|
-
export
|
|
168
|
-
const component =
|
|
191
|
+
export function parseCalendar(text: string): Calendar {
|
|
192
|
+
const component = deserializeComponentString(text)
|
|
169
193
|
return new Calendar(component)
|
|
170
194
|
}
|
|
171
195
|
|
|
@@ -174,8 +198,8 @@ export async function parseCalendar(text: string): Promise<Calendar> {
|
|
|
174
198
|
* @param text A serialized event as you would see in an iCalendar file.
|
|
175
199
|
* @returns The parsed event object.
|
|
176
200
|
*/
|
|
177
|
-
export
|
|
178
|
-
const component =
|
|
201
|
+
export function parseEvent(text: string): CalendarEvent {
|
|
202
|
+
const component = deserializeComponentString(text)
|
|
179
203
|
return new CalendarEvent(component)
|
|
180
204
|
}
|
|
181
205
|
|
package/src/property/Property.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { CalendarDateOrTime } from '
|
|
1
|
+
import { CalendarDateOrTime, CalendarDate, CalendarDateTime, isCalendarDateOrTime } from '../date'
|
|
2
|
+
import { CalendarDuration } from '../duration'
|
|
2
3
|
import {
|
|
3
4
|
escapePropertyParameterValue,
|
|
4
5
|
escapeTextPropertyValue,
|
|
@@ -16,7 +17,7 @@ import {
|
|
|
16
17
|
RsvpExpectation,
|
|
17
18
|
} from './parameter'
|
|
18
19
|
import { validateCalendarUserAddress, validateContentType } from './validate'
|
|
19
|
-
import { AllowedValueType, getDefaultValueType } from './valueType'
|
|
20
|
+
import { AllowedValueType, KnownValueType, getDefaultValueType } from './valueType'
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Represents a property of a calendar component as described by RFC 5545 in
|
|
@@ -55,13 +56,72 @@ export class Property {
|
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
static fromDate(name: string, value: CalendarDateOrTime): Property {
|
|
59
|
+
const valueType = value.isFullDay() ? 'DATE' : 'DATE-TIME'
|
|
60
|
+
let properties: { [k: string]: string | string[] } | undefined = undefined
|
|
61
|
+
if (getDefaultValueType(name) !== valueType) {
|
|
62
|
+
properties = { VALUE: valueType }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return new Property(
|
|
66
|
+
name,
|
|
67
|
+
value.getValue(),
|
|
68
|
+
properties,
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static fromDuration(name: string, value: CalendarDuration): Property {
|
|
58
73
|
return new Property(
|
|
59
74
|
name,
|
|
60
75
|
value.getValue(),
|
|
61
|
-
|
|
76
|
+
{ VALUE: 'CALENDARDATE' },
|
|
62
77
|
)
|
|
63
78
|
}
|
|
64
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Get the value of this property, converted into the appropriate class if possible.
|
|
82
|
+
* @returns The value as a string or appropriate class.
|
|
83
|
+
*/
|
|
84
|
+
getValue(): string | CalendarDateOrTime | CalendarDuration {
|
|
85
|
+
const valueType = this.getValueType()
|
|
86
|
+
switch (valueType) {
|
|
87
|
+
case 'DATE':
|
|
88
|
+
return new CalendarDate(this.value)
|
|
89
|
+
case 'DATE-TIME':
|
|
90
|
+
return new CalendarDateTime(this.value)
|
|
91
|
+
case 'DURATION':
|
|
92
|
+
return new CalendarDuration(this.value)
|
|
93
|
+
default:
|
|
94
|
+
return this.value
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Set the value of this property and change the value type if a class is used.
|
|
100
|
+
* @param value The new value as a string or class.
|
|
101
|
+
*/
|
|
102
|
+
setValue(value: string | CalendarDateOrTime | CalendarDuration) {
|
|
103
|
+
const valueTypeBefore = this.getExplicitValueType()
|
|
104
|
+
if (typeof value === 'string') {
|
|
105
|
+
// Set string
|
|
106
|
+
this.value = value
|
|
107
|
+
} else if (isCalendarDateOrTime(value)) {
|
|
108
|
+
// Set date
|
|
109
|
+
this.value = value.getValue()
|
|
110
|
+
this.setValueType(value.isFullDay() ? 'DATE' : 'DATE-TIME')
|
|
111
|
+
} else {
|
|
112
|
+
// Set duration
|
|
113
|
+
this.value = value.getValue()
|
|
114
|
+
this.setValueType('DURATION')
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Remove value type if set to default, unless it was already set
|
|
118
|
+
const valueType = this.getExplicitValueType()
|
|
119
|
+
const defaultValueType = this.getDefaultValueType()
|
|
120
|
+
if (valueType === defaultValueType && valueType !== valueTypeBefore) {
|
|
121
|
+
this.removeValueType()
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
65
125
|
setParameter(name: string, value: string | string[]) {
|
|
66
126
|
this._parameters.set(
|
|
67
127
|
name.toUpperCase(),
|
|
@@ -148,8 +208,23 @@ export class Property {
|
|
|
148
208
|
* @returns The value type of this property.
|
|
149
209
|
*/
|
|
150
210
|
getValueType(): AllowedValueType {
|
|
151
|
-
|
|
152
|
-
|
|
211
|
+
return this.getExplicitValueType() ?? this.getDefaultValueType()
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Get the value type of this property.
|
|
216
|
+
* @returns The value type of this property, or `undefined` if unset.
|
|
217
|
+
*/
|
|
218
|
+
getExplicitValueType(): AllowedValueType | undefined {
|
|
219
|
+
return this.getParameter('VALUE')?.[0].toUpperCase()
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Get the default value type for this property.
|
|
224
|
+
* @returns The default value type based on the name of this property.
|
|
225
|
+
*/
|
|
226
|
+
getDefaultValueType(): KnownValueType {
|
|
227
|
+
return getDefaultValueType(this.name)
|
|
153
228
|
}
|
|
154
229
|
|
|
155
230
|
/**
|
package/src/property/validate.ts
CHANGED