@tomgiee/tsdp 1.0.1 → 1.1.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.
Files changed (68) hide show
  1. package/README.md +0 -39
  2. package/dist/src/builder/media-builder.d.ts.map +1 -1
  3. package/dist/src/builder/media-builder.js +5 -12
  4. package/dist/src/builder/session-builder.d.ts.map +1 -1
  5. package/dist/src/builder/session-builder.js +4 -14
  6. package/dist/src/index.d.ts +6 -10
  7. package/dist/src/index.d.ts.map +1 -1
  8. package/dist/src/index.js +37 -49
  9. package/dist/src/parser/core.d.ts +366 -0
  10. package/dist/src/parser/core.d.ts.map +1 -0
  11. package/dist/src/parser/core.js +802 -0
  12. package/dist/src/parser/field-parser.d.ts +51 -8
  13. package/dist/src/parser/field-parser.d.ts.map +1 -1
  14. package/dist/src/parser/field-parser.js +91 -23
  15. package/dist/src/parser/media-parser.d.ts +1 -1
  16. package/dist/src/parser/media-parser.d.ts.map +1 -1
  17. package/dist/src/parser/media-parser.js +9 -15
  18. package/dist/src/parser/session-parser.d.ts.map +1 -1
  19. package/dist/src/parser/session-parser.js +16 -17
  20. package/dist/src/parser/time-parser.d.ts +1 -1
  21. package/dist/src/parser/time-parser.d.ts.map +1 -1
  22. package/dist/src/parser/time-parser.js +8 -8
  23. package/dist/src/serializer/fields.d.ts +167 -0
  24. package/dist/src/serializer/fields.d.ts.map +1 -0
  25. package/dist/src/serializer/fields.js +320 -0
  26. package/dist/src/serializer/media-serializer.js +6 -7
  27. package/dist/src/serializer/session-serializer.js +13 -15
  28. package/dist/src/types/attributes.d.ts.map +1 -1
  29. package/dist/src/types/fields.d.ts +5 -5
  30. package/dist/src/types/fields.d.ts.map +1 -1
  31. package/dist/src/types/fields.js +4 -4
  32. package/dist/src/types/media.d.ts +9 -10
  33. package/dist/src/types/media.d.ts.map +1 -1
  34. package/dist/src/types/media.js +2 -4
  35. package/dist/src/types/network.d.ts +15 -56
  36. package/dist/src/types/network.d.ts.map +1 -1
  37. package/dist/src/types/network.js +3 -34
  38. package/dist/src/types/primitives.d.ts +3 -147
  39. package/dist/src/types/primitives.d.ts.map +1 -1
  40. package/dist/src/types/primitives.js +2 -171
  41. package/dist/src/types/session.d.ts +14 -14
  42. package/dist/src/types/session.d.ts.map +1 -1
  43. package/dist/src/types/time.d.ts +4 -4
  44. package/dist/src/types/time.d.ts.map +1 -1
  45. package/dist/src/types/time.js +8 -6
  46. package/dist/src/utils/address-parser.d.ts +4 -4
  47. package/dist/src/utils/address-parser.d.ts.map +1 -1
  48. package/dist/src/utils/address-parser.js +9 -16
  49. package/dist/src/validator/validator.d.ts +94 -0
  50. package/dist/src/validator/validator.d.ts.map +1 -0
  51. package/dist/src/validator/validator.js +573 -0
  52. package/dist/tests/unit/parser/attribute-parser.test.js +106 -107
  53. package/dist/tests/unit/parser/field-parser.test.js +66 -66
  54. package/dist/tests/unit/parser/media-parser.test.js +38 -38
  55. package/dist/tests/unit/parser/primitive-parser.test.js +89 -90
  56. package/dist/tests/unit/parser/scanner.test.js +32 -32
  57. package/dist/tests/unit/parser/time-parser.test.js +22 -22
  58. package/dist/tests/unit/serializer/attribute-serializer.test.js +22 -22
  59. package/dist/tests/unit/serializer/field-serializer.test.js +57 -57
  60. package/dist/tests/unit/serializer/media-serializer.test.js +5 -6
  61. package/dist/tests/unit/serializer/session-serializer.test.js +24 -24
  62. package/dist/tests/unit/serializer/time-serializer.test.js +16 -16
  63. package/dist/tests/unit/types/network.test.js +21 -56
  64. package/dist/tests/unit/types/primitives.test.js +0 -39
  65. package/dist/tests/unit/validator/media-validator.test.js +34 -35
  66. package/dist/tests/unit/validator/semantic-validator.test.js +36 -37
  67. package/dist/tests/unit/validator/session-validator.test.js +54 -54
  68. package/package.json +1 -1
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Core parsing infrastructure for SDP (RFC 8866)
3
+ *
4
+ * This module consolidates:
5
+ * - Scanner: Low-level tokenization with position tracking
6
+ * - Primitive parsers: Basic grammar elements (tokens, integers, addresses, times)
7
+ * - Attribute parsers: SDP attributes (a= fields)
8
+ */
9
+ import { Position, TypedTime } from '../types/primitives';
10
+ import { Attribute, RtpmapValue, FmtpValue } from '../types/attributes';
11
+ /**
12
+ * Scanner class for parsing SDP text
13
+ *
14
+ * Maintains position information and provides character-level operations
15
+ * for parsing SDP fields according to RFC 8866 grammar.
16
+ */
17
+ export declare class Scanner {
18
+ private readonly input;
19
+ private position;
20
+ private line;
21
+ private column;
22
+ /**
23
+ * Create a new Scanner
24
+ *
25
+ * @param input - SDP text to scan
26
+ */
27
+ constructor(input: string);
28
+ /**
29
+ * Peek at the current character without consuming it
30
+ *
31
+ * @returns Current character or null if at EOF
32
+ */
33
+ peek(): string | null;
34
+ /**
35
+ * Peek ahead n characters without consuming
36
+ *
37
+ * @param n - Number of characters to peek ahead
38
+ * @returns Character at position+n or null if beyond EOF
39
+ */
40
+ peekAhead(n: number): string | null;
41
+ /**
42
+ * Advance to the next character and return the current one
43
+ *
44
+ * Updates line and column tracking when encountering newlines.
45
+ *
46
+ * @returns Current character or null if at EOF
47
+ */
48
+ advance(): string | null;
49
+ /**
50
+ * Read characters until a delimiter is found
51
+ *
52
+ * Does NOT consume the delimiter.
53
+ *
54
+ * @param delimiter - String or RegExp to match
55
+ * @returns String of characters read (may be empty)
56
+ */
57
+ readUntil(delimiter: string | RegExp): string;
58
+ /**
59
+ * Read while a condition is true
60
+ *
61
+ * @param predicate - Function that returns true to continue reading
62
+ * @returns String of characters read
63
+ */
64
+ readWhile(predicate: (ch: string) => boolean): string;
65
+ /**
66
+ * Skip whitespace characters (space and tab)
67
+ *
68
+ * Does NOT skip newlines (CRLF/LF/CR).
69
+ */
70
+ skipWhitespace(): void;
71
+ /**
72
+ * Skip to the next line
73
+ *
74
+ * Consumes all characters until and including the next line ending (CRLF/LF/CR).
75
+ */
76
+ skipToNextLine(): void;
77
+ /**
78
+ * Get current position in the input
79
+ *
80
+ * @returns Position object with offset, line, and column
81
+ */
82
+ getPosition(): Position;
83
+ /**
84
+ * Check if at end of file
85
+ *
86
+ * @returns true if no more characters to read
87
+ */
88
+ isEOF(): boolean;
89
+ /**
90
+ * Expect a specific string at the current position
91
+ *
92
+ * Consumes the string if it matches, throws otherwise.
93
+ *
94
+ * @param expected - String to expect
95
+ * @throws ParseError if string doesn't match
96
+ */
97
+ expect(expected: string): void;
98
+ /**
99
+ * Expect a character that matches a condition
100
+ *
101
+ * Consumes the character if it matches, throws otherwise.
102
+ *
103
+ * @param predicate - Function that returns true for valid character
104
+ * @param description - Description of expected character for error messages
105
+ * @returns The matched character
106
+ * @throws ParseError if character doesn't match
107
+ */
108
+ expectChar(predicate: (ch: string) => boolean, description: string): string;
109
+ /**
110
+ * Expect end of line (CRLF, LF, or CR)
111
+ *
112
+ * @throws ParseError if not at end of line
113
+ */
114
+ expectEOL(): void;
115
+ /**
116
+ * Expect space character
117
+ *
118
+ * @throws ParseError if not a space
119
+ */
120
+ expectSpace(): void;
121
+ /**
122
+ * Get context around a position for error messages
123
+ *
124
+ * Returns a snippet of the input around the position.
125
+ *
126
+ * @param pos - Position to get context for
127
+ * @returns Context string (may be empty)
128
+ */
129
+ private getContext;
130
+ /**
131
+ * Get remaining input from current position
132
+ *
133
+ * @returns Remaining input string
134
+ */
135
+ getRemainingInput(): string;
136
+ /**
137
+ * Get a substring of the input
138
+ *
139
+ * @param start - Start position
140
+ * @param end - End position (optional, defaults to current position)
141
+ * @returns Substring
142
+ */
143
+ getSubstring(start: number, end?: number): string;
144
+ }
145
+ /**
146
+ * Parse a token (RFC 8866 Section 9)
147
+ *
148
+ * token = 1*token-char
149
+ * token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
150
+ *
151
+ * Essentially: any visible ASCII character except space and separators like ()[]{}:;,<>?=@\"
152
+ *
153
+ * @param scanner - Scanner instance
154
+ * @returns Parsed token string
155
+ * @throws ParseError if no valid token found
156
+ */
157
+ export declare function parseToken(scanner: Scanner): string;
158
+ /**
159
+ * Parse an integer
160
+ *
161
+ * @param scanner - Scanner instance
162
+ * @returns Parsed integer
163
+ * @throws ParseError if no valid integer found
164
+ */
165
+ export declare function parseInteger(scanner: Scanner): number;
166
+ /**
167
+ * Parse a byte (0-255)
168
+ *
169
+ * @param scanner - Scanner instance
170
+ * @returns Parsed byte value
171
+ * @throws ParseError if not a valid byte
172
+ */
173
+ export declare function parseByte(scanner: Scanner): number;
174
+ /**
175
+ * Parse a non-whitespace string
176
+ *
177
+ * Reads characters until whitespace or end of line.
178
+ *
179
+ * @param scanner - Scanner instance
180
+ * @returns Parsed string
181
+ * @throws ParseError if empty
182
+ */
183
+ export declare function parseNonWSString(scanner: Scanner): string;
184
+ /**
185
+ * Parse a byte-string (RFC 8866 Section 9)
186
+ *
187
+ * byte-string = 1*(%x01-09 / %x0B-0C / %x0E-FF)
188
+ * (any byte except NUL, CR, LF)
189
+ *
190
+ * @param scanner - Scanner instance
191
+ * @returns Parsed byte-string
192
+ * @throws ParseError if invalid characters found
193
+ */
194
+ export declare function parseByteString(scanner: Scanner): string;
195
+ /**
196
+ * Parse an IPv4 address
197
+ *
198
+ * Format: a.b.c.d where each octet is 0-255
199
+ *
200
+ * @param scanner - Scanner instance
201
+ * @returns Parsed IPv4 address
202
+ * @throws ParseError if invalid IPv4 address
203
+ */
204
+ export declare function parseIP4Address(scanner: Scanner): string;
205
+ /**
206
+ * Parse an IPv6 address
207
+ *
208
+ * Supports all IPv6 formats including compression (::) and mixed IPv4
209
+ *
210
+ * @param scanner - Scanner instance
211
+ * @returns Parsed IPv6 address
212
+ * @throws ParseError if invalid IPv6 address
213
+ */
214
+ export declare function parseIP6Address(scanner: Scanner): string;
215
+ /**
216
+ * Parse an FQDN (Fully Qualified Domain Name)
217
+ *
218
+ * @param scanner - Scanner instance
219
+ * @returns Parsed FQDN
220
+ * @throws ParseError if invalid FQDN
221
+ */
222
+ export declare function parseFQDN(scanner: Scanner): string;
223
+ /**
224
+ * Parse an NTP timestamp
225
+ *
226
+ * NTP time is seconds since January 1, 1900 00:00:00 UTC
227
+ * 0 means unbounded/permanent
228
+ *
229
+ * @param scanner - Scanner instance
230
+ * @returns Parsed NTP time
231
+ * @throws ParseError if invalid
232
+ */
233
+ export declare function parseNtpTime(scanner: Scanner): number;
234
+ /**
235
+ * Parse a typed time value
236
+ *
237
+ * Format: [-]<integer>[d|h|m|s]
238
+ * - d = days
239
+ * - h = hours
240
+ * - m = minutes
241
+ * - s or no suffix = seconds
242
+ * - Can be negative (for timezone offsets)
243
+ *
244
+ * @param scanner - Scanner instance
245
+ * @returns Parsed typed time
246
+ * @throws ParseError if invalid
247
+ */
248
+ export declare function parseTypedTime(scanner: Scanner): TypedTime;
249
+ /**
250
+ * Parse an email address or display name with email
251
+ *
252
+ * Format: email-address / displayable-name <email-address>
253
+ *
254
+ * @param scanner - Scanner instance
255
+ * @returns Parsed email string
256
+ */
257
+ export declare function parseEmail(scanner: Scanner): string;
258
+ /**
259
+ * Parse a phone number or display name with phone
260
+ *
261
+ * Format: phone-number / displayable-name <phone-number>
262
+ *
263
+ * @param scanner - Scanner instance
264
+ * @returns Parsed phone string
265
+ */
266
+ export declare function parsePhone(scanner: Scanner): string;
267
+ /**
268
+ * Parse a URI
269
+ *
270
+ * @param scanner - Scanner instance
271
+ * @returns Parsed URI string
272
+ */
273
+ export declare function parseURI(scanner: Scanner): string;
274
+ /**
275
+ * Parse attribute field
276
+ *
277
+ * Format:
278
+ * - Property attribute: a=<attribute-name>
279
+ * - Value attribute: a=<attribute-name>:<attribute-value>
280
+ *
281
+ * Property attributes have no value (e.g., a=recvonly, a=sendrecv).
282
+ * Value attributes have a value after colon (e.g., a=rtpmap:0 PCMU/8000).
283
+ *
284
+ * @param scanner - Scanner instance
285
+ * @returns Attribute object
286
+ * @throws ParseError if invalid format
287
+ */
288
+ export declare function parseAttributeField(scanner: Scanner): Attribute;
289
+ /**
290
+ * Parse rtpmap attribute value
291
+ *
292
+ * Format: <payload-type> <encoding-name>/<clock-rate>[/<encoding-params>]
293
+ *
294
+ * Examples:
295
+ * - "0 PCMU/8000"
296
+ * - "96 H264/90000"
297
+ * - "97 L16/8000/2" (2 channels)
298
+ *
299
+ * @param value - rtpmap attribute value string
300
+ * @returns Parsed RtpmapValue
301
+ * @throws ParseError if invalid format
302
+ */
303
+ export declare function parseRtpmapValue(value: string): RtpmapValue;
304
+ /**
305
+ * Parse fmtp attribute value
306
+ *
307
+ * Format: <format> <format-specific-params>
308
+ *
309
+ * Examples:
310
+ * - "96 profile-level-id=42e01f;packetization-mode=1"
311
+ * - "97 apt=96"
312
+ *
313
+ * @param value - fmtp attribute value string
314
+ * @returns Parsed FmtpValue
315
+ * @throws ParseError if invalid format
316
+ */
317
+ export declare function parseFmtpValue(value: string): FmtpValue;
318
+ /**
319
+ * Parse ptime attribute value
320
+ *
321
+ * Format: <packet-time-in-milliseconds>
322
+ *
323
+ * RFC 8866 Section 6.4: ptime-value = non-zero-int-or-real
324
+ * Decimal values are allowed (e.g., "20.5")
325
+ *
326
+ * @param value - ptime attribute value string
327
+ * @returns Packet time in milliseconds (can be fractional)
328
+ * @throws ParseError if invalid
329
+ */
330
+ export declare function parsePtimeValue(value: string): number;
331
+ /**
332
+ * Parse maxptime attribute value
333
+ *
334
+ * Format: <max-packet-time-in-milliseconds>
335
+ *
336
+ * RFC 8866 Section 6.5: maxptime-value = non-zero-int-or-real
337
+ * Decimal values are allowed (e.g., "40.0")
338
+ *
339
+ * @param value - maxptime attribute value string
340
+ * @returns Maximum packet time in milliseconds (can be fractional)
341
+ * @throws ParseError if invalid
342
+ */
343
+ export declare function parseMaxptimeValue(value: string): number;
344
+ /**
345
+ * Parse framerate attribute value
346
+ *
347
+ * Format: <frames-per-second>
348
+ *
349
+ * @param value - framerate attribute value string
350
+ * @returns Frame rate (frames per second)
351
+ * @throws ParseError if invalid
352
+ */
353
+ export declare function parseFramerateValue(value: string): number;
354
+ /**
355
+ * Parse quality attribute value
356
+ *
357
+ * Format: <quality-value>
358
+ *
359
+ * Quality is 0-10, where 10 is best quality.
360
+ *
361
+ * @param value - quality attribute value string
362
+ * @returns Quality value (0-10)
363
+ * @throws ParseError if invalid
364
+ */
365
+ export declare function parseQualityValue(value: string): number;
366
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/parser/core.ts"],"names":[],"mappings":"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"}