@tomgiee/tsdp 1.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.
Files changed (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/dist/src/builder/media-builder.d.ts +221 -0
  4. package/dist/src/builder/media-builder.d.ts.map +1 -0
  5. package/dist/src/builder/media-builder.js +385 -0
  6. package/dist/src/builder/session-builder.d.ts +195 -0
  7. package/dist/src/builder/session-builder.d.ts.map +1 -0
  8. package/dist/src/builder/session-builder.js +366 -0
  9. package/dist/src/index.d.ts +67 -0
  10. package/dist/src/index.d.ts.map +1 -0
  11. package/dist/src/index.js +250 -0
  12. package/dist/src/parser/attribute-parser.d.ts +100 -0
  13. package/dist/src/parser/attribute-parser.d.ts.map +1 -0
  14. package/dist/src/parser/attribute-parser.js +217 -0
  15. package/dist/src/parser/field-parser.d.ts +124 -0
  16. package/dist/src/parser/field-parser.d.ts.map +1 -0
  17. package/dist/src/parser/field-parser.js +335 -0
  18. package/dist/src/parser/media-parser.d.ts +45 -0
  19. package/dist/src/parser/media-parser.d.ts.map +1 -0
  20. package/dist/src/parser/media-parser.js +157 -0
  21. package/dist/src/parser/primitive-parser.d.ts +138 -0
  22. package/dist/src/parser/primitive-parser.d.ts.map +1 -0
  23. package/dist/src/parser/primitive-parser.js +316 -0
  24. package/dist/src/parser/scanner.d.ts +142 -0
  25. package/dist/src/parser/scanner.d.ts.map +1 -0
  26. package/dist/src/parser/scanner.js +284 -0
  27. package/dist/src/parser/session-parser.d.ts +35 -0
  28. package/dist/src/parser/session-parser.d.ts.map +1 -0
  29. package/dist/src/parser/session-parser.js +207 -0
  30. package/dist/src/parser/time-parser.d.ts +74 -0
  31. package/dist/src/parser/time-parser.d.ts.map +1 -0
  32. package/dist/src/parser/time-parser.js +168 -0
  33. package/dist/src/serializer/attribute-serializer.d.ts +18 -0
  34. package/dist/src/serializer/attribute-serializer.d.ts.map +1 -0
  35. package/dist/src/serializer/attribute-serializer.js +34 -0
  36. package/dist/src/serializer/field-serializer.d.ts +112 -0
  37. package/dist/src/serializer/field-serializer.d.ts.map +1 -0
  38. package/dist/src/serializer/field-serializer.js +212 -0
  39. package/dist/src/serializer/media-serializer.d.ts +31 -0
  40. package/dist/src/serializer/media-serializer.d.ts.map +1 -0
  41. package/dist/src/serializer/media-serializer.js +83 -0
  42. package/dist/src/serializer/session-serializer.d.ts +29 -0
  43. package/dist/src/serializer/session-serializer.d.ts.map +1 -0
  44. package/dist/src/serializer/session-serializer.js +99 -0
  45. package/dist/src/serializer/time-serializer.d.ts +46 -0
  46. package/dist/src/serializer/time-serializer.d.ts.map +1 -0
  47. package/dist/src/serializer/time-serializer.js +86 -0
  48. package/dist/src/types/attributes.d.ts +318 -0
  49. package/dist/src/types/attributes.d.ts.map +1 -0
  50. package/dist/src/types/attributes.js +225 -0
  51. package/dist/src/types/errors.d.ts +129 -0
  52. package/dist/src/types/errors.d.ts.map +1 -0
  53. package/dist/src/types/errors.js +186 -0
  54. package/dist/src/types/fields.d.ts +100 -0
  55. package/dist/src/types/fields.d.ts.map +1 -0
  56. package/dist/src/types/fields.js +48 -0
  57. package/dist/src/types/media.d.ts +148 -0
  58. package/dist/src/types/media.d.ts.map +1 -0
  59. package/dist/src/types/media.js +137 -0
  60. package/dist/src/types/network.d.ts +136 -0
  61. package/dist/src/types/network.d.ts.map +1 -0
  62. package/dist/src/types/network.js +130 -0
  63. package/dist/src/types/primitives.d.ts +193 -0
  64. package/dist/src/types/primitives.d.ts.map +1 -0
  65. package/dist/src/types/primitives.js +195 -0
  66. package/dist/src/types/session.d.ts +122 -0
  67. package/dist/src/types/session.d.ts.map +1 -0
  68. package/dist/src/types/session.js +81 -0
  69. package/dist/src/types/time.d.ts +129 -0
  70. package/dist/src/types/time.d.ts.map +1 -0
  71. package/dist/src/types/time.js +84 -0
  72. package/dist/src/utils/address-parser.d.ts +100 -0
  73. package/dist/src/utils/address-parser.d.ts.map +1 -0
  74. package/dist/src/utils/address-parser.js +338 -0
  75. package/dist/src/utils/format-validators.d.ts +77 -0
  76. package/dist/src/utils/format-validators.d.ts.map +1 -0
  77. package/dist/src/utils/format-validators.js +504 -0
  78. package/dist/src/utils/line-reader.d.ts +84 -0
  79. package/dist/src/utils/line-reader.d.ts.map +1 -0
  80. package/dist/src/utils/line-reader.js +169 -0
  81. package/dist/src/utils/time-converter.d.ts +99 -0
  82. package/dist/src/utils/time-converter.d.ts.map +1 -0
  83. package/dist/src/utils/time-converter.js +195 -0
  84. package/dist/src/validator/media-validator.d.ts +27 -0
  85. package/dist/src/validator/media-validator.d.ts.map +1 -0
  86. package/dist/src/validator/media-validator.js +241 -0
  87. package/dist/src/validator/semantic-validator.d.ts +47 -0
  88. package/dist/src/validator/semantic-validator.d.ts.map +1 -0
  89. package/dist/src/validator/semantic-validator.js +207 -0
  90. package/dist/src/validator/session-validator.d.ts +36 -0
  91. package/dist/src/validator/session-validator.d.ts.map +1 -0
  92. package/dist/src/validator/session-validator.js +280 -0
  93. package/dist/tests/integration/round-trip.test.d.ts +5 -0
  94. package/dist/tests/integration/round-trip.test.d.ts.map +1 -0
  95. package/dist/tests/integration/round-trip.test.js +320 -0
  96. package/dist/tests/integration/voip-examples.test.d.ts +5 -0
  97. package/dist/tests/integration/voip-examples.test.d.ts.map +1 -0
  98. package/dist/tests/integration/voip-examples.test.js +361 -0
  99. package/dist/tests/unit/builder/media-builder.test.d.ts +5 -0
  100. package/dist/tests/unit/builder/media-builder.test.d.ts.map +1 -0
  101. package/dist/tests/unit/builder/media-builder.test.js +524 -0
  102. package/dist/tests/unit/builder/session-builder.test.d.ts +5 -0
  103. package/dist/tests/unit/builder/session-builder.test.d.ts.map +1 -0
  104. package/dist/tests/unit/builder/session-builder.test.js +367 -0
  105. package/dist/tests/unit/parser/attribute-parser.test.d.ts +5 -0
  106. package/dist/tests/unit/parser/attribute-parser.test.d.ts.map +1 -0
  107. package/dist/tests/unit/parser/attribute-parser.test.js +319 -0
  108. package/dist/tests/unit/parser/field-parser.test.d.ts +5 -0
  109. package/dist/tests/unit/parser/field-parser.test.d.ts.map +1 -0
  110. package/dist/tests/unit/parser/field-parser.test.js +355 -0
  111. package/dist/tests/unit/parser/media-parser.test.d.ts +5 -0
  112. package/dist/tests/unit/parser/media-parser.test.d.ts.map +1 -0
  113. package/dist/tests/unit/parser/media-parser.test.js +241 -0
  114. package/dist/tests/unit/parser/primitive-parser.test.d.ts +5 -0
  115. package/dist/tests/unit/parser/primitive-parser.test.d.ts.map +1 -0
  116. package/dist/tests/unit/parser/primitive-parser.test.js +261 -0
  117. package/dist/tests/unit/parser/scanner.test.d.ts +5 -0
  118. package/dist/tests/unit/parser/scanner.test.d.ts.map +1 -0
  119. package/dist/tests/unit/parser/scanner.test.js +241 -0
  120. package/dist/tests/unit/parser/session-parser.test.d.ts +5 -0
  121. package/dist/tests/unit/parser/session-parser.test.d.ts.map +1 -0
  122. package/dist/tests/unit/parser/session-parser.test.js +346 -0
  123. package/dist/tests/unit/parser/time-parser.test.d.ts +5 -0
  124. package/dist/tests/unit/parser/time-parser.test.d.ts.map +1 -0
  125. package/dist/tests/unit/parser/time-parser.test.js +173 -0
  126. package/dist/tests/unit/serializer/attribute-serializer.test.d.ts +5 -0
  127. package/dist/tests/unit/serializer/attribute-serializer.test.d.ts.map +1 -0
  128. package/dist/tests/unit/serializer/attribute-serializer.test.js +78 -0
  129. package/dist/tests/unit/serializer/field-serializer.test.d.ts +5 -0
  130. package/dist/tests/unit/serializer/field-serializer.test.d.ts.map +1 -0
  131. package/dist/tests/unit/serializer/field-serializer.test.js +159 -0
  132. package/dist/tests/unit/serializer/media-serializer.test.d.ts +5 -0
  133. package/dist/tests/unit/serializer/media-serializer.test.d.ts.map +1 -0
  134. package/dist/tests/unit/serializer/media-serializer.test.js +155 -0
  135. package/dist/tests/unit/serializer/session-serializer.test.d.ts +5 -0
  136. package/dist/tests/unit/serializer/session-serializer.test.d.ts.map +1 -0
  137. package/dist/tests/unit/serializer/session-serializer.test.js +317 -0
  138. package/dist/tests/unit/serializer/time-serializer.test.d.ts +5 -0
  139. package/dist/tests/unit/serializer/time-serializer.test.d.ts.map +1 -0
  140. package/dist/tests/unit/serializer/time-serializer.test.js +115 -0
  141. package/dist/tests/unit/types/errors.test.d.ts +5 -0
  142. package/dist/tests/unit/types/errors.test.d.ts.map +1 -0
  143. package/dist/tests/unit/types/errors.test.js +127 -0
  144. package/dist/tests/unit/types/network.test.d.ts +5 -0
  145. package/dist/tests/unit/types/network.test.d.ts.map +1 -0
  146. package/dist/tests/unit/types/network.test.js +132 -0
  147. package/dist/tests/unit/types/primitives.test.d.ts +5 -0
  148. package/dist/tests/unit/types/primitives.test.d.ts.map +1 -0
  149. package/dist/tests/unit/types/primitives.test.js +108 -0
  150. package/dist/tests/unit/utils/address-parser.test.d.ts +5 -0
  151. package/dist/tests/unit/utils/address-parser.test.d.ts.map +1 -0
  152. package/dist/tests/unit/utils/address-parser.test.js +203 -0
  153. package/dist/tests/unit/utils/format-validators.test.d.ts +5 -0
  154. package/dist/tests/unit/utils/format-validators.test.d.ts.map +1 -0
  155. package/dist/tests/unit/utils/format-validators.test.js +224 -0
  156. package/dist/tests/unit/utils/line-reader.test.d.ts +5 -0
  157. package/dist/tests/unit/utils/line-reader.test.d.ts.map +1 -0
  158. package/dist/tests/unit/utils/line-reader.test.js +157 -0
  159. package/dist/tests/unit/utils/time-converter.test.d.ts +5 -0
  160. package/dist/tests/unit/utils/time-converter.test.d.ts.map +1 -0
  161. package/dist/tests/unit/utils/time-converter.test.js +190 -0
  162. package/dist/tests/unit/validator/media-validator.test.d.ts +5 -0
  163. package/dist/tests/unit/validator/media-validator.test.d.ts.map +1 -0
  164. package/dist/tests/unit/validator/media-validator.test.js +313 -0
  165. package/dist/tests/unit/validator/semantic-validator.test.d.ts +5 -0
  166. package/dist/tests/unit/validator/semantic-validator.test.d.ts.map +1 -0
  167. package/dist/tests/unit/validator/semantic-validator.test.js +262 -0
  168. package/dist/tests/unit/validator/session-validator.test.d.ts +5 -0
  169. package/dist/tests/unit/validator/session-validator.test.d.ts.map +1 -0
  170. package/dist/tests/unit/validator/session-validator.test.js +447 -0
  171. package/package.json +50 -0
@@ -0,0 +1,261 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for primitive-parser.ts
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const scanner_1 = require("../../../src/parser/scanner");
7
+ const primitive_parser_1 = require("../../../src/parser/primitive-parser");
8
+ const errors_1 = require("../../../src/types/errors");
9
+ describe('primitive-parser', () => {
10
+ describe('parseToken', () => {
11
+ it('should parse valid tokens', () => {
12
+ const scanner = new scanner_1.Scanner('RTP');
13
+ const token = (0, primitive_parser_1.parseToken)(scanner);
14
+ expect(token).toBe('RTP');
15
+ });
16
+ it('should parse tokens with various characters', () => {
17
+ const scanner = new scanner_1.Scanner('a1B2-test.name_v123');
18
+ const token = (0, primitive_parser_1.parseToken)(scanner);
19
+ expect(token).toBe('a1B2-test.name_v123');
20
+ });
21
+ it('should stop at whitespace', () => {
22
+ const scanner = new scanner_1.Scanner('token next');
23
+ const token = (0, primitive_parser_1.parseToken)(scanner);
24
+ expect(token).toBe('token');
25
+ expect(scanner.peek()).toBe(' ');
26
+ });
27
+ it('should throw if no token found', () => {
28
+ const scanner = new scanner_1.Scanner(' ');
29
+ expect(() => (0, primitive_parser_1.parseToken)(scanner)).toThrow(errors_1.ParseError);
30
+ });
31
+ });
32
+ describe('parseInteger', () => {
33
+ it('should parse positive integers', () => {
34
+ const scanner = new scanner_1.Scanner('12345');
35
+ const num = (0, primitive_parser_1.parseInteger)(scanner);
36
+ expect(num).toBe(12345);
37
+ });
38
+ it('should parse zero', () => {
39
+ const scanner = new scanner_1.Scanner('0');
40
+ const num = (0, primitive_parser_1.parseInteger)(scanner);
41
+ expect(num).toBe(0);
42
+ });
43
+ it('should stop at non-digit', () => {
44
+ const scanner = new scanner_1.Scanner('123abc');
45
+ const num = (0, primitive_parser_1.parseInteger)(scanner);
46
+ expect(num).toBe(123);
47
+ expect(scanner.peek()).toBe('a');
48
+ });
49
+ it('should throw if no digits found', () => {
50
+ const scanner = new scanner_1.Scanner('abc');
51
+ expect(() => (0, primitive_parser_1.parseInteger)(scanner)).toThrow(errors_1.ParseError);
52
+ });
53
+ });
54
+ describe('parseByte', () => {
55
+ it('should parse valid byte values', () => {
56
+ expect((0, primitive_parser_1.parseByte)(new scanner_1.Scanner('0'))).toBe(0);
57
+ expect((0, primitive_parser_1.parseByte)(new scanner_1.Scanner('128'))).toBe(128);
58
+ expect((0, primitive_parser_1.parseByte)(new scanner_1.Scanner('255'))).toBe(255);
59
+ });
60
+ it('should throw for values > 255', () => {
61
+ expect(() => (0, primitive_parser_1.parseByte)(new scanner_1.Scanner('256'))).toThrow(errors_1.ParseError);
62
+ expect(() => (0, primitive_parser_1.parseByte)(new scanner_1.Scanner('256'))).toThrow('out of range');
63
+ });
64
+ it('should throw for negative values', () => {
65
+ const scanner = new scanner_1.Scanner('-1');
66
+ expect(() => (0, primitive_parser_1.parseByte)(scanner)).toThrow(errors_1.ParseError);
67
+ });
68
+ });
69
+ describe('parseNonWSString', () => {
70
+ it('should parse non-whitespace string', () => {
71
+ const scanner = new scanner_1.Scanner('hello world');
72
+ const str = (0, primitive_parser_1.parseNonWSString)(scanner);
73
+ expect(str).toBe('hello');
74
+ expect(scanner.peek()).toBe(' ');
75
+ });
76
+ it('should stop at newline', () => {
77
+ const scanner = new scanner_1.Scanner('test\nnext');
78
+ const str = (0, primitive_parser_1.parseNonWSString)(scanner);
79
+ expect(str).toBe('test');
80
+ expect(scanner.peek()).toBe('\n');
81
+ });
82
+ it('should throw if starts with whitespace', () => {
83
+ const scanner = new scanner_1.Scanner(' test');
84
+ expect(() => (0, primitive_parser_1.parseNonWSString)(scanner)).toThrow(errors_1.ParseError);
85
+ });
86
+ });
87
+ describe('parseByteString', () => {
88
+ it('should parse byte-string', () => {
89
+ const scanner = new scanner_1.Scanner('test123!@#');
90
+ const str = (0, primitive_parser_1.parseByteString)(scanner);
91
+ expect(str).toBe('test123!@#');
92
+ });
93
+ it('should stop at newline', () => {
94
+ const scanner = new scanner_1.Scanner('test\nnext');
95
+ const str = (0, primitive_parser_1.parseByteString)(scanner);
96
+ expect(str).toBe('test');
97
+ });
98
+ });
99
+ describe('parseIP4Address', () => {
100
+ it('should parse valid IPv4 addresses', () => {
101
+ expect((0, primitive_parser_1.parseIP4Address)(new scanner_1.Scanner('192.168.1.1'))).toBe('192.168.1.1');
102
+ expect((0, primitive_parser_1.parseIP4Address)(new scanner_1.Scanner('0.0.0.0'))).toBe('0.0.0.0');
103
+ expect((0, primitive_parser_1.parseIP4Address)(new scanner_1.Scanner('255.255.255.255'))).toBe('255.255.255.255');
104
+ });
105
+ it('should stop at whitespace', () => {
106
+ const scanner = new scanner_1.Scanner('192.168.1.1 next');
107
+ const addr = (0, primitive_parser_1.parseIP4Address)(scanner);
108
+ expect(addr).toBe('192.168.1.1');
109
+ expect(scanner.peek()).toBe(' ');
110
+ });
111
+ it('should throw for invalid IPv4', () => {
112
+ expect(() => (0, primitive_parser_1.parseIP4Address)(new scanner_1.Scanner('256.1.1.1'))).toThrow(errors_1.ParseError);
113
+ expect(() => (0, primitive_parser_1.parseIP4Address)(new scanner_1.Scanner('192.168.1'))).toThrow(errors_1.ParseError);
114
+ });
115
+ });
116
+ describe('parseIP6Address', () => {
117
+ it('should parse valid IPv6 addresses', () => {
118
+ expect((0, primitive_parser_1.parseIP6Address)(new scanner_1.Scanner('2001:db8::1'))).toBe('2001:db8::1');
119
+ expect((0, primitive_parser_1.parseIP6Address)(new scanner_1.Scanner('::1'))).toBe('::1');
120
+ expect((0, primitive_parser_1.parseIP6Address)(new scanner_1.Scanner('fe80::1'))).toBe('fe80::1');
121
+ });
122
+ it('should parse IPv6 with mixed IPv4', () => {
123
+ const addr = (0, primitive_parser_1.parseIP6Address)(new scanner_1.Scanner('::ffff:192.0.2.1'));
124
+ expect(addr).toBe('::ffff:192.0.2.1');
125
+ });
126
+ it('should stop at whitespace', () => {
127
+ const scanner = new scanner_1.Scanner('2001:db8::1 next');
128
+ const addr = (0, primitive_parser_1.parseIP6Address)(scanner);
129
+ expect(addr).toBe('2001:db8::1');
130
+ expect(scanner.peek()).toBe(' ');
131
+ });
132
+ it('should throw for invalid IPv6', () => {
133
+ expect(() => (0, primitive_parser_1.parseIP6Address)(new scanner_1.Scanner('gggg::1'))).toThrow(errors_1.ParseError);
134
+ expect(() => (0, primitive_parser_1.parseIP6Address)(new scanner_1.Scanner('::1::2'))).toThrow(errors_1.ParseError);
135
+ });
136
+ });
137
+ describe('parseFQDN', () => {
138
+ it('should parse valid FQDNs', () => {
139
+ expect((0, primitive_parser_1.parseFQDN)(new scanner_1.Scanner('example.com'))).toBe('example.com');
140
+ expect((0, primitive_parser_1.parseFQDN)(new scanner_1.Scanner('sub.domain.example.org'))).toBe('sub.domain.example.org');
141
+ expect((0, primitive_parser_1.parseFQDN)(new scanner_1.Scanner('localhost'))).toBe('localhost');
142
+ });
143
+ it('should parse FQDN with hyphens', () => {
144
+ expect((0, primitive_parser_1.parseFQDN)(new scanner_1.Scanner('my-server.example.com'))).toBe('my-server.example.com');
145
+ });
146
+ it('should stop at whitespace', () => {
147
+ const scanner = new scanner_1.Scanner('example.com next');
148
+ const fqdn = (0, primitive_parser_1.parseFQDN)(scanner);
149
+ expect(fqdn).toBe('example.com');
150
+ expect(scanner.peek()).toBe(' ');
151
+ });
152
+ it('should throw for invalid FQDN', () => {
153
+ expect(() => (0, primitive_parser_1.parseFQDN)(new scanner_1.Scanner('-invalid.com'))).toThrow(errors_1.ParseError);
154
+ expect(() => (0, primitive_parser_1.parseFQDN)(new scanner_1.Scanner('invalid-.com'))).toThrow(errors_1.ParseError);
155
+ });
156
+ });
157
+ describe('parseNtpTime', () => {
158
+ it('should parse NTP timestamps', () => {
159
+ expect((0, primitive_parser_1.parseNtpTime)(new scanner_1.Scanner('0'))).toBe(0);
160
+ expect((0, primitive_parser_1.parseNtpTime)(new scanner_1.Scanner('3724394400'))).toBe(3724394400);
161
+ });
162
+ it('should stop at non-digit', () => {
163
+ const scanner = new scanner_1.Scanner('123 456');
164
+ const time = (0, primitive_parser_1.parseNtpTime)(scanner);
165
+ expect(time).toBe(123);
166
+ expect(scanner.peek()).toBe(' ');
167
+ });
168
+ it('should throw for negative values', () => {
169
+ const scanner = new scanner_1.Scanner('-1');
170
+ expect(() => (0, primitive_parser_1.parseNtpTime)(scanner)).toThrow(errors_1.ParseError);
171
+ });
172
+ });
173
+ describe('parseTypedTime', () => {
174
+ it('should parse time with days', () => {
175
+ const time = (0, primitive_parser_1.parseTypedTime)(new scanner_1.Scanner('7d'));
176
+ expect(time.value).toBe(7);
177
+ expect(time.unit).toBe('days');
178
+ });
179
+ it('should parse time with hours', () => {
180
+ const time = (0, primitive_parser_1.parseTypedTime)(new scanner_1.Scanner('3h'));
181
+ expect(time.value).toBe(3);
182
+ expect(time.unit).toBe('hours');
183
+ });
184
+ it('should parse time with minutes', () => {
185
+ const time = (0, primitive_parser_1.parseTypedTime)(new scanner_1.Scanner('120m'));
186
+ expect(time.value).toBe(120);
187
+ expect(time.unit).toBe('minutes');
188
+ });
189
+ it('should parse time with seconds (no suffix)', () => {
190
+ const time = (0, primitive_parser_1.parseTypedTime)(new scanner_1.Scanner('3600'));
191
+ expect(time.value).toBe(3600);
192
+ expect(time.unit).toBe('seconds');
193
+ });
194
+ it('should parse time with explicit seconds', () => {
195
+ const time = (0, primitive_parser_1.parseTypedTime)(new scanner_1.Scanner('30s'));
196
+ expect(time.value).toBe(30);
197
+ expect(time.unit).toBe('seconds');
198
+ });
199
+ it('should stop at whitespace', () => {
200
+ const scanner = new scanner_1.Scanner('7d 3h');
201
+ const time = (0, primitive_parser_1.parseTypedTime)(scanner);
202
+ expect(time.value).toBe(7);
203
+ expect(time.unit).toBe('days');
204
+ expect(scanner.peek()).toBe(' ');
205
+ });
206
+ it('should throw for invalid format', () => {
207
+ expect(() => (0, primitive_parser_1.parseTypedTime)(new scanner_1.Scanner('abc'))).toThrow(errors_1.ParseError);
208
+ });
209
+ });
210
+ describe('parseEmail', () => {
211
+ it('should parse email address', () => {
212
+ const scanner = new scanner_1.Scanner('user@example.com\n');
213
+ const email = (0, primitive_parser_1.parseEmail)(scanner);
214
+ expect(email).toBe('user@example.com');
215
+ });
216
+ it('should parse email with display name', () => {
217
+ const scanner = new scanner_1.Scanner('John Doe <john@example.com>\n');
218
+ const email = (0, primitive_parser_1.parseEmail)(scanner);
219
+ expect(email).toBe('John Doe <john@example.com>');
220
+ });
221
+ it('should stop at newline', () => {
222
+ const scanner = new scanner_1.Scanner('user@example.com\r\nnext line');
223
+ const email = (0, primitive_parser_1.parseEmail)(scanner);
224
+ expect(email).toBe('user@example.com');
225
+ });
226
+ });
227
+ describe('parsePhone', () => {
228
+ it('should parse phone number', () => {
229
+ const scanner = new scanner_1.Scanner('+1-555-1234\n');
230
+ const phone = (0, primitive_parser_1.parsePhone)(scanner);
231
+ expect(phone).toBe('+1-555-1234');
232
+ });
233
+ it('should parse phone with display name', () => {
234
+ const scanner = new scanner_1.Scanner('John Doe +1-555-1234\n');
235
+ const phone = (0, primitive_parser_1.parsePhone)(scanner);
236
+ expect(phone).toBe('John Doe +1-555-1234');
237
+ });
238
+ it('should stop at newline', () => {
239
+ const scanner = new scanner_1.Scanner('+1-555-1234\r\nnext');
240
+ const phone = (0, primitive_parser_1.parsePhone)(scanner);
241
+ expect(phone).toBe('+1-555-1234');
242
+ });
243
+ });
244
+ describe('parseURI', () => {
245
+ it('should parse HTTP URI', () => {
246
+ const scanner = new scanner_1.Scanner('http://example.com/path\n');
247
+ const uri = (0, primitive_parser_1.parseURI)(scanner);
248
+ expect(uri).toBe('http://example.com/path');
249
+ });
250
+ it('should parse HTTPS URI', () => {
251
+ const scanner = new scanner_1.Scanner('https://example.com:8080/path?query=value\n');
252
+ const uri = (0, primitive_parser_1.parseURI)(scanner);
253
+ expect(uri).toBe('https://example.com:8080/path?query=value');
254
+ });
255
+ it('should stop at newline', () => {
256
+ const scanner = new scanner_1.Scanner('http://example.com\r\nnext');
257
+ const uri = (0, primitive_parser_1.parseURI)(scanner);
258
+ expect(uri).toBe('http://example.com');
259
+ });
260
+ });
261
+ });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for scanner.ts
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=scanner.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.test.d.ts","sourceRoot":"","sources":["../../../../tests/unit/parser/scanner.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,241 @@
1
+ "use strict";
2
+ /**
3
+ * Tests for scanner.ts
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const scanner_1 = require("../../../src/parser/scanner");
7
+ const errors_1 = require("../../../src/types/errors");
8
+ describe('Scanner', () => {
9
+ describe('basic operations', () => {
10
+ it('should peek at current character', () => {
11
+ const scanner = new scanner_1.Scanner('abc');
12
+ expect(scanner.peek()).toBe('a');
13
+ expect(scanner.peek()).toBe('a'); // Peek doesn't advance
14
+ });
15
+ it('should return null when peeking at EOF', () => {
16
+ const scanner = new scanner_1.Scanner('');
17
+ expect(scanner.peek()).toBeNull();
18
+ });
19
+ it('should advance through characters', () => {
20
+ const scanner = new scanner_1.Scanner('abc');
21
+ expect(scanner.advance()).toBe('a');
22
+ expect(scanner.advance()).toBe('b');
23
+ expect(scanner.advance()).toBe('c');
24
+ expect(scanner.advance()).toBeNull();
25
+ });
26
+ it('should peek ahead', () => {
27
+ const scanner = new scanner_1.Scanner('abcdef');
28
+ expect(scanner.peekAhead(0)).toBe('a');
29
+ expect(scanner.peekAhead(1)).toBe('b');
30
+ expect(scanner.peekAhead(5)).toBe('f');
31
+ expect(scanner.peekAhead(6)).toBeNull();
32
+ });
33
+ });
34
+ describe('position tracking', () => {
35
+ it('should track line and column', () => {
36
+ const scanner = new scanner_1.Scanner('abc\ndef');
37
+ const pos1 = scanner.getPosition();
38
+ expect(pos1.line).toBe(1);
39
+ expect(pos1.column).toBe(1);
40
+ expect(pos1.offset).toBe(0);
41
+ scanner.advance(); // 'a'
42
+ scanner.advance(); // 'b'
43
+ const pos2 = scanner.getPosition();
44
+ expect(pos2.line).toBe(1);
45
+ expect(pos2.column).toBe(3);
46
+ expect(pos2.offset).toBe(2);
47
+ scanner.advance(); // 'c'
48
+ scanner.advance(); // '\n'
49
+ const pos3 = scanner.getPosition();
50
+ expect(pos3.line).toBe(2);
51
+ expect(pos3.column).toBe(1);
52
+ });
53
+ it('should handle CRLF line endings', () => {
54
+ const scanner = new scanner_1.Scanner('a\r\nb');
55
+ scanner.advance(); // 'a'
56
+ scanner.advance(); // '\r\n'
57
+ const pos = scanner.getPosition();
58
+ expect(pos.line).toBe(2);
59
+ expect(pos.column).toBe(1);
60
+ expect(scanner.peek()).toBe('b');
61
+ });
62
+ it('should handle CR line endings', () => {
63
+ const scanner = new scanner_1.Scanner('a\rb');
64
+ scanner.advance(); // 'a'
65
+ scanner.advance(); // '\r'
66
+ const pos = scanner.getPosition();
67
+ expect(pos.line).toBe(2);
68
+ expect(pos.column).toBe(1);
69
+ expect(scanner.peek()).toBe('b');
70
+ });
71
+ it('should handle LF line endings', () => {
72
+ const scanner = new scanner_1.Scanner('a\nb');
73
+ scanner.advance(); // 'a'
74
+ scanner.advance(); // '\n'
75
+ const pos = scanner.getPosition();
76
+ expect(pos.line).toBe(2);
77
+ expect(pos.column).toBe(1);
78
+ expect(scanner.peek()).toBe('b');
79
+ });
80
+ });
81
+ describe('readUntil', () => {
82
+ it('should read until string delimiter', () => {
83
+ const scanner = new scanner_1.Scanner('hello world');
84
+ const result = scanner.readUntil(' ');
85
+ expect(result).toBe('hello');
86
+ expect(scanner.peek()).toBe(' ');
87
+ });
88
+ it('should read until regex delimiter', () => {
89
+ const scanner = new scanner_1.Scanner('abc123def');
90
+ const result = scanner.readUntil(/\d/);
91
+ expect(result).toBe('abc');
92
+ expect(scanner.peek()).toBe('1');
93
+ });
94
+ it('should read entire input if delimiter not found', () => {
95
+ const scanner = new scanner_1.Scanner('hello');
96
+ const result = scanner.readUntil('x');
97
+ expect(result).toBe('hello');
98
+ expect(scanner.isEOF()).toBe(true);
99
+ });
100
+ });
101
+ describe('readWhile', () => {
102
+ it('should read while predicate is true', () => {
103
+ const scanner = new scanner_1.Scanner('12345abc');
104
+ const result = scanner.readWhile(ch => ch >= '0' && ch <= '9');
105
+ expect(result).toBe('12345');
106
+ expect(scanner.peek()).toBe('a');
107
+ });
108
+ it('should return empty string if predicate immediately false', () => {
109
+ const scanner = new scanner_1.Scanner('abc');
110
+ const result = scanner.readWhile(ch => ch >= '0' && ch <= '9');
111
+ expect(result).toBe('');
112
+ expect(scanner.peek()).toBe('a');
113
+ });
114
+ });
115
+ describe('whitespace handling', () => {
116
+ it('should skip spaces and tabs', () => {
117
+ const scanner = new scanner_1.Scanner(' \t abc');
118
+ scanner.skipWhitespace();
119
+ expect(scanner.peek()).toBe('a');
120
+ });
121
+ it('should not skip newlines', () => {
122
+ const scanner = new scanner_1.Scanner(' \n abc');
123
+ scanner.skipWhitespace();
124
+ expect(scanner.peek()).toBe('\n');
125
+ });
126
+ it('should skip to next line', () => {
127
+ const scanner = new scanner_1.Scanner('hello world\nnext line');
128
+ scanner.skipToNextLine();
129
+ expect(scanner.peek()).toBe('n');
130
+ const pos = scanner.getPosition();
131
+ expect(pos.line).toBe(2);
132
+ });
133
+ });
134
+ describe('expect methods', () => {
135
+ it('should expect exact string', () => {
136
+ const scanner = new scanner_1.Scanner('v=0');
137
+ scanner.expect('v=');
138
+ expect(scanner.peek()).toBe('0');
139
+ });
140
+ it('should throw if string not matched', () => {
141
+ const scanner = new scanner_1.Scanner('o=test');
142
+ expect(() => scanner.expect('v=')).toThrow(errors_1.ParseError);
143
+ });
144
+ it('should throw if string extends past EOF', () => {
145
+ const scanner = new scanner_1.Scanner('v');
146
+ expect(() => scanner.expect('v=')).toThrow(errors_1.ParseError);
147
+ });
148
+ it('should expect character with predicate', () => {
149
+ const scanner = new scanner_1.Scanner('a123');
150
+ const ch = scanner.expectChar(c => c >= 'a' && c <= 'z', 'lowercase letter');
151
+ expect(ch).toBe('a');
152
+ expect(scanner.peek()).toBe('1');
153
+ });
154
+ it('should throw if character does not match predicate', () => {
155
+ const scanner = new scanner_1.Scanner('123');
156
+ expect(() => scanner.expectChar(c => c >= 'a' && c <= 'z', 'lowercase letter')).toThrow(errors_1.ParseError);
157
+ });
158
+ it('should expect space', () => {
159
+ const scanner = new scanner_1.Scanner(' abc');
160
+ scanner.expectSpace();
161
+ expect(scanner.peek()).toBe('a');
162
+ });
163
+ it('should throw if not space', () => {
164
+ const scanner = new scanner_1.Scanner('abc');
165
+ expect(() => scanner.expectSpace()).toThrow(errors_1.ParseError);
166
+ });
167
+ it('should expect end of line (CRLF)', () => {
168
+ const scanner = new scanner_1.Scanner('test\r\nnext');
169
+ scanner.advance();
170
+ scanner.advance();
171
+ scanner.advance();
172
+ scanner.advance();
173
+ scanner.expectEOL();
174
+ expect(scanner.peek()).toBe('n');
175
+ });
176
+ it('should expect end of line (LF)', () => {
177
+ const scanner = new scanner_1.Scanner('test\nnext');
178
+ scanner.advance();
179
+ scanner.advance();
180
+ scanner.advance();
181
+ scanner.advance();
182
+ scanner.expectEOL();
183
+ expect(scanner.peek()).toBe('n');
184
+ });
185
+ it('should accept EOF as EOL', () => {
186
+ const scanner = new scanner_1.Scanner('test');
187
+ scanner.advance();
188
+ scanner.advance();
189
+ scanner.advance();
190
+ scanner.advance();
191
+ scanner.expectEOL(); // Should not throw at EOF
192
+ });
193
+ it('should throw if not at EOL', () => {
194
+ const scanner = new scanner_1.Scanner('test');
195
+ expect(() => scanner.expectEOL()).toThrow(errors_1.ParseError);
196
+ });
197
+ });
198
+ describe('utility methods', () => {
199
+ it('should check if at EOF', () => {
200
+ const scanner = new scanner_1.Scanner('ab');
201
+ expect(scanner.isEOF()).toBe(false);
202
+ scanner.advance();
203
+ expect(scanner.isEOF()).toBe(false);
204
+ scanner.advance();
205
+ expect(scanner.isEOF()).toBe(true);
206
+ });
207
+ it('should get remaining input', () => {
208
+ const scanner = new scanner_1.Scanner('hello world');
209
+ scanner.advance();
210
+ scanner.advance();
211
+ expect(scanner.getRemainingInput()).toBe('llo world');
212
+ });
213
+ it('should get substring', () => {
214
+ const scanner = new scanner_1.Scanner('hello world');
215
+ scanner.advance();
216
+ scanner.advance();
217
+ scanner.advance();
218
+ const sub = scanner.getSubstring(0);
219
+ expect(sub).toBe('hel');
220
+ });
221
+ });
222
+ describe('error context', () => {
223
+ it('should provide context in error messages', () => {
224
+ const scanner = new scanner_1.Scanner('v=0\no=test 123 456 IN IP4 192.168.1.1\ns=Session');
225
+ scanner.advance();
226
+ scanner.advance();
227
+ scanner.advance();
228
+ scanner.advance(); // Move to 'o'
229
+ try {
230
+ scanner.expect('INVALID');
231
+ fail('Should have thrown');
232
+ }
233
+ catch (error) {
234
+ expect(error).toBeInstanceOf(errors_1.ParseError);
235
+ const parseError = error;
236
+ expect(parseError.line).toBe(2);
237
+ expect(parseError.column).toBe(1);
238
+ }
239
+ });
240
+ });
241
+ });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Tests for session-parser.ts
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=session-parser.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-parser.test.d.ts","sourceRoot":"","sources":["../../../../tests/unit/parser/session-parser.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}